]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - libs/picomodel/pm_ms3d.c
set eol-style
[xonotic/netradiant.git] / libs / picomodel / pm_ms3d.c
index 4bbd9b388e27c3664a2ad41006f4bb680b951bf1..27147bc0053095f0a705911e82430bd035038b05 100644 (file)
-/* -----------------------------------------------------------------------------\r
-\r
-PicoModel Library\r
-\r
-Copyright (c) 2002, Randy Reddig & seaw0lf\r
-All rights reserved.\r
-\r
-Redistribution and use in source and binary forms, with or without modification,\r
-are permitted provided that the following conditions are met:\r
-\r
-Redistributions of source code must retain the above copyright notice, this list\r
-of conditions and the following disclaimer.\r
-\r
-Redistributions in binary form must reproduce the above copyright notice, this\r
-list of conditions and the following disclaimer in the documentation and/or\r
-other materials provided with the distribution.\r
-\r
-Neither the names of the copyright holders nor the names of its contributors may\r
-be used to endorse or promote products derived from this software without\r
-specific prior written permission.\r
-\r
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\r
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
-\r
------------------------------------------------------------------------------ */\r
-\r
-\r
-\r
-/* marker */\r
-#define PM_MS3D_C\r
-\r
-/* dependencies */\r
-#include "picointernal.h"\r
-\r
-/* disable warnings */\r
-#ifdef _WIN32\r
-#pragma warning( disable:4100 )                /* unref param */\r
-#endif\r
-\r
-/* remarks:\r
- * - loader seems stable\r
- * todo:\r
- * - fix uv coordinate problem\r
- * - check for buffer overflows ('bufptr' accesses)\r
- */\r
-/* uncomment when debugging this module */\r
- #define DEBUG_PM_MS3D\r
- #define DEBUG_PM_MS3D_EX\r
-\r
-/* plain white */\r
-static picoColor_t white = { 255,255,255,255 };\r
-\r
-/* ms3d limits */\r
-#define MS3D_MAX_VERTS         8192\r
-#define MS3D_MAX_TRIS          16384\r
-#define MS3D_MAX_GROUPS                128\r
-#define MS3D_MAX_MATERIALS     128\r
-#define MS3D_MAX_JOINTS                128\r
-#define MS3D_MAX_KEYFRAMES     216\r
-\r
-/* ms3d flags */\r
-#define MS3D_SELECTED          1\r
-#define MS3D_HIDDEN                    2\r
-#define MS3D_SELECTED2         4\r
-#define MS3D_DIRTY                     8\r
-\r
-/* this freaky loader needs byte alignment */\r
-#pragma pack(push, 1)\r
-\r
-/* ms3d header */\r
-typedef struct SMsHeader\r
-{\r
-       char                    magic[10];\r
-       int                             version;\r
-}\r
-TMsHeader;\r
-\r
-/* ms3d vertex */\r
-typedef struct SMsVertex\r
-{\r
-       unsigned char   flags;                          /* sel, sel2, or hidden */\r
-       float                   xyz[3];\r
-       char                    boneID;                         /* -1 means 'no bone' */\r
-       unsigned char   refCount;\r
-}\r
-TMsVertex;\r
-\r
-/* ms3d triangle */\r
-typedef struct SMsTriangle\r
-{\r
-       unsigned short  flags;                          /* sel, sel2, or hidden */\r
-       unsigned short  vertexIndices[3];\r
-       float                   vertexNormals[3][3];\r
-       float                   s[3];\r
-       float                   t[3];\r
-       unsigned char   smoothingGroup;         /* 1 - 32 */\r
-       unsigned char   groupIndex;\r
-}\r
-TMsTriangle;\r
-\r
-/* ms3d material */\r
-typedef struct SMsMaterial\r
-{\r
-       char                    name[32];\r
-       float                   ambient[4];\r
-       float                   diffuse[4];\r
-       float                   specular[4];\r
-       float                   emissive[4];\r
-       float                   shininess;                      /* range 0..128 */\r
-       float                   transparency;           /* range 0..1 */\r
-       unsigned char   mode;\r
-       char                    texture [128];          /* texture.bmp */\r
-       char                    alphamap[128];          /* alpha.bmp */\r
-}\r
-TMsMaterial;\r
-\r
-// ms3d group (static part)\r
-// followed by a variable size block (see below)\r
-typedef struct SMsGroup\r
-{\r
-       unsigned char   flags;                          // sel, hidden\r
-       char                    name[32];\r
-       unsigned short  numTriangles;\r
-/*\r
-       unsigned short  triangleIndices[ numTriangles ];\r
-       char                    materialIndex;          // -1 means 'no material'\r
-*/\r
-}\r
-TMsGroup;\r
-\r
-// ms3d joint\r
-typedef struct SMsJoint\r
-{\r
-       unsigned char   flags;\r
-       char                    name[32];\r
-       char                    parentName[32];\r
-       float                   rotation[3];\r
-       float                   translation[3];\r
-       unsigned short  numRotationKeyframes;\r
-       unsigned short  numTranslationKeyframes;\r
-}\r
-TMsJoint;\r
-\r
-// ms3d keyframe\r
-typedef struct SMsKeyframe\r
-{\r
-       float                   time;\r
-       float                   parameter[3];\r
-}\r
-TMsKeyframe;\r
-\r
-/* restore previous data alignment */\r
-#pragma pack(pop)\r
-\r
-/* _ms3d_canload:\r
- *     validates a milkshape3d model file.\r
- */\r
-static int _ms3d_canload( PM_PARAMS_CANLOAD )\r
-{\r
-       TMsHeader *hdr;\r
-       \r
-       \r
-       /* to keep the compiler happy */\r
-       *fileName = *fileName;\r
-\r
-       /* sanity check */\r
-       if (bufSize < sizeof(TMsHeader))\r
-               return PICO_PMV_ERROR_SIZE;\r
-\r
-       /* get ms3d header */\r
-       hdr = (TMsHeader *)buffer;\r
-\r
-       /* check ms3d magic */\r
-       if (strncmp(hdr->magic,"MS3D000000",10) != 0)\r
-               return PICO_PMV_ERROR_IDENT;\r
-\r
-       /* check ms3d version */\r
-       if (_pico_little_long(hdr->version) < 3 ||\r
-               _pico_little_long(hdr->version) > 4)\r
-       {\r
-               _pico_printf( PICO_ERROR,"MS3D file ignored. Only MS3D 1.3 and 1.4 is supported." );\r
-               return PICO_PMV_ERROR_VERSION;\r
-       }\r
-       /* file seems to be a valid ms3d */\r
-       return PICO_PMV_OK;\r
-}\r
-\r
-static unsigned char *GetWord( unsigned char *bufptr, int *out )\r
-{\r
-       if (bufptr == NULL) return NULL;\r
-       *out = _pico_little_short( *(unsigned short *)bufptr );\r
-       return( bufptr + 2 );\r
-}\r
-\r
-/* _ms3d_load:\r
- *     loads a milkshape3d model file.\r
-*/\r
-static picoModel_t *_ms3d_load( PM_PARAMS_LOAD )\r
-{\r
-       picoModel_t        *model;\r
-       unsigned char  *bufptr;\r
-       int                             shaderRefs[ MS3D_MAX_GROUPS ];\r
-       int                             numGroups;\r
-       int                             numMaterials;\r
-//     unsigned char  *ptrToGroups;\r
-       int                             numVerts;\r
-       unsigned char  *ptrToVerts;\r
-       int                             numTris;\r
-       unsigned char  *ptrToTris;\r
-       int                             i,k,m;\r
-\r
-       /* create new pico model */\r
-       model = PicoNewModel();\r
-       if (model == NULL) return NULL;\r
-\r
-       /* do model setup */\r
-       PicoSetModelFrameNum( model, frameNum );\r
-       PicoSetModelName( model, fileName );\r
-       PicoSetModelFileName( model, fileName );\r
-\r
-       /* skip header */\r
-       bufptr = (unsigned char *)buffer + sizeof(TMsHeader);\r
-\r
-       /* get number of vertices */\r
-       bufptr = GetWord( bufptr,&numVerts );\r
-       ptrToVerts = bufptr;\r
-\r
-#ifdef DEBUG_PM_MS3D\r
-       printf("NumVertices: %d\n",numVerts);\r
-#endif\r
-       /* swap verts */\r
-       for (i=0; i<numVerts; i++)\r
-       {\r
-               TMsVertex *vertex;\r
-               vertex = (TMsVertex *)bufptr;\r
-               bufptr += sizeof( TMsVertex );\r
-\r
-               vertex->xyz[ 0 ] = _pico_little_float( vertex->xyz[ 0 ] );\r
-               vertex->xyz[ 1 ] = _pico_little_float( vertex->xyz[ 1 ] );\r
-               vertex->xyz[ 2 ] = _pico_little_float( vertex->xyz[ 2 ] );\r
-\r
-#ifdef DEBUG_PM_MS3D_EX_\r
-               printf("Vertex: x: %f y: %f z: %f\n",\r
-                       msvd[i]->vertex[0],\r
-                       msvd[i]->vertex[1],\r
-                       msvd[i]->vertex[2]);\r
-#endif\r
-       }\r
-       /* get number of triangles */\r
-       bufptr = GetWord( bufptr,&numTris );\r
-       ptrToTris = bufptr;\r
-\r
-#ifdef DEBUG_PM_MS3D\r
-       printf("NumTriangles: %d\n",numTris);\r
-#endif\r
-       /* swap tris */\r
-       for (i=0; i<numTris; i++)\r
-       {\r
-               TMsTriangle *triangle;\r
-               triangle = (TMsTriangle *)bufptr;\r
-               bufptr += sizeof( TMsTriangle );\r
-\r
-               triangle->flags = _pico_little_short( triangle->flags );\r
-\r
-               /* run through all tri verts */\r
-               for (k=0; k<3; k++)\r
-               {\r
-                       /* swap tex coords */\r
-                       triangle->s[ k ] = _pico_little_float( triangle->s[ k ] );\r
-                       triangle->t[ k ] = _pico_little_float( triangle->t[ k ] );\r
-\r
-                       /* swap fields */\r
-                       triangle->vertexIndices[ k ]      = _pico_little_short( triangle->vertexIndices[ k ] );\r
-                       triangle->vertexNormals[ 0 ][ k ] = _pico_little_float( triangle->vertexNormals[ 0 ][ k ] );\r
-                       triangle->vertexNormals[ 1 ][ k ] = _pico_little_float( triangle->vertexNormals[ 1 ][ k ] );\r
-                       triangle->vertexNormals[ 2 ][ k ] = _pico_little_float( triangle->vertexNormals[ 2 ][ k ] );\r
-\r
-                       /* check for out of range indices */\r
-                       if (triangle->vertexIndices[ k ] >= numVerts)\r
-                       {\r
-                               _pico_printf( PICO_ERROR,"Vertex %d index %d out of range (%d, max %d)",i,k,triangle->vertexIndices[k],numVerts-1);\r
-                               PicoFreeModel( model );\r
-                               return NULL; /* yuck */\r
-                       }\r
-               }\r
-       }\r
-       /* get number of groups */\r
-       bufptr = GetWord( bufptr,&numGroups );\r
-//     ptrToGroups = bufptr;\r
-\r
-#ifdef DEBUG_PM_MS3D\r
-       printf("NumGroups: %d\n",numGroups);\r
-#endif\r
-       /* run through all groups in model */\r
-       for (i=0; i<numGroups && i<MS3D_MAX_GROUPS; i++)\r
-       {\r
-               picoSurface_t *surface;\r
-               TMsGroup          *group;\r
-\r
-               group = (TMsGroup *)bufptr;\r
-               bufptr += sizeof( TMsGroup );\r
-\r
-               /* we ignore hidden groups */\r
-               if (group->flags & MS3D_HIDDEN)\r
-               {\r
-                       bufptr += (group->numTriangles * 2) + 1;\r
-                       continue;\r
-               }\r
-               /* forced null term of group name */\r
-               group->name[ 31 ] = '\0';\r
-\r
-               /* create new pico surface */\r
-               surface = PicoNewSurface( model );\r
-               if (surface == NULL)\r
-               {\r
-                       PicoFreeModel( model );\r
-                       return NULL;\r
-               }\r
-               /* do surface setup */\r
-               PicoSetSurfaceType( surface,PICO_TRIANGLES );\r
-               PicoSetSurfaceName( surface,group->name );\r
-\r
-               /* process triangle indices */\r
-               for (k=0; k<group->numTriangles; k++)\r
-               {\r
-                       TMsTriangle *triangle;\r
-                       unsigned int triangleIndex;\r
-\r
-                       /* get triangle index */\r
-                       bufptr = GetWord( bufptr,(int *)&triangleIndex );\r
-\r
-                       /* get ptr to triangle data */\r
-                       triangle = (TMsTriangle *)(ptrToTris + (sizeof(TMsTriangle) * triangleIndex));\r
-\r
-                       /* run through triangle vertices */\r
-                       for (m=0; m<3; m++)\r
-                       {\r
-                               TMsVertex   *vertex;\r
-                               unsigned int vertexIndex;\r
-                               picoVec2_t   texCoord;\r
-\r
-                               /* get ptr to vertex data */\r
-                               vertexIndex = triangle->vertexIndices[ m ];\r
-                               vertex = (TMsVertex *)(ptrToVerts + (sizeof(TMsVertex) * vertexIndex));\r
-\r
-                               /* store vertex origin */\r
-                               PicoSetSurfaceXYZ( surface,vertexIndex,vertex->xyz );\r
-\r
-                               /* store vertex color */\r
-                               PicoSetSurfaceColor( surface,0,vertexIndex,white );\r
-\r
-                               /* store vertex normal */\r
-                               PicoSetSurfaceNormal( surface,vertexIndex,triangle->vertexNormals[ m ] );\r
-\r
-                               /* store current face vertex index */\r
-                               PicoSetSurfaceIndex( surface,(k * 3 + (2 - m)),(picoIndex_t)vertexIndex );\r
-\r
-                               /* get texture vertex coord */\r
-                               texCoord[ 0 ] = triangle->s[ m ];\r
-                               texCoord[ 1 ] = -triangle->t[ m ];      /* flip t */\r
-\r
-                               /* store texture vertex coord */\r
-                               PicoSetSurfaceST( surface,0,vertexIndex,texCoord );\r
-                       }\r
-               }\r
-               /* store material */\r
-               shaderRefs[ i ] = *bufptr++;\r
-\r
-#ifdef DEBUG_PM_MS3D\r
-               printf("Group %d: '%s' (%d tris)\n",i,group->name,group->numTriangles);\r
-#endif\r
-       }\r
-       /* get number of materials */\r
-       bufptr = GetWord( bufptr,&numMaterials );\r
-\r
-#ifdef DEBUG_PM_MS3D\r
-       printf("NumMaterials: %d\n",numMaterials);\r
-#endif\r
-       /* run through all materials in model */\r
-       for (i=0; i<numMaterials; i++)\r
-       {\r
-               picoShader_t *shader;\r
-               picoColor_t   ambient,diffuse,specular;\r
-               TMsMaterial  *material;\r
-               int           k;\r
-\r
-               material = (TMsMaterial *)bufptr;\r
-               bufptr += sizeof( TMsMaterial );\r
-\r
-               /* null term strings */\r
-               material->name    [  31 ] = '\0';\r
-               material->texture [ 127 ] = '\0';\r
-               material->alphamap[ 127 ] = '\0';\r
-\r
-               /* ltrim strings */\r
-               _pico_strltrim( material->name );\r
-               _pico_strltrim( material->texture );\r
-               _pico_strltrim( material->alphamap );\r
-\r
-               /* rtrim strings */\r
-               _pico_strrtrim( material->name );\r
-               _pico_strrtrim( material->texture );\r
-               _pico_strrtrim( material->alphamap );\r
-\r
-               /* create new pico shader */\r
-               shader = PicoNewShader( model );\r
-               if (shader == NULL)\r
-               {\r
-                       PicoFreeModel( model );\r
-                       return NULL;\r
-               }\r
-               /* scale shader colors */\r
-               for (k=0; k<4; k++)\r
-               {\r
-                       ambient [ k ] = (picoByte_t) (material->ambient[ k ] * 255);\r
-                       diffuse [ k ] = (picoByte_t) (material->diffuse[ k ] * 255);\r
-                       specular[ k ] = (picoByte_t) (material->specular[ k ] * 255);\r
-               }\r
-               /* set shader colors */\r
-               PicoSetShaderAmbientColor( shader,ambient );\r
-               PicoSetShaderDiffuseColor( shader,diffuse );\r
-               PicoSetShaderSpecularColor( shader,specular );\r
-\r
-               /* set shader transparency */\r
-               PicoSetShaderTransparency( shader,material->transparency );\r
-\r
-               /* set shader shininess (0..127) */\r
-               PicoSetShaderShininess( shader,material->shininess );\r
-\r
-               /* set shader name */\r
-               PicoSetShaderName( shader,material->name );\r
-\r
-               /* set shader texture map name */\r
-               PicoSetShaderMapName( shader,material->texture );\r
-\r
-#ifdef DEBUG_PM_MS3D\r
-               printf("Material %d: '%s' ('%s','%s')\n",i,material->name,material->texture,material->alphamap);\r
-#endif\r
-       }\r
-       /* assign shaders to surfaces */\r
-       for (i=0; i<numGroups && i<MS3D_MAX_GROUPS; i++)\r
-       {\r
-               picoSurface_t *surface;\r
-               picoShader_t  *shader;\r
-\r
-               /* sanity check */\r
-               if (shaderRefs[ i ] >= MS3D_MAX_MATERIALS ||\r
-                       shaderRefs[ i ] < 0)\r
-                       continue;\r
-\r
-               /* get surface */\r
-               surface = PicoGetModelSurface( model,i );\r
-               if (surface == NULL) continue;\r
-\r
-               /* get shader */\r
-               shader = PicoGetModelShader( model,shaderRefs[ i ] );\r
-               if (shader == NULL) continue;\r
-\r
-               /* assign shader */\r
-               PicoSetSurfaceShader( surface,shader );\r
-\r
-#ifdef DEBUG_PM_MS3D\r
-               printf("Mapped: %d ('%s') to %d (%s)\n",\r
-                       shaderRefs[i],shader->name,i,surface->name);\r
-#endif\r
-       }\r
-       /* return allocated pico model */\r
-       return model;\r
-//     return NULL;\r
-}\r
-\r
-/* pico file format module definition */\r
-const picoModule_t picoModuleMS3D =\r
-{\r
-       "0.4-a",                                        /* module version string */\r
-       "Milkshape 3D",                         /* module display name */\r
-       "seaw0lf",                                      /* author's name */\r
-       "2002 seaw0lf",                         /* module copyright */\r
-       {\r
-               "ms3d",NULL,NULL,NULL   /* default extensions to use */\r
-       },\r
-       _ms3d_canload,                          /* validation routine */\r
-       _ms3d_load,                                     /* load routine */\r
-        NULL,                                          /* save validation routine */\r
-        NULL                                           /* save routine */\r
-};\r
+/* -----------------------------------------------------------------------------
+
+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; i<numVerts; i++)
+       {
+               TMsVertex *vertex;
+               vertex = (TMsVertex *)bufptr;
+               bufptr += sizeof( TMsVertex );
+
+               vertex->xyz[ 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; i<numTris; i++)
+       {
+               TMsTriangle *triangle;
+               triangle = (TMsTriangle *)bufptr;
+               bufptr += sizeof( TMsTriangle );
+
+               triangle->flags = _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<numGroups && i<MS3D_MAX_GROUPS; i++)
+       {
+               picoSurface_t *surface;
+               TMsGroup          *group;
+
+               group = (TMsGroup *)bufptr;
+               bufptr += sizeof( TMsGroup );
+
+               /* we ignore hidden groups */
+               if (group->flags & MS3D_HIDDEN)
+               {
+                       bufptr += (group->numTriangles * 2) + 1;
+                       continue;
+               }
+               /* forced null term of group name */
+               group->name[ 31 ] = '\0';
+
+               /* create new pico surface */
+               surface = PicoNewSurface( model );
+               if (surface == NULL)
+               {
+                       PicoFreeModel( model );
+                       return NULL;
+               }
+               /* do surface setup */
+               PicoSetSurfaceType( surface,PICO_TRIANGLES );
+               PicoSetSurfaceName( surface,group->name );
+
+               /* process triangle indices */
+               for (k=0; k<group->numTriangles; k++)
+               {
+                       TMsTriangle *triangle;
+                       unsigned int triangleIndex;
+
+                       /* get triangle index */
+                       bufptr = GetWord( bufptr,(int *)&triangleIndex );
+
+                       /* get ptr to triangle data */
+                       triangle = (TMsTriangle *)(ptrToTris + (sizeof(TMsTriangle) * triangleIndex));
+
+                       /* run through triangle vertices */
+                       for (m=0; m<3; m++)
+                       {
+                               TMsVertex   *vertex;
+                               unsigned int vertexIndex;
+                               picoVec2_t   texCoord;
+
+                               /* get ptr to vertex data */
+                               vertexIndex = triangle->vertexIndices[ m ];
+                               vertex = (TMsVertex *)(ptrToVerts + (sizeof(TMsVertex) * vertexIndex));
+
+                               /* store vertex origin */
+                               PicoSetSurfaceXYZ( surface,vertexIndex,vertex->xyz );
+
+                               /* store vertex color */
+                               PicoSetSurfaceColor( surface,0,vertexIndex,white );
+
+                               /* store vertex normal */
+                               PicoSetSurfaceNormal( surface,vertexIndex,triangle->vertexNormals[ m ] );
+
+                               /* store current face vertex index */
+                               PicoSetSurfaceIndex( surface,(k * 3 + (2 - m)),(picoIndex_t)vertexIndex );
+
+                               /* get texture vertex coord */
+                               texCoord[ 0 ] = triangle->s[ m ];
+                               texCoord[ 1 ] = -triangle->t[ m ];      /* flip t */
+
+                               /* store texture vertex coord */
+                               PicoSetSurfaceST( surface,0,vertexIndex,texCoord );
+                       }
+               }
+               /* store material */
+               shaderRefs[ i ] = *bufptr++;
+
+#ifdef DEBUG_PM_MS3D
+               printf("Group %d: '%s' (%d tris)\n",i,group->name,group->numTriangles);
+#endif
+       }
+       /* get number of materials */
+       bufptr = GetWord( bufptr,&numMaterials );
+
+#ifdef DEBUG_PM_MS3D
+       printf("NumMaterials: %d\n",numMaterials);
+#endif
+       /* run through all materials in model */
+       for (i=0; i<numMaterials; i++)
+       {
+               picoShader_t *shader;
+               picoColor_t   ambient,diffuse,specular;
+               TMsMaterial  *material;
+               int           k;
+
+               material = (TMsMaterial *)bufptr;
+               bufptr += sizeof( TMsMaterial );
+
+               /* null term strings */
+               material->name    [  31 ] = '\0';
+               material->texture [ 127 ] = '\0';
+               material->alphamap[ 127 ] = '\0';
+
+               /* ltrim strings */
+               _pico_strltrim( material->name );
+               _pico_strltrim( material->texture );
+               _pico_strltrim( material->alphamap );
+
+               /* rtrim strings */
+               _pico_strrtrim( material->name );
+               _pico_strrtrim( material->texture );
+               _pico_strrtrim( material->alphamap );
+
+               /* create new pico shader */
+               shader = PicoNewShader( model );
+               if (shader == NULL)
+               {
+                       PicoFreeModel( model );
+                       return NULL;
+               }
+               /* scale shader colors */
+               for (k=0; k<4; k++)
+               {
+                       ambient [ k ] = (picoByte_t) (material->ambient[ k ] * 255);
+                       diffuse [ k ] = (picoByte_t) (material->diffuse[ k ] * 255);
+                       specular[ k ] = (picoByte_t) (material->specular[ k ] * 255);
+               }
+               /* set shader colors */
+               PicoSetShaderAmbientColor( shader,ambient );
+               PicoSetShaderDiffuseColor( shader,diffuse );
+               PicoSetShaderSpecularColor( shader,specular );
+
+               /* set shader transparency */
+               PicoSetShaderTransparency( shader,material->transparency );
+
+               /* set shader shininess (0..127) */
+               PicoSetShaderShininess( shader,material->shininess );
+
+               /* set shader name */
+               PicoSetShaderName( shader,material->name );
+
+               /* set shader texture map name */
+               PicoSetShaderMapName( shader,material->texture );
+
+#ifdef DEBUG_PM_MS3D
+               printf("Material %d: '%s' ('%s','%s')\n",i,material->name,material->texture,material->alphamap);
+#endif
+       }
+       /* assign shaders to surfaces */
+       for (i=0; i<numGroups && i<MS3D_MAX_GROUPS; i++)
+       {
+               picoSurface_t *surface;
+               picoShader_t  *shader;
+
+               /* sanity check */
+               if (shaderRefs[ i ] >= MS3D_MAX_MATERIALS ||
+                       shaderRefs[ i ] < 0)
+                       continue;
+
+               /* get surface */
+               surface = PicoGetModelSurface( model,i );
+               if (surface == NULL) continue;
+
+               /* get shader */
+               shader = PicoGetModelShader( model,shaderRefs[ i ] );
+               if (shader == NULL) continue;
+
+               /* assign shader */
+               PicoSetSurfaceShader( surface,shader );
+
+#ifdef DEBUG_PM_MS3D
+               printf("Mapped: %d ('%s') to %d (%s)\n",
+                       shaderRefs[i],shader->name,i,surface->name);
+#endif
+       }
+       /* return allocated pico model */
+       return model;
+//     return NULL;
+}
+
+/* pico file format module definition */
+const picoModule_t picoModuleMS3D =
+{
+       "0.4-a",                                        /* module version string */
+       "Milkshape 3D",                         /* module display name */
+       "seaw0lf",                                      /* author's name */
+       "2002 seaw0lf",                         /* module copyright */
+       {
+               "ms3d",NULL,NULL,NULL   /* default extensions to use */
+       },
+       _ms3d_canload,                          /* validation routine */
+       _ms3d_load,                                     /* load routine */
+        NULL,                                          /* save validation routine */
+        NULL                                           /* save routine */
+};