m3g/m3gcore11/src/m3g_loader.c
changeset 0 5d03bc08d59c
child 116 171fae344dd4
equal deleted inserted replaced
-1:000000000000 0:5d03bc08d59c
       
     1 /*
       
     2 * Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: Native implementation of the Loader class
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 /*!
       
    20  * \internal
       
    21  * \file
       
    22  * \brief Native implementation of the Loader class
       
    23  *
       
    24 */
       
    25 
       
    26 #include "m3g_object.h"
       
    27 #include "m3g_array.h"
       
    28 
       
    29 /*----------------------------------------------------------------------
       
    30  * Internal data types
       
    31  *--------------------------------------------------------------------*/
       
    32 
       
    33 /*!
       
    34  * \internal
       
    35  * \brief Possible global states for the loader
       
    36  */
       
    37 typedef enum {
       
    38     /*! \internal \brief Loading not supported yet */
       
    39     LOADSTATE_NOT_SUPPORTED = -2,
       
    40     /*! \internal \brief Loading has terminated with an error */
       
    41     LOADSTATE_ERROR         = -1,
       
    42     /*! \internal \brief Loading has not started yet */
       
    43     LOADSTATE_INITIAL       =  0,
       
    44     /*! \internal \brief The identifier of the file is being read */
       
    45     LOADSTATE_IDENTIFIER,
       
    46     /*! \internal \brief The header of the section is being read */
       
    47     LOADSTATE_SECTION,
       
    48     /*! \internal \brief The header field of an object is being read */
       
    49     LOADSTATE_OBJECT,
       
    50     /*! \internal \brief Loading is finished */
       
    51     LOADSTATE_DONE
       
    52 } LoaderState;
       
    53 
       
    54 /*!
       
    55  * \internal
       
    56  * \brief Possible local states for the loader
       
    57  */
       
    58 typedef enum {
       
    59     /*! \internal \brief Local state is entered */
       
    60     LOADSTATE_ENTER,
       
    61     /*! \internal \brief Local state is exited */
       
    62     LOADSTATE_EXIT,
       
    63     /*! \internal \brief Local state is section checksum */
       
    64     LOADSTATE_CHECKSUM
       
    65 } LoaderLocalState;
       
    66 
       
    67 /*!
       
    68  * \internal
       
    69  * \brief Buffered byte stream class
       
    70  */
       
    71 typedef struct
       
    72 {
       
    73     M3Gubyte *allocatedData;
       
    74     M3Gubyte *data;
       
    75     M3Gsizei capacity, bytesAvailable, totalBytes;
       
    76 } BufferedStream;
       
    77 
       
    78 /*!
       
    79  * \internal
       
    80  * \brief User data for a loaded object
       
    81  */
       
    82 typedef struct
       
    83 {
       
    84     M3GObject object;
       
    85     M3Gint numParams;
       
    86     M3Gbyte **params;
       
    87     M3Gsizei *paramLengths;
       
    88     M3Gint *paramId;
       
    89 } UserData;
       
    90 
       
    91 /*!
       
    92  * \internal
       
    93  * \brief Loader instance data
       
    94  */
       
    95 typedef struct M3GLoaderImpl
       
    96 {
       
    97     Object object;
       
    98 
       
    99     BufferedStream stream;
       
   100     M3Gsizei bytesRequired;
       
   101     M3Gsizei sectionBytesRequired;
       
   102 
       
   103     PointerArray refArray;
       
   104     PointerArray userDataArray;
       
   105 
       
   106     /*!
       
   107      * \internal
       
   108      * \brief The global state the loader is in
       
   109      *
       
   110      * This is a rather ordinary state machine thing; basically the
       
   111      * type of object being loaded, or one of the possible error
       
   112      * conditions. In here, it also amounts to a particular coroutine
       
   113      * execution context.
       
   114      */
       
   115     LoaderState state;
       
   116 
       
   117     /*!
       
   118      * \internal
       
   119      * \brief The local state of the loader
       
   120      *
       
   121      * This is basically the line number within a particular coroutine
       
   122      * function.
       
   123      */
       
   124     M3Gint localState;
       
   125 
       
   126     /*!
       
   127      * \internal
       
   128      * \brief Object being loaded
       
   129      */
       
   130     M3Gint objectType;
       
   131 
       
   132     /*!
       
   133      * \internal
       
   134      * \brief Loaded object
       
   135      */
       
   136     M3GObject loadedObject;
       
   137 
       
   138     /*!
       
   139      * \internal
       
   140      * \brief Pointer to the beginning of an object
       
   141      */
       
   142     M3Gubyte *objectData;
       
   143 
       
   144     /*!
       
   145      * \internal
       
   146      * \brief Pointer to the end of an object
       
   147      */
       
   148     M3Gubyte *objectDataEnd;
       
   149 
       
   150     /*!
       
   151      * \internal
       
   152      * \brief Pointer to the context data for the current coroutine
       
   153      * context
       
   154      */
       
   155     M3Gubyte *localData;
       
   156 
       
   157     /*!
       
   158      * \internal
       
   159      * \brief Size of the current coroutine data
       
   160      *
       
   161      * This is grown dynamically as necessary, rather than trying to
       
   162      * maintain a single size that fits all coroutines.
       
   163      */
       
   164     size_t localDataSize;
       
   165 
       
   166     /* File information */
       
   167     M3Gbool hasReferences;
       
   168     M3Gsizei fileSize;
       
   169     M3Gsizei contentSize;
       
   170     M3Gint triCount;
       
   171     M3Gint triConstraint;
       
   172 
       
   173     /* Section information */
       
   174     M3Gbool compressed;
       
   175     M3Gint sectionLength;
       
   176     M3Gint sectionNum;
       
   177     M3Gint inflatedLength;
       
   178     M3Gubyte *sectionData;
       
   179     M3Gubyte *allocatedSectionData;
       
   180     
       
   181     /* Adler data */
       
   182     M3Gint S12[2];
       
   183 } Loader;
       
   184 
       
   185 typedef struct {
       
   186     const unsigned char *data;
       
   187     int read;
       
   188     int length;
       
   189 } compressedData;
       
   190 
       
   191 /* Type ID used for classifying objects derived from Node */
       
   192 #define ANY_NODE_CLASS ((M3GClass)(-1))
       
   193 
       
   194 #include <string.h>
       
   195 #define m3gCmp(s1, s2, len)  memcmp(s1, s2, len)
       
   196 
       
   197 /*----------------------------------------------------------------------
       
   198  * Private constants
       
   199  *--------------------------------------------------------------------*/
       
   200 
       
   201 #define M3G_MIN_OBJECT_SIZE     (1 + 4)
       
   202 #define M3G_MIN_SECTION_SIZE    (1 + 4 + 4)
       
   203 #define M3G_CHECKSUM_SIZE       4
       
   204 
       
   205 #define M3G_ADLER_CONST         65521;
       
   206 
       
   207 static const M3Gubyte M3G_FILE_IDENTIFIER[] = {
       
   208     0xAB, 0x4A, 0x53, 0x52, 0x31, 0x38, 0x34, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
       
   209 };
       
   210 
       
   211 static const M3Gubyte PNG_FILE_IDENTIFIER[] = {
       
   212     0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a
       
   213 };
       
   214 
       
   215 static void m3gCleanupLoader(M3GLoader loader);
       
   216 
       
   217 /*----------------------------------------------------------------------
       
   218  * Platform-specific "inflate" decompression code
       
   219  *--------------------------------------------------------------------*/
       
   220 
       
   221 /*!
       
   222  * \internal
       
   223  * \brief Decompresses a block of data into an output buffer
       
   224  *
       
   225  * \param srcLength number of bytes in the input (compressed) buffer
       
   226  * \param src       pointer to the input buffer
       
   227  * \param dstLength number of bytes allocated in the output buffer
       
   228  * \param dst       pointer to the output buffer
       
   229  * \return the number of bytes written to \c dst
       
   230  */
       
   231 static M3Gsizei m3gInflateBlock(M3Gsizei srcLength, const M3Gubyte *src,
       
   232                                 M3Gsizei dstLength, M3Gubyte *dst);
       
   233                            
       
   234 /* Include the platform-dependent implementation */
       
   235 #if !defined(M3G_TARGET_GENERIC)
       
   236 #   include "m3g_loader_inflate.inl"
       
   237 #endif
       
   238 
       
   239 /*----------------------------------------------------------------------
       
   240  * Private functions
       
   241  *--------------------------------------------------------------------*/
       
   242 
       
   243 /*!
       
   244  * \internal
       
   245  * \brief Destructor
       
   246  */
       
   247 static void m3gDestroyLoader(Object *obj)
       
   248 {
       
   249     Loader* loader = (Loader *) obj;
       
   250     M3G_VALIDATE_OBJECT(loader);
       
   251     {
       
   252         Interface *m3g = M3G_INTERFACE(loader);
       
   253         M3Gint n, i;
       
   254 
       
   255         m3gCleanupLoader(loader);
       
   256         m3gDestroyArray(&loader->refArray, m3g);
       
   257         n = m3gArraySize(&loader->userDataArray);
       
   258         for (i = 0; i < n; ++i)
       
   259         {
       
   260             UserData *data = (UserData *)m3gGetArrayElement(&loader->userDataArray, i);
       
   261             m3gFree(m3g, data->params);
       
   262             m3gFree(m3g, data->paramLengths);
       
   263             m3gFree(m3g, data->paramId);
       
   264             m3gFree(m3g, data);
       
   265         }
       
   266         m3gDestroyArray(&loader->userDataArray, m3g);
       
   267         m3gFree(m3g, loader->stream.allocatedData);
       
   268         m3gFree(m3g, loader->allocatedSectionData);
       
   269     }
       
   270     m3gDestroyObject(obj);
       
   271 }
       
   272 
       
   273 /*!
       
   274  * \internal
       
   275  * \brief Stores new data in the stream buffer of this loader
       
   276  */
       
   277 static M3Gbool m3gBufferData( M3GInterface m3g,
       
   278                            BufferedStream *stream,
       
   279                            M3Gsizei bytes,
       
   280                            const M3Gubyte *data)
       
   281 {
       
   282     M3Gsizei used;
       
   283 
       
   284     /* Allocate initial buffer */
       
   285     if (stream->allocatedData == NULL) {
       
   286         stream->capacity = bytes + 512;
       
   287         stream->allocatedData = m3gAllocZ(m3g, stream->capacity);
       
   288         if (!stream->allocatedData) {
       
   289             return M3G_FALSE;
       
   290         }
       
   291         stream->data = stream->allocatedData;
       
   292         stream->bytesAvailable = 0;
       
   293         stream->totalBytes = 0;
       
   294     }
       
   295 
       
   296     /* First skip used bytes */
       
   297     used = stream->data - stream->allocatedData;
       
   298     if (used > 0) {
       
   299         m3gMove(stream->allocatedData, stream->data, stream->bytesAvailable);
       
   300         stream->data = stream->allocatedData;
       
   301     }
       
   302 
       
   303     /* Check if new data fits in current buffer */
       
   304     if ((stream->capacity - stream->bytesAvailable) < bytes) {
       
   305         M3Gubyte *newData;
       
   306         stream->capacity = stream->capacity + bytes + 512;
       
   307         newData = m3gAllocZ(m3g, stream->capacity);
       
   308         if (!newData) {
       
   309             m3gFree(m3g, stream->allocatedData);
       
   310             stream->allocatedData = NULL;
       
   311             return M3G_FALSE;
       
   312         }
       
   313         m3gCopy(newData, stream->data, stream->bytesAvailable);
       
   314         m3gFree(m3g, stream->allocatedData);
       
   315         stream->allocatedData = newData;
       
   316         stream->data = stream->allocatedData;
       
   317     }
       
   318 
       
   319     m3gCopy(stream->data + stream->bytesAvailable, data, bytes);
       
   320     stream->bytesAvailable += bytes;
       
   321 
       
   322     return M3G_TRUE;
       
   323 }
       
   324 
       
   325 /*!
       
   326  * \internal
       
   327  * \brief Resets buffered data
       
   328  */
       
   329 static void m3gResetBufferedData(BufferedStream *stream)
       
   330 {
       
   331     stream->bytesAvailable = 0;
       
   332     stream->data = stream->allocatedData;
       
   333     stream->totalBytes = 0;
       
   334 }
       
   335 
       
   336 /*!
       
   337  * \internal
       
   338  * \brief Gets buffered data pointer
       
   339  */
       
   340 static M3Gubyte *m3gGetBufferedDataPtr(BufferedStream *stream, M3Gint length)
       
   341 {
       
   342     if (stream->bytesAvailable >= length) {
       
   343         return stream->data;
       
   344     }
       
   345     else {
       
   346         return NULL;
       
   347     }
       
   348 }
       
   349 
       
   350 /*!
       
   351  * \internal
       
   352  * \brief Advances buffered data pointer
       
   353  */
       
   354 static void m3gAdvanceBufferedData(BufferedStream *stream, M3Gint length)
       
   355 {
       
   356     stream->data += length;
       
   357     stream->bytesAvailable -= length;
       
   358     stream->totalBytes += length;
       
   359 }
       
   360 
       
   361 /*!
       
   362  * \internal
       
   363  * \brief Verify a boolean
       
   364  */
       
   365 static M3Gbool m3gVerifyBool(M3Gubyte *data)
       
   366 {
       
   367     return (*data == 0 || *data == 1);
       
   368 }
       
   369 
       
   370 /*!
       
   371  * \internal
       
   372  * \brief Loads ARGB color from data array
       
   373  */
       
   374 static M3Guint m3gLoadARGB(M3Gubyte *data)
       
   375 {
       
   376     M3Guint v = data[3];
       
   377     v <<= 8;
       
   378     v |=  data[0];
       
   379     v <<= 8;
       
   380     v |=  data[1];
       
   381     v <<= 8;
       
   382     v |=  data[2];
       
   383 
       
   384     return v;
       
   385 }
       
   386 
       
   387 /*!
       
   388  * \internal
       
   389  * \brief Loads RGB color from data array
       
   390  */
       
   391 static M3Guint m3gLoadRGB(M3Gubyte *data)
       
   392 {
       
   393     M3Guint v = data[0];
       
   394     v <<= 8;
       
   395     v |=  data[1];
       
   396     v <<= 8;
       
   397     v |=  data[2];
       
   398 
       
   399     return v;
       
   400 }
       
   401 
       
   402 /*!
       
   403  * \internal
       
   404  * \brief Loads short from data array
       
   405  */
       
   406 static M3Gshort m3gLoadShort(M3Gubyte *data)
       
   407 {
       
   408     M3Gshort v = data[1];
       
   409     v <<= 8;
       
   410     v |=  data[0];
       
   411 
       
   412     return v;
       
   413 }
       
   414 
       
   415 /*!
       
   416  * \internal
       
   417  * \brief Loads integer from data array
       
   418  */
       
   419 static M3Gint m3gLoadInt(M3Gubyte *data)
       
   420 {
       
   421     M3Gint v = data[3];
       
   422     v <<= 8;
       
   423     v |=  data[2];
       
   424     v <<= 8;
       
   425     v |=  data[1];
       
   426     v <<= 8;
       
   427     v |=  data[0];
       
   428 
       
   429     return v;
       
   430 }
       
   431 
       
   432 /*!
       
   433  * \internal
       
   434  * \brief Loads integer from data array
       
   435  */
       
   436 static M3Gbool m3gLoadFloat(M3Gubyte *data, M3Gfloat *res)
       
   437 {
       
   438     M3Guint v = data[3];
       
   439     v <<= 8;
       
   440     v |=  data[2];
       
   441     v <<= 8;
       
   442     v |=  data[1];
       
   443     v <<= 8;
       
   444     v |=  data[0];
       
   445 
       
   446     *res = (*(M3Gfloat*)&(v));
       
   447     if ((v & 0x7f800000) ==  0x7f800000 ||
       
   448         v == 0x80000000 || // negative zero
       
   449         ((v & 0x007FFFFF ) != 0 && ( v & 0x7F800000 ) == 0))
       
   450         return M3G_FALSE;
       
   451     return M3G_TRUE;
       
   452 }
       
   453 
       
   454 /*!
       
   455  * \internal
       
   456  * \brief Loads 4 * 4 matrix from data array
       
   457  */
       
   458 static M3Gbool m3gLoadMatrix(Matrix *m, M3Gubyte *data)
       
   459 {
       
   460     M3Gint i;
       
   461     M3Gfloat array[16];
       
   462 
       
   463     for (i = 0; i < 16; i++) {
       
   464         if (!m3gLoadFloat(data + 4 * i, &array[i]))
       
   465             return M3G_FALSE;
       
   466     }
       
   467 
       
   468     m3gSetMatrixRows(m, array);
       
   469     return M3G_TRUE;
       
   470 }
       
   471 
       
   472 /*!
       
   473  * \internal
       
   474  * \brief Inflates a section
       
   475  */
       
   476 static M3Gubyte *m3gInflateSection(Loader *loader,
       
   477                                    M3Gubyte *compressed,
       
   478                                    M3Gint cLength, M3Gint iLength)
       
   479 {
       
   480     M3Gubyte *inflated = m3gAllocZ(M3G_INTERFACE(loader), iLength);
       
   481     if (inflated && !m3gInflateBlock(cLength, compressed, iLength, inflated)) {
       
   482         m3gFree(M3G_INTERFACE(loader), inflated);
       
   483         return NULL;
       
   484     }
       
   485 
       
   486     return inflated;
       
   487 }
       
   488 
       
   489 /*!
       
   490  * \internal
       
   491  * \brief Loads file identifier
       
   492  */
       
   493 static LoaderState m3gLoadIdentifier(Loader *loader)
       
   494 {
       
   495     M3Gubyte *data = m3gGetBufferedDataPtr(&loader->stream, loader->bytesRequired);
       
   496 
       
   497     if (loader->localState == LOADSTATE_ENTER) {
       
   498         if (m3gCmp(data, PNG_FILE_IDENTIFIER, sizeof(PNG_FILE_IDENTIFIER)) == 0) {
       
   499             m3gAdvanceBufferedData(&loader->stream, loader->bytesRequired);
       
   500             return LOADSTATE_NOT_SUPPORTED;
       
   501         }
       
   502         else {
       
   503             loader->localState = LOADSTATE_EXIT;
       
   504             loader->bytesRequired = sizeof(M3G_FILE_IDENTIFIER);
       
   505             return LOADSTATE_IDENTIFIER;
       
   506         }
       
   507     }
       
   508     else {
       
   509         if (m3gCmp(data, M3G_FILE_IDENTIFIER, sizeof(M3G_FILE_IDENTIFIER)) == 0) {
       
   510             m3gAdvanceBufferedData(&loader->stream, loader->bytesRequired);
       
   511             loader->localState = LOADSTATE_ENTER;
       
   512             loader->bytesRequired = M3G_MIN_SECTION_SIZE;
       
   513             return LOADSTATE_SECTION;
       
   514         }
       
   515 
       
   516         loader->bytesRequired = 0;
       
   517         return LOADSTATE_ERROR;
       
   518     }
       
   519 }
       
   520 
       
   521 /*!
       
   522  * \internal
       
   523  * \brief Adler helper functions
       
   524  */
       
   525 
       
   526 static void m3gInitAdler(M3Gint *S12)
       
   527 {
       
   528     S12[0] = 1; S12[1] = 0;
       
   529 }
       
   530 
       
   531 static void m3gUpdateAdler(M3Gint *S12, M3Gubyte *data, M3Gint length)
       
   532 {
       
   533     int i;
       
   534     for (i = 0; i < length; i++) {
       
   535         S12[0] = (S12[0] + data[i]) % M3G_ADLER_CONST;
       
   536         S12[1] = (S12[1] + S12[0])  % M3G_ADLER_CONST;
       
   537     }
       
   538 }
       
   539 
       
   540 static M3Gint m3gGetAdler(M3Gint *S12)
       
   541 {
       
   542     return (S12[1] << 16) | S12[0];
       
   543 }
       
   544 
       
   545 /*!
       
   546  * \internal
       
   547  * \brief Loads a section
       
   548  */
       
   549 static LoaderState m3gLoadSection(Loader *loader)
       
   550 {
       
   551     M3Gubyte *data = m3gGetBufferedDataPtr(&loader->stream, loader->bytesRequired);
       
   552 
       
   553     if (data == NULL) {
       
   554         m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
       
   555         return LOADSTATE_ERROR;
       
   556     }
       
   557 
       
   558     switch(loader->localState) {
       
   559     case LOADSTATE_ENTER:
       
   560         m3gAdvanceBufferedData(&loader->stream, loader->bytesRequired);
       
   561         m3gInitAdler(loader->S12);
       
   562         m3gUpdateAdler(loader->S12, data, loader->bytesRequired);
       
   563 
       
   564         if (*data > 1)
       
   565         {
       
   566             m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
       
   567             return LOADSTATE_ERROR;
       
   568         }
       
   569         loader->compressed = data[0];
       
   570         loader->sectionLength = m3gLoadInt(data + 1);
       
   571         loader->inflatedLength = m3gLoadInt(data + 5);
       
   572 
       
   573         loader->localState = LOADSTATE_EXIT;
       
   574         loader->bytesRequired = loader->sectionLength - loader->bytesRequired;
       
   575         if (!loader->compressed && loader->inflatedLength != (loader->bytesRequired - M3G_CHECKSUM_SIZE))
       
   576         {
       
   577             m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
       
   578             return LOADSTATE_ERROR;
       
   579         }
       
   580 
       
   581         loader->sectionNum++;
       
   582 
       
   583         /* Special case for empty sections */
       
   584         if (loader->bytesRequired == M3G_CHECKSUM_SIZE) {
       
   585             loader->localData = data + loader->sectionLength - M3G_CHECKSUM_SIZE;
       
   586             loader->sectionData = loader->localData;
       
   587             loader->compressed = M3G_FALSE;
       
   588             loader->localState = LOADSTATE_CHECKSUM;
       
   589         }
       
   590         return LOADSTATE_SECTION;
       
   591 
       
   592     case LOADSTATE_EXIT:
       
   593     default:
       
   594         m3gUpdateAdler(loader->S12, data, loader->bytesRequired - M3G_CHECKSUM_SIZE);
       
   595 
       
   596         if (loader->compressed) {
       
   597             if (loader->inflatedLength > 0) {
       
   598                 m3gFree(M3G_INTERFACE(loader), loader->allocatedSectionData);
       
   599                 loader->sectionData = m3gInflateSection(loader, data, loader->bytesRequired, loader->inflatedLength);
       
   600                 loader->allocatedSectionData = loader->sectionData;
       
   601 
       
   602                 if (!loader->sectionData) {
       
   603                     if (m3gErrorRaised(M3G_INTERFACE(loader)) == M3G_NO_ERROR)
       
   604                         m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
       
   605                     return LOADSTATE_ERROR;
       
   606                 }
       
   607             }
       
   608             else {
       
   609                 loader->sectionData = NULL;
       
   610             }
       
   611         }
       
   612         else {
       
   613             loader->sectionData = data;
       
   614         }
       
   615 
       
   616         loader->localData = loader->sectionData;
       
   617         loader->sectionBytesRequired = M3G_MIN_OBJECT_SIZE;
       
   618         loader->localState = LOADSTATE_ENTER;
       
   619         return LOADSTATE_OBJECT;
       
   620 
       
   621     case LOADSTATE_CHECKSUM:
       
   622         if (loader->localData != loader->sectionData + loader->inflatedLength || /* Length */
       
   623             m3gLoadInt(data + loader->bytesRequired - M3G_CHECKSUM_SIZE) != m3gGetAdler(loader->S12))
       
   624         {
       
   625             m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
       
   626             m3gFree(M3G_INTERFACE(loader), loader->allocatedSectionData);
       
   627             loader->allocatedSectionData = NULL;
       
   628             return LOADSTATE_ERROR;
       
   629         }
       
   630         m3gAdvanceBufferedData(&loader->stream, loader->bytesRequired);
       
   631 
       
   632         m3gFree(M3G_INTERFACE(loader), loader->allocatedSectionData);
       
   633         loader->allocatedSectionData = NULL;
       
   634 
       
   635         loader->localState = LOADSTATE_ENTER;
       
   636         loader->bytesRequired = M3G_MIN_SECTION_SIZE;
       
   637         return LOADSTATE_SECTION;
       
   638     }
       
   639 }
       
   640 
       
   641 /*!
       
   642  * \internal
       
   643  * \brief Resets section data pointer to the beginning of an object
       
   644  */
       
   645 static void m3gRewindObject(Loader *loader)
       
   646 {
       
   647     loader->localData = loader->objectData;
       
   648 }
       
   649 
       
   650 /*!
       
   651  * \internal
       
   652  * \brief Resets section data pointer to the end of an object
       
   653  */
       
   654 static void m3gSkipObject(Loader *loader)
       
   655 {
       
   656     loader->localData = loader->objectDataEnd;
       
   657 }
       
   658 
       
   659 /*!
       
   660  * \internal
       
   661  * \brief Marks object to begin
       
   662  */
       
   663 static void m3gBeginObject(Loader *loader)
       
   664 {
       
   665     loader->objectData = loader->localData;
       
   666 }
       
   667 
       
   668 /*!
       
   669  * \internal
       
   670  * \brief Marks object to end
       
   671  */
       
   672 static void m3gEndObject(Loader *loader)
       
   673 {
       
   674     loader->objectDataEnd = loader->localData;
       
   675 }
       
   676 
       
   677 /*!
       
   678  * \internal
       
   679  * \brief Gets section data pointer
       
   680  */
       
   681 static M3Gubyte *m3gGetSectionDataPtr(Loader *loader, M3Gint length)
       
   682 {
       
   683     if ((loader->localData + length) <= (loader->sectionData + loader->inflatedLength)) {
       
   684         return loader->localData;
       
   685     }
       
   686     else {
       
   687         return NULL;
       
   688     }
       
   689 }
       
   690 
       
   691 /*!
       
   692  * \internal
       
   693  * \brief Advances section data pointer
       
   694  */
       
   695 static void m3gAdvanceSectionData(Loader *loader, M3Gint length)
       
   696 {
       
   697     loader->localData += length;
       
   698 }
       
   699 
       
   700 /*!
       
   701  * \internal
       
   702  * \brief Check length of the available section data
       
   703  */
       
   704 static M3Gbool m3gCheckSectionDataLength(Loader *loader, const M3Gubyte *data, M3Gsizei length)
       
   705 {
       
   706     if (data + length < data) return M3G_FALSE; /* Check for overflow */
       
   707     return ((data + length) <= (loader->sectionData + loader->inflatedLength));
       
   708 }
       
   709 
       
   710 /*!
       
   711  * \internal
       
   712  * \brief References an object in the object array
       
   713  *
       
   714  * \note Uses lowest bit of the pointer to mark a reference
       
   715  */
       
   716 static void m3gReferenceLoaded(PointerArray *array, M3Gint idx)
       
   717 {
       
   718     M3Guint ptr = (M3Guint)m3gGetArrayElement(array, idx);
       
   719     ptr |= 1;
       
   720     m3gSetArrayElement(array, idx, (void *)ptr);
       
   721 }
       
   722 
       
   723 /*!
       
   724  * \internal
       
   725  * \brief Gets an object in the object array and
       
   726  * returns reference status
       
   727  */
       
   728 static M3GObject m3gGetLoadedPtr(PointerArray *array, M3Gint idx, M3Gbool *referenced)
       
   729 {
       
   730     M3Guint ptr = (M3Guint)m3gGetArrayElement(array, idx);
       
   731     if (referenced != NULL) {
       
   732         *referenced = ptr & 1;
       
   733     }
       
   734     return (M3GObject)(ptr & (~1));
       
   735 }
       
   736 
       
   737 /*!
       
   738  * \internal
       
   739  * \brief Gets a loaded object and marks it referenced
       
   740  */
       
   741 static M3GObject m3gGetLoaded(Loader *loader, M3Gint idx, M3GClass classID)
       
   742 {
       
   743     M3GObject obj;
       
   744     M3GClass objClassID;
       
   745     M3Gbool isCompatible;
       
   746 
       
   747     if (idx == 0) return NULL;
       
   748     idx -= 2;
       
   749 
       
   750     if (idx < 0 || idx >= m3gArraySize(&loader->refArray)) {
       
   751         /* Error, not loaded */
       
   752         m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
       
   753         return NULL;
       
   754     }
       
   755 
       
   756     obj = m3gGetLoadedPtr(&loader->refArray, idx, NULL);
       
   757     objClassID = M3G_CLASS(obj);
       
   758 
       
   759     /* Class type check; handle nodes as a special case */
       
   760     
       
   761     if (classID == ANY_NODE_CLASS) {
       
   762         switch (objClassID) {
       
   763         case M3G_CLASS_CAMERA:
       
   764         case M3G_CLASS_GROUP:
       
   765         case M3G_CLASS_LIGHT:
       
   766         case M3G_CLASS_MESH:
       
   767         case M3G_CLASS_MORPHING_MESH:
       
   768         case M3G_CLASS_SKINNED_MESH:
       
   769         case M3G_CLASS_SPRITE:
       
   770         case M3G_CLASS_WORLD:
       
   771             isCompatible = M3G_TRUE;
       
   772             break;
       
   773         default:
       
   774             isCompatible = M3G_FALSE;
       
   775         }
       
   776     }
       
   777     else {
       
   778         switch (classID) {
       
   779         case M3G_ABSTRACT_CLASS:
       
   780             M3G_ASSERT(M3G_FALSE);
       
   781             isCompatible = M3G_FALSE;
       
   782             break;
       
   783         case M3G_CLASS_MESH:
       
   784             isCompatible = (classID == M3G_CLASS_MESH)
       
   785                 || (classID == M3G_CLASS_MORPHING_MESH)
       
   786                 || (classID == M3G_CLASS_SKINNED_MESH);
       
   787             break;
       
   788         default:
       
   789             isCompatible = (classID == objClassID);
       
   790         }
       
   791     }
       
   792 
       
   793     if (!isCompatible) {
       
   794         /* Error, class mismatch */
       
   795         m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
       
   796         return NULL;
       
   797     }
       
   798 
       
   799     /* Mark object as referenced */
       
   800     m3gReferenceLoaded(&loader->refArray, idx);
       
   801     return obj;
       
   802 }
       
   803 
       
   804 /*!
       
   805  * \internal
       
   806  * \brief Loads Object3D data
       
   807  */
       
   808 static M3Gbool m3gLoadObject3DData(Loader *loader, M3GObject obj)
       
   809 {
       
   810     M3Guint animTracks, i, userParams, paramId, paramLength;
       
   811     UserData *userData = NULL;
       
   812     M3Gubyte *data = m3gGetSectionDataPtr(loader, 8);
       
   813     if (data == NULL) return M3G_FALSE;
       
   814 
       
   815     m3gSetUserID(obj, m3gLoadInt(data));
       
   816     data += 4;
       
   817 
       
   818     animTracks = m3gLoadInt(data);
       
   819     data += 4;
       
   820 
       
   821     /* Overflow? */
       
   822     if (animTracks >= 0x1fffffff) {
       
   823         return M3G_FALSE;
       
   824     }
       
   825 
       
   826     if (m3gCheckSectionDataLength(loader, data, animTracks * 4 + 4) == M3G_FALSE) return M3G_FALSE;
       
   827     for (i = 0; i < animTracks; i++) {
       
   828         M3GAnimationTrack at = (M3GAnimationTrack)m3gGetLoaded(loader, m3gLoadInt(data),M3G_CLASS_ANIMATION_TRACK);
       
   829         if (at == NULL || m3gAddAnimationTrack(obj, at) == -1) {
       
   830             return M3G_FALSE;
       
   831         }
       
   832         data += 4;
       
   833     }
       
   834 
       
   835     userParams = m3gLoadInt(data);
       
   836     data += 4;
       
   837 
       
   838     if (userParams != 0) {
       
   839         /* Overflow? */
       
   840         if (userParams >= 0x10000000) {
       
   841             return M3G_FALSE;
       
   842         }
       
   843 
       
   844         if (m3gCheckSectionDataLength(loader, data, userParams * 8) == M3G_FALSE)
       
   845             return M3G_FALSE; /* Check the minimum size to avoid useless allocation */
       
   846         userData = (UserData *)m3gAllocZ(M3G_INTERFACE(loader), sizeof(UserData));
       
   847         if (userData == NULL)
       
   848             return M3G_FALSE;
       
   849         userData->object = obj;
       
   850         userData->numParams = userParams;
       
   851         userData->params = (M3Gbyte **)m3gAllocZ(M3G_INTERFACE(loader), userParams*sizeof(M3Gbyte *));
       
   852         userData->paramLengths = (M3Gsizei *)m3gAlloc(M3G_INTERFACE(loader), userParams*sizeof(M3Gsizei));
       
   853         userData->paramId = (M3Gint *)m3gAlloc(M3G_INTERFACE(loader), userParams*sizeof(M3Gint));
       
   854         if (userData->params == NULL ||
       
   855             userData->paramLengths == NULL ||
       
   856             userData->paramId == NULL ||
       
   857             m3gArrayAppend(&loader->userDataArray, userData, M3G_INTERFACE(loader)) == -1) {
       
   858             m3gFree(M3G_INTERFACE(loader), userData->params);
       
   859             m3gFree(M3G_INTERFACE(loader), userData->paramLengths);
       
   860             m3gFree(M3G_INTERFACE(loader), userData->paramId);
       
   861             m3gFree(M3G_INTERFACE(loader), userData);
       
   862             return M3G_FALSE;
       
   863         }
       
   864 
       
   865         for (i = 0; i < userParams; i++) {
       
   866             if (m3gCheckSectionDataLength(loader, data, 8) == M3G_FALSE) return M3G_FALSE;
       
   867             paramId = m3gLoadInt(data);
       
   868             data += 4;
       
   869             paramLength = m3gLoadInt(data);
       
   870             data += 4;
       
   871             userData->paramId[i] = paramId;
       
   872             userData->paramLengths[i] = paramLength;
       
   873             if (m3gCheckSectionDataLength(loader, data, paramLength) == M3G_FALSE) return M3G_FALSE;
       
   874             userData->params[i] = (M3Gbyte *)m3gAlloc(M3G_INTERFACE(loader), paramLength*sizeof(M3Gbyte));
       
   875             if (userData->params[i] == NULL)
       
   876                 return M3G_FALSE;
       
   877             m3gCopy(userData->params[i], data, paramLength);
       
   878             data += paramLength;
       
   879         }
       
   880     }
       
   881 
       
   882     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
   883     return M3G_TRUE;
       
   884 }
       
   885 
       
   886 /*!
       
   887  * \internal
       
   888  * \brief Skips Object3D data
       
   889  */
       
   890 static M3Gbool m3gSkipObject3DData(Loader *loader)
       
   891 {
       
   892     M3Guint animTracks, i, userParams, paramLength;
       
   893     M3Gubyte *data = m3gGetSectionDataPtr(loader, 8);
       
   894     if (data == NULL) return M3G_FALSE;
       
   895 
       
   896     data += 4;
       
   897     animTracks = m3gLoadInt(data);
       
   898     data += 4;
       
   899 
       
   900     /* Overflow? */
       
   901     if (animTracks >= 0x1fffffff) {
       
   902         return M3G_FALSE;
       
   903     }
       
   904 
       
   905     if (m3gCheckSectionDataLength(loader, data, animTracks * 4 + 4) == M3G_FALSE) return M3G_FALSE;
       
   906     for (i = 0; i < animTracks; i++) {
       
   907         data += 4;
       
   908     }
       
   909 
       
   910     userParams = m3gLoadInt(data);
       
   911     data += 4;
       
   912 
       
   913     for (i = 0; i < userParams; i++) {
       
   914         if (m3gCheckSectionDataLength(loader, data, 8) == M3G_FALSE) return M3G_FALSE;
       
   915         data += 4;
       
   916         paramLength = m3gLoadInt(data);
       
   917         if (m3gCheckSectionDataLength(loader, data, paramLength) == M3G_FALSE) return M3G_FALSE;
       
   918         data += 4 + paramLength;
       
   919     }
       
   920 
       
   921     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
   922     return M3G_TRUE;
       
   923 }
       
   924 
       
   925 /*!
       
   926  * \internal
       
   927  * \brief Loads transformable data
       
   928  */
       
   929 static M3Gbool m3gLoadTransformableData(Loader *loader, M3GTransformable obj)
       
   930 {
       
   931     M3Gfloat f1, f2, f3, f4;
       
   932     M3Gubyte *data;
       
   933     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
       
   934         return M3G_FALSE;
       
   935     }
       
   936 
       
   937     data = m3gGetSectionDataPtr(loader, 1);
       
   938     if (data == NULL) return M3G_FALSE;
       
   939 
       
   940     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
   941     /* Component transform ? */
       
   942     if (*data++) {
       
   943         if (m3gCheckSectionDataLength(loader, data, 40) == M3G_FALSE) return M3G_FALSE;
       
   944         if (!m3gLoadFloat(data + 0, &f1) ||
       
   945             !m3gLoadFloat(data + 4, &f2) ||
       
   946             !m3gLoadFloat(data + 8, &f3))
       
   947             return M3G_FALSE;
       
   948         m3gSetTranslation(obj, f1, f2, f3);
       
   949         if (!m3gLoadFloat(data + 12, &f1) ||
       
   950             !m3gLoadFloat(data + 16, &f2) ||
       
   951             !m3gLoadFloat(data + 20, &f3))
       
   952             return M3G_FALSE;
       
   953         m3gSetScale(obj, f1, f2, f3);
       
   954         if (!m3gLoadFloat(data + 24, &f1) ||
       
   955             !m3gLoadFloat(data + 28, &f2) ||
       
   956             !m3gLoadFloat(data + 32, &f3) ||
       
   957             !m3gLoadFloat(data + 36, &f4))
       
   958             return M3G_FALSE;
       
   959         m3gSetOrientation(obj, f1, f2, f3, f4);
       
   960         data += 40;
       
   961     }
       
   962 
       
   963     if (m3gCheckSectionDataLength(loader, data, 1) == M3G_FALSE) return M3G_FALSE;
       
   964     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
   965     /* Generic transform */
       
   966     if (*data++) {
       
   967         Matrix m;
       
   968         if (m3gCheckSectionDataLength(loader, data, 64) == M3G_FALSE) return M3G_FALSE;
       
   969         if (!m3gLoadMatrix(&m, data)) return M3G_FALSE;
       
   970         m3gSetTransform(obj, &m);
       
   971         data += 64;
       
   972     }
       
   973 
       
   974     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
   975     return M3G_TRUE;
       
   976 }
       
   977 
       
   978 /*!
       
   979  * \internal
       
   980  * \brief Skips transformable data
       
   981  */
       
   982 static M3Gbool m3gSkipTransformableData(Loader *loader)
       
   983 {
       
   984     M3Gubyte *data;
       
   985     if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
       
   986 
       
   987     data = m3gGetSectionDataPtr(loader, 1);
       
   988     if (data == NULL) return M3G_FALSE;
       
   989 
       
   990     /* Component transform ? */
       
   991     if (*data++) {
       
   992         if (m3gCheckSectionDataLength(loader, data, 40) == M3G_FALSE) return M3G_FALSE;
       
   993         data += 40;
       
   994     }
       
   995 
       
   996     if (m3gCheckSectionDataLength(loader, data, 1) == M3G_FALSE) return M3G_FALSE;
       
   997     /* Generic transform */
       
   998     if (*data++) {
       
   999         if (m3gCheckSectionDataLength(loader, data, 64) == M3G_FALSE) return M3G_FALSE;
       
  1000         data += 64;
       
  1001     }
       
  1002 
       
  1003     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  1004     return M3G_TRUE;
       
  1005 }
       
  1006 
       
  1007 /*!
       
  1008  * \internal
       
  1009  * \brief Loads node data
       
  1010  */
       
  1011 static M3Gbool m3gLoadNodeData(Loader *loader, M3GNode obj)
       
  1012 {
       
  1013     M3Gubyte *data;
       
  1014     if (!m3gLoadTransformableData(loader, (M3GTransformable)obj)) {
       
  1015         return M3G_FALSE;
       
  1016     }
       
  1017 
       
  1018     data = m3gGetSectionDataPtr(loader, 8);
       
  1019     if (data == NULL) return M3G_FALSE;
       
  1020 
       
  1021     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
  1022     m3gEnable(obj, 0, *data++);
       
  1023     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
  1024     m3gEnable(obj, 1, *data++);
       
  1025     {
       
  1026         unsigned a = *data++; 
       
  1027         m3gSetAlphaFactor(obj, m3gDivif(a, 255));
       
  1028     }
       
  1029     m3gSetScope(obj, m3gLoadInt(data));
       
  1030     data += 4;
       
  1031 
       
  1032     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
  1033     if (*data++) {
       
  1034         M3Gubyte zt, yt;
       
  1035         M3Gint zr, yr;
       
  1036         if (m3gCheckSectionDataLength(loader, data, 10) == M3G_FALSE) return M3G_FALSE;
       
  1037         zt = *data++;
       
  1038         yt = *data++;
       
  1039         zr = m3gLoadInt(data);
       
  1040         yr = m3gLoadInt(data + 4);
       
  1041         m3gSetAlignment(obj,    (M3GNode)m3gGetLoaded(loader, zr, ANY_NODE_CLASS),
       
  1042                                 zt,
       
  1043                                 (M3GNode)m3gGetLoaded(loader, yr, ANY_NODE_CLASS),
       
  1044                                 yt);
       
  1045         data += 8;
       
  1046     }
       
  1047 
       
  1048     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  1049     return M3G_TRUE;
       
  1050 }
       
  1051 
       
  1052 /*!
       
  1053  * \internal
       
  1054  * \brief Skips node data
       
  1055  */
       
  1056 static M3Gbool m3gSkipNodeData(Loader *loader)
       
  1057 {
       
  1058     M3Gubyte *data;
       
  1059     if (!m3gSkipTransformableData(loader)) return M3G_FALSE;
       
  1060 
       
  1061     data = m3gGetSectionDataPtr(loader, 8);
       
  1062     if (data == NULL) return M3G_FALSE;
       
  1063     data += 7;
       
  1064 
       
  1065     /* Alignment? */
       
  1066     if (*data++) {
       
  1067         if (m3gCheckSectionDataLength(loader, data, 10) == M3G_FALSE) return M3G_FALSE;
       
  1068         data += 10;
       
  1069     }
       
  1070 
       
  1071     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  1072     return M3G_TRUE;
       
  1073 }
       
  1074 
       
  1075 /*!
       
  1076  * \internal
       
  1077  * \brief Loads a camera
       
  1078  */
       
  1079 static M3Gbool m3gLoadCamera(Loader *loader)
       
  1080 {
       
  1081     M3Gfloat f1, f2, f3, f4;
       
  1082     M3Gubyte *data;
       
  1083     M3GCamera obj = m3gCreateCamera(M3G_INTERFACE(loader));
       
  1084     loader->loadedObject = (M3GObject)obj;
       
  1085     if (!obj) return M3G_FALSE;
       
  1086 
       
  1087     if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
       
  1088         return M3G_FALSE;
       
  1089     }
       
  1090 
       
  1091     data = m3gGetSectionDataPtr(loader, 1);
       
  1092     if (data == NULL) return M3G_FALSE;
       
  1093 
       
  1094     switch(*data++) {
       
  1095     case M3G_GENERIC:
       
  1096         {
       
  1097             Matrix m;
       
  1098             if (m3gCheckSectionDataLength(loader, data, 64) == M3G_FALSE) return M3G_FALSE;
       
  1099             if (!m3gLoadMatrix(&m, data)) return M3G_FALSE;
       
  1100             m3gSetProjectionMatrix(obj, &m);
       
  1101             data += 64;
       
  1102         }
       
  1103         break;
       
  1104     case M3G_PERSPECTIVE:
       
  1105         if (m3gCheckSectionDataLength(loader, data, 16) == M3G_FALSE) return M3G_FALSE;
       
  1106         if (!m3gLoadFloat(data + 0, &f1) ||
       
  1107             !m3gLoadFloat(data + 4, &f2) ||
       
  1108             !m3gLoadFloat(data + 8, &f3) ||
       
  1109             !m3gLoadFloat(data + 12, &f4))
       
  1110             return M3G_FALSE;
       
  1111         m3gSetPerspective(obj, f1, f2, f3, f4);
       
  1112         data += 16;
       
  1113         break;
       
  1114     case M3G_PARALLEL:
       
  1115         if (m3gCheckSectionDataLength(loader, data, 16) == M3G_FALSE) return M3G_FALSE;
       
  1116         if (!m3gLoadFloat(data + 0, &f1) ||
       
  1117             !m3gLoadFloat(data + 4, &f2) ||
       
  1118             !m3gLoadFloat(data + 8, &f3) ||
       
  1119             !m3gLoadFloat(data + 12, &f4))
       
  1120             return M3G_FALSE;
       
  1121         m3gSetParallel(obj, f1, f2, f3, f4);
       
  1122         data += 16;
       
  1123         break;
       
  1124     default:
       
  1125         /* Error */
       
  1126         break;
       
  1127     }
       
  1128 
       
  1129     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  1130 
       
  1131     return M3G_TRUE;
       
  1132 }
       
  1133 
       
  1134 /*!
       
  1135  * \internal
       
  1136  * \brief Loads a background
       
  1137  */
       
  1138 static M3Gbool m3gLoadBackground(Loader *loader)
       
  1139 {
       
  1140     M3Gubyte *data;
       
  1141     M3GBackground obj = m3gCreateBackground(M3G_INTERFACE(loader));
       
  1142     loader->loadedObject = (M3GObject)obj;
       
  1143     if (!obj) return M3G_FALSE;
       
  1144 
       
  1145     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
       
  1146         return M3G_FALSE;
       
  1147     }
       
  1148 
       
  1149     data = m3gGetSectionDataPtr(loader, 28);
       
  1150     if (data == NULL) return M3G_FALSE;
       
  1151 
       
  1152     m3gSetBgColor(obj, m3gLoadARGB(data));
       
  1153     data += 4;
       
  1154     m3gSetBgImage(obj, (M3GImage)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_IMAGE));
       
  1155     data += 4;
       
  1156     m3gSetBgMode(obj, data[0], data[1]);
       
  1157     data += 2;
       
  1158     m3gSetBgCrop(obj,   m3gLoadInt(data),
       
  1159                         m3gLoadInt(data + 4),
       
  1160                         m3gLoadInt(data + 8),
       
  1161                         m3gLoadInt(data + 12) );
       
  1162     data += 16;
       
  1163 
       
  1164     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
  1165     m3gSetBgEnable(obj, 0, *data++);
       
  1166     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
  1167     m3gSetBgEnable(obj, 1, *data++);
       
  1168 
       
  1169     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  1170 
       
  1171     return M3G_TRUE;
       
  1172 }
       
  1173 
       
  1174 /*!
       
  1175  * \internal
       
  1176  * \brief Loads a vertex array
       
  1177  */
       
  1178 static M3Gbool m3gLoadVertexArray(Loader *loader)
       
  1179 {
       
  1180     M3Gint i, j;
       
  1181     M3Guint size;
       
  1182     M3Gushort vertices;
       
  1183     M3Gubyte *data, components, encoding;
       
  1184     M3Gdatatype componentSize;
       
  1185     M3GVertexArray obj;
       
  1186 
       
  1187     m3gBeginObject(loader);
       
  1188     if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
       
  1189 
       
  1190     data = m3gGetSectionDataPtr(loader, 5);
       
  1191     if (data == NULL) return M3G_FALSE;
       
  1192 
       
  1193     if (*data != 1 && *data != 2) return M3G_FALSE;
       
  1194     componentSize = (*data++ == 1) ? M3G_BYTE : M3G_SHORT;
       
  1195     components    = *data++;
       
  1196     encoding      = *data++;
       
  1197     vertices      = m3gLoadShort(data);
       
  1198     data += 2;
       
  1199 
       
  1200     size = vertices * components * (componentSize == M3G_BYTE ? 1 : 2);
       
  1201 
       
  1202     /* Overflow? */
       
  1203     if (size < vertices) {
       
  1204         return M3G_FALSE;
       
  1205     }
       
  1206 
       
  1207     if (m3gCheckSectionDataLength(loader, data, size) == M3G_FALSE) return M3G_FALSE;
       
  1208     obj = m3gCreateVertexArray(M3G_INTERFACE(loader), vertices, components, componentSize);
       
  1209     loader->loadedObject = (M3GObject)obj;
       
  1210     if (!obj) return M3G_FALSE;
       
  1211 
       
  1212     if (componentSize == M3G_BYTE) {
       
  1213         M3Gbyte previousValues[4];
       
  1214         m3gZero(previousValues, sizeof(previousValues));
       
  1215 
       
  1216         for (i = 0; i < vertices; i++) {
       
  1217             for (j = 0; j < components; j++) {
       
  1218                 if (encoding == 0) {
       
  1219                     previousValues[j] = *data++;
       
  1220                 }
       
  1221                 else {
       
  1222                     previousValues[j] = (M3Gbyte) (previousValues[j] + *data++);
       
  1223                 }
       
  1224             }
       
  1225             m3gSetVertexArrayElements(obj, i, 1, sizeof(previousValues), componentSize, previousValues);
       
  1226         }
       
  1227     }
       
  1228     else {
       
  1229         M3Gshort previousValues[4];
       
  1230         m3gZero(previousValues, sizeof(previousValues));
       
  1231 
       
  1232         for (i = 0; i < vertices; i++) {
       
  1233             for (j = 0; j < components; j++) {
       
  1234                 if (encoding == 0) {
       
  1235                     previousValues[j] = m3gLoadShort(data);
       
  1236                 }
       
  1237                 else {
       
  1238                     previousValues[j] = (M3Gshort) (previousValues[j] + m3gLoadShort(data));
       
  1239                 }
       
  1240                 data += 2;
       
  1241             }
       
  1242             m3gSetVertexArrayElements(obj, i, 1, sizeof(previousValues), componentSize, previousValues);
       
  1243         }
       
  1244     }
       
  1245 
       
  1246     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  1247 
       
  1248     m3gEndObject(loader);
       
  1249     m3gRewindObject(loader);
       
  1250     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
       
  1251         return M3G_FALSE;
       
  1252     }
       
  1253     m3gSkipObject(loader);
       
  1254 
       
  1255     return M3G_TRUE;
       
  1256 }
       
  1257 
       
  1258 /*!
       
  1259  * \internal
       
  1260  * \brief Loads a vertex buffer
       
  1261  */
       
  1262 static M3Gbool m3gLoadVertexBuffer(Loader *loader)
       
  1263 {
       
  1264     M3Gubyte *data;
       
  1265     M3GVertexArray va;
       
  1266     M3Gfloat bias[3], scale;
       
  1267     M3Guint i, taCount;
       
  1268     M3GVertexBuffer obj = m3gCreateVertexBuffer(M3G_INTERFACE(loader));
       
  1269     loader->loadedObject = (M3GObject)obj;
       
  1270     if (!obj) return M3G_FALSE;
       
  1271 
       
  1272     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
       
  1273         return M3G_FALSE;
       
  1274     }
       
  1275 
       
  1276     data = m3gGetSectionDataPtr(loader, 36);
       
  1277     if (data == NULL) return M3G_FALSE;
       
  1278 
       
  1279     m3gSetVertexDefaultColor(obj, m3gLoadARGB(data));
       
  1280     data += 4;
       
  1281 
       
  1282     /* Positions */
       
  1283     va = (M3GVertexArray)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_ARRAY);
       
  1284     data += 4;
       
  1285     if (!m3gLoadFloat(data + 0, &bias[0])) return M3G_FALSE;
       
  1286     if (!m3gLoadFloat(data + 4, &bias[1])) return M3G_FALSE;
       
  1287     if (!m3gLoadFloat(data + 8, &bias[2])) return M3G_FALSE;
       
  1288     if (!m3gLoadFloat(data + 12, &scale)) return M3G_FALSE;
       
  1289     if (va != NULL) {
       
  1290         m3gSetVertexArray(obj, va, scale, bias, 3);
       
  1291     }
       
  1292     data += 16;
       
  1293 
       
  1294     /* Normals */
       
  1295     va = (M3GVertexArray)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_ARRAY);
       
  1296     data += 4;
       
  1297     if (va != NULL) {
       
  1298         m3gSetNormalArray(obj, va);
       
  1299     }
       
  1300 
       
  1301     /* Colors */
       
  1302     va = (M3GVertexArray)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_ARRAY);
       
  1303     data += 4;
       
  1304     if (va != NULL) {
       
  1305         m3gSetColorArray(obj, va);
       
  1306     }
       
  1307 
       
  1308     /* Texture coordinates */
       
  1309     taCount = m3gLoadInt(data);
       
  1310     data += 4;
       
  1311 
       
  1312     /* Overflow? */
       
  1313     if (taCount >= 0x0ccccccc) {
       
  1314         return M3G_FALSE;
       
  1315     }
       
  1316 
       
  1317     if (m3gCheckSectionDataLength(loader, data, taCount * 20) == M3G_FALSE) return M3G_FALSE;
       
  1318     for (i = 0; i < taCount; i++) {
       
  1319         va = (M3GVertexArray)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_ARRAY);
       
  1320         data += 4;
       
  1321         if (!m3gLoadFloat(data + 0, &bias[0])) return M3G_FALSE;
       
  1322         if (!m3gLoadFloat(data + 4, &bias[1])) return M3G_FALSE;
       
  1323         if (!m3gLoadFloat(data + 8, &bias[2])) return M3G_FALSE;
       
  1324         if (!m3gLoadFloat(data + 12, &scale)) return M3G_FALSE;
       
  1325         if (va != NULL) {
       
  1326             m3gSetTexCoordArray(obj, i, va, scale, bias, 3);
       
  1327         }
       
  1328         else {
       
  1329             return M3G_FALSE;
       
  1330         }
       
  1331         data += 16;
       
  1332     }
       
  1333 
       
  1334     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  1335 
       
  1336     return M3G_TRUE;
       
  1337 }
       
  1338 
       
  1339 
       
  1340 /*!
       
  1341  * \internal
       
  1342  * \brief Loads a triangle strip array
       
  1343  */
       
  1344 static M3Gbool m3gLoadTsa(Loader *loader)
       
  1345 {
       
  1346     M3Gubyte *data;
       
  1347     M3GIndexBuffer obj = 0;
       
  1348     M3Gubyte encoding;
       
  1349     M3Guint startIndex = 0, indicesCount = 0, *indices = NULL;
       
  1350     M3Guint lengthCount;
       
  1351     M3Gint *lengths = NULL;
       
  1352     M3Guint i;
       
  1353 
       
  1354     m3gBeginObject(loader);
       
  1355     if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
       
  1356 
       
  1357     data = m3gGetSectionDataPtr(loader, 1);
       
  1358     if (data == NULL) return M3G_FALSE;
       
  1359 
       
  1360     encoding = *data++;
       
  1361 
       
  1362     switch(encoding) {
       
  1363     case 0:
       
  1364         if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
       
  1365         startIndex = m3gLoadInt(data);
       
  1366         data += 4;
       
  1367         break;
       
  1368 
       
  1369     case 1:
       
  1370         if (m3gCheckSectionDataLength(loader, data, 1) == M3G_FALSE) return M3G_FALSE;
       
  1371         startIndex = *data++;
       
  1372         break;
       
  1373 
       
  1374     case 2:
       
  1375         if (m3gCheckSectionDataLength(loader, data, 2) == M3G_FALSE) return M3G_FALSE;
       
  1376         startIndex = (M3Gushort) m3gLoadShort(data);
       
  1377         data += 2;
       
  1378         break;
       
  1379 
       
  1380     case 128:
       
  1381         if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
       
  1382         indicesCount = m3gLoadInt(data);
       
  1383         data += 4;
       
  1384 
       
  1385         /* Overflow? */
       
  1386         if (indicesCount >= 0x20000000) {
       
  1387             return M3G_FALSE;
       
  1388         }
       
  1389 
       
  1390         if (m3gCheckSectionDataLength(loader, data, indicesCount * 4) == M3G_FALSE) return M3G_FALSE;
       
  1391         indices = m3gAllocZ(M3G_INTERFACE(loader), sizeof(M3Gint) * indicesCount);
       
  1392         if (!indices) return M3G_FALSE;
       
  1393         for (i = 0; i < indicesCount; i++ ) {
       
  1394             indices[i] = m3gLoadInt(data);
       
  1395             data += 4;
       
  1396         }
       
  1397         break;
       
  1398 
       
  1399     case 129:
       
  1400         if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
       
  1401         indicesCount = m3gLoadInt(data);
       
  1402         data += 4;
       
  1403         if (m3gCheckSectionDataLength(loader, data, indicesCount) == M3G_FALSE) return M3G_FALSE;
       
  1404         indices = m3gAllocZ(M3G_INTERFACE(loader), sizeof(M3Gint) * indicesCount);
       
  1405         if (!indices) return M3G_FALSE;
       
  1406         for (i = 0; i < indicesCount; i++ ) {
       
  1407             indices[i] = *data++;
       
  1408         }
       
  1409         break;
       
  1410 
       
  1411     case 130:
       
  1412         if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
       
  1413         indicesCount = m3gLoadInt(data);
       
  1414         data += 4;
       
  1415 
       
  1416         /* Overflow? */
       
  1417         if (indicesCount >= 0x40000000) {
       
  1418             return M3G_FALSE;
       
  1419         }
       
  1420 
       
  1421         if (m3gCheckSectionDataLength(loader, data, indicesCount * 2) == M3G_FALSE) return M3G_FALSE;
       
  1422         indices = m3gAllocZ(M3G_INTERFACE(loader), sizeof(M3Gint) * indicesCount);
       
  1423         if (!indices) return M3G_FALSE;
       
  1424         for (i = 0; i < indicesCount; i++) {
       
  1425             indices[i] = (M3Gushort)m3gLoadShort(data);
       
  1426             data += 2;
       
  1427         }
       
  1428         break;
       
  1429 
       
  1430     default:
       
  1431         return M3G_FALSE;
       
  1432     }
       
  1433 
       
  1434     if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) goto cleanup;
       
  1435     lengthCount = m3gLoadInt(data);
       
  1436     data += 4;
       
  1437 
       
  1438     /* Overflow? */
       
  1439     if (lengthCount >= 0x20000000) {
       
  1440         goto cleanup;
       
  1441     }
       
  1442 
       
  1443     if (m3gCheckSectionDataLength(loader, data, lengthCount * 4) == M3G_FALSE) goto cleanup;
       
  1444     lengths = m3gAllocZ(M3G_INTERFACE(loader), sizeof(M3Gint) * lengthCount);
       
  1445     if (!lengths) goto cleanup;
       
  1446 
       
  1447     for (i = 0; i < lengthCount; i++) {
       
  1448         lengths[i] = m3gLoadInt(data);
       
  1449         data += 4;
       
  1450     }
       
  1451 
       
  1452     if (encoding == 0 || encoding == 1 || encoding == 2) {
       
  1453         obj = m3gCreateImplicitStripBuffer( M3G_INTERFACE(loader),
       
  1454                                             lengthCount,
       
  1455                                             lengths,
       
  1456                                             startIndex);
       
  1457     }
       
  1458     else {
       
  1459         obj = m3gCreateStripBuffer( M3G_INTERFACE(loader),
       
  1460                                     M3G_TRIANGLE_STRIPS,
       
  1461                                     lengthCount,
       
  1462                                     lengths,
       
  1463                                     M3G_INT,
       
  1464                                     indicesCount,
       
  1465                                     indices);
       
  1466     }
       
  1467 
       
  1468 cleanup:
       
  1469     m3gFree(M3G_INTERFACE(loader), indices);
       
  1470     m3gFree(M3G_INTERFACE(loader), lengths);
       
  1471 
       
  1472     loader->loadedObject = (M3GObject)obj;
       
  1473     if (!obj) return M3G_FALSE;
       
  1474 
       
  1475     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  1476 
       
  1477     m3gEndObject(loader);
       
  1478     m3gRewindObject(loader);
       
  1479     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
       
  1480         return M3G_FALSE;
       
  1481     }
       
  1482     m3gSkipObject(loader);
       
  1483 
       
  1484     return M3G_TRUE;
       
  1485 }
       
  1486 
       
  1487 /*!
       
  1488  * \internal
       
  1489  * \brief Loads a compositing mode
       
  1490  */
       
  1491 static M3Gbool m3gLoadCompositingMode(Loader *loader)
       
  1492 {
       
  1493     M3Gfloat f1, f2;
       
  1494     M3Gubyte *data;
       
  1495     M3GCompositingMode obj = m3gCreateCompositingMode(M3G_INTERFACE(loader));
       
  1496     loader->loadedObject = (M3GObject)obj;
       
  1497     if (!obj) return M3G_FALSE;
       
  1498 
       
  1499     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
       
  1500         return M3G_FALSE;
       
  1501     }
       
  1502 
       
  1503     data = m3gGetSectionDataPtr(loader, 14);
       
  1504     if (data == NULL) return M3G_FALSE;
       
  1505 
       
  1506     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
  1507     m3gEnableDepthTest      (obj, *data++);
       
  1508     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
  1509     m3gEnableDepthWrite     (obj, *data++);
       
  1510     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
  1511     m3gEnableColorWrite     (obj, *data++);
       
  1512     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
  1513     m3gSetAlphaWriteEnable  (obj, *data++);
       
  1514     m3gSetBlending          (obj, *data++);
       
  1515     {
       
  1516         unsigned a = *data++; 
       
  1517         m3gSetAlphaThreshold(obj, m3gDivif(a, 255));
       
  1518     }
       
  1519     if (!m3gLoadFloat(data, &f1) || !m3gLoadFloat(data + 4, &f2)) return M3G_FALSE;
       
  1520     m3gSetDepthOffset       (obj, f1, f2);
       
  1521     data += 8;
       
  1522 
       
  1523     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  1524 
       
  1525     return M3G_TRUE;
       
  1526 }
       
  1527 
       
  1528 /*!
       
  1529  * \internal
       
  1530  * \brief Loads a polygon mode
       
  1531  */
       
  1532 static M3Gbool m3gLoadPolygonMode(Loader *loader)
       
  1533 {
       
  1534     M3Gubyte *data;
       
  1535     M3GPolygonMode obj = m3gCreatePolygonMode(M3G_INTERFACE(loader));
       
  1536     loader->loadedObject = (M3GObject)obj;
       
  1537     if (!obj) return M3G_FALSE;
       
  1538 
       
  1539     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
       
  1540         return M3G_FALSE;
       
  1541     }
       
  1542 
       
  1543     data = m3gGetSectionDataPtr(loader, 6);
       
  1544     if (data == NULL) return M3G_FALSE;
       
  1545 
       
  1546     m3gSetCulling                       (obj, *data++);
       
  1547     m3gSetShading                       (obj, *data++);
       
  1548     m3gSetWinding                       (obj, *data++);
       
  1549     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
  1550     m3gSetTwoSidedLightingEnable        (obj, *data++);
       
  1551     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
  1552     m3gSetLocalCameraLightingEnable     (obj, *data++);
       
  1553     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
  1554     m3gSetPerspectiveCorrectionEnable   (obj, *data++);
       
  1555 
       
  1556     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  1557 
       
  1558     return M3G_TRUE;
       
  1559 }
       
  1560 
       
  1561 /*!
       
  1562  * \internal
       
  1563  * \brief Loads an appearance
       
  1564  */
       
  1565 static M3Gbool m3gLoadAppearance(Loader *loader)
       
  1566 {
       
  1567     M3Guint textures, i;
       
  1568     M3Gubyte *data;
       
  1569     M3GAppearance obj = m3gCreateAppearance(M3G_INTERFACE(loader));
       
  1570     loader->loadedObject = (M3GObject)obj;
       
  1571     if (!obj) return M3G_FALSE;
       
  1572 
       
  1573     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
       
  1574         return M3G_FALSE;
       
  1575     }
       
  1576 
       
  1577     data = m3gGetSectionDataPtr(loader, 21);
       
  1578     if (data == NULL) return M3G_FALSE;
       
  1579 
       
  1580     m3gSetLayer(obj, (M3Gbyte)*data++);
       
  1581     m3gSetCompositingMode(obj, (M3GCompositingMode)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_COMPOSITING_MODE));
       
  1582     data += 4;
       
  1583     m3gSetFog(obj, (M3GFog)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_FOG));
       
  1584     data += 4;
       
  1585     m3gSetPolygonMode(obj, (M3GPolygonMode)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_POLYGON_MODE));
       
  1586     data += 4;
       
  1587     m3gSetMaterial(obj, (M3GMaterial)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_MATERIAL));
       
  1588     data += 4;
       
  1589 
       
  1590     textures = m3gLoadInt(data);
       
  1591     data += 4;
       
  1592 
       
  1593     /* Overflow? */
       
  1594     if (textures >= 0x20000000) {
       
  1595         return M3G_FALSE;
       
  1596     }
       
  1597 
       
  1598     if (m3gCheckSectionDataLength(loader, data, textures * 4) == M3G_FALSE) return M3G_FALSE;
       
  1599     for (i = 0; i < textures; i++) {
       
  1600         M3GTexture tex = (M3GTexture)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_TEXTURE);
       
  1601         if (!tex) {
       
  1602             return M3G_FALSE;
       
  1603         }
       
  1604         m3gSetTexture(obj, i, tex);
       
  1605         data += 4;
       
  1606     }
       
  1607 
       
  1608     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  1609 
       
  1610     return M3G_TRUE;
       
  1611 }
       
  1612 
       
  1613 /*!
       
  1614  * \internal
       
  1615  * \brief Loads a mesh
       
  1616  */
       
  1617 static M3Gbool m3gLoadMesh(Loader *loader)
       
  1618 {
       
  1619     M3Guint subMeshCount, i;
       
  1620     M3GVertexBuffer vb;
       
  1621     M3GIndexBuffer *ib = NULL;
       
  1622     M3GAppearance *ap = NULL;
       
  1623     M3Gubyte *data;
       
  1624     M3GMesh obj = NULL;
       
  1625 
       
  1626     m3gBeginObject(loader);
       
  1627     if (!m3gSkipNodeData(loader)) return M3G_FALSE;
       
  1628 
       
  1629     data = m3gGetSectionDataPtr(loader, 8);
       
  1630     if (data == NULL) return M3G_FALSE;
       
  1631 
       
  1632     vb = (M3GVertexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_BUFFER);
       
  1633     if (vb == NULL) return M3G_FALSE;
       
  1634     data += 4;
       
  1635     subMeshCount = m3gLoadInt(data);
       
  1636     data += 4;
       
  1637 
       
  1638     /* Overflow? */
       
  1639     if (subMeshCount >= 0x10000000) {
       
  1640         return M3G_FALSE;
       
  1641     }
       
  1642 
       
  1643     if (m3gCheckSectionDataLength(loader, data, subMeshCount * 8) == M3G_FALSE) return M3G_FALSE;
       
  1644     ib = m3gAllocZ(M3G_INTERFACE(loader), sizeof(*ib) * subMeshCount);
       
  1645     ap = m3gAllocZ(M3G_INTERFACE(loader), sizeof(*ap) * subMeshCount);
       
  1646     if (!ib || !ap) goto cleanup;
       
  1647 
       
  1648     for (i = 0; i < subMeshCount; i++) {
       
  1649         M3GIndexBuffer indexBuffer;
       
  1650         indexBuffer = (M3GIndexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_INDEX_BUFFER);
       
  1651         if (indexBuffer != NULL && loader->triConstraint != 0) {
       
  1652             loader->triCount += indexBuffer->indexCount;
       
  1653             if (loader->triCount > loader->triConstraint) goto cleanup;
       
  1654         }
       
  1655         ib[i] = indexBuffer;
       
  1656         data += 4;
       
  1657         ap[i] = (M3GAppearance)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_APPEARANCE);
       
  1658         data += 4;
       
  1659     }
       
  1660 
       
  1661     obj = m3gCreateMesh(    M3G_INTERFACE(loader),
       
  1662                             vb,
       
  1663                             ib,
       
  1664                             ap,
       
  1665                             subMeshCount);
       
  1666 
       
  1667 cleanup:
       
  1668     m3gFree(M3G_INTERFACE(loader), ib);
       
  1669     m3gFree(M3G_INTERFACE(loader), ap);
       
  1670     loader->loadedObject = (M3GObject)obj;
       
  1671     if (!obj) return M3G_FALSE;
       
  1672 
       
  1673     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  1674 
       
  1675     m3gEndObject(loader);
       
  1676     m3gRewindObject(loader);
       
  1677     if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
       
  1678         return M3G_FALSE;
       
  1679     }
       
  1680     m3gSkipObject(loader);
       
  1681 
       
  1682     return M3G_TRUE;
       
  1683 }
       
  1684 
       
  1685 /*!
       
  1686  * \internal
       
  1687  * \brief Loads group data
       
  1688  */
       
  1689 static M3Gbool m3gLoadGroupData(Loader *loader, M3GGroup obj)
       
  1690 {
       
  1691     M3Guint childCount, i;
       
  1692     M3Gubyte *data;
       
  1693 
       
  1694     if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
       
  1695         return M3G_FALSE;
       
  1696     }
       
  1697 
       
  1698     data = m3gGetSectionDataPtr(loader, 4);
       
  1699     if (data == NULL) return M3G_FALSE;
       
  1700 
       
  1701     childCount = m3gLoadInt(data);
       
  1702     data += 4;
       
  1703 
       
  1704     /* Overflow? */
       
  1705     if (childCount >= 0x20000000) {
       
  1706         return M3G_FALSE;
       
  1707     }
       
  1708 
       
  1709     if (m3gCheckSectionDataLength(loader, data, childCount * 4) == M3G_FALSE) return M3G_FALSE;
       
  1710     for (i = 0; i < childCount; i++) {
       
  1711         m3gAddChild(obj, (M3GNode)m3gGetLoaded(loader, m3gLoadInt(data), ANY_NODE_CLASS));
       
  1712         data += 4;
       
  1713     }
       
  1714 
       
  1715     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  1716 
       
  1717     return M3G_TRUE;
       
  1718 }
       
  1719 
       
  1720 /*!
       
  1721  * \internal
       
  1722  * \brief Loads a group
       
  1723  */
       
  1724 static M3Gbool m3gLoadGroup(Loader *loader)
       
  1725 {
       
  1726     M3GGroup obj = m3gCreateGroup(M3G_INTERFACE(loader));
       
  1727     loader->loadedObject = (M3GObject)obj;
       
  1728     if (!obj) return M3G_FALSE;
       
  1729 
       
  1730     if (!m3gLoadGroupData(loader, obj)) {
       
  1731         return M3G_FALSE;
       
  1732     }
       
  1733 
       
  1734     return M3G_TRUE;
       
  1735 }
       
  1736 
       
  1737 /*!
       
  1738  * \internal
       
  1739  * \brief Loads a world
       
  1740  */
       
  1741 static M3Gbool m3gLoadWorld(Loader *loader)
       
  1742 {
       
  1743     M3GCamera cam;
       
  1744     M3Gubyte *data;
       
  1745     M3GWorld obj = m3gCreateWorld(M3G_INTERFACE(loader));
       
  1746     loader->loadedObject = (M3GObject)obj;
       
  1747     if (!obj) return M3G_FALSE;
       
  1748 
       
  1749     if (!m3gLoadGroupData(loader, (M3GGroup)obj)) {
       
  1750         return M3G_FALSE;
       
  1751     }
       
  1752 
       
  1753     data = m3gGetSectionDataPtr(loader, 8);
       
  1754     if (data == NULL) return M3G_FALSE;
       
  1755 
       
  1756     cam = (M3GCamera)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_CAMERA);
       
  1757     data += 4;
       
  1758     if (cam != NULL) {
       
  1759         m3gSetActiveCamera(obj, cam);
       
  1760     }
       
  1761     m3gSetBackground(obj, (M3GBackground)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_BACKGROUND));
       
  1762     data += 4;
       
  1763 
       
  1764     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  1765 
       
  1766     return M3G_TRUE;
       
  1767 }
       
  1768 
       
  1769 /*!
       
  1770  * \internal
       
  1771  * \brief Loads a light
       
  1772  */
       
  1773 static M3Gbool m3gLoadLight(Loader *loader)
       
  1774 {
       
  1775     M3Gfloat f1, f2, f3;
       
  1776     M3Gubyte *data;
       
  1777     M3GLight obj = m3gCreateLight(M3G_INTERFACE(loader));
       
  1778     loader->loadedObject = (M3GObject)obj;
       
  1779     if (!obj) return M3G_FALSE;
       
  1780 
       
  1781     if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
       
  1782         return M3G_FALSE;
       
  1783     }
       
  1784 
       
  1785     data = m3gGetSectionDataPtr(loader, 28);
       
  1786     if (data == NULL) return M3G_FALSE;
       
  1787 
       
  1788     if (!m3gLoadFloat(data, &f1) ||
       
  1789         !m3gLoadFloat(data + 4, &f2) ||
       
  1790         !m3gLoadFloat(data + 8, &f3)) return M3G_FALSE;
       
  1791     m3gSetAttenuation   (obj, f1, f2, f3);
       
  1792     data += 12;
       
  1793     m3gSetLightColor    (obj, m3gLoadRGB(data));
       
  1794     data += 3;
       
  1795     m3gSetLightMode     (obj, *data++);
       
  1796     if (!m3gLoadFloat(data, &f1)) return M3G_FALSE;
       
  1797     m3gSetIntensity     (obj, f1);
       
  1798     data += 4;
       
  1799     if (!m3gLoadFloat(data, &f1)) return M3G_FALSE;
       
  1800     m3gSetSpotAngle     (obj, f1);
       
  1801     data += 4;
       
  1802     if (!m3gLoadFloat(data, &f1)) return M3G_FALSE;
       
  1803     m3gSetSpotExponent  (obj, f1);
       
  1804     data += 4;
       
  1805 
       
  1806     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  1807 
       
  1808     return M3G_TRUE;
       
  1809 }
       
  1810 
       
  1811 /*!
       
  1812  * \internal
       
  1813  * \brief Loads a keyframe sequence
       
  1814  */
       
  1815 static M3Gbool m3gLoadKeyframeSequence(Loader *loader)
       
  1816 {
       
  1817     M3Guint i, j, interpolation, repeatMode, encoding, duration,
       
  1818             rangeFirst, rangeLast, components, keyFrames, size;
       
  1819     M3Gfloat *values;
       
  1820     M3Gubyte *data;
       
  1821     M3GKeyframeSequence obj;
       
  1822 
       
  1823     m3gBeginObject(loader);
       
  1824     if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
       
  1825 
       
  1826     data = m3gGetSectionDataPtr(loader, 23);
       
  1827     if (data == NULL) return M3G_FALSE;
       
  1828 
       
  1829     interpolation = *data++;
       
  1830     repeatMode    = *data++;
       
  1831     encoding      = *data++;
       
  1832     duration      = m3gLoadInt(data);
       
  1833     data += 4;
       
  1834     rangeFirst    = m3gLoadInt(data);
       
  1835     data += 4;
       
  1836     rangeLast     = m3gLoadInt(data);
       
  1837     data += 4;
       
  1838     components    = m3gLoadInt(data);
       
  1839     data += 4;
       
  1840     keyFrames     = m3gLoadInt(data);
       
  1841     data += 4;
       
  1842 
       
  1843     if (encoding == 0) {
       
  1844         size = keyFrames * (4 + components * 4);
       
  1845     }
       
  1846     else {
       
  1847         size = components * 8 + keyFrames * (4 + components * (encoding == 1 ? 1 : 2));
       
  1848     }
       
  1849 
       
  1850     /* Overflow? */
       
  1851     if (size < keyFrames) {
       
  1852         return M3G_FALSE;
       
  1853     }
       
  1854 
       
  1855     if (m3gCheckSectionDataLength(loader, data, size) == M3G_FALSE) return M3G_FALSE;
       
  1856 
       
  1857     obj = m3gCreateKeyframeSequence(M3G_INTERFACE(loader), keyFrames, components, interpolation);
       
  1858     loader->loadedObject = (M3GObject)obj;
       
  1859     if (!obj) return M3G_FALSE;
       
  1860 
       
  1861     m3gSetRepeatMode(obj, repeatMode);
       
  1862     m3gSetDuration(obj, duration);
       
  1863     m3gSetValidRange(obj, rangeFirst, rangeLast);
       
  1864 
       
  1865     values = m3gAllocZ(M3G_INTERFACE(loader), sizeof(M3Gfloat) * components);
       
  1866     if (!values) return M3G_FALSE;
       
  1867 
       
  1868     if (encoding == 0) {
       
  1869         for (i = 0; i < keyFrames; i++ ) {
       
  1870             M3Gint time = m3gLoadInt(data);
       
  1871             data += 4;
       
  1872 
       
  1873             for (j = 0; j < components; j++ ) {
       
  1874                 if (!m3gLoadFloat(data, &values[j])) {
       
  1875                     m3gFree(M3G_INTERFACE(loader), values);
       
  1876                     return M3G_FALSE;
       
  1877                 }
       
  1878                 data += 4;
       
  1879             }
       
  1880 
       
  1881             m3gSetKeyframe(obj, i, time, components, values);
       
  1882         }
       
  1883     }
       
  1884     else {
       
  1885         M3Gfloat *vectorBiasScale = m3gAllocZ(M3G_INTERFACE(loader), sizeof(M3Gfloat) * components * 2);
       
  1886         if (!vectorBiasScale) {
       
  1887             m3gFree(M3G_INTERFACE(loader), values);
       
  1888             return M3G_FALSE;
       
  1889         }
       
  1890 
       
  1891         for (i = 0; i < components; i++ ) {
       
  1892             if (!m3gLoadFloat(data, &vectorBiasScale[i])) {
       
  1893                 m3gFree(M3G_INTERFACE(loader), vectorBiasScale);
       
  1894                 m3gFree(M3G_INTERFACE(loader), values);
       
  1895                 return M3G_FALSE;
       
  1896             }
       
  1897             data += 4;
       
  1898         }
       
  1899         for (i = 0; i < components; i++ ) {
       
  1900             if (!m3gLoadFloat(data, &vectorBiasScale[i + components])) {
       
  1901                 m3gFree(M3G_INTERFACE(loader), vectorBiasScale);
       
  1902                 m3gFree(M3G_INTERFACE(loader), values);
       
  1903                 return M3G_FALSE;
       
  1904             }
       
  1905             data += 4;
       
  1906         }
       
  1907 
       
  1908         for (i = 0; i < keyFrames; i++ ) {
       
  1909             M3Gint time;
       
  1910             time = m3gLoadInt(data);
       
  1911             data += 4;
       
  1912 
       
  1913             if (encoding == 1) {
       
  1914                 for (j = 0; j < components; j++ ) {
       
  1915                     M3Gubyte v = *data++;
       
  1916                     values[j] = vectorBiasScale[j] + ((vectorBiasScale[j + components] * v ) / 255.0f);
       
  1917                 }
       
  1918             }
       
  1919             else {
       
  1920                 for (j = 0; j < components; j++ ) {
       
  1921                     M3Gushort v = m3gLoadShort(data);
       
  1922                     data += 2;
       
  1923                     values[j] = vectorBiasScale[j] + ((vectorBiasScale[j + components] * v) / 65535.0f);
       
  1924                 }
       
  1925             }
       
  1926 
       
  1927             m3gSetKeyframe(obj, i, time, components, values);
       
  1928         }
       
  1929 
       
  1930         m3gFree(M3G_INTERFACE(loader), vectorBiasScale);
       
  1931     }
       
  1932 
       
  1933     m3gFree(M3G_INTERFACE(loader), values);
       
  1934 
       
  1935     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  1936 
       
  1937     m3gEndObject(loader);
       
  1938     m3gRewindObject(loader);
       
  1939     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
       
  1940         return M3G_FALSE;
       
  1941     }
       
  1942     m3gSkipObject(loader);
       
  1943 
       
  1944     return M3G_TRUE;
       
  1945 }
       
  1946 
       
  1947 /*!
       
  1948  * \internal
       
  1949  * \brief Loads an animation controller
       
  1950  */
       
  1951 static M3Gbool m3gLoadAnimationController(Loader *loader)
       
  1952 {
       
  1953     M3Gfloat speed, weight, referenceSeqTime;
       
  1954     M3Gint referenceWorldTime;
       
  1955     M3Gubyte *data;
       
  1956     M3GAnimationController obj = m3gCreateAnimationController(M3G_INTERFACE(loader));
       
  1957     loader->loadedObject = (M3GObject)obj;
       
  1958     if (!obj) return M3G_FALSE;
       
  1959 
       
  1960     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
       
  1961         return M3G_FALSE;
       
  1962     }
       
  1963 
       
  1964     data = m3gGetSectionDataPtr(loader, 24);
       
  1965     if (data == NULL) return M3G_FALSE;
       
  1966 
       
  1967     if (!m3gLoadFloat(data, &speed)) return M3G_FALSE;
       
  1968     data += 4;
       
  1969     if (!m3gLoadFloat(data, &weight)) return M3G_FALSE;
       
  1970     data += 4;
       
  1971     m3gSetActiveInterval(obj, m3gLoadInt(data), m3gLoadInt(data + 4));
       
  1972     data += 8;
       
  1973     if (!m3gLoadFloat(data, &referenceSeqTime)) return M3G_FALSE;
       
  1974     data += 4;
       
  1975     referenceWorldTime = m3gLoadInt(data);
       
  1976     data += 4;
       
  1977 
       
  1978     m3gSetPosition(obj, referenceSeqTime, referenceWorldTime);
       
  1979     m3gSetSpeed(obj, speed, referenceWorldTime);
       
  1980     m3gSetWeight(obj, weight);
       
  1981 
       
  1982     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  1983 
       
  1984     return M3G_TRUE;
       
  1985 }
       
  1986 
       
  1987 /*!
       
  1988  * \internal
       
  1989  * \brief Loads an animation track
       
  1990  */
       
  1991 static M3Gbool m3gLoadAnimationTrack(Loader *loader)
       
  1992 {
       
  1993     M3Gint property;
       
  1994     M3GKeyframeSequence ks;
       
  1995     M3GAnimationController ac;
       
  1996     M3Gubyte *data;
       
  1997     M3GAnimationTrack obj;
       
  1998 
       
  1999     m3gBeginObject(loader);
       
  2000     if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
       
  2001 
       
  2002     data = m3gGetSectionDataPtr(loader, 12);
       
  2003     if (data == NULL) return M3G_FALSE;
       
  2004 
       
  2005     ks = (M3GKeyframeSequence)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_KEYFRAME_SEQUENCE);
       
  2006     data += 4;
       
  2007     ac = (M3GAnimationController)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_ANIMATION_CONTROLLER);
       
  2008     data += 4;
       
  2009     property = m3gLoadInt(data);
       
  2010     data += 4;
       
  2011 
       
  2012     obj = m3gCreateAnimationTrack(M3G_INTERFACE(loader), ks, property);
       
  2013     loader->loadedObject = (M3GObject)obj;
       
  2014     if (!obj) return M3G_FALSE;
       
  2015 
       
  2016     m3gSetController(obj, ac);
       
  2017 
       
  2018     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  2019 
       
  2020     m3gEndObject(loader);
       
  2021     m3gRewindObject(loader);
       
  2022     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
       
  2023         return M3G_FALSE;
       
  2024     }
       
  2025     m3gSkipObject(loader);
       
  2026 
       
  2027     return M3G_TRUE;
       
  2028 }
       
  2029 
       
  2030 /*!
       
  2031  * \internal
       
  2032  * \brief Loads a material
       
  2033  */
       
  2034 static M3Gbool m3gLoadMaterial(Loader *loader)
       
  2035 {
       
  2036     M3Gfloat f1;
       
  2037     M3Gubyte *data;
       
  2038     M3GMaterial obj = m3gCreateMaterial(M3G_INTERFACE(loader));
       
  2039     loader->loadedObject = (M3GObject)obj;
       
  2040     if (!obj) return M3G_FALSE;
       
  2041 
       
  2042     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
       
  2043         return M3G_FALSE;
       
  2044     }
       
  2045 
       
  2046     data = m3gGetSectionDataPtr(loader, 18);
       
  2047     if (data == NULL) return M3G_FALSE;
       
  2048 
       
  2049     m3gSetColor(obj, M3G_AMBIENT_BIT, m3gLoadRGB(data));
       
  2050     data += 3;
       
  2051     m3gSetColor(obj, M3G_DIFFUSE_BIT, m3gLoadARGB(data));
       
  2052     data += 4;
       
  2053     m3gSetColor(obj, M3G_EMISSIVE_BIT, m3gLoadRGB(data));
       
  2054     data += 3;
       
  2055     m3gSetColor(obj, M3G_SPECULAR_BIT, m3gLoadRGB(data));
       
  2056     data += 3;
       
  2057     if (!m3gLoadFloat(data, &f1)) return M3G_FALSE;
       
  2058     m3gSetShininess(obj, f1);
       
  2059     data += 4;
       
  2060     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
  2061     m3gSetVertexColorTrackingEnable(obj, *data++);
       
  2062 
       
  2063     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  2064 
       
  2065     return M3G_TRUE;
       
  2066 }
       
  2067 
       
  2068 /*!
       
  2069  * \internal
       
  2070  * \brief Loads a fog
       
  2071  */
       
  2072 static M3Gbool m3gLoadFog(Loader *loader)
       
  2073 {
       
  2074     M3Gfloat f1, f2;
       
  2075     M3Gubyte *data;
       
  2076     M3GFog obj = m3gCreateFog(M3G_INTERFACE(loader));
       
  2077     loader->loadedObject = (M3GObject)obj;
       
  2078     if (!obj) return M3G_FALSE;
       
  2079 
       
  2080     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
       
  2081         return M3G_FALSE;
       
  2082     }
       
  2083 
       
  2084     data = m3gGetSectionDataPtr(loader, 4);
       
  2085     if (data == NULL) return M3G_FALSE;
       
  2086 
       
  2087     m3gSetFogColor(obj, m3gLoadRGB(data));
       
  2088     data += 3;
       
  2089     m3gSetFogMode(obj, *data);
       
  2090 
       
  2091     if (*data++ == M3G_EXPONENTIAL_FOG) {
       
  2092         if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
       
  2093         if (!m3gLoadFloat(data, &f1)) return M3G_FALSE;
       
  2094         m3gSetFogDensity(obj, f1);
       
  2095         data += 4;
       
  2096     }
       
  2097     else {
       
  2098         if (m3gCheckSectionDataLength(loader, data, 8) == M3G_FALSE) return M3G_FALSE;
       
  2099         if (!m3gLoadFloat(data, &f1) || !m3gLoadFloat(data + 4, &f2)) return M3G_FALSE;
       
  2100         m3gSetFogLinear(obj, f1, f2);
       
  2101         data += 8;
       
  2102     }
       
  2103 
       
  2104     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  2105 
       
  2106     return M3G_TRUE;
       
  2107 }
       
  2108 
       
  2109 /*!
       
  2110  * \internal
       
  2111  * \brief Loads an image
       
  2112  */
       
  2113 static M3Gbool m3gLoadImage(Loader *loader)
       
  2114 {
       
  2115     M3GImageFormat format;
       
  2116     M3Guint width, height;
       
  2117     M3Gbyte isMutable;
       
  2118     M3Gubyte *data;
       
  2119     M3GImage obj;
       
  2120 
       
  2121     m3gBeginObject(loader);
       
  2122     if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
       
  2123 
       
  2124     data = m3gGetSectionDataPtr(loader, 10);
       
  2125     if (data == NULL) return M3G_FALSE;
       
  2126 
       
  2127     format = (M3GImageFormat)*data++;
       
  2128     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
  2129     isMutable = *data++;
       
  2130     width = m3gLoadInt(data);
       
  2131     data += 4;
       
  2132     height = m3gLoadInt(data);
       
  2133     data += 4;
       
  2134 
       
  2135     if (isMutable) {
       
  2136         obj = m3gCreateImage(M3G_INTERFACE(loader), format,
       
  2137                                                     width, height,
       
  2138                                                     M3G_RENDERING_TARGET);
       
  2139     }
       
  2140     else {
       
  2141         M3Gubyte *palette = NULL, *pixels = NULL;
       
  2142         M3Gint paletteLength, pixelsLength, bpp;
       
  2143 
       
  2144         switch(format) {
       
  2145         case M3G_ALPHA:             bpp = 1; break;
       
  2146         case M3G_LUMINANCE:         bpp = 1; break;
       
  2147         case M3G_LUMINANCE_ALPHA:   bpp = 2; break;
       
  2148         case M3G_RGB:               bpp = 3; break;
       
  2149         case M3G_RGBA:              bpp = 4; break;
       
  2150         default:                    return M3G_FALSE;
       
  2151         }
       
  2152 
       
  2153         if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
       
  2154         paletteLength = m3gLoadInt(data);
       
  2155         data += 4;
       
  2156 
       
  2157         if (paletteLength > 0) {
       
  2158             if (m3gCheckSectionDataLength(loader, data, paletteLength) == M3G_FALSE) return M3G_FALSE;
       
  2159             palette = data;
       
  2160             data += paletteLength;
       
  2161         }
       
  2162 
       
  2163         if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
       
  2164         pixelsLength = m3gLoadInt(data);
       
  2165         data += 4;
       
  2166         if (m3gCheckSectionDataLength(loader, data, pixelsLength) == M3G_FALSE) return M3G_FALSE;
       
  2167         pixels = data;
       
  2168         data += pixelsLength;
       
  2169 
       
  2170         if (palette != NULL) {
       
  2171             obj = m3gCreateImage(M3G_INTERFACE(loader), format,
       
  2172                                                         width, height,
       
  2173                                                         M3G_PALETTED);
       
  2174             if (obj != NULL) {
       
  2175                 M3Gint numEntries = paletteLength / bpp;
       
  2176                 if (numEntries > 256) {
       
  2177                     numEntries = 256;
       
  2178                 }
       
  2179                 m3gSetImage(obj, pixels);
       
  2180                 m3gSetImagePalette(obj, numEntries, palette);
       
  2181                 m3gCommitImage(obj);
       
  2182             }
       
  2183         }
       
  2184         else {
       
  2185             obj = m3gCreateImage(M3G_INTERFACE(loader), format,
       
  2186                                                         width, height,
       
  2187                                                         0);
       
  2188             if (obj != NULL) {
       
  2189                 m3gSetImage(obj, pixels);
       
  2190                 m3gCommitImage(obj);
       
  2191             }
       
  2192         }
       
  2193     }
       
  2194 
       
  2195     loader->loadedObject = (M3GObject)obj;
       
  2196     if (!obj) return M3G_FALSE;
       
  2197 
       
  2198     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  2199 
       
  2200     m3gEndObject(loader);
       
  2201     m3gRewindObject(loader);
       
  2202     if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
       
  2203         return M3G_FALSE;
       
  2204     }
       
  2205     m3gSkipObject(loader);
       
  2206 
       
  2207     return M3G_TRUE;
       
  2208 }
       
  2209 
       
  2210 /*!
       
  2211  * \internal
       
  2212  * \brief Loads a texture
       
  2213  */
       
  2214 static M3Gbool m3gLoadTexture(Loader *loader)
       
  2215 {
       
  2216     M3GImage image;
       
  2217     M3Gubyte *data;
       
  2218     M3GTexture obj;
       
  2219 
       
  2220     m3gBeginObject(loader);
       
  2221     if (!m3gSkipTransformableData(loader)) return M3G_FALSE;
       
  2222 
       
  2223     data = m3gGetSectionDataPtr(loader, 12);
       
  2224     if (data == NULL) return M3G_FALSE;
       
  2225 
       
  2226     image = (M3GImage)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_IMAGE);
       
  2227     data += 4;
       
  2228 
       
  2229     obj = m3gCreateTexture(M3G_INTERFACE(loader), image);
       
  2230     loader->loadedObject = (M3GObject)obj;
       
  2231     if (!obj) return M3G_FALSE;
       
  2232 
       
  2233     m3gSetBlendColor(obj, m3gLoadRGB(data));
       
  2234     data += 3;
       
  2235     m3gTextureSetBlending(obj, *data++);
       
  2236     m3gSetWrapping(obj, data[0], data[1]);
       
  2237     data += 2;
       
  2238     m3gSetFiltering(obj, data[0], data[1]);
       
  2239     data += 2;
       
  2240 
       
  2241     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  2242 
       
  2243     m3gEndObject(loader);
       
  2244     m3gRewindObject(loader);
       
  2245     if (!m3gLoadTransformableData(loader, (M3GTransformable)obj)) {
       
  2246         return M3G_FALSE;
       
  2247     }
       
  2248     m3gSkipObject(loader);
       
  2249 
       
  2250     return M3G_TRUE;
       
  2251 }
       
  2252 
       
  2253 /*!
       
  2254  * \internal
       
  2255  * \brief Loads a skinned mesh
       
  2256  */
       
  2257 static M3Gbool m3gLoadSkinnedMesh(Loader *loader)
       
  2258 {
       
  2259     M3GVertexBuffer vb;
       
  2260     M3Guint i, subMeshCount, transformReferenceCount, firstVertex, vertexCount;
       
  2261     M3Gint weight;
       
  2262     M3GIndexBuffer *ib = NULL;
       
  2263     M3GAppearance *ap = NULL;
       
  2264     M3GGroup skeleton;
       
  2265     M3GNode bone;
       
  2266     M3Gubyte *data;
       
  2267     M3GSkinnedMesh obj = NULL;
       
  2268 
       
  2269     m3gBeginObject(loader);
       
  2270     if (!m3gSkipNodeData(loader)) return M3G_FALSE;
       
  2271 
       
  2272     data = m3gGetSectionDataPtr(loader, 8);
       
  2273     if (data == NULL) return M3G_FALSE;
       
  2274 
       
  2275     vb = (M3GVertexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_BUFFER);
       
  2276     if (vb == NULL) return M3G_FALSE;
       
  2277     data += 4;
       
  2278     subMeshCount = m3gLoadInt(data);
       
  2279     data += 4;
       
  2280 
       
  2281     /* Overflow? */
       
  2282     if (subMeshCount >= 0x10000000) {
       
  2283         return M3G_FALSE;
       
  2284     }
       
  2285 
       
  2286     if (m3gCheckSectionDataLength(loader, data, subMeshCount * 8) == M3G_FALSE) return M3G_FALSE;
       
  2287     ib = m3gAllocZ(M3G_INTERFACE(loader), sizeof(*ib) * subMeshCount);
       
  2288     ap = m3gAllocZ(M3G_INTERFACE(loader), sizeof(*ap) * subMeshCount);
       
  2289     if (!ib || !ap) goto cleanup;
       
  2290 
       
  2291     for (i = 0; i < subMeshCount; i++) {
       
  2292         ib[i] = (M3GIndexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_INDEX_BUFFER);
       
  2293         data += 4;
       
  2294         ap[i] = (M3GAppearance)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_APPEARANCE);
       
  2295         data += 4;
       
  2296     }
       
  2297 
       
  2298     if (m3gCheckSectionDataLength(loader, data, 8) == M3G_FALSE) goto cleanup;
       
  2299     skeleton = (M3GGroup)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_GROUP);
       
  2300     data += 4;
       
  2301 
       
  2302     obj = m3gCreateSkinnedMesh( M3G_INTERFACE(loader),
       
  2303                                 vb,
       
  2304                                 ib,
       
  2305                                 ap,
       
  2306                                 subMeshCount,
       
  2307                                 skeleton);
       
  2308 
       
  2309 cleanup:
       
  2310     m3gFree(M3G_INTERFACE(loader), ib);
       
  2311     m3gFree(M3G_INTERFACE(loader), ap);
       
  2312     loader->loadedObject = (M3GObject)obj;
       
  2313     if (!obj) return M3G_FALSE;
       
  2314 
       
  2315     transformReferenceCount = m3gLoadInt(data);
       
  2316     data += 4;
       
  2317 
       
  2318     /* Overflow? */
       
  2319     if (transformReferenceCount >= 0x08000000) {
       
  2320         return M3G_FALSE;
       
  2321     }
       
  2322 
       
  2323     if (m3gCheckSectionDataLength(loader, data, transformReferenceCount * 16) == M3G_FALSE) return M3G_FALSE;
       
  2324     for (i = 0; i < transformReferenceCount; i++) {
       
  2325         bone        = (M3GNode)m3gGetLoaded(loader, m3gLoadInt(data), ANY_NODE_CLASS);
       
  2326         data += 4;
       
  2327         firstVertex = m3gLoadInt(data);
       
  2328         data += 4;
       
  2329         vertexCount = m3gLoadInt(data);
       
  2330         data += 4;
       
  2331         weight      = m3gLoadInt(data);
       
  2332         data += 4;
       
  2333         m3gAddTransform(obj, bone, weight, firstVertex, vertexCount);
       
  2334     }
       
  2335 
       
  2336     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  2337 
       
  2338     m3gEndObject(loader);
       
  2339     m3gRewindObject(loader);
       
  2340     if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
       
  2341         return M3G_FALSE;
       
  2342     }
       
  2343     m3gSkipObject(loader);
       
  2344 
       
  2345     return M3G_TRUE;
       
  2346 }
       
  2347 
       
  2348 /*!
       
  2349  * \internal
       
  2350  * \brief Loads a morphing mesh
       
  2351  */
       
  2352 static M3Gbool m3gLoadMorphingMesh(Loader *loader)
       
  2353 {
       
  2354     M3GVertexBuffer vb, *targets = NULL;
       
  2355     M3Guint i, subMeshCount, targetCount;
       
  2356     M3Gfloat *weights = NULL;
       
  2357     M3GIndexBuffer *ib = NULL;
       
  2358     M3GAppearance *ap = NULL;
       
  2359     M3Gubyte *data;
       
  2360     M3GMorphingMesh obj = NULL;
       
  2361 
       
  2362     m3gBeginObject(loader);
       
  2363     if (!m3gSkipNodeData(loader)) return M3G_FALSE;
       
  2364 
       
  2365     data = m3gGetSectionDataPtr(loader, 8);
       
  2366     if (data == NULL) return M3G_FALSE;
       
  2367 
       
  2368     vb = (M3GVertexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_BUFFER);
       
  2369     if (vb == NULL) return M3G_FALSE;
       
  2370     data += 4;
       
  2371     subMeshCount = m3gLoadInt(data);
       
  2372     data += 4;
       
  2373 
       
  2374     /* Overflow? */
       
  2375     if (subMeshCount >= 0x10000000) {
       
  2376         return M3G_FALSE;
       
  2377     }
       
  2378 
       
  2379     if (m3gCheckSectionDataLength(loader, data, subMeshCount * 8) == M3G_FALSE) return M3G_FALSE;
       
  2380     ib = m3gAllocZ(M3G_INTERFACE(loader), sizeof(*ib) * subMeshCount);
       
  2381     ap = m3gAllocZ(M3G_INTERFACE(loader), sizeof(*ap) * subMeshCount);
       
  2382     if (!ib || !ap) goto cleanup;
       
  2383 
       
  2384     for (i = 0; i < subMeshCount; i++) {
       
  2385         ib[i] = (M3GIndexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_INDEX_BUFFER);
       
  2386         data += 4;
       
  2387         ap[i] = (M3GAppearance)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_APPEARANCE);
       
  2388         data += 4;
       
  2389     }
       
  2390 
       
  2391     if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) goto cleanup;
       
  2392     targetCount = m3gLoadInt(data);
       
  2393     data += 4;
       
  2394 
       
  2395     /* Overflow? */
       
  2396     if (targetCount >= 0x10000000) {
       
  2397         goto cleanup;
       
  2398     }
       
  2399 
       
  2400     if (m3gCheckSectionDataLength(loader, data, targetCount * 8) == M3G_FALSE) goto cleanup;
       
  2401     weights = m3gAllocZ(M3G_INTERFACE(loader), sizeof(M3Gfloat) * targetCount);
       
  2402     targets = m3gAllocZ(M3G_INTERFACE(loader), sizeof(*targets) * targetCount);
       
  2403     if (!weights || !targets) goto cleanup;
       
  2404 
       
  2405     for (i = 0; i < targetCount; i++) {
       
  2406         targets[i] = (M3GVertexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_BUFFER);
       
  2407         data += 4;
       
  2408         if (!m3gLoadFloat(data, &weights[i])) goto cleanup;
       
  2409         data += 4;
       
  2410     }
       
  2411 
       
  2412     obj = m3gCreateMorphingMesh(    M3G_INTERFACE(loader),
       
  2413                                     vb,
       
  2414                                     targets,
       
  2415                                     ib,
       
  2416                                     ap,
       
  2417                                     subMeshCount,
       
  2418                                     targetCount);
       
  2419 
       
  2420 cleanup:
       
  2421     m3gFree(M3G_INTERFACE(loader), ib);
       
  2422     m3gFree(M3G_INTERFACE(loader), ap);
       
  2423     m3gFree(M3G_INTERFACE(loader), targets);
       
  2424     m3gFree(M3G_INTERFACE(loader), weights);
       
  2425     loader->loadedObject = (M3GObject)obj;
       
  2426     if (!obj) return M3G_FALSE;
       
  2427 
       
  2428     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  2429 
       
  2430     m3gEndObject(loader);
       
  2431     m3gRewindObject(loader);
       
  2432     if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
       
  2433         return M3G_FALSE;
       
  2434     }
       
  2435     m3gSkipObject(loader);
       
  2436 
       
  2437     return M3G_TRUE;
       
  2438 }
       
  2439 
       
  2440 /*!
       
  2441  * \internal
       
  2442  * \brief Loads a sprite
       
  2443  */
       
  2444 static M3Gbool m3gLoadSprite(Loader *loader)
       
  2445 {
       
  2446     M3GImage image;
       
  2447     M3GAppearance appearance;
       
  2448     M3Gubyte *data;
       
  2449     M3GSprite obj;
       
  2450 
       
  2451     m3gBeginObject(loader);
       
  2452     if (!m3gSkipNodeData(loader)) return M3G_FALSE;
       
  2453 
       
  2454     data = m3gGetSectionDataPtr(loader, 25);
       
  2455     if (data == NULL) return M3G_FALSE;
       
  2456 
       
  2457     image = (M3GImage)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_IMAGE);
       
  2458     data += 4;
       
  2459     appearance = (M3GAppearance)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_APPEARANCE);
       
  2460     data += 4;
       
  2461 
       
  2462     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
  2463     obj = m3gCreateSprite(  M3G_INTERFACE(loader),
       
  2464                             *data++,
       
  2465                             image,
       
  2466                             appearance);
       
  2467     loader->loadedObject = (M3GObject)obj;
       
  2468     if (!obj) return M3G_FALSE;
       
  2469 
       
  2470     m3gSetCrop(obj, m3gLoadInt(data),
       
  2471                     m3gLoadInt(data + 4),
       
  2472                     m3gLoadInt(data + 8),
       
  2473                     m3gLoadInt(data + 12));
       
  2474     data += 16;
       
  2475 
       
  2476     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  2477 
       
  2478     m3gEndObject(loader);
       
  2479     m3gRewindObject(loader);
       
  2480     if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
       
  2481         return M3G_FALSE;
       
  2482     }
       
  2483     m3gSkipObject(loader);
       
  2484 
       
  2485     return M3G_TRUE;
       
  2486 }
       
  2487 
       
  2488 /*!
       
  2489  * \internal
       
  2490  * \brief Loads a M3G file header
       
  2491  */
       
  2492 static M3Gbool m3gLoadHeader(Loader *loader)
       
  2493 {
       
  2494     M3Gubyte *data;
       
  2495     data = m3gGetSectionDataPtr(loader, 12);
       
  2496     if (data == NULL) return M3G_FALSE;
       
  2497 
       
  2498     /* Check version */
       
  2499     if (data[0] != 1 || data[1] != 0 || loader->sectionNum != 0) {
       
  2500         return M3G_FALSE;
       
  2501     }
       
  2502     data += 2;
       
  2503 
       
  2504     if (!m3gVerifyBool(data)) return M3G_FALSE;
       
  2505     loader->hasReferences = *data++;
       
  2506     loader->fileSize = m3gLoadInt(data);
       
  2507     data += 4;
       
  2508     loader->contentSize = m3gLoadInt(data);
       
  2509     data += 4;
       
  2510 
       
  2511     /* Skip authoring field */
       
  2512     while(*data++)
       
  2513         if (m3gCheckSectionDataLength(loader, data, 1) == M3G_FALSE) return M3G_FALSE;
       
  2514 
       
  2515     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  2516 
       
  2517     return M3G_TRUE;
       
  2518 }
       
  2519 
       
  2520 /*!
       
  2521  * \internal
       
  2522  * \brief Skips external reference
       
  2523  */
       
  2524 static M3Gbool m3gLoadExternalReference(Loader *loader)
       
  2525 {
       
  2526     M3Gubyte *data;
       
  2527     if (loader->sectionNum != 1 || !loader->hasReferences)
       
  2528         return M3G_FALSE;
       
  2529     data = m3gGetSectionDataPtr(loader, 1);
       
  2530     while(*data++) { /* Skip string */
       
  2531         if (m3gCheckSectionDataLength(loader, data, 1) == M3G_FALSE)
       
  2532             return M3G_FALSE;
       
  2533     }
       
  2534     m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
       
  2535     return M3G_TRUE;
       
  2536 }
       
  2537 
       
  2538 /*!
       
  2539  * \internal
       
  2540  * \brief Loads an object
       
  2541  */
       
  2542 static LoaderState m3gLoadObject(Loader *loader)
       
  2543 {
       
  2544     M3Gubyte *data = m3gGetSectionDataPtr(loader, loader->sectionBytesRequired);
       
  2545 
       
  2546     if (data == NULL) {
       
  2547         loader->localState = LOADSTATE_CHECKSUM;
       
  2548         return LOADSTATE_SECTION;
       
  2549     }
       
  2550 
       
  2551     m3gAdvanceSectionData(loader, loader->sectionBytesRequired);
       
  2552 
       
  2553     if (loader->localState == LOADSTATE_ENTER) {
       
  2554         M3Gbool status = M3G_TRUE;
       
  2555 
       
  2556         loader->objectType = *data++;
       
  2557         loader->loadedObject = NULL;
       
  2558         loader->localState = LOADSTATE_EXIT;
       
  2559         loader->sectionBytesRequired = m3gLoadInt(data);
       
  2560         data += 4;
       
  2561         if (loader->sectionNum == 0 && loader->objectType != 0) {
       
  2562             m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
       
  2563             return LOADSTATE_ERROR;
       
  2564         }
       
  2565 
       
  2566         switch(loader->objectType) {
       
  2567         case 0: /* Header Object */
       
  2568             status = m3gLoadHeader(loader);
       
  2569             break;
       
  2570         case 1: /* AnimationController */
       
  2571             status = m3gLoadAnimationController(loader);
       
  2572             break;
       
  2573         case 2: /* AnimationTrack */
       
  2574             status = m3gLoadAnimationTrack(loader);
       
  2575             break;
       
  2576         case 3: /* Appearance */
       
  2577             status = m3gLoadAppearance(loader);
       
  2578             break;
       
  2579         case 4: /* Background */
       
  2580             status = m3gLoadBackground(loader);
       
  2581             break;
       
  2582         case 5: /* Camera */
       
  2583             status = m3gLoadCamera(loader);
       
  2584             break;
       
  2585         case 6: /* CompositingMode */
       
  2586             status = m3gLoadCompositingMode(loader);
       
  2587             break;
       
  2588         case 7: /* Fog */
       
  2589             status = m3gLoadFog(loader);
       
  2590             break;
       
  2591         case 8: /* PolygonMode */
       
  2592             status = m3gLoadPolygonMode(loader);
       
  2593             break;
       
  2594         case 9: /* Group */
       
  2595             status = m3gLoadGroup(loader);
       
  2596             break;
       
  2597         case 10: /* Image2D */
       
  2598             status = m3gLoadImage(loader);
       
  2599             break;
       
  2600         case 11: /* TriangleStripArray */
       
  2601             status = m3gLoadTsa(loader);
       
  2602             break;
       
  2603         case 12: /* Light */
       
  2604             status = m3gLoadLight(loader);
       
  2605             break;
       
  2606         case 13: /* Material */
       
  2607             status = m3gLoadMaterial(loader);
       
  2608             break;
       
  2609         case 14: /* Mesh */
       
  2610             status = m3gLoadMesh(loader);
       
  2611             break;
       
  2612         case 15: /* MorphingMesh */
       
  2613             status = m3gLoadMorphingMesh(loader);
       
  2614             break;
       
  2615         case 16: /* SkinnedMesh */
       
  2616             status = m3gLoadSkinnedMesh(loader);
       
  2617             break;
       
  2618         case 17: /* Texture2D */
       
  2619             status = m3gLoadTexture(loader);
       
  2620             break;
       
  2621         case 18: /* Sprite */
       
  2622             status = m3gLoadSprite(loader);
       
  2623             break;
       
  2624         case 19: /* KeyframeSequence */
       
  2625             status = m3gLoadKeyframeSequence(loader);
       
  2626             break;
       
  2627         case 20: /* VertexArray */
       
  2628             status = m3gLoadVertexArray(loader);
       
  2629             break;
       
  2630         case 21: /* VertexBuffer */
       
  2631             status = m3gLoadVertexBuffer(loader);
       
  2632             break;
       
  2633         case 22: /* World */
       
  2634             status = m3gLoadWorld(loader);
       
  2635             break;
       
  2636         case 255: /* External Reference */
       
  2637             status = m3gLoadExternalReference(loader);
       
  2638             break;
       
  2639         default:  /* 23 ... 254 Reserved for use in future versions of the file format */
       
  2640             status = M3G_FALSE;
       
  2641             break;
       
  2642         }
       
  2643 
       
  2644         /* Check if object loading caused an error */
       
  2645         if (m3gErrorRaised(M3G_INTERFACE(loader))) {
       
  2646             m3gDeleteObject(loader->loadedObject);
       
  2647             return LOADSTATE_ERROR;
       
  2648         }
       
  2649         if (!status || 
       
  2650             m3gGetSectionDataPtr(loader, 0) != data + loader->sectionBytesRequired) {
       
  2651             m3gDeleteObject(loader->loadedObject);
       
  2652             m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
       
  2653             return LOADSTATE_ERROR;
       
  2654         }
       
  2655         loader->sectionBytesRequired = 0;
       
  2656         
       
  2657         /* Add object to loaded objects array */
       
  2658         if (loader->loadedObject != NULL) {
       
  2659             if (m3gArrayAppend(&loader->refArray, loader->loadedObject, M3G_INTERFACE(loader)) == -1) {
       
  2660                 /* OOM */
       
  2661                 m3gDeleteObject(loader->loadedObject);
       
  2662                 return LOADSTATE_ERROR;
       
  2663             }
       
  2664             m3gAddRef(loader->loadedObject);
       
  2665         }
       
  2666     }
       
  2667     else {
       
  2668         loader->sectionBytesRequired = M3G_MIN_OBJECT_SIZE;
       
  2669         loader->localState = LOADSTATE_ENTER;
       
  2670     }
       
  2671 
       
  2672     return LOADSTATE_OBJECT;
       
  2673 }
       
  2674 
       
  2675 /*!
       
  2676  * \internal
       
  2677  * \brief Handles branching to different subroutines upon re-entry
       
  2678  *
       
  2679  * When sufficient data is available in internal buffers, this
       
  2680  * function gets called and directs execution into the coroutine
       
  2681  * matching the current global state.
       
  2682  */
       
  2683 static LoaderState m3gLoaderMain(Loader *loader)
       
  2684 {
       
  2685     M3G_VALIDATE_OBJECT(loader);
       
  2686     M3G_ASSERT(loader->bytesRequired > 0);
       
  2687     M3G_ASSERT(loader->bytesRequired <= loader->stream.bytesAvailable);
       
  2688 
       
  2689     switch (loader->state) {
       
  2690     case LOADSTATE_INITIAL:
       
  2691         loader->stream.totalBytes = 0;
       
  2692         loader->localState = LOADSTATE_ENTER;
       
  2693         loader->fileSize = 0x00ffffff;
       
  2694         loader->bytesRequired = sizeof(PNG_FILE_IDENTIFIER);
       
  2695         return LOADSTATE_IDENTIFIER;
       
  2696     case LOADSTATE_IDENTIFIER:
       
  2697         return m3gLoadIdentifier(loader);
       
  2698     case LOADSTATE_SECTION:
       
  2699         return m3gLoadSection(loader);
       
  2700     case LOADSTATE_OBJECT:
       
  2701         return m3gLoadObject(loader);
       
  2702     default:
       
  2703         loader->bytesRequired = 0;
       
  2704         return LOADSTATE_ERROR;
       
  2705     }
       
  2706 }
       
  2707 
       
  2708 /*!
       
  2709  * \brief Deletes all unreferenced objects
       
  2710  */
       
  2711 static void m3gCleanupLoader(M3GLoader loader)
       
  2712 {
       
  2713     M3Gint i, j, n;
       
  2714     PointerArray *refs;
       
  2715     M3Gbool referenced;
       
  2716     M3GObject obj;    
       
  2717 
       
  2718     refs = &loader->refArray;
       
  2719     n = m3gArraySize(refs);
       
  2720 
       
  2721     /* All unreferenced objects will be deleted, as their ref count becomes 0 */
       
  2722     for (i = 0; i < n; ++i) {
       
  2723         obj = m3gGetLoadedPtr(refs, i, &referenced);
       
  2724         m3gDeleteRef(obj);
       
  2725     }
       
  2726     m3gClearArray(&loader->refArray);
       
  2727 
       
  2728     n = m3gArraySize(&loader->userDataArray);
       
  2729     for (i = 0; i < n; ++i)
       
  2730     {
       
  2731         UserData *data = (UserData *)m3gGetArrayElement(&loader->userDataArray, i);
       
  2732         for (j = 0; j < data->numParams; ++j)
       
  2733             m3gFree(M3G_INTERFACE(loader), data->params[j]);
       
  2734         m3gFree(M3G_INTERFACE(loader), data->params);
       
  2735         m3gFree(M3G_INTERFACE(loader), data->paramLengths);
       
  2736         m3gFree(M3G_INTERFACE(loader), data->paramId);
       
  2737         m3gFree(M3G_INTERFACE(loader), data);
       
  2738     }
       
  2739     m3gClearArray(&loader->userDataArray);
       
  2740 
       
  2741     m3gFree(M3G_INTERFACE(loader), loader->allocatedSectionData);
       
  2742     loader->allocatedSectionData = NULL;
       
  2743 }
       
  2744 
       
  2745 /*!
       
  2746  * \internal
       
  2747  * \brief Resets the loader
       
  2748  */
       
  2749 static void m3gResetLoader(Loader *loader)
       
  2750 {
       
  2751     /* Reset loader state */
       
  2752     loader->state = LOADSTATE_INITIAL;
       
  2753     loader->bytesRequired = sizeof(PNG_FILE_IDENTIFIER);
       
  2754 
       
  2755     m3gCleanupLoader(loader);
       
  2756     m3gResetBufferedData(&loader->stream);
       
  2757 }
       
  2758 
       
  2759 /*----------------------------------------------------------------------
       
  2760  * Virtual function table
       
  2761  *--------------------------------------------------------------------*/
       
  2762 
       
  2763 static const ObjectVFTable m3gvf_Loader = {
       
  2764     NULL, /* ApplyAnimation */
       
  2765     NULL, /* IsCompatible */
       
  2766     NULL, /* UpdateProperty */
       
  2767     NULL, /* DoGetReferences */
       
  2768     NULL, /* FindID */
       
  2769     NULL, /* Duplicate */
       
  2770     m3gDestroyLoader
       
  2771 };
       
  2772     
       
  2773 
       
  2774 /*----------------------------------------------------------------------
       
  2775  * Public interface
       
  2776  *--------------------------------------------------------------------*/
       
  2777 
       
  2778 /*!
       
  2779  * \brief Creates a new loader instance
       
  2780  */
       
  2781 M3G_API M3GLoader m3gCreateLoader(M3GInterface m3g)
       
  2782 {
       
  2783     Loader *loader;
       
  2784     M3G_VALIDATE_INTERFACE(m3g);
       
  2785 
       
  2786     loader = m3gAllocZ(m3g, sizeof(*loader));
       
  2787     if (loader != NULL) {
       
  2788         m3gInitObject(&loader->object, m3g, M3G_CLASS_LOADER);
       
  2789         m3gInitArray(&loader->refArray);
       
  2790         m3gInitArray(&loader->userDataArray);
       
  2791         loader->bytesRequired = sizeof(PNG_FILE_IDENTIFIER);
       
  2792         loader->state = LOADSTATE_INITIAL;
       
  2793         loader->sectionNum = -1;
       
  2794     }
       
  2795     return loader;
       
  2796 }
       
  2797 
       
  2798 /*!
       
  2799  * \brief Import a set of objects into the reference table of a loader
       
  2800  *
       
  2801  * This is intended for passing in external references, decoded in
       
  2802  * Java
       
  2803  */
       
  2804 M3G_API void m3gImportObjects(M3GLoader loader, M3Gint n, M3GObject *refs)
       
  2805 {
       
  2806     int i;
       
  2807     M3G_VALIDATE_OBJECT(loader);
       
  2808 
       
  2809     if (loader->state == LOADSTATE_DONE)
       
  2810         m3gResetLoader(loader);
       
  2811     for (i = 0; i < n; ++i) {
       
  2812         /* For loop is interrupted in case of OOM */
       
  2813         if (m3gArrayAppend(&loader->refArray,
       
  2814                            refs[i],
       
  2815                            M3G_INTERFACE(loader)) == -1) {
       
  2816             break;
       
  2817         }
       
  2818         m3gAddRef(refs[i]);
       
  2819     }
       
  2820 }
       
  2821 
       
  2822 /*!
       
  2823  * \brief Return the complete reference table for this loader instance
       
  2824  *
       
  2825  * The reference table will contain the handle of each object that has
       
  2826  * been loaded so far.
       
  2827  *
       
  2828  * \param loader loader instance
       
  2829  * \param buffer destination buffer, or NULL to just get
       
  2830  *               the number of unreferenced objects
       
  2831  * \return number of unreferenced objects
       
  2832  */
       
  2833 M3G_API M3Gint m3gGetLoadedObjects(M3GLoader loader, M3GObject *buffer)
       
  2834 {
       
  2835     PointerArray *refs;
       
  2836     int i, n, unref = 0;
       
  2837     M3Gbool referenced;
       
  2838     M3GObject obj, *dst = buffer;
       
  2839     M3G_VALIDATE_OBJECT(loader);
       
  2840 
       
  2841     /* If error in decoding, reset and return 0 objects */
       
  2842     if (loader->state < LOADSTATE_INITIAL) {
       
  2843         return 0;
       
  2844     }
       
  2845 
       
  2846     refs = &loader->refArray;
       
  2847     n = m3gArraySize(refs);
       
  2848 
       
  2849     /* Scan unreferenced objects */
       
  2850     for (i = 0; i < n; ++i) {
       
  2851         obj = m3gGetLoadedPtr(refs, i, &referenced);
       
  2852         if (!referenced) {
       
  2853             unref++;
       
  2854             if (dst != NULL) {
       
  2855                 *dst++ = obj;
       
  2856             }
       
  2857         }
       
  2858     }
       
  2859 
       
  2860     return unref;
       
  2861 }
       
  2862 
       
  2863 /*!
       
  2864  * \brief Submits data to the loader for processing
       
  2865  *
       
  2866  * Upon data input, the loader will either read more objects from the
       
  2867  * stream or buffer the data for processing later on. The return value
       
  2868  * will indicate how many bytes of data are required before the next
       
  2869  * data element can be loaded, but that data can still be submitted in
       
  2870  * smaller blocks.
       
  2871  *
       
  2872  * \param loader the loader instance
       
  2873  * \param bytes  the number of bytes in the data
       
  2874  * \param data   pointer to the data
       
  2875  *
       
  2876  * \return the number of bytes required to load the next data element,
       
  2877  * or zero to indicate that loading has finished
       
  2878  */
       
  2879 
       
  2880 #ifdef M3G_ENABLE_PROFILING
       
  2881 static M3Gsizei m3gDecodeDataInternal(M3GLoader loader,
       
  2882                                M3Gsizei bytes,
       
  2883                                const M3Gubyte *data);
       
  2884 
       
  2885 M3G_API M3Gsizei m3gDecodeData(M3GLoader loader,
       
  2886                                M3Gsizei bytes,
       
  2887                                const M3Gubyte *data)
       
  2888 {
       
  2889     M3Gsizei bytesReq;
       
  2890     M3G_BEGIN_PROFILE(M3G_INTERFACE(loader), M3G_PROFILE_LOADER_DECODE);
       
  2891     bytesReq = m3gDecodeDataInternal(loader, bytes, data);
       
  2892     M3G_END_PROFILE(M3G_INTERFACE(loader), M3G_PROFILE_LOADER_DECODE);
       
  2893     return bytesReq;
       
  2894 }
       
  2895 
       
  2896 static M3Gsizei m3gDecodeDataInternal(M3GLoader loader,
       
  2897                                M3Gsizei bytes,
       
  2898                                const M3Gubyte *data)
       
  2899 
       
  2900 #else
       
  2901 M3G_API M3Gsizei m3gDecodeData(M3GLoader loader,
       
  2902                                M3Gsizei bytes,
       
  2903                                const M3Gubyte *data)
       
  2904 
       
  2905 #endif
       
  2906 {
       
  2907     m3gErrorHandler *errorHandler;
       
  2908     Interface *m3g = M3G_INTERFACE(loader);
       
  2909 
       
  2910     M3G_VALIDATE_OBJECT(loader);
       
  2911     M3G_VALIDATE_INTERFACE(m3g);
       
  2912 
       
  2913     /* Check for errors */
       
  2914     if (bytes <= 0 || data == NULL) {
       
  2915         m3gRaiseError(m3g, M3G_INVALID_VALUE);
       
  2916         return 0;
       
  2917     }
       
  2918 
       
  2919     if (loader->state == LOADSTATE_DONE)
       
  2920         m3gResetLoader(loader);
       
  2921 
       
  2922     /* Submit data, then load until we run out of data again or are
       
  2923      * finished */
       
  2924 
       
  2925     if (!m3gBufferData(m3g, &loader->stream, bytes, data)) {
       
  2926         return 0;
       
  2927     }
       
  2928 
       
  2929     /* Disable error handler */
       
  2930     errorHandler = m3gSetErrorHandler(m3g, NULL);
       
  2931 
       
  2932     /* Continue loading if sufficient data has arrived */
       
  2933     while (loader->bytesRequired > 0
       
  2934            && loader->bytesRequired <= loader->stream.bytesAvailable) {
       
  2935         loader->state = m3gLoaderMain(loader);
       
  2936     }
       
  2937 
       
  2938     /* Restore error handler */
       
  2939     m3gSetErrorHandler(m3g, errorHandler); 
       
  2940 
       
  2941     /* Check if error was raised */
       
  2942     if (m3gErrorRaised(m3g) != M3G_NO_ERROR) {
       
  2943         /* Need to free all loaded objects */
       
  2944         m3gResetLoader(loader);
       
  2945 
       
  2946         /* Raise again with original error handler in place */
       
  2947         if (m3gErrorRaised(m3g) == M3G_OUT_OF_MEMORY)
       
  2948             m3gRaiseError(m3g, M3G_OUT_OF_MEMORY);
       
  2949         else
       
  2950             m3gRaiseError(m3g, M3G_IO_ERROR);
       
  2951         return 0;
       
  2952     }
       
  2953 
       
  2954     /* Return the number of bytes we need for loading to proceed
       
  2955      * further; clamp to zero in case we're exiting due to an error,
       
  2956      * or just have been fed excess data */
       
  2957     {
       
  2958         M3Gsizei bytesReq =
       
  2959             loader->bytesRequired - loader->stream.bytesAvailable;
       
  2960 
       
  2961         /* Check if whole file is done */
       
  2962         if (loader->stream.totalBytes >= loader->fileSize) {
       
  2963             loader->state = LOADSTATE_DONE;
       
  2964             bytesReq = 0;
       
  2965         }
       
  2966 
       
  2967         return (bytesReq >= 0) ? bytesReq : 0;
       
  2968     }
       
  2969 }
       
  2970 
       
  2971 /*!
       
  2972  * \brief Return all loaded objects with user parameters
       
  2973  *
       
  2974  * \param loader  the loader instance
       
  2975  * \param objects an array for objects with user parameters,
       
  2976  *                or null to return the number of objects
       
  2977  *
       
  2978  * \return Number of objects with user parameters
       
  2979  */
       
  2980 M3G_API M3Gint m3gGetObjectsWithUserParameters(M3GLoader loader, M3GObject *objects) {
       
  2981     const Loader *ldr = (const Loader *) loader;
       
  2982     M3G_VALIDATE_OBJECT(ldr);
       
  2983     {
       
  2984         M3Gint i, n;
       
  2985         n = m3gArraySize(&ldr->userDataArray);
       
  2986     
       
  2987         if (objects != NULL)
       
  2988             for (i = 0; i < n; ++i)
       
  2989             {
       
  2990                 const UserData *data = (const UserData *)m3gGetArrayElement(&ldr->userDataArray, i);
       
  2991                 objects[i] = data->object;
       
  2992             }
       
  2993         return n;
       
  2994     }
       
  2995 }
       
  2996 
       
  2997 /*!
       
  2998  * \brief Return the number of user parameters loaded for an object
       
  2999  */
       
  3000 M3G_API M3Gint m3gGetNumUserParameters(M3GLoader loader, M3Gint object)
       
  3001 {
       
  3002     const Loader *ldr = (const Loader *) loader;
       
  3003     M3G_VALIDATE_OBJECT(ldr);
       
  3004     {
       
  3005         const UserData *data = (const UserData *)m3gGetArrayElement(&ldr->userDataArray, object);
       
  3006         return (data != NULL) ? data->numParams : 0;
       
  3007     }
       
  3008 }
       
  3009 
       
  3010 /*!
       
  3011  * \brief Set constraints for loading.
       
  3012  * \param triConstraint maximum triangle count
       
  3013  */
       
  3014 M3G_API void m3gSetConstraints(M3GLoader loader, M3Gint triConstraint)
       
  3015 {
       
  3016     M3G_VALIDATE_OBJECT(loader);
       
  3017     loader->triConstraint = triConstraint;
       
  3018 }
       
  3019 
       
  3020 /*!
       
  3021  * \brief Return the given user parameter for an object
       
  3022  *
       
  3023  * \param loader the loader instance
       
  3024  * \param object the object to query
       
  3025  * \param index  index of the string to query
       
  3026  * \param buffer buffer to copy the data into,
       
  3027  *               or NULL to just query the length
       
  3028  *
       
  3029  * \return id of the parameter, or the length of the string if data was NULL
       
  3030  */
       
  3031 M3G_API M3Gsizei m3gGetUserParameter(M3GLoader loader,
       
  3032                                      M3Gint object,
       
  3033                                      M3Gint index,
       
  3034                                      M3Gbyte *buffer)
       
  3035 {
       
  3036     const Loader *ldr = (const Loader *) loader;
       
  3037     M3G_VALIDATE_OBJECT(ldr);
       
  3038     {
       
  3039         const UserData *data = (const UserData *)m3gGetArrayElement(&ldr->userDataArray, object);
       
  3040         if (data != NULL && m3gInRange(index, 0, data->numParams - 1)) {
       
  3041             const char *src = (const char *)data->params[index];
       
  3042             M3Gsizei len = data->paramLengths[index];
       
  3043             if (buffer != NULL) {
       
  3044                 m3gCopy(buffer, src, len);
       
  3045                 return data->paramId[index];
       
  3046             }
       
  3047             else
       
  3048                 return len;
       
  3049         }
       
  3050         else
       
  3051             return 0;
       
  3052     }
       
  3053 }
       
  3054 
       
  3055 #undef ANY_NODE_CLASS
       
  3056