First public contribution.
2 * Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
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".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
14 * Description: Native implementation of the Loader class
22 * \brief Native implementation of the Loader class
26 #include "m3g_object.h"
27 #include "m3g_array.h"
29 /*----------------------------------------------------------------------
31 *--------------------------------------------------------------------*/
35 * \brief Possible global states for the loader
38 /*! \internal \brief Loading not supported yet */
39 LOADSTATE_NOT_SUPPORTED = -2,
40 /*! \internal \brief Loading has terminated with an error */
42 /*! \internal \brief Loading has not started yet */
43 LOADSTATE_INITIAL = 0,
44 /*! \internal \brief The identifier of the file is being read */
46 /*! \internal \brief The header of the section is being read */
48 /*! \internal \brief The header field of an object is being read */
50 /*! \internal \brief Loading is finished */
56 * \brief Possible local states for the loader
59 /*! \internal \brief Local state is entered */
61 /*! \internal \brief Local state is exited */
63 /*! \internal \brief Local state is section checksum */
69 * \brief Buffered byte stream class
73 M3Gubyte *allocatedData;
75 M3Gsizei capacity, bytesAvailable, totalBytes;
80 * \brief User data for a loaded object
87 M3Gsizei *paramLengths;
93 * \brief Loader instance data
95 typedef struct M3GLoaderImpl
99 BufferedStream stream;
100 M3Gsizei bytesRequired;
101 M3Gsizei sectionBytesRequired;
103 PointerArray refArray;
104 PointerArray userDataArray;
108 * \brief The global state the loader is in
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
119 * \brief The local state of the loader
121 * This is basically the line number within a particular coroutine
128 * \brief Object being loaded
134 * \brief Loaded object
136 M3GObject loadedObject;
140 * \brief Pointer to the beginning of an object
142 M3Gubyte *objectData;
146 * \brief Pointer to the end of an object
148 M3Gubyte *objectDataEnd;
152 * \brief Pointer to the context data for the current coroutine
159 * \brief Size of the current coroutine data
161 * This is grown dynamically as necessary, rather than trying to
162 * maintain a single size that fits all coroutines.
164 size_t localDataSize;
166 /* File information */
167 M3Gbool hasReferences;
169 M3Gsizei contentSize;
171 M3Gint triConstraint;
173 /* Section information */
175 M3Gint sectionLength;
177 M3Gint inflatedLength;
178 M3Gubyte *sectionData;
179 M3Gubyte *allocatedSectionData;
186 const unsigned char *data;
191 /* Type ID used for classifying objects derived from Node */
192 #define ANY_NODE_CLASS ((M3GClass)(-1))
195 #define m3gCmp(s1, s2, len) memcmp(s1, s2, len)
197 /*----------------------------------------------------------------------
199 *--------------------------------------------------------------------*/
201 #define M3G_MIN_OBJECT_SIZE (1 + 4)
202 #define M3G_MIN_SECTION_SIZE (1 + 4 + 4)
203 #define M3G_CHECKSUM_SIZE 4
205 #define M3G_ADLER_CONST 65521;
207 static const M3Gubyte M3G_FILE_IDENTIFIER[] = {
208 0xAB, 0x4A, 0x53, 0x52, 0x31, 0x38, 0x34, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
211 static const M3Gubyte PNG_FILE_IDENTIFIER[] = {
212 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a
215 static void m3gCleanupLoader(M3GLoader loader);
217 /*----------------------------------------------------------------------
218 * Platform-specific "inflate" decompression code
219 *--------------------------------------------------------------------*/
223 * \brief Decompresses a block of data into an output buffer
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
231 static M3Gsizei m3gInflateBlock(M3Gsizei srcLength, const M3Gubyte *src,
232 M3Gsizei dstLength, M3Gubyte *dst);
234 /* Include the platform-dependent implementation */
235 #if !defined(M3G_TARGET_GENERIC)
236 # include "m3g_loader_inflate.inl"
239 /*----------------------------------------------------------------------
241 *--------------------------------------------------------------------*/
247 static void m3gDestroyLoader(Object *obj)
249 Loader* loader = (Loader *) obj;
250 M3G_VALIDATE_OBJECT(loader);
252 Interface *m3g = M3G_INTERFACE(loader);
255 m3gCleanupLoader(loader);
256 m3gDestroyArray(&loader->refArray, m3g);
257 n = m3gArraySize(&loader->userDataArray);
258 for (i = 0; i < n; ++i)
260 UserData *data = (UserData *)m3gGetArrayElement(&loader->userDataArray, i);
261 m3gFree(m3g, data->params);
262 m3gFree(m3g, data->paramLengths);
263 m3gFree(m3g, data->paramId);
266 m3gDestroyArray(&loader->userDataArray, m3g);
267 m3gFree(m3g, loader->stream.allocatedData);
268 m3gFree(m3g, loader->allocatedSectionData);
270 m3gDestroyObject(obj);
275 * \brief Stores new data in the stream buffer of this loader
277 static M3Gbool m3gBufferData( M3GInterface m3g,
278 BufferedStream *stream,
280 const M3Gubyte *data)
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) {
291 stream->data = stream->allocatedData;
292 stream->bytesAvailable = 0;
293 stream->totalBytes = 0;
296 /* First skip used bytes */
297 used = stream->data - stream->allocatedData;
299 m3gMove(stream->allocatedData, stream->data, stream->bytesAvailable);
300 stream->data = stream->allocatedData;
303 /* Check if new data fits in current buffer */
304 if ((stream->capacity - stream->bytesAvailable) < bytes) {
306 stream->capacity = stream->capacity + bytes + 512;
307 newData = m3gAllocZ(m3g, stream->capacity);
309 m3gFree(m3g, stream->allocatedData);
310 stream->allocatedData = NULL;
313 m3gCopy(newData, stream->data, stream->bytesAvailable);
314 m3gFree(m3g, stream->allocatedData);
315 stream->allocatedData = newData;
316 stream->data = stream->allocatedData;
319 m3gCopy(stream->data + stream->bytesAvailable, data, bytes);
320 stream->bytesAvailable += bytes;
327 * \brief Resets buffered data
329 static void m3gResetBufferedData(BufferedStream *stream)
331 stream->bytesAvailable = 0;
332 stream->data = stream->allocatedData;
333 stream->totalBytes = 0;
338 * \brief Gets buffered data pointer
340 static M3Gubyte *m3gGetBufferedDataPtr(BufferedStream *stream, M3Gint length)
342 if (stream->bytesAvailable >= length) {
352 * \brief Advances buffered data pointer
354 static void m3gAdvanceBufferedData(BufferedStream *stream, M3Gint length)
356 stream->data += length;
357 stream->bytesAvailable -= length;
358 stream->totalBytes += length;
363 * \brief Verify a boolean
365 static M3Gbool m3gVerifyBool(M3Gubyte *data)
367 return (*data == 0 || *data == 1);
372 * \brief Loads ARGB color from data array
374 static M3Guint m3gLoadARGB(M3Gubyte *data)
389 * \brief Loads RGB color from data array
391 static M3Guint m3gLoadRGB(M3Gubyte *data)
404 * \brief Loads short from data array
406 static M3Gshort m3gLoadShort(M3Gubyte *data)
408 M3Gshort v = data[1];
417 * \brief Loads integer from data array
419 static M3Gint m3gLoadInt(M3Gubyte *data)
434 * \brief Loads integer from data array
436 static M3Gbool m3gLoadFloat(M3Gubyte *data, M3Gfloat *res)
446 *res = (*(M3Gfloat*)&(v));
447 if ((v & 0x7f800000) == 0x7f800000 ||
448 v == 0x80000000 || // negative zero
449 ((v & 0x007FFFFF ) != 0 && ( v & 0x7F800000 ) == 0))
456 * \brief Loads 4 * 4 matrix from data array
458 static M3Gbool m3gLoadMatrix(Matrix *m, M3Gubyte *data)
463 for (i = 0; i < 16; i++) {
464 if (!m3gLoadFloat(data + 4 * i, &array[i]))
468 m3gSetMatrixRows(m, array);
474 * \brief Inflates a section
476 static M3Gubyte *m3gInflateSection(Loader *loader,
477 M3Gubyte *compressed,
478 M3Gint cLength, M3Gint iLength)
480 M3Gubyte *inflated = m3gAllocZ(M3G_INTERFACE(loader), iLength);
481 if (inflated && !m3gInflateBlock(cLength, compressed, iLength, inflated)) {
482 m3gFree(M3G_INTERFACE(loader), inflated);
491 * \brief Loads file identifier
493 static LoaderState m3gLoadIdentifier(Loader *loader)
495 M3Gubyte *data = m3gGetBufferedDataPtr(&loader->stream, loader->bytesRequired);
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;
503 loader->localState = LOADSTATE_EXIT;
504 loader->bytesRequired = sizeof(M3G_FILE_IDENTIFIER);
505 return LOADSTATE_IDENTIFIER;
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;
516 loader->bytesRequired = 0;
517 return LOADSTATE_ERROR;
523 * \brief Adler helper functions
526 static void m3gInitAdler(M3Gint *S12)
528 S12[0] = 1; S12[1] = 0;
531 static void m3gUpdateAdler(M3Gint *S12, M3Gubyte *data, M3Gint length)
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;
540 static M3Gint m3gGetAdler(M3Gint *S12)
542 return (S12[1] << 16) | S12[0];
547 * \brief Loads a section
549 static LoaderState m3gLoadSection(Loader *loader)
551 M3Gubyte *data = m3gGetBufferedDataPtr(&loader->stream, loader->bytesRequired);
554 m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
555 return LOADSTATE_ERROR;
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);
566 m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
567 return LOADSTATE_ERROR;
569 loader->compressed = data[0];
570 loader->sectionLength = m3gLoadInt(data + 1);
571 loader->inflatedLength = m3gLoadInt(data + 5);
573 loader->localState = LOADSTATE_EXIT;
574 loader->bytesRequired = loader->sectionLength - loader->bytesRequired;
575 if (!loader->compressed && loader->inflatedLength != (loader->bytesRequired - M3G_CHECKSUM_SIZE))
577 m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
578 return LOADSTATE_ERROR;
581 loader->sectionNum++;
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;
590 return LOADSTATE_SECTION;
594 m3gUpdateAdler(loader->S12, data, loader->bytesRequired - M3G_CHECKSUM_SIZE);
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;
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;
609 loader->sectionData = NULL;
613 loader->sectionData = data;
616 loader->localData = loader->sectionData;
617 loader->sectionBytesRequired = M3G_MIN_OBJECT_SIZE;
618 loader->localState = LOADSTATE_ENTER;
619 return LOADSTATE_OBJECT;
621 case LOADSTATE_CHECKSUM:
622 if (loader->localData != loader->sectionData + loader->inflatedLength || /* Length */
623 m3gLoadInt(data + loader->bytesRequired - M3G_CHECKSUM_SIZE) != m3gGetAdler(loader->S12))
625 m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
626 m3gFree(M3G_INTERFACE(loader), loader->allocatedSectionData);
627 loader->allocatedSectionData = NULL;
628 return LOADSTATE_ERROR;
630 m3gAdvanceBufferedData(&loader->stream, loader->bytesRequired);
632 m3gFree(M3G_INTERFACE(loader), loader->allocatedSectionData);
633 loader->allocatedSectionData = NULL;
635 loader->localState = LOADSTATE_ENTER;
636 loader->bytesRequired = M3G_MIN_SECTION_SIZE;
637 return LOADSTATE_SECTION;
643 * \brief Resets section data pointer to the beginning of an object
645 static void m3gRewindObject(Loader *loader)
647 loader->localData = loader->objectData;
652 * \brief Resets section data pointer to the end of an object
654 static void m3gSkipObject(Loader *loader)
656 loader->localData = loader->objectDataEnd;
661 * \brief Marks object to begin
663 static void m3gBeginObject(Loader *loader)
665 loader->objectData = loader->localData;
670 * \brief Marks object to end
672 static void m3gEndObject(Loader *loader)
674 loader->objectDataEnd = loader->localData;
679 * \brief Gets section data pointer
681 static M3Gubyte *m3gGetSectionDataPtr(Loader *loader, M3Gint length)
683 if ((loader->localData + length) <= (loader->sectionData + loader->inflatedLength)) {
684 return loader->localData;
693 * \brief Advances section data pointer
695 static void m3gAdvanceSectionData(Loader *loader, M3Gint length)
697 loader->localData += length;
702 * \brief Check length of the available section data
704 static M3Gbool m3gCheckSectionDataLength(Loader *loader, const M3Gubyte *data, M3Gsizei length)
706 if (data + length < data) return M3G_FALSE; /* Check for overflow */
707 return ((data + length) <= (loader->sectionData + loader->inflatedLength));
712 * \brief References an object in the object array
714 * \note Uses lowest bit of the pointer to mark a reference
716 static void m3gReferenceLoaded(PointerArray *array, M3Gint idx)
718 M3Guint ptr = (M3Guint)m3gGetArrayElement(array, idx);
720 m3gSetArrayElement(array, idx, (void *)ptr);
725 * \brief Gets an object in the object array and
726 * returns reference status
728 static M3GObject m3gGetLoadedPtr(PointerArray *array, M3Gint idx, M3Gbool *referenced)
730 M3Guint ptr = (M3Guint)m3gGetArrayElement(array, idx);
731 if (referenced != NULL) {
732 *referenced = ptr & 1;
734 return (M3GObject)(ptr & (~1));
739 * \brief Gets a loaded object and marks it referenced
741 static M3GObject m3gGetLoaded(Loader *loader, M3Gint idx, M3GClass classID)
745 M3Gbool isCompatible;
747 if (idx == 0) return NULL;
750 if (idx < 0 || idx >= m3gArraySize(&loader->refArray)) {
751 /* Error, not loaded */
752 m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
756 obj = m3gGetLoadedPtr(&loader->refArray, idx, NULL);
757 objClassID = M3G_CLASS(obj);
759 /* Class type check; handle nodes as a special case */
761 if (classID == ANY_NODE_CLASS) {
762 switch (objClassID) {
763 case M3G_CLASS_CAMERA:
764 case M3G_CLASS_GROUP:
765 case M3G_CLASS_LIGHT:
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;
774 isCompatible = M3G_FALSE;
779 case M3G_ABSTRACT_CLASS:
780 M3G_ASSERT(M3G_FALSE);
781 isCompatible = M3G_FALSE;
784 isCompatible = (objClassID == M3G_CLASS_MESH)
785 || (objClassID == M3G_CLASS_MORPHING_MESH)
786 || (objClassID == M3G_CLASS_SKINNED_MESH);
789 isCompatible = (classID == objClassID);
794 /* Error, class mismatch */
795 m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
799 /* Mark object as referenced */
800 m3gReferenceLoaded(&loader->refArray, idx);
806 * \brief Loads Object3D data
808 static M3Gbool m3gLoadObject3DData(Loader *loader, M3GObject obj)
810 M3Guint animTracks, i, userParams, paramId, paramLength;
811 UserData *userData = NULL;
812 M3Gubyte *data = m3gGetSectionDataPtr(loader, 8);
813 if (data == NULL) return M3G_FALSE;
815 m3gSetUserID(obj, m3gLoadInt(data));
818 animTracks = m3gLoadInt(data);
822 if (animTracks >= 0x1fffffff) {
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) {
835 userParams = m3gLoadInt(data);
838 if (userParams != 0) {
840 if (userParams >= 0x10000000) {
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)
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);
865 for (i = 0; i < userParams; i++) {
866 if (m3gCheckSectionDataLength(loader, data, 8) == M3G_FALSE) return M3G_FALSE;
867 paramId = m3gLoadInt(data);
869 paramLength = m3gLoadInt(data);
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)
877 m3gCopy(userData->params[i], data, paramLength);
882 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
888 * \brief Skips Object3D data
890 static M3Gbool m3gSkipObject3DData(Loader *loader)
892 M3Guint animTracks, i, userParams, paramLength;
893 M3Gubyte *data = m3gGetSectionDataPtr(loader, 8);
894 if (data == NULL) return M3G_FALSE;
897 animTracks = m3gLoadInt(data);
901 if (animTracks >= 0x1fffffff) {
905 if (m3gCheckSectionDataLength(loader, data, animTracks * 4 + 4) == M3G_FALSE) return M3G_FALSE;
906 for (i = 0; i < animTracks; i++) {
910 userParams = m3gLoadInt(data);
913 for (i = 0; i < userParams; i++) {
914 if (m3gCheckSectionDataLength(loader, data, 8) == M3G_FALSE) return M3G_FALSE;
916 paramLength = m3gLoadInt(data);
917 if (m3gCheckSectionDataLength(loader, data, paramLength) == M3G_FALSE) return M3G_FALSE;
918 data += 4 + paramLength;
921 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
927 * \brief Loads transformable data
929 static M3Gbool m3gLoadTransformableData(Loader *loader, M3GTransformable obj)
931 M3Gfloat f1, f2, f3, f4;
933 if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
937 data = m3gGetSectionDataPtr(loader, 1);
938 if (data == NULL) return M3G_FALSE;
940 if (!m3gVerifyBool(data)) return M3G_FALSE;
941 /* Component transform ? */
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))
948 m3gSetTranslation(obj, f1, f2, f3);
949 if (!m3gLoadFloat(data + 12, &f1) ||
950 !m3gLoadFloat(data + 16, &f2) ||
951 !m3gLoadFloat(data + 20, &f3))
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))
959 m3gSetOrientation(obj, f1, f2, f3, f4);
963 if (m3gCheckSectionDataLength(loader, data, 1) == M3G_FALSE) return M3G_FALSE;
964 if (!m3gVerifyBool(data)) return M3G_FALSE;
965 /* Generic transform */
968 if (m3gCheckSectionDataLength(loader, data, 64) == M3G_FALSE) return M3G_FALSE;
969 if (!m3gLoadMatrix(&m, data)) return M3G_FALSE;
970 m3gSetTransform(obj, &m);
974 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
980 * \brief Skips transformable data
982 static M3Gbool m3gSkipTransformableData(Loader *loader)
985 if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
987 data = m3gGetSectionDataPtr(loader, 1);
988 if (data == NULL) return M3G_FALSE;
990 /* Component transform ? */
992 if (m3gCheckSectionDataLength(loader, data, 40) == M3G_FALSE) return M3G_FALSE;
996 if (m3gCheckSectionDataLength(loader, data, 1) == M3G_FALSE) return M3G_FALSE;
997 /* Generic transform */
999 if (m3gCheckSectionDataLength(loader, data, 64) == M3G_FALSE) return M3G_FALSE;
1003 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
1009 * \brief Loads node data
1011 static M3Gbool m3gLoadNodeData(Loader *loader, M3GNode obj)
1014 if (!m3gLoadTransformableData(loader, (M3GTransformable)obj)) {
1018 data = m3gGetSectionDataPtr(loader, 8);
1019 if (data == NULL) return M3G_FALSE;
1021 if (!m3gVerifyBool(data)) return M3G_FALSE;
1022 m3gEnable(obj, 0, *data++);
1023 if (!m3gVerifyBool(data)) return M3G_FALSE;
1024 m3gEnable(obj, 1, *data++);
1026 unsigned a = *data++;
1027 m3gSetAlphaFactor(obj, m3gDivif(a, 255));
1029 m3gSetScope(obj, m3gLoadInt(data));
1032 if (!m3gVerifyBool(data)) return M3G_FALSE;
1036 if (m3gCheckSectionDataLength(loader, data, 10) == M3G_FALSE) return M3G_FALSE;
1039 zr = m3gLoadInt(data);
1040 yr = m3gLoadInt(data + 4);
1041 m3gSetAlignment(obj, (M3GNode)m3gGetLoaded(loader, zr, ANY_NODE_CLASS),
1043 (M3GNode)m3gGetLoaded(loader, yr, ANY_NODE_CLASS),
1048 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
1054 * \brief Skips node data
1056 static M3Gbool m3gSkipNodeData(Loader *loader)
1059 if (!m3gSkipTransformableData(loader)) return M3G_FALSE;
1061 data = m3gGetSectionDataPtr(loader, 8);
1062 if (data == NULL) return M3G_FALSE;
1067 if (m3gCheckSectionDataLength(loader, data, 10) == M3G_FALSE) return M3G_FALSE;
1071 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
1077 * \brief Loads a camera
1079 static M3Gbool m3gLoadCamera(Loader *loader)
1081 M3Gfloat f1, f2, f3, f4;
1083 M3GCamera obj = m3gCreateCamera(M3G_INTERFACE(loader));
1084 loader->loadedObject = (M3GObject)obj;
1085 if (!obj) return M3G_FALSE;
1087 if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
1091 data = m3gGetSectionDataPtr(loader, 1);
1092 if (data == NULL) return M3G_FALSE;
1098 if (m3gCheckSectionDataLength(loader, data, 64) == M3G_FALSE) return M3G_FALSE;
1099 if (!m3gLoadMatrix(&m, data)) return M3G_FALSE;
1100 m3gSetProjectionMatrix(obj, &m);
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))
1111 m3gSetPerspective(obj, f1, f2, f3, f4);
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))
1121 m3gSetParallel(obj, f1, f2, f3, f4);
1129 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
1136 * \brief Loads a background
1138 static M3Gbool m3gLoadBackground(Loader *loader)
1141 M3GBackground obj = m3gCreateBackground(M3G_INTERFACE(loader));
1142 loader->loadedObject = (M3GObject)obj;
1143 if (!obj) return M3G_FALSE;
1145 if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
1149 data = m3gGetSectionDataPtr(loader, 28);
1150 if (data == NULL) return M3G_FALSE;
1152 m3gSetBgColor(obj, m3gLoadARGB(data));
1154 m3gSetBgImage(obj, (M3GImage)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_IMAGE));
1156 m3gSetBgMode(obj, data[0], data[1]);
1158 m3gSetBgCrop(obj, m3gLoadInt(data),
1159 m3gLoadInt(data + 4),
1160 m3gLoadInt(data + 8),
1161 m3gLoadInt(data + 12) );
1164 if (!m3gVerifyBool(data)) return M3G_FALSE;
1165 m3gSetBgEnable(obj, 0, *data++);
1166 if (!m3gVerifyBool(data)) return M3G_FALSE;
1167 m3gSetBgEnable(obj, 1, *data++);
1169 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
1176 * \brief Loads a vertex array
1178 static M3Gbool m3gLoadVertexArray(Loader *loader)
1183 M3Gubyte *data, components, encoding;
1184 M3Gdatatype componentSize;
1187 m3gBeginObject(loader);
1188 if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
1190 data = m3gGetSectionDataPtr(loader, 5);
1191 if (data == NULL) return M3G_FALSE;
1193 if (*data != 1 && *data != 2) return M3G_FALSE;
1194 componentSize = (*data++ == 1) ? M3G_BYTE : M3G_SHORT;
1195 components = *data++;
1197 vertices = m3gLoadShort(data);
1200 size = vertices * components * (componentSize == M3G_BYTE ? 1 : 2);
1203 if (size < vertices) {
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;
1212 if (componentSize == M3G_BYTE) {
1213 M3Gbyte previousValues[4];
1214 m3gZero(previousValues, sizeof(previousValues));
1216 for (i = 0; i < vertices; i++) {
1217 for (j = 0; j < components; j++) {
1218 if (encoding == 0) {
1219 previousValues[j] = *data++;
1222 previousValues[j] = (M3Gbyte) (previousValues[j] + *data++);
1225 m3gSetVertexArrayElements(obj, i, 1, sizeof(previousValues), componentSize, previousValues);
1229 M3Gshort previousValues[4];
1230 m3gZero(previousValues, sizeof(previousValues));
1232 for (i = 0; i < vertices; i++) {
1233 for (j = 0; j < components; j++) {
1234 if (encoding == 0) {
1235 previousValues[j] = m3gLoadShort(data);
1238 previousValues[j] = (M3Gshort) (previousValues[j] + m3gLoadShort(data));
1242 m3gSetVertexArrayElements(obj, i, 1, sizeof(previousValues), componentSize, previousValues);
1246 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
1248 m3gEndObject(loader);
1249 m3gRewindObject(loader);
1250 if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
1253 m3gSkipObject(loader);
1260 * \brief Loads a vertex buffer
1262 static M3Gbool m3gLoadVertexBuffer(Loader *loader)
1266 M3Gfloat bias[3], scale;
1268 M3GVertexBuffer obj = m3gCreateVertexBuffer(M3G_INTERFACE(loader));
1269 loader->loadedObject = (M3GObject)obj;
1270 if (!obj) return M3G_FALSE;
1272 if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
1276 data = m3gGetSectionDataPtr(loader, 36);
1277 if (data == NULL) return M3G_FALSE;
1279 m3gSetVertexDefaultColor(obj, m3gLoadARGB(data));
1283 va = (M3GVertexArray)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_ARRAY);
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;
1290 m3gSetVertexArray(obj, va, scale, bias, 3);
1295 va = (M3GVertexArray)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_ARRAY);
1298 m3gSetNormalArray(obj, va);
1302 va = (M3GVertexArray)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_ARRAY);
1305 m3gSetColorArray(obj, va);
1308 /* Texture coordinates */
1309 taCount = m3gLoadInt(data);
1313 if (taCount >= 0x0ccccccc) {
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);
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;
1326 m3gSetTexCoordArray(obj, i, va, scale, bias, 3);
1334 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
1342 * \brief Loads a triangle strip array
1344 static M3Gbool m3gLoadTsa(Loader *loader)
1347 M3GIndexBuffer obj = 0;
1349 M3Guint startIndex = 0, indicesCount = 0, *indices = NULL;
1350 M3Guint lengthCount;
1351 M3Gint *lengths = NULL;
1354 m3gBeginObject(loader);
1355 if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
1357 data = m3gGetSectionDataPtr(loader, 1);
1358 if (data == NULL) return M3G_FALSE;
1364 if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
1365 startIndex = m3gLoadInt(data);
1370 if (m3gCheckSectionDataLength(loader, data, 1) == M3G_FALSE) return M3G_FALSE;
1371 startIndex = *data++;
1375 if (m3gCheckSectionDataLength(loader, data, 2) == M3G_FALSE) return M3G_FALSE;
1376 startIndex = (M3Gushort) m3gLoadShort(data);
1381 if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
1382 indicesCount = m3gLoadInt(data);
1386 if (indicesCount >= 0x20000000) {
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);
1400 if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
1401 indicesCount = m3gLoadInt(data);
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++;
1412 if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
1413 indicesCount = m3gLoadInt(data);
1417 if (indicesCount >= 0x40000000) {
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);
1434 if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) goto cleanup;
1435 lengthCount = m3gLoadInt(data);
1439 if (lengthCount >= 0x20000000) {
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;
1447 for (i = 0; i < lengthCount; i++) {
1448 lengths[i] = m3gLoadInt(data);
1452 if (encoding == 0 || encoding == 1 || encoding == 2) {
1453 obj = m3gCreateImplicitStripBuffer( M3G_INTERFACE(loader),
1459 obj = m3gCreateStripBuffer( M3G_INTERFACE(loader),
1460 M3G_TRIANGLE_STRIPS,
1469 m3gFree(M3G_INTERFACE(loader), indices);
1470 m3gFree(M3G_INTERFACE(loader), lengths);
1472 loader->loadedObject = (M3GObject)obj;
1473 if (!obj) return M3G_FALSE;
1475 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
1477 m3gEndObject(loader);
1478 m3gRewindObject(loader);
1479 if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
1482 m3gSkipObject(loader);
1489 * \brief Loads a compositing mode
1491 static M3Gbool m3gLoadCompositingMode(Loader *loader)
1495 M3GCompositingMode obj = m3gCreateCompositingMode(M3G_INTERFACE(loader));
1496 loader->loadedObject = (M3GObject)obj;
1497 if (!obj) return M3G_FALSE;
1499 if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
1503 data = m3gGetSectionDataPtr(loader, 14);
1504 if (data == NULL) return M3G_FALSE;
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++);
1516 unsigned a = *data++;
1517 m3gSetAlphaThreshold(obj, m3gDivif(a, 255));
1519 if (!m3gLoadFloat(data, &f1) || !m3gLoadFloat(data + 4, &f2)) return M3G_FALSE;
1520 m3gSetDepthOffset (obj, f1, f2);
1523 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
1530 * \brief Loads a polygon mode
1532 static M3Gbool m3gLoadPolygonMode(Loader *loader)
1535 M3GPolygonMode obj = m3gCreatePolygonMode(M3G_INTERFACE(loader));
1536 loader->loadedObject = (M3GObject)obj;
1537 if (!obj) return M3G_FALSE;
1539 if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
1543 data = m3gGetSectionDataPtr(loader, 6);
1544 if (data == NULL) return M3G_FALSE;
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++);
1556 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
1563 * \brief Loads an appearance
1565 static M3Gbool m3gLoadAppearance(Loader *loader)
1567 M3Guint textures, i;
1569 M3GAppearance obj = m3gCreateAppearance(M3G_INTERFACE(loader));
1570 loader->loadedObject = (M3GObject)obj;
1571 if (!obj) return M3G_FALSE;
1573 if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
1577 data = m3gGetSectionDataPtr(loader, 21);
1578 if (data == NULL) return M3G_FALSE;
1580 m3gSetLayer(obj, (M3Gbyte)*data++);
1581 m3gSetCompositingMode(obj, (M3GCompositingMode)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_COMPOSITING_MODE));
1583 m3gSetFog(obj, (M3GFog)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_FOG));
1585 m3gSetPolygonMode(obj, (M3GPolygonMode)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_POLYGON_MODE));
1587 m3gSetMaterial(obj, (M3GMaterial)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_MATERIAL));
1590 textures = m3gLoadInt(data);
1594 if (textures >= 0x20000000) {
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);
1604 m3gSetTexture(obj, i, tex);
1608 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
1615 * \brief Loads a mesh
1617 static M3Gbool m3gLoadMesh(Loader *loader)
1619 M3Guint subMeshCount, i;
1621 M3GIndexBuffer *ib = NULL;
1622 M3GAppearance *ap = NULL;
1626 m3gBeginObject(loader);
1627 if (!m3gSkipNodeData(loader)) return M3G_FALSE;
1629 data = m3gGetSectionDataPtr(loader, 8);
1630 if (data == NULL) return M3G_FALSE;
1632 vb = (M3GVertexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_BUFFER);
1633 if (vb == NULL) return M3G_FALSE;
1635 subMeshCount = m3gLoadInt(data);
1639 if (subMeshCount >= 0x10000000) {
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;
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;
1655 ib[i] = indexBuffer;
1657 ap[i] = (M3GAppearance)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_APPEARANCE);
1661 obj = m3gCreateMesh( M3G_INTERFACE(loader),
1668 m3gFree(M3G_INTERFACE(loader), ib);
1669 m3gFree(M3G_INTERFACE(loader), ap);
1670 loader->loadedObject = (M3GObject)obj;
1671 if (!obj) return M3G_FALSE;
1673 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
1675 m3gEndObject(loader);
1676 m3gRewindObject(loader);
1677 if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
1680 m3gSkipObject(loader);
1687 * \brief Loads group data
1689 static M3Gbool m3gLoadGroupData(Loader *loader, M3GGroup obj)
1691 M3Guint childCount, i;
1694 if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
1698 data = m3gGetSectionDataPtr(loader, 4);
1699 if (data == NULL) return M3G_FALSE;
1701 childCount = m3gLoadInt(data);
1705 if (childCount >= 0x20000000) {
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));
1715 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
1722 * \brief Loads a group
1724 static M3Gbool m3gLoadGroup(Loader *loader)
1726 M3GGroup obj = m3gCreateGroup(M3G_INTERFACE(loader));
1727 loader->loadedObject = (M3GObject)obj;
1728 if (!obj) return M3G_FALSE;
1730 if (!m3gLoadGroupData(loader, obj)) {
1739 * \brief Loads a world
1741 static M3Gbool m3gLoadWorld(Loader *loader)
1745 M3GWorld obj = m3gCreateWorld(M3G_INTERFACE(loader));
1746 loader->loadedObject = (M3GObject)obj;
1747 if (!obj) return M3G_FALSE;
1749 if (!m3gLoadGroupData(loader, (M3GGroup)obj)) {
1753 data = m3gGetSectionDataPtr(loader, 8);
1754 if (data == NULL) return M3G_FALSE;
1756 cam = (M3GCamera)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_CAMERA);
1759 m3gSetActiveCamera(obj, cam);
1761 m3gSetBackground(obj, (M3GBackground)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_BACKGROUND));
1764 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
1771 * \brief Loads a light
1773 static M3Gbool m3gLoadLight(Loader *loader)
1775 M3Gfloat f1, f2, f3;
1777 M3GLight obj = m3gCreateLight(M3G_INTERFACE(loader));
1778 loader->loadedObject = (M3GObject)obj;
1779 if (!obj) return M3G_FALSE;
1781 if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
1785 data = m3gGetSectionDataPtr(loader, 28);
1786 if (data == NULL) return M3G_FALSE;
1788 if (!m3gLoadFloat(data, &f1) ||
1789 !m3gLoadFloat(data + 4, &f2) ||
1790 !m3gLoadFloat(data + 8, &f3)) return M3G_FALSE;
1791 m3gSetAttenuation (obj, f1, f2, f3);
1793 m3gSetLightColor (obj, m3gLoadRGB(data));
1795 m3gSetLightMode (obj, *data++);
1796 if (!m3gLoadFloat(data, &f1)) return M3G_FALSE;
1797 m3gSetIntensity (obj, f1);
1799 if (!m3gLoadFloat(data, &f1)) return M3G_FALSE;
1800 m3gSetSpotAngle (obj, f1);
1802 if (!m3gLoadFloat(data, &f1)) return M3G_FALSE;
1803 m3gSetSpotExponent (obj, f1);
1806 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
1813 * \brief Loads a keyframe sequence
1815 static M3Gbool m3gLoadKeyframeSequence(Loader *loader)
1817 M3Guint i, j, interpolation, repeatMode, encoding, duration,
1818 rangeFirst, rangeLast, components, keyFrames, size;
1821 M3GKeyframeSequence obj;
1823 m3gBeginObject(loader);
1824 if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
1826 data = m3gGetSectionDataPtr(loader, 23);
1827 if (data == NULL) return M3G_FALSE;
1829 interpolation = *data++;
1830 repeatMode = *data++;
1832 duration = m3gLoadInt(data);
1834 rangeFirst = m3gLoadInt(data);
1836 rangeLast = m3gLoadInt(data);
1838 components = m3gLoadInt(data);
1840 keyFrames = m3gLoadInt(data);
1843 if (encoding == 0) {
1844 size = keyFrames * (4 + components * 4);
1847 size = components * 8 + keyFrames * (4 + components * (encoding == 1 ? 1 : 2));
1851 if (size < keyFrames) {
1855 if (m3gCheckSectionDataLength(loader, data, size) == M3G_FALSE) return M3G_FALSE;
1857 obj = m3gCreateKeyframeSequence(M3G_INTERFACE(loader), keyFrames, components, interpolation);
1858 loader->loadedObject = (M3GObject)obj;
1859 if (!obj) return M3G_FALSE;
1861 m3gSetRepeatMode(obj, repeatMode);
1862 m3gSetDuration(obj, duration);
1863 m3gSetValidRange(obj, rangeFirst, rangeLast);
1865 values = m3gAllocZ(M3G_INTERFACE(loader), sizeof(M3Gfloat) * components);
1866 if (!values) return M3G_FALSE;
1868 if (encoding == 0) {
1869 for (i = 0; i < keyFrames; i++ ) {
1870 M3Gint time = m3gLoadInt(data);
1873 for (j = 0; j < components; j++ ) {
1874 if (!m3gLoadFloat(data, &values[j])) {
1875 m3gFree(M3G_INTERFACE(loader), values);
1881 m3gSetKeyframe(obj, i, time, components, values);
1885 M3Gfloat *vectorBiasScale = m3gAllocZ(M3G_INTERFACE(loader), sizeof(M3Gfloat) * components * 2);
1886 if (!vectorBiasScale) {
1887 m3gFree(M3G_INTERFACE(loader), values);
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);
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);
1908 for (i = 0; i < keyFrames; i++ ) {
1910 time = m3gLoadInt(data);
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);
1920 for (j = 0; j < components; j++ ) {
1921 M3Gushort v = m3gLoadShort(data);
1923 values[j] = vectorBiasScale[j] + ((vectorBiasScale[j + components] * v) / 65535.0f);
1927 m3gSetKeyframe(obj, i, time, components, values);
1930 m3gFree(M3G_INTERFACE(loader), vectorBiasScale);
1933 m3gFree(M3G_INTERFACE(loader), values);
1935 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
1937 m3gEndObject(loader);
1938 m3gRewindObject(loader);
1939 if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
1942 m3gSkipObject(loader);
1949 * \brief Loads an animation controller
1951 static M3Gbool m3gLoadAnimationController(Loader *loader)
1953 M3Gfloat speed, weight, referenceSeqTime;
1954 M3Gint referenceWorldTime;
1956 M3GAnimationController obj = m3gCreateAnimationController(M3G_INTERFACE(loader));
1957 loader->loadedObject = (M3GObject)obj;
1958 if (!obj) return M3G_FALSE;
1960 if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
1964 data = m3gGetSectionDataPtr(loader, 24);
1965 if (data == NULL) return M3G_FALSE;
1967 if (!m3gLoadFloat(data, &speed)) return M3G_FALSE;
1969 if (!m3gLoadFloat(data, &weight)) return M3G_FALSE;
1971 m3gSetActiveInterval(obj, m3gLoadInt(data), m3gLoadInt(data + 4));
1973 if (!m3gLoadFloat(data, &referenceSeqTime)) return M3G_FALSE;
1975 referenceWorldTime = m3gLoadInt(data);
1978 m3gSetPosition(obj, referenceSeqTime, referenceWorldTime);
1979 m3gSetSpeed(obj, speed, referenceWorldTime);
1980 m3gSetWeight(obj, weight);
1982 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
1989 * \brief Loads an animation track
1991 static M3Gbool m3gLoadAnimationTrack(Loader *loader)
1994 M3GKeyframeSequence ks;
1995 M3GAnimationController ac;
1997 M3GAnimationTrack obj;
1999 m3gBeginObject(loader);
2000 if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
2002 data = m3gGetSectionDataPtr(loader, 12);
2003 if (data == NULL) return M3G_FALSE;
2005 ks = (M3GKeyframeSequence)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_KEYFRAME_SEQUENCE);
2007 ac = (M3GAnimationController)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_ANIMATION_CONTROLLER);
2009 property = m3gLoadInt(data);
2012 obj = m3gCreateAnimationTrack(M3G_INTERFACE(loader), ks, property);
2013 loader->loadedObject = (M3GObject)obj;
2014 if (!obj) return M3G_FALSE;
2016 m3gSetController(obj, ac);
2018 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
2020 m3gEndObject(loader);
2021 m3gRewindObject(loader);
2022 if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
2025 m3gSkipObject(loader);
2032 * \brief Loads a material
2034 static M3Gbool m3gLoadMaterial(Loader *loader)
2038 M3GMaterial obj = m3gCreateMaterial(M3G_INTERFACE(loader));
2039 loader->loadedObject = (M3GObject)obj;
2040 if (!obj) return M3G_FALSE;
2042 if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
2046 data = m3gGetSectionDataPtr(loader, 18);
2047 if (data == NULL) return M3G_FALSE;
2049 m3gSetColor(obj, M3G_AMBIENT_BIT, m3gLoadRGB(data));
2051 m3gSetColor(obj, M3G_DIFFUSE_BIT, m3gLoadARGB(data));
2053 m3gSetColor(obj, M3G_EMISSIVE_BIT, m3gLoadRGB(data));
2055 m3gSetColor(obj, M3G_SPECULAR_BIT, m3gLoadRGB(data));
2057 if (!m3gLoadFloat(data, &f1)) return M3G_FALSE;
2058 m3gSetShininess(obj, f1);
2060 if (!m3gVerifyBool(data)) return M3G_FALSE;
2061 m3gSetVertexColorTrackingEnable(obj, *data++);
2063 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
2070 * \brief Loads a fog
2072 static M3Gbool m3gLoadFog(Loader *loader)
2076 M3GFog obj = m3gCreateFog(M3G_INTERFACE(loader));
2077 loader->loadedObject = (M3GObject)obj;
2078 if (!obj) return M3G_FALSE;
2080 if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
2084 data = m3gGetSectionDataPtr(loader, 4);
2085 if (data == NULL) return M3G_FALSE;
2087 m3gSetFogColor(obj, m3gLoadRGB(data));
2089 m3gSetFogMode(obj, *data);
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);
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);
2104 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
2111 * \brief Loads an image
2113 static M3Gbool m3gLoadImage(Loader *loader)
2115 M3GImageFormat format;
2116 M3Guint width, height;
2121 m3gBeginObject(loader);
2122 if (!m3gSkipObject3DData(loader)) return M3G_FALSE;
2124 data = m3gGetSectionDataPtr(loader, 10);
2125 if (data == NULL) return M3G_FALSE;
2127 format = (M3GImageFormat)*data++;
2128 if (!m3gVerifyBool(data)) return M3G_FALSE;
2129 isMutable = *data++;
2130 width = m3gLoadInt(data);
2132 height = m3gLoadInt(data);
2136 obj = m3gCreateImage(M3G_INTERFACE(loader), format,
2138 M3G_RENDERING_TARGET);
2141 M3Gubyte *palette = NULL, *pixels = NULL;
2142 M3Gint paletteLength, pixelsLength, bpp;
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;
2153 if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
2154 paletteLength = m3gLoadInt(data);
2157 if (paletteLength > 0) {
2158 if (m3gCheckSectionDataLength(loader, data, paletteLength) == M3G_FALSE) return M3G_FALSE;
2160 data += paletteLength;
2163 if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) return M3G_FALSE;
2164 pixelsLength = m3gLoadInt(data);
2166 if (m3gCheckSectionDataLength(loader, data, pixelsLength) == M3G_FALSE) return M3G_FALSE;
2168 data += pixelsLength;
2170 if (palette != NULL) {
2171 obj = m3gCreateImage(M3G_INTERFACE(loader), format,
2175 M3Gint numEntries = paletteLength / bpp;
2176 if (numEntries > 256) {
2179 m3gSetImage(obj, pixels);
2180 m3gSetImagePalette(obj, numEntries, palette);
2181 m3gCommitImage(obj);
2185 obj = m3gCreateImage(M3G_INTERFACE(loader), format,
2189 m3gSetImage(obj, pixels);
2190 m3gCommitImage(obj);
2195 loader->loadedObject = (M3GObject)obj;
2196 if (!obj) return M3G_FALSE;
2198 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
2200 m3gEndObject(loader);
2201 m3gRewindObject(loader);
2202 if (!m3gLoadObject3DData(loader, (M3GObject)obj)) {
2205 m3gSkipObject(loader);
2212 * \brief Loads a texture
2214 static M3Gbool m3gLoadTexture(Loader *loader)
2220 m3gBeginObject(loader);
2221 if (!m3gSkipTransformableData(loader)) return M3G_FALSE;
2223 data = m3gGetSectionDataPtr(loader, 12);
2224 if (data == NULL) return M3G_FALSE;
2226 image = (M3GImage)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_IMAGE);
2229 obj = m3gCreateTexture(M3G_INTERFACE(loader), image);
2230 loader->loadedObject = (M3GObject)obj;
2231 if (!obj) return M3G_FALSE;
2233 m3gSetBlendColor(obj, m3gLoadRGB(data));
2235 m3gTextureSetBlending(obj, *data++);
2236 m3gSetWrapping(obj, data[0], data[1]);
2238 m3gSetFiltering(obj, data[0], data[1]);
2241 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
2243 m3gEndObject(loader);
2244 m3gRewindObject(loader);
2245 if (!m3gLoadTransformableData(loader, (M3GTransformable)obj)) {
2248 m3gSkipObject(loader);
2255 * \brief Loads a skinned mesh
2257 static M3Gbool m3gLoadSkinnedMesh(Loader *loader)
2260 M3Guint i, subMeshCount, transformReferenceCount, firstVertex, vertexCount;
2262 M3GIndexBuffer *ib = NULL;
2263 M3GAppearance *ap = NULL;
2267 M3GSkinnedMesh obj = NULL;
2269 m3gBeginObject(loader);
2270 if (!m3gSkipNodeData(loader)) return M3G_FALSE;
2272 data = m3gGetSectionDataPtr(loader, 8);
2273 if (data == NULL) return M3G_FALSE;
2275 vb = (M3GVertexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_BUFFER);
2276 if (vb == NULL) return M3G_FALSE;
2278 subMeshCount = m3gLoadInt(data);
2282 if (subMeshCount >= 0x10000000) {
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;
2291 for (i = 0; i < subMeshCount; i++) {
2292 ib[i] = (M3GIndexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_INDEX_BUFFER);
2294 ap[i] = (M3GAppearance)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_APPEARANCE);
2298 if (m3gCheckSectionDataLength(loader, data, 8) == M3G_FALSE) goto cleanup;
2299 skeleton = (M3GGroup)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_GROUP);
2302 obj = m3gCreateSkinnedMesh( M3G_INTERFACE(loader),
2310 m3gFree(M3G_INTERFACE(loader), ib);
2311 m3gFree(M3G_INTERFACE(loader), ap);
2312 loader->loadedObject = (M3GObject)obj;
2313 if (!obj) return M3G_FALSE;
2315 transformReferenceCount = m3gLoadInt(data);
2319 if (transformReferenceCount >= 0x08000000) {
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);
2327 firstVertex = m3gLoadInt(data);
2329 vertexCount = m3gLoadInt(data);
2331 weight = m3gLoadInt(data);
2333 m3gAddTransform(obj, bone, weight, firstVertex, vertexCount);
2336 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
2338 m3gEndObject(loader);
2339 m3gRewindObject(loader);
2340 if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
2343 m3gSkipObject(loader);
2350 * \brief Loads a morphing mesh
2352 static M3Gbool m3gLoadMorphingMesh(Loader *loader)
2354 M3GVertexBuffer vb, *targets = NULL;
2355 M3Guint i, subMeshCount, targetCount;
2356 M3Gfloat *weights = NULL;
2357 M3GIndexBuffer *ib = NULL;
2358 M3GAppearance *ap = NULL;
2360 M3GMorphingMesh obj = NULL;
2362 m3gBeginObject(loader);
2363 if (!m3gSkipNodeData(loader)) return M3G_FALSE;
2365 data = m3gGetSectionDataPtr(loader, 8);
2366 if (data == NULL) return M3G_FALSE;
2368 vb = (M3GVertexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_BUFFER);
2369 if (vb == NULL) return M3G_FALSE;
2371 subMeshCount = m3gLoadInt(data);
2375 if (subMeshCount >= 0x10000000) {
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;
2384 for (i = 0; i < subMeshCount; i++) {
2385 ib[i] = (M3GIndexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_INDEX_BUFFER);
2387 ap[i] = (M3GAppearance)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_APPEARANCE);
2391 if (m3gCheckSectionDataLength(loader, data, 4) == M3G_FALSE) goto cleanup;
2392 targetCount = m3gLoadInt(data);
2396 if (targetCount >= 0x10000000) {
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;
2405 for (i = 0; i < targetCount; i++) {
2406 targets[i] = (M3GVertexBuffer)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_VERTEX_BUFFER);
2408 if (!m3gLoadFloat(data, &weights[i])) goto cleanup;
2412 obj = m3gCreateMorphingMesh( M3G_INTERFACE(loader),
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;
2428 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
2430 m3gEndObject(loader);
2431 m3gRewindObject(loader);
2432 if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
2435 m3gSkipObject(loader);
2442 * \brief Loads a sprite
2444 static M3Gbool m3gLoadSprite(Loader *loader)
2447 M3GAppearance appearance;
2451 m3gBeginObject(loader);
2452 if (!m3gSkipNodeData(loader)) return M3G_FALSE;
2454 data = m3gGetSectionDataPtr(loader, 25);
2455 if (data == NULL) return M3G_FALSE;
2457 image = (M3GImage)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_IMAGE);
2459 appearance = (M3GAppearance)m3gGetLoaded(loader, m3gLoadInt(data), M3G_CLASS_APPEARANCE);
2462 if (!m3gVerifyBool(data)) return M3G_FALSE;
2463 obj = m3gCreateSprite( M3G_INTERFACE(loader),
2467 loader->loadedObject = (M3GObject)obj;
2468 if (!obj) return M3G_FALSE;
2470 m3gSetCrop(obj, m3gLoadInt(data),
2471 m3gLoadInt(data + 4),
2472 m3gLoadInt(data + 8),
2473 m3gLoadInt(data + 12));
2476 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
2478 m3gEndObject(loader);
2479 m3gRewindObject(loader);
2480 if (!m3gLoadNodeData(loader, (M3GNode)obj)) {
2483 m3gSkipObject(loader);
2490 * \brief Loads a M3G file header
2492 static M3Gbool m3gLoadHeader(Loader *loader)
2495 data = m3gGetSectionDataPtr(loader, 12);
2496 if (data == NULL) return M3G_FALSE;
2499 if (data[0] != 1 || data[1] != 0 || loader->sectionNum != 0) {
2504 if (!m3gVerifyBool(data)) return M3G_FALSE;
2505 loader->hasReferences = *data++;
2506 loader->fileSize = m3gLoadInt(data);
2508 loader->contentSize = m3gLoadInt(data);
2511 /* Skip authoring field */
2513 if (m3gCheckSectionDataLength(loader, data, 1) == M3G_FALSE) return M3G_FALSE;
2515 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
2522 * \brief Skips external reference
2524 static M3Gbool m3gLoadExternalReference(Loader *loader)
2527 if (loader->sectionNum != 1 || !loader->hasReferences)
2529 data = m3gGetSectionDataPtr(loader, 1);
2530 while(*data++) { /* Skip string */
2531 if (m3gCheckSectionDataLength(loader, data, 1) == M3G_FALSE)
2534 m3gAdvanceSectionData(loader, data - m3gGetSectionDataPtr(loader, 0));
2540 * \brief Loads an object
2542 static LoaderState m3gLoadObject(Loader *loader)
2544 M3Gubyte *data = m3gGetSectionDataPtr(loader, loader->sectionBytesRequired);
2547 loader->localState = LOADSTATE_CHECKSUM;
2548 return LOADSTATE_SECTION;
2551 m3gAdvanceSectionData(loader, loader->sectionBytesRequired);
2553 if (loader->localState == LOADSTATE_ENTER) {
2554 M3Gbool status = M3G_TRUE;
2556 loader->objectType = *data++;
2557 loader->loadedObject = NULL;
2558 loader->localState = LOADSTATE_EXIT;
2559 loader->sectionBytesRequired = m3gLoadInt(data);
2561 if (loader->sectionNum == 0 && loader->objectType != 0) {
2562 m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
2563 return LOADSTATE_ERROR;
2566 switch(loader->objectType) {
2567 case 0: /* Header Object */
2568 status = m3gLoadHeader(loader);
2570 case 1: /* AnimationController */
2571 status = m3gLoadAnimationController(loader);
2573 case 2: /* AnimationTrack */
2574 status = m3gLoadAnimationTrack(loader);
2576 case 3: /* Appearance */
2577 status = m3gLoadAppearance(loader);
2579 case 4: /* Background */
2580 status = m3gLoadBackground(loader);
2582 case 5: /* Camera */
2583 status = m3gLoadCamera(loader);
2585 case 6: /* CompositingMode */
2586 status = m3gLoadCompositingMode(loader);
2589 status = m3gLoadFog(loader);
2591 case 8: /* PolygonMode */
2592 status = m3gLoadPolygonMode(loader);
2595 status = m3gLoadGroup(loader);
2597 case 10: /* Image2D */
2598 status = m3gLoadImage(loader);
2600 case 11: /* TriangleStripArray */
2601 status = m3gLoadTsa(loader);
2603 case 12: /* Light */
2604 status = m3gLoadLight(loader);
2606 case 13: /* Material */
2607 status = m3gLoadMaterial(loader);
2610 status = m3gLoadMesh(loader);
2612 case 15: /* MorphingMesh */
2613 status = m3gLoadMorphingMesh(loader);
2615 case 16: /* SkinnedMesh */
2616 status = m3gLoadSkinnedMesh(loader);
2618 case 17: /* Texture2D */
2619 status = m3gLoadTexture(loader);
2621 case 18: /* Sprite */
2622 status = m3gLoadSprite(loader);
2624 case 19: /* KeyframeSequence */
2625 status = m3gLoadKeyframeSequence(loader);
2627 case 20: /* VertexArray */
2628 status = m3gLoadVertexArray(loader);
2630 case 21: /* VertexBuffer */
2631 status = m3gLoadVertexBuffer(loader);
2633 case 22: /* World */
2634 status = m3gLoadWorld(loader);
2636 case 255: /* External Reference */
2637 status = m3gLoadExternalReference(loader);
2639 default: /* 23 ... 254 Reserved for use in future versions of the file format */
2644 /* Check if object loading caused an error */
2645 if (m3gErrorRaised(M3G_INTERFACE(loader))) {
2646 m3gDeleteObject(loader->loadedObject);
2647 return LOADSTATE_ERROR;
2650 m3gGetSectionDataPtr(loader, 0) != data + loader->sectionBytesRequired) {
2651 m3gDeleteObject(loader->loadedObject);
2652 m3gRaiseError(M3G_INTERFACE(loader), M3G_IO_ERROR);
2653 return LOADSTATE_ERROR;
2655 loader->sectionBytesRequired = 0;
2657 /* Add object to loaded objects array */
2658 if (loader->loadedObject != NULL) {
2659 if (m3gArrayAppend(&loader->refArray, loader->loadedObject, M3G_INTERFACE(loader)) == -1) {
2661 m3gDeleteObject(loader->loadedObject);
2662 return LOADSTATE_ERROR;
2664 m3gAddRef(loader->loadedObject);
2668 loader->sectionBytesRequired = M3G_MIN_OBJECT_SIZE;
2669 loader->localState = LOADSTATE_ENTER;
2672 return LOADSTATE_OBJECT;
2677 * \brief Handles branching to different subroutines upon re-entry
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.
2683 static LoaderState m3gLoaderMain(Loader *loader)
2685 M3G_VALIDATE_OBJECT(loader);
2686 M3G_ASSERT(loader->bytesRequired > 0);
2687 M3G_ASSERT(loader->bytesRequired <= loader->stream.bytesAvailable);
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);
2703 loader->bytesRequired = 0;
2704 return LOADSTATE_ERROR;
2709 * \brief Deletes all unreferenced objects
2711 static void m3gCleanupLoader(M3GLoader loader)
2718 refs = &loader->refArray;
2719 n = m3gArraySize(refs);
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);
2726 m3gClearArray(&loader->refArray);
2728 n = m3gArraySize(&loader->userDataArray);
2729 for (i = 0; i < n; ++i)
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);
2739 m3gClearArray(&loader->userDataArray);
2741 m3gFree(M3G_INTERFACE(loader), loader->allocatedSectionData);
2742 loader->allocatedSectionData = NULL;
2747 * \brief Resets the loader
2749 static void m3gResetLoader(Loader *loader)
2751 /* Reset loader state */
2752 loader->state = LOADSTATE_INITIAL;
2753 loader->bytesRequired = sizeof(PNG_FILE_IDENTIFIER);
2755 m3gCleanupLoader(loader);
2756 m3gResetBufferedData(&loader->stream);
2759 /*----------------------------------------------------------------------
2760 * Virtual function table
2761 *--------------------------------------------------------------------*/
2763 static const ObjectVFTable m3gvf_Loader = {
2764 NULL, /* ApplyAnimation */
2765 NULL, /* IsCompatible */
2766 NULL, /* UpdateProperty */
2767 NULL, /* DoGetReferences */
2769 NULL, /* Duplicate */
2774 /*----------------------------------------------------------------------
2776 *--------------------------------------------------------------------*/
2779 * \brief Creates a new loader instance
2781 M3G_API M3GLoader m3gCreateLoader(M3GInterface m3g)
2784 M3G_VALIDATE_INTERFACE(m3g);
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;
2799 * \brief Import a set of objects into the reference table of a loader
2801 * This is intended for passing in external references, decoded in
2804 M3G_API void m3gImportObjects(M3GLoader loader, M3Gint n, M3GObject *refs)
2807 M3G_VALIDATE_OBJECT(loader);
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,
2815 M3G_INTERFACE(loader)) == -1) {
2823 * \brief Return the complete reference table for this loader instance
2825 * The reference table will contain the handle of each object that has
2826 * been loaded so far.
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
2833 M3G_API M3Gint m3gGetLoadedObjects(M3GLoader loader, M3GObject *buffer)
2836 int i, n, unref = 0;
2838 M3GObject obj, *dst = buffer;
2839 M3G_VALIDATE_OBJECT(loader);
2841 /* If error in decoding, reset and return 0 objects */
2842 if (loader->state < LOADSTATE_INITIAL) {
2846 refs = &loader->refArray;
2847 n = m3gArraySize(refs);
2849 /* Scan unreferenced objects */
2850 for (i = 0; i < n; ++i) {
2851 obj = m3gGetLoadedPtr(refs, i, &referenced);
2864 * \brief Submits data to the loader for processing
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
2872 * \param loader the loader instance
2873 * \param bytes the number of bytes in the data
2874 * \param data pointer to the data
2876 * \return the number of bytes required to load the next data element,
2877 * or zero to indicate that loading has finished
2880 #ifdef M3G_ENABLE_PROFILING
2881 static M3Gsizei m3gDecodeDataInternal(M3GLoader loader,
2883 const M3Gubyte *data);
2885 M3G_API M3Gsizei m3gDecodeData(M3GLoader loader,
2887 const M3Gubyte *data)
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);
2896 static M3Gsizei m3gDecodeDataInternal(M3GLoader loader,
2898 const M3Gubyte *data)
2901 M3G_API M3Gsizei m3gDecodeData(M3GLoader loader,
2903 const M3Gubyte *data)
2907 m3gErrorHandler *errorHandler;
2908 Interface *m3g = M3G_INTERFACE(loader);
2910 M3G_VALIDATE_OBJECT(loader);
2911 M3G_VALIDATE_INTERFACE(m3g);
2913 /* Check for errors */
2914 if (bytes <= 0 || data == NULL) {
2915 m3gRaiseError(m3g, M3G_INVALID_VALUE);
2919 if (loader->state == LOADSTATE_DONE)
2920 m3gResetLoader(loader);
2922 /* Submit data, then load until we run out of data again or are
2925 if (!m3gBufferData(m3g, &loader->stream, bytes, data)) {
2929 /* Disable error handler */
2930 errorHandler = m3gSetErrorHandler(m3g, NULL);
2932 /* Continue loading if sufficient data has arrived */
2933 while (loader->bytesRequired > 0
2934 && loader->bytesRequired <= loader->stream.bytesAvailable) {
2935 loader->state = m3gLoaderMain(loader);
2938 /* Restore error handler */
2939 m3gSetErrorHandler(m3g, errorHandler);
2941 /* Check if error was raised */
2942 if (m3gErrorRaised(m3g) != M3G_NO_ERROR) {
2943 /* Need to free all loaded objects */
2944 m3gResetLoader(loader);
2946 /* Raise again with original error handler in place */
2947 if (m3gErrorRaised(m3g) == M3G_OUT_OF_MEMORY)
2948 m3gRaiseError(m3g, M3G_OUT_OF_MEMORY);
2950 m3gRaiseError(m3g, M3G_IO_ERROR);
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 */
2959 loader->bytesRequired - loader->stream.bytesAvailable;
2961 /* Check if whole file is done */
2962 if (loader->stream.totalBytes >= loader->fileSize) {
2963 loader->state = LOADSTATE_DONE;
2967 return (bytesReq >= 0) ? bytesReq : 0;
2972 * \brief Return all loaded objects with user parameters
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
2978 * \return Number of objects with user parameters
2980 M3G_API M3Gint m3gGetObjectsWithUserParameters(M3GLoader loader, M3GObject *objects) {
2981 const Loader *ldr = (const Loader *) loader;
2982 M3G_VALIDATE_OBJECT(ldr);
2985 n = m3gArraySize(&ldr->userDataArray);
2987 if (objects != NULL)
2988 for (i = 0; i < n; ++i)
2990 const UserData *data = (const UserData *)m3gGetArrayElement(&ldr->userDataArray, i);
2991 objects[i] = data->object;
2998 * \brief Return the number of user parameters loaded for an object
3000 M3G_API M3Gint m3gGetNumUserParameters(M3GLoader loader, M3Gint object)
3002 const Loader *ldr = (const Loader *) loader;
3003 M3G_VALIDATE_OBJECT(ldr);
3005 const UserData *data = (const UserData *)m3gGetArrayElement(&ldr->userDataArray, object);
3006 return (data != NULL) ? data->numParams : 0;
3011 * \brief Set constraints for loading.
3012 * \param triConstraint maximum triangle count
3014 M3G_API void m3gSetConstraints(M3GLoader loader, M3Gint triConstraint)
3016 M3G_VALIDATE_OBJECT(loader);
3017 loader->triConstraint = triConstraint;
3021 * \brief Return the given user parameter for an object
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
3029 * \return id of the parameter, or the length of the string if data was NULL
3031 M3G_API M3Gsizei m3gGetUserParameter(M3GLoader loader,
3036 const Loader *ldr = (const Loader *) loader;
3037 M3G_VALIDATE_OBJECT(ldr);
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];
3055 #undef ANY_NODE_CLASS