/* ----------------------------------------------------------------------------- PicoModel Library Copyright (c) 2002, Randy Reddig & seaw0lf All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the names of the copyright holders nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ /* marker */ #define PM_MS3D_C /* dependencies */ #include "picointernal.h" /* disable warnings */ #ifdef WIN32 #pragma warning( disable:4100 ) /* unref param */ #endif /* remarks: * - loader seems stable * todo: * - fix uv coordinate problem * - check for buffer overflows ('bufptr' accesses) */ /* uncomment when debugging this module */ #define DEBUG_PM_MS3D #define DEBUG_PM_MS3D_EX /* plain white */ static picoColor_t white = { 255,255,255,255 }; /* ms3d limits */ #define MS3D_MAX_VERTS 8192 #define MS3D_MAX_TRIS 16384 #define MS3D_MAX_GROUPS 128 #define MS3D_MAX_MATERIALS 128 #define MS3D_MAX_JOINTS 128 #define MS3D_MAX_KEYFRAMES 216 /* ms3d flags */ #define MS3D_SELECTED 1 #define MS3D_HIDDEN 2 #define MS3D_SELECTED2 4 #define MS3D_DIRTY 8 /* this freaky loader needs byte alignment */ #pragma pack(push, 1) /* ms3d header */ typedef struct SMsHeader { char magic[10]; int version; } TMsHeader; /* ms3d vertex */ typedef struct SMsVertex { unsigned char flags; /* sel, sel2, or hidden */ float xyz[3]; char boneID; /* -1 means 'no bone' */ unsigned char refCount; } TMsVertex; /* ms3d triangle */ typedef struct SMsTriangle { unsigned short flags; /* sel, sel2, or hidden */ unsigned short vertexIndices[3]; float vertexNormals[3][3]; float s[3]; float t[3]; unsigned char smoothingGroup; /* 1 - 32 */ unsigned char groupIndex; } TMsTriangle; /* ms3d material */ typedef struct SMsMaterial { char name[32]; float ambient[4]; float diffuse[4]; float specular[4]; float emissive[4]; float shininess; /* range 0..128 */ float transparency; /* range 0..1 */ unsigned char mode; char texture [128]; /* texture.bmp */ char alphamap[128]; /* alpha.bmp */ } TMsMaterial; // ms3d group (static part) // followed by a variable size block (see below) typedef struct SMsGroup { unsigned char flags; // sel, hidden char name[32]; unsigned short numTriangles; /* unsigned short triangleIndices[ numTriangles ]; char materialIndex; // -1 means 'no material' */ } TMsGroup; // ms3d joint typedef struct SMsJoint { unsigned char flags; char name[32]; char parentName[32]; float rotation[3]; float translation[3]; unsigned short numRotationKeyframes; unsigned short numTranslationKeyframes; } TMsJoint; // ms3d keyframe typedef struct SMsKeyframe { float time; float parameter[3]; } TMsKeyframe; /* restore previous data alignment */ #pragma pack(pop) /* _ms3d_canload: * validates a milkshape3d model file. */ static int _ms3d_canload( PM_PARAMS_CANLOAD ) { TMsHeader *hdr; /* to keep the compiler happy */ *fileName = *fileName; /* sanity check */ if (bufSize < sizeof(TMsHeader)) return PICO_PMV_ERROR_SIZE; /* get ms3d header */ hdr = (TMsHeader *)buffer; /* check ms3d magic */ if (strncmp(hdr->magic,"MS3D000000",10) != 0) return PICO_PMV_ERROR_IDENT; /* check ms3d version */ if (_pico_little_long(hdr->version) < 3 || _pico_little_long(hdr->version) > 4) { _pico_printf( PICO_ERROR,"MS3D file ignored. Only MS3D 1.3 and 1.4 is supported." ); return PICO_PMV_ERROR_VERSION; } /* file seems to be a valid ms3d */ return PICO_PMV_OK; } static unsigned char *GetWord( unsigned char *bufptr, int *out ) { if (bufptr == NULL) return NULL; *out = _pico_little_short( *(unsigned short *)bufptr ); return( bufptr + 2 ); } /* _ms3d_load: * loads a milkshape3d model file. */ static picoModel_t *_ms3d_load( PM_PARAMS_LOAD ) { picoModel_t *model; unsigned char *bufptr; int shaderRefs[ MS3D_MAX_GROUPS ]; int numGroups; int numMaterials; // unsigned char *ptrToGroups; int numVerts; unsigned char *ptrToVerts; int numTris; unsigned char *ptrToTris; int i,k,m; /* create new pico model */ model = PicoNewModel(); if (model == NULL) return NULL; /* do model setup */ PicoSetModelFrameNum( model, frameNum ); PicoSetModelName( model, fileName ); PicoSetModelFileName( model, fileName ); /* skip header */ bufptr = (unsigned char *)buffer + sizeof(TMsHeader); /* get number of vertices */ bufptr = GetWord( bufptr,&numVerts ); ptrToVerts = bufptr; #ifdef DEBUG_PM_MS3D printf("NumVertices: %d\n",numVerts); #endif /* swap verts */ for (i=0; ixyz[ 0 ] = _pico_little_float( vertex->xyz[ 0 ] ); vertex->xyz[ 1 ] = _pico_little_float( vertex->xyz[ 1 ] ); vertex->xyz[ 2 ] = _pico_little_float( vertex->xyz[ 2 ] ); #ifdef DEBUG_PM_MS3D_EX_ printf("Vertex: x: %f y: %f z: %f\n", msvd[i]->vertex[0], msvd[i]->vertex[1], msvd[i]->vertex[2]); #endif } /* get number of triangles */ bufptr = GetWord( bufptr,&numTris ); ptrToTris = bufptr; #ifdef DEBUG_PM_MS3D printf("NumTriangles: %d\n",numTris); #endif /* swap tris */ for (i=0; iflags = _pico_little_short( triangle->flags ); /* run through all tri verts */ for (k=0; k<3; k++) { /* swap tex coords */ triangle->s[ k ] = _pico_little_float( triangle->s[ k ] ); triangle->t[ k ] = _pico_little_float( triangle->t[ k ] ); /* swap fields */ triangle->vertexIndices[ k ] = _pico_little_short( triangle->vertexIndices[ k ] ); triangle->vertexNormals[ 0 ][ k ] = _pico_little_float( triangle->vertexNormals[ 0 ][ k ] ); triangle->vertexNormals[ 1 ][ k ] = _pico_little_float( triangle->vertexNormals[ 1 ][ k ] ); triangle->vertexNormals[ 2 ][ k ] = _pico_little_float( triangle->vertexNormals[ 2 ][ k ] ); /* check for out of range indices */ if (triangle->vertexIndices[ k ] >= numVerts) { _pico_printf( PICO_ERROR,"Vertex %d index %d out of range (%d, max %d)",i,k,triangle->vertexIndices[k],numVerts-1); PicoFreeModel( model ); return NULL; /* yuck */ } } } /* get number of groups */ bufptr = GetWord( bufptr,&numGroups ); // ptrToGroups = bufptr; #ifdef DEBUG_PM_MS3D printf("NumGroups: %d\n",numGroups); #endif /* run through all groups in model */ for (i=0; i