]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - libs/picomodel/pm_md3.c
eol style
[xonotic/netradiant.git] / libs / picomodel / pm_md3.c
index 6d87469d80e796bd1bac7673db1adcaa0e90058c..55022b287030b3ea47feb6d895a8934c7b7a76f9 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_MD3_C\r
-\r
-\r
-\r
-/* dependencies */\r
-#include "picointernal.h"\r
-\r
-\r
-\r
-/* md3 model format */\r
-#define MD3_MAGIC                      "IDP3"\r
-#define MD3_VERSION                    15\r
-\r
-/* md3 vertex scale */\r
-#define MD3_SCALE                (1.0f / 64.0f)\r
-\r
-/* md3 model frame information */\r
-typedef struct md3Frame_s\r
-{\r
-       float           bounds[ 2 ][ 3 ];\r
-       float           localOrigin[ 3 ];\r
-       float           radius;\r
-       char            creator[ 16 ];\r
-}\r
-md3Frame_t;\r
-\r
-/* md3 model tag information */\r
-typedef struct md3Tag_s\r
-{\r
-       char            name[ 64 ];\r
-       float           origin[ 3 ];\r
-       float           axis[ 3 ][ 3 ];\r
-}\r
-md3Tag_t;\r
-\r
-/* md3 surface md3 (one object mesh) */\r
-typedef struct md3Surface_s\r
-{\r
-       char            magic[ 4 ];\r
-       char            name[ 64 ];             /* polyset name */\r
-       int                     flags;\r
-       int                     numFrames;              /* all model surfaces should have the same */\r
-       int                     numShaders;             /* all model surfaces should have the same */\r
-       int                     numVerts;\r
-       int                     numTriangles;\r
-       int                     ofsTriangles;\r
-       int                     ofsShaders;             /* offset from start of md3Surface_t */\r
-       int                     ofsSt;                  /* texture coords are common for all frames */\r
-       int                     ofsVertexes;    /* numVerts * numFrames */\r
-       int                     ofsEnd;                 /* next surface follows */\r
-}\r
-md3Surface_t;\r
-\r
-typedef struct md3Shader_s\r
-{\r
-       char            name[ 64 ];\r
-       int                     shaderIndex;    /* for ingame use */\r
-}\r
-md3Shader_t;\r
-\r
-typedef struct md3Triangle_s\r
-{\r
-       int                     indexes[ 3 ];\r
-}\r
-md3Triangle_t;\r
-\r
-typedef struct md3TexCoord_s\r
-{\r
-       float           st[ 2 ];\r
-}\r
-md3TexCoord_t;\r
-\r
-typedef struct md3Vertex_s\r
-{\r
-       short           xyz[ 3 ];\r
-       short           normal;\r
-}\r
-md3Vertex_t;\r
-\r
-\r
-/* md3 model file md3 structure */\r
-typedef struct md3_s\r
-{\r
-       char            magic[ 4 ];             /* MD3_MAGIC */\r
-       int                     version;\r
-       char            name[ 64 ];             /* model name */\r
-       int                     flags;\r
-       int                     numFrames;\r
-       int                     numTags;\r
-       int                     numSurfaces;\r
-       int                     numSkins;               /* number of skins for the mesh */\r
-       int                     ofsFrames;              /* offset for first frame */\r
-       int                     ofsTags;                /* numFrames * numTags */\r
-       int                     ofsSurfaces;    /* first surface, others follow */\r
-       int                     ofsEnd;                 /* end of file */\r
-}\r
-md3_t;\r
-\r
-\r
-\r
-\r
-/*\r
-_md3_canload()\r
-validates a quake3 arena md3 model file. btw, i use the\r
-preceding underscore cause it's a static func referenced\r
-by one structure only.\r
-*/\r
-\r
-static int _md3_canload( PM_PARAMS_CANLOAD )\r
-{\r
-       md3_t   *md3;\r
-       \r
-\r
-       /* to keep the compiler happy */\r
-       *fileName = *fileName;\r
-       \r
-       /* sanity check */\r
-       if( bufSize < ( sizeof( *md3 ) * 2) )\r
-               return PICO_PMV_ERROR_SIZE;\r
-       \r
-       /* set as md3 */\r
-       md3     = (md3_t*) buffer;\r
-       \r
-       /* check md3 magic */\r
-       if( *((int*) md3->magic) != *((int*) MD3_MAGIC) ) \r
-               return PICO_PMV_ERROR_IDENT;\r
-       \r
-       /* check md3 version */\r
-       if( _pico_little_long( md3->version ) != MD3_VERSION )\r
-               return PICO_PMV_ERROR_VERSION;\r
-       \r
-       /* file seems to be a valid md3 */\r
-       return PICO_PMV_OK;\r
-}\r
-\r
-\r
-\r
-/*\r
-_md3_load()\r
-loads a quake3 arena md3 model file.\r
-*/\r
-\r
-static picoModel_t *_md3_load( PM_PARAMS_LOAD )\r
-{\r
-       int                             i, j;\r
-       picoByte_t              *bb;\r
-       md3_t                   *md3;\r
-       md3Surface_t    *surface;\r
-       md3Shader_t             *shader;\r
-       md3TexCoord_t   *texCoord;\r
-       md3Frame_t              *frame;\r
-       md3Triangle_t   *triangle;\r
-       md3Vertex_t             *vertex;\r
-       double                  lat, lng;\r
-       \r
-       picoModel_t             *picoModel;\r
-       picoSurface_t   *picoSurface;\r
-       picoShader_t    *picoShader;\r
-       picoVec3_t              xyz, normal;\r
-       picoVec2_t              st;\r
-       picoColor_t             color;\r
-       \r
-       \r
-       /* -------------------------------------------------\r
-       md3 loading\r
-       ------------------------------------------------- */\r
-\r
-\r
-       /* set as md3 */\r
-       bb = (picoByte_t*) buffer;\r
-       md3     = (md3_t*) buffer;\r
-       \r
-       /* check ident and version */\r
-       if( *((int*) md3->magic) != *((int*) MD3_MAGIC) || _pico_little_long( md3->version ) != MD3_VERSION )\r
-       {\r
-               /* not an md3 file (todo: set error) */\r
-               return NULL;\r
-       }\r
-       \r
-       /* swap md3; sea: swaps fixed */\r
-       md3->version = _pico_little_long( md3->version );\r
-       md3->numFrames = _pico_little_long( md3->numFrames );\r
-       md3->numTags = _pico_little_long( md3->numTags );\r
-       md3->numSurfaces = _pico_little_long( md3->numSurfaces );\r
-       md3->numSkins = _pico_little_long( md3->numSkins );\r
-       md3->ofsFrames = _pico_little_long( md3->ofsFrames );\r
-       md3->ofsTags = _pico_little_long( md3->ofsTags );\r
-       md3->ofsSurfaces = _pico_little_long( md3->ofsSurfaces );\r
-       md3->ofsEnd = _pico_little_long( md3->ofsEnd );\r
-       \r
-       /* do frame check */\r
-       if( md3->numFrames < 1 )\r
-       {\r
-               _pico_printf( PICO_ERROR, "MD3 with 0 frames" );\r
-               return NULL;\r
-       }\r
-       \r
-       if( frameNum < 0 || frameNum >= md3->numFrames )\r
-       {\r
-               _pico_printf( PICO_ERROR, "Invalid or out-of-range MD3 frame specified" );\r
-               return NULL;\r
-       }\r
-       \r
-       /* swap frames */\r
-       frame = (md3Frame_t*) (bb + md3->ofsFrames );\r
-       for( i = 0; i < md3->numFrames; i++, frame++ )\r
-       {\r
-               frame->radius = _pico_little_float( frame->radius );\r
-               for( j = 0; j < 3; j++ )\r
-               {\r
-                       frame->bounds[ 0 ][ j ] = _pico_little_float( frame->bounds[ 0 ][ j ] );\r
-                       frame->bounds[ 1 ][ j ] = _pico_little_float( frame->bounds[ 1 ][ j ] );\r
-                       frame->localOrigin[ j ] = _pico_little_float( frame->localOrigin[ j ] );\r
-               }\r
-       }\r
-       \r
-       /* swap surfaces */\r
-       surface = (md3Surface_t*) (bb + md3->ofsSurfaces);\r
-       for( i = 0; i < md3->numSurfaces; i++ )\r
-       {\r
-               /* swap surface md3; sea: swaps fixed */\r
-               surface->flags = _pico_little_long( surface->flags );\r
-               surface->numFrames = _pico_little_long( surface->numFrames );\r
-               surface->numShaders = _pico_little_long( surface->numShaders );\r
-               surface->numTriangles = _pico_little_long( surface->numTriangles );\r
-               surface->ofsTriangles = _pico_little_long( surface->ofsTriangles );\r
-               surface->numVerts = _pico_little_long( surface->numVerts );\r
-               surface->ofsShaders = _pico_little_long( surface->ofsShaders );\r
-               surface->ofsSt = _pico_little_long( surface->ofsSt );\r
-               surface->ofsVertexes = _pico_little_long( surface->ofsVertexes );\r
-               surface->ofsEnd = _pico_little_long( surface->ofsEnd );\r
-               \r
-               /* swap triangles */\r
-               triangle = (md3Triangle_t*) ((picoByte_t*) surface + surface->ofsTriangles);\r
-               for( j = 0; j < surface->numTriangles; j++, triangle++ )\r
-               {\r
-                       /* sea: swaps fixed */\r
-                       triangle->indexes[ 0 ] = _pico_little_long( triangle->indexes[ 0 ] );\r
-                       triangle->indexes[ 1 ] = _pico_little_long( triangle->indexes[ 1 ] );\r
-                       triangle->indexes[ 2 ] = _pico_little_long( triangle->indexes[ 2 ] );\r
-               }\r
-               \r
-               /* swap st coords */\r
-               texCoord = (md3TexCoord_t*) ((picoByte_t*) surface + surface->ofsSt);\r
-               for( j = 0; j < surface->numVerts; j++, texCoord++ )\r
-               {\r
-                       texCoord->st[ 0 ] = _pico_little_float( texCoord->st[ 0 ] );\r
-                       texCoord->st[ 1 ] = _pico_little_float( texCoord->st[ 1 ] );\r
-               }\r
-               \r
-               /* swap xyz/normals */\r
-               vertex = (md3Vertex_t*) ((picoByte_t*) surface + surface->ofsVertexes);\r
-               for( j = 0; j < (surface->numVerts * surface->numFrames); j++, vertex++)\r
-               {\r
-                       vertex->xyz[ 0 ] = _pico_little_short( vertex->xyz[ 0 ] );\r
-                       vertex->xyz[ 1 ] = _pico_little_short( vertex->xyz[ 1 ] );\r
-                       vertex->xyz[ 2 ] = _pico_little_short( vertex->xyz[ 2 ] );\r
-                       vertex->normal   = _pico_little_short( vertex->normal );\r
-               }\r
-               \r
-               /* get next surface */\r
-               surface = (md3Surface_t*) ((picoByte_t*) surface + surface->ofsEnd);\r
-       }\r
-       \r
-       /* -------------------------------------------------\r
-       pico model creation\r
-       ------------------------------------------------- */\r
-       \r
-       /* create new pico model */\r
-       picoModel = PicoNewModel();\r
-       if( picoModel == NULL )\r
-       {\r
-               _pico_printf( PICO_ERROR, "Unable to allocate a new model" );\r
-               return NULL;\r
-       }\r
-       \r
-       /* do model setup */\r
-       PicoSetModelFrameNum( picoModel, frameNum );\r
-       PicoSetModelNumFrames( picoModel, md3->numFrames ); /* sea */\r
-       PicoSetModelName( picoModel, fileName );\r
-       PicoSetModelFileName( picoModel, fileName );\r
-       \r
-       /* md3 surfaces become picomodel surfaces */\r
-       surface = (md3Surface_t*) (bb + md3->ofsSurfaces);\r
-       \r
-       /* run through md3 surfaces */\r
-       for( i = 0; i < md3->numSurfaces; i++ )\r
-       {\r
-               /* allocate new pico surface */\r
-               picoSurface = PicoNewSurface( picoModel );\r
-               if( picoSurface == NULL )\r
-               {\r
-                       _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );\r
-                       PicoFreeModel( picoModel ); /* sea */\r
-                       return NULL;\r
-               }\r
-               \r
-               /* md3 model surfaces are all triangle meshes */\r
-               PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );\r
-               \r
-               /* set surface name */\r
-               PicoSetSurfaceName( picoSurface, surface->name );\r
-               \r
-               /* create new pico shader -sea */\r
-               picoShader = PicoNewShader( picoModel );\r
-               if( picoShader == NULL )\r
-               {\r
-                       _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );\r
-                       PicoFreeModel( picoModel );\r
-                       return NULL;\r
-               }\r
-               \r
-               /* detox and set shader name */\r
-               shader = (md3Shader_t*) ((picoByte_t*) surface + surface->ofsShaders);\r
-               _pico_setfext( shader->name, "" );\r
-               _pico_unixify( shader->name );\r
-               PicoSetShaderName( picoShader, shader->name );\r
-               \r
-               /* associate current surface with newly created shader */\r
-               PicoSetSurfaceShader( picoSurface, picoShader );\r
-               \r
-               /* copy indexes */\r
-               triangle = (md3Triangle_t *) ((picoByte_t*) surface + surface->ofsTriangles);\r
-               \r
-               for( j = 0; j < surface->numTriangles; j++, triangle++ )\r
-               {\r
-                       PicoSetSurfaceIndex( picoSurface, (j * 3 + 0), (picoIndex_t) triangle->indexes[ 0 ] );\r
-                       PicoSetSurfaceIndex( picoSurface, (j * 3 + 1), (picoIndex_t) triangle->indexes[ 1 ] );\r
-                       PicoSetSurfaceIndex( picoSurface, (j * 3 + 2), (picoIndex_t) triangle->indexes[ 2 ] );\r
-               }\r
-               \r
-               /* copy vertexes */\r
-               texCoord = (md3TexCoord_t*) ((picoByte_t *) surface + surface->ofsSt);\r
-               vertex = (md3Vertex_t*) ((picoByte_t*) surface + surface->ofsVertexes + surface->numVerts * frameNum * sizeof( md3Vertex_t ) );\r
-               _pico_set_color( color, 255, 255, 255, 255 );\r
-               \r
-               for( j = 0; j < surface->numVerts; j++, texCoord++, vertex++ )\r
-               {\r
-                       /* set vertex origin */\r
-                       xyz[ 0 ] = MD3_SCALE * vertex->xyz[ 0 ];\r
-                       xyz[ 1 ] = MD3_SCALE * vertex->xyz[ 1 ];\r
-                       xyz[ 2 ] = MD3_SCALE * vertex->xyz[ 2 ];\r
-                       PicoSetSurfaceXYZ( picoSurface, j, xyz );\r
-                       \r
-                       /* decode lat/lng normal to 3 float normal */\r
-                       lat = (float) ((vertex->normal >> 8) & 0xff);\r
-                       lng = (float) (vertex->normal & 0xff);\r
-                       lat *= PICO_PI / 128;\r
-                       lng *= PICO_PI / 128;\r
-                       normal[ 0 ] = (picoVec_t) cos( lat ) * (picoVec_t) sin( lng );\r
-                       normal[ 1 ] = (picoVec_t) sin( lat ) * (picoVec_t) sin( lng );\r
-                       normal[ 2 ] = (picoVec_t) cos( lng );\r
-                       PicoSetSurfaceNormal( picoSurface, j, normal );\r
-                       \r
-                       /* set st coords */\r
-                       st[ 0 ] = texCoord->st[ 0 ];\r
-                       st[ 1 ] = texCoord->st[ 1 ];\r
-                       PicoSetSurfaceST( picoSurface, 0, j, st );\r
-\r
-                       /* set color */\r
-                       PicoSetSurfaceColor( picoSurface, 0, j, color );\r
-               }\r
-               \r
-               /* get next surface */\r
-               surface = (md3Surface_t*) ((picoByte_t*) surface + surface->ofsEnd);\r
-       }\r
-       \r
-       /* return the new pico model */\r
-       return picoModel;\r
-}\r
-\r
-\r
-\r
-/* pico file format module definition */\r
-const picoModule_t picoModuleMD3 =\r
-{\r
-       "1.3",                                          /* module version string */\r
-       "Quake 3 Arena",                        /* module display name */\r
-       "Randy Reddig",                         /* author's name */\r
-       "2002 Randy Reddig",            /* module copyright */\r
-       {\r
-               "md3", NULL, NULL, NULL /* default extensions to use */\r
-       },\r
-       _md3_canload,                           /* validation routine */\r
-       _md3_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_MD3_C
+
+
+
+/* dependencies */
+#include "picointernal.h"
+
+
+
+/* md3 model format */
+#define MD3_MAGIC                      "IDP3"
+#define MD3_VERSION                    15
+
+/* md3 vertex scale */
+#define MD3_SCALE                (1.0f / 64.0f)
+
+/* md3 model frame information */
+typedef struct md3Frame_s
+{
+       float           bounds[ 2 ][ 3 ];
+       float           localOrigin[ 3 ];
+       float           radius;
+       char            creator[ 16 ];
+}
+md3Frame_t;
+
+/* md3 model tag information */
+typedef struct md3Tag_s
+{
+       char            name[ 64 ];
+       float           origin[ 3 ];
+       float           axis[ 3 ][ 3 ];
+}
+md3Tag_t;
+
+/* md3 surface md3 (one object mesh) */
+typedef struct md3Surface_s
+{
+       char            magic[ 4 ];
+       char            name[ 64 ];             /* polyset name */
+       int                     flags;
+       int                     numFrames;              /* all model surfaces should have the same */
+       int                     numShaders;             /* all model surfaces should have the same */
+       int                     numVerts;
+       int                     numTriangles;
+       int                     ofsTriangles;
+       int                     ofsShaders;             /* offset from start of md3Surface_t */
+       int                     ofsSt;                  /* texture coords are common for all frames */
+       int                     ofsVertexes;    /* numVerts * numFrames */
+       int                     ofsEnd;                 /* next surface follows */
+}
+md3Surface_t;
+
+typedef struct md3Shader_s
+{
+       char            name[ 64 ];
+       int                     shaderIndex;    /* for ingame use */
+}
+md3Shader_t;
+
+typedef struct md3Triangle_s
+{
+       int                     indexes[ 3 ];
+}
+md3Triangle_t;
+
+typedef struct md3TexCoord_s
+{
+       float           st[ 2 ];
+}
+md3TexCoord_t;
+
+typedef struct md3Vertex_s
+{
+       short           xyz[ 3 ];
+       short           normal;
+}
+md3Vertex_t;
+
+
+/* md3 model file md3 structure */
+typedef struct md3_s
+{
+       char            magic[ 4 ];             /* MD3_MAGIC */
+       int                     version;
+       char            name[ 64 ];             /* model name */
+       int                     flags;
+       int                     numFrames;
+       int                     numTags;
+       int                     numSurfaces;
+       int                     numSkins;               /* number of skins for the mesh */
+       int                     ofsFrames;              /* offset for first frame */
+       int                     ofsTags;                /* numFrames * numTags */
+       int                     ofsSurfaces;    /* first surface, others follow */
+       int                     ofsEnd;                 /* end of file */
+}
+md3_t;
+
+
+
+
+/*
+_md3_canload()
+validates a quake3 arena md3 model file. btw, i use the
+preceding underscore cause it's a static func referenced
+by one structure only.
+*/
+
+static int _md3_canload( PM_PARAMS_CANLOAD )
+{
+       md3_t   *md3;
+       
+
+       /* to keep the compiler happy */
+       *fileName = *fileName;
+       
+       /* sanity check */
+       if( bufSize < ( sizeof( *md3 ) * 2) )
+               return PICO_PMV_ERROR_SIZE;
+       
+       /* set as md3 */
+       md3     = (md3_t*) buffer;
+       
+       /* check md3 magic */
+       if( *((int*) md3->magic) != *((int*) MD3_MAGIC) ) 
+               return PICO_PMV_ERROR_IDENT;
+       
+       /* check md3 version */
+       if( _pico_little_long( md3->version ) != MD3_VERSION )
+               return PICO_PMV_ERROR_VERSION;
+       
+       /* file seems to be a valid md3 */
+       return PICO_PMV_OK;
+}
+
+
+
+/*
+_md3_load()
+loads a quake3 arena md3 model file.
+*/
+
+static picoModel_t *_md3_load( PM_PARAMS_LOAD )
+{
+       int                             i, j;
+       picoByte_t              *bb;
+       md3_t                   *md3;
+       md3Surface_t    *surface;
+       md3Shader_t             *shader;
+       md3TexCoord_t   *texCoord;
+       md3Frame_t              *frame;
+       md3Triangle_t   *triangle;
+       md3Vertex_t             *vertex;
+       double                  lat, lng;
+       
+       picoModel_t             *picoModel;
+       picoSurface_t   *picoSurface;
+       picoShader_t    *picoShader;
+       picoVec3_t              xyz, normal;
+       picoVec2_t              st;
+       picoColor_t             color;
+       
+       
+       /* -------------------------------------------------
+       md3 loading
+       ------------------------------------------------- */
+
+
+       /* set as md3 */
+       bb = (picoByte_t*) buffer;
+       md3     = (md3_t*) buffer;
+       
+       /* check ident and version */
+       if( *((int*) md3->magic) != *((int*) MD3_MAGIC) || _pico_little_long( md3->version ) != MD3_VERSION )
+       {
+               /* not an md3 file (todo: set error) */
+               return NULL;
+       }
+       
+       /* swap md3; sea: swaps fixed */
+       md3->version = _pico_little_long( md3->version );
+       md3->numFrames = _pico_little_long( md3->numFrames );
+       md3->numTags = _pico_little_long( md3->numTags );
+       md3->numSurfaces = _pico_little_long( md3->numSurfaces );
+       md3->numSkins = _pico_little_long( md3->numSkins );
+       md3->ofsFrames = _pico_little_long( md3->ofsFrames );
+       md3->ofsTags = _pico_little_long( md3->ofsTags );
+       md3->ofsSurfaces = _pico_little_long( md3->ofsSurfaces );
+       md3->ofsEnd = _pico_little_long( md3->ofsEnd );
+       
+       /* do frame check */
+       if( md3->numFrames < 1 )
+       {
+               _pico_printf( PICO_ERROR, "MD3 with 0 frames" );
+               return NULL;
+       }
+       
+       if( frameNum < 0 || frameNum >= md3->numFrames )
+       {
+               _pico_printf( PICO_ERROR, "Invalid or out-of-range MD3 frame specified" );
+               return NULL;
+       }
+       
+       /* swap frames */
+       frame = (md3Frame_t*) (bb + md3->ofsFrames );
+       for( i = 0; i < md3->numFrames; i++, frame++ )
+       {
+               frame->radius = _pico_little_float( frame->radius );
+               for( j = 0; j < 3; j++ )
+               {
+                       frame->bounds[ 0 ][ j ] = _pico_little_float( frame->bounds[ 0 ][ j ] );
+                       frame->bounds[ 1 ][ j ] = _pico_little_float( frame->bounds[ 1 ][ j ] );
+                       frame->localOrigin[ j ] = _pico_little_float( frame->localOrigin[ j ] );
+               }
+       }
+       
+       /* swap surfaces */
+       surface = (md3Surface_t*) (bb + md3->ofsSurfaces);
+       for( i = 0; i < md3->numSurfaces; i++ )
+       {
+               /* swap surface md3; sea: swaps fixed */
+               surface->flags = _pico_little_long( surface->flags );
+               surface->numFrames = _pico_little_long( surface->numFrames );
+               surface->numShaders = _pico_little_long( surface->numShaders );
+               surface->numTriangles = _pico_little_long( surface->numTriangles );
+               surface->ofsTriangles = _pico_little_long( surface->ofsTriangles );
+               surface->numVerts = _pico_little_long( surface->numVerts );
+               surface->ofsShaders = _pico_little_long( surface->ofsShaders );
+               surface->ofsSt = _pico_little_long( surface->ofsSt );
+               surface->ofsVertexes = _pico_little_long( surface->ofsVertexes );
+               surface->ofsEnd = _pico_little_long( surface->ofsEnd );
+               
+               /* swap triangles */
+               triangle = (md3Triangle_t*) ((picoByte_t*) surface + surface->ofsTriangles);
+               for( j = 0; j < surface->numTriangles; j++, triangle++ )
+               {
+                       /* sea: swaps fixed */
+                       triangle->indexes[ 0 ] = _pico_little_long( triangle->indexes[ 0 ] );
+                       triangle->indexes[ 1 ] = _pico_little_long( triangle->indexes[ 1 ] );
+                       triangle->indexes[ 2 ] = _pico_little_long( triangle->indexes[ 2 ] );
+               }
+               
+               /* swap st coords */
+               texCoord = (md3TexCoord_t*) ((picoByte_t*) surface + surface->ofsSt);
+               for( j = 0; j < surface->numVerts; j++, texCoord++ )
+               {
+                       texCoord->st[ 0 ] = _pico_little_float( texCoord->st[ 0 ] );
+                       texCoord->st[ 1 ] = _pico_little_float( texCoord->st[ 1 ] );
+               }
+               
+               /* swap xyz/normals */
+               vertex = (md3Vertex_t*) ((picoByte_t*) surface + surface->ofsVertexes);
+               for( j = 0; j < (surface->numVerts * surface->numFrames); j++, vertex++)
+               {
+                       vertex->xyz[ 0 ] = _pico_little_short( vertex->xyz[ 0 ] );
+                       vertex->xyz[ 1 ] = _pico_little_short( vertex->xyz[ 1 ] );
+                       vertex->xyz[ 2 ] = _pico_little_short( vertex->xyz[ 2 ] );
+                       vertex->normal   = _pico_little_short( vertex->normal );
+               }
+               
+               /* get next surface */
+               surface = (md3Surface_t*) ((picoByte_t*) surface + surface->ofsEnd);
+       }
+       
+       /* -------------------------------------------------
+       pico model creation
+       ------------------------------------------------- */
+       
+       /* create new pico model */
+       picoModel = PicoNewModel();
+       if( picoModel == NULL )
+       {
+               _pico_printf( PICO_ERROR, "Unable to allocate a new model" );
+               return NULL;
+       }
+       
+       /* do model setup */
+       PicoSetModelFrameNum( picoModel, frameNum );
+       PicoSetModelNumFrames( picoModel, md3->numFrames ); /* sea */
+       PicoSetModelName( picoModel, fileName );
+       PicoSetModelFileName( picoModel, fileName );
+       
+       /* md3 surfaces become picomodel surfaces */
+       surface = (md3Surface_t*) (bb + md3->ofsSurfaces);
+       
+       /* run through md3 surfaces */
+       for( i = 0; i < md3->numSurfaces; i++ )
+       {
+               /* allocate new pico surface */
+               picoSurface = PicoNewSurface( picoModel );
+               if( picoSurface == NULL )
+               {
+                       _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
+                       PicoFreeModel( picoModel ); /* sea */
+                       return NULL;
+               }
+               
+               /* md3 model surfaces are all triangle meshes */
+               PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
+               
+               /* set surface name */
+               PicoSetSurfaceName( picoSurface, surface->name );
+               
+               /* create new pico shader -sea */
+               picoShader = PicoNewShader( picoModel );
+               if( picoShader == NULL )
+               {
+                       _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
+                       PicoFreeModel( picoModel );
+                       return NULL;
+               }
+               
+               /* detox and set shader name */
+               shader = (md3Shader_t*) ((picoByte_t*) surface + surface->ofsShaders);
+               _pico_setfext( shader->name, "" );
+               _pico_unixify( shader->name );
+               PicoSetShaderName( picoShader, shader->name );
+               
+               /* associate current surface with newly created shader */
+               PicoSetSurfaceShader( picoSurface, picoShader );
+               
+               /* copy indexes */
+               triangle = (md3Triangle_t *) ((picoByte_t*) surface + surface->ofsTriangles);
+               
+               for( j = 0; j < surface->numTriangles; j++, triangle++ )
+               {
+                       PicoSetSurfaceIndex( picoSurface, (j * 3 + 0), (picoIndex_t) triangle->indexes[ 0 ] );
+                       PicoSetSurfaceIndex( picoSurface, (j * 3 + 1), (picoIndex_t) triangle->indexes[ 1 ] );
+                       PicoSetSurfaceIndex( picoSurface, (j * 3 + 2), (picoIndex_t) triangle->indexes[ 2 ] );
+               }
+               
+               /* copy vertexes */
+               texCoord = (md3TexCoord_t*) ((picoByte_t *) surface + surface->ofsSt);
+               vertex = (md3Vertex_t*) ((picoByte_t*) surface + surface->ofsVertexes + surface->numVerts * frameNum * sizeof( md3Vertex_t ) );
+               _pico_set_color( color, 255, 255, 255, 255 );
+               
+               for( j = 0; j < surface->numVerts; j++, texCoord++, vertex++ )
+               {
+                       /* set vertex origin */
+                       xyz[ 0 ] = MD3_SCALE * vertex->xyz[ 0 ];
+                       xyz[ 1 ] = MD3_SCALE * vertex->xyz[ 1 ];
+                       xyz[ 2 ] = MD3_SCALE * vertex->xyz[ 2 ];
+                       PicoSetSurfaceXYZ( picoSurface, j, xyz );
+                       
+                       /* decode lat/lng normal to 3 float normal */
+                       lat = (float) ((vertex->normal >> 8) & 0xff);
+                       lng = (float) (vertex->normal & 0xff);
+                       lat *= PICO_PI / 128;
+                       lng *= PICO_PI / 128;
+                       normal[ 0 ] = (picoVec_t) cos( lat ) * (picoVec_t) sin( lng );
+                       normal[ 1 ] = (picoVec_t) sin( lat ) * (picoVec_t) sin( lng );
+                       normal[ 2 ] = (picoVec_t) cos( lng );
+                       PicoSetSurfaceNormal( picoSurface, j, normal );
+                       
+                       /* set st coords */
+                       st[ 0 ] = texCoord->st[ 0 ];
+                       st[ 1 ] = texCoord->st[ 1 ];
+                       PicoSetSurfaceST( picoSurface, 0, j, st );
+
+                       /* set color */
+                       PicoSetSurfaceColor( picoSurface, 0, j, color );
+               }
+               
+               /* get next surface */
+               surface = (md3Surface_t*) ((picoByte_t*) surface + surface->ofsEnd);
+       }
+       
+       /* return the new pico model */
+       return picoModel;
+}
+
+
+
+/* pico file format module definition */
+const picoModule_t picoModuleMD3 =
+{
+       "1.3",                                          /* module version string */
+       "Quake 3 Arena",                        /* module display name */
+       "Randy Reddig",                         /* author's name */
+       "2002 Randy Reddig",            /* module copyright */
+       {
+               "md3", NULL, NULL, NULL /* default extensions to use */
+       },
+       _md3_canload,                           /* validation routine */
+       _md3_load,                                      /* load routine */
+        NULL,                                          /* save validation routine */
+        NULL                                           /* save routine */
+};