-/* -----------------------------------------------------------------------------\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
-Nurail: Used pm_md3.c (Randy Reddig) as a template.\r
-*/\r
-\r
-\r
-/* marker */\r
-#define PM_MD2_C\r
-\r
-/* dependencies */\r
-#include "picointernal.h"\r
-\r
-\r
-/* md2 model format */\r
-#define MD2_MAGIC "IDP2"\r
-#define MD2_VERSION 8\r
-\r
-#define MD2_NUMVERTEXNORMALS 162\r
-#define MD2_MAX_SKINNAME 64\r
-#define MD2_MAX_TRIANGLES 4096\r
-#define MD2_MAX_VERTS 2048\r
-#define MD2_MAX_FRAMES 512\r
-#define MD2_MAX_MD2SKINS 32\r
-#define MD2_MAX_SKINNAME 64\r
-\r
-#ifndef byte\r
- #define byte unsigned char\r
-#endif\r
-\r
-typedef struct index_LUT_s\r
-{\r
- short Vert;\r
- short ST;\r
- struct index_LUT_s *next;\r
-\r
-} index_LUT_t;\r
-\r
-typedef struct index_DUP_LUT_s\r
-{\r
- short ST;\r
- short OldVert;\r
-\r
-} index_DUP_LUT_t;\r
-\r
-typedef struct\r
-{\r
- short s;\r
- short t;\r
-} md2St_t;\r
-\r
-typedef struct\r
-{\r
- short index_xyz[3];\r
- short index_st[3];\r
-} md2Triangle_t;\r
-\r
-typedef struct\r
-{\r
- byte v[3]; // scaled byte to fit in frame mins/maxs\r
- byte lightnormalindex;\r
-} md2XyzNormal_t;\r
-\r
-typedef struct md2Frame_s\r
-{\r
- float scale[3]; // multiply byte verts by this\r
- float translate[3]; // then add this\r
- char name[16]; // frame name from grabbing\r
- md2XyzNormal_t verts[1]; // variable sized\r
-}\r
-md2Frame_t;\r
-\r
-\r
-/* md2 model file md2 structure */\r
-typedef struct md2_s\r
-{\r
- char magic[ 4 ];\r
- int version;\r
-\r
- int skinWidth;\r
- int skinHeight;\r
- int frameSize;\r
-\r
- int numSkins;\r
- int numXYZ;\r
- int numST;\r
- int numTris;\r
- int numGLCmds;\r
- int numFrames;\r
-\r
- int ofsSkins;\r
- int ofsST;\r
- int ofsTris;\r
- int ofsFrames;\r
- int ofsGLCmds;\r
- int ofsEnd;\r
-}\r
-md2_t;\r
-\r
-float md2_normals[ MD2_NUMVERTEXNORMALS ][ 3 ] =\r
-{\r
- { -0.525731f, 0.000000f, 0.850651f },\r
- { -0.442863f, 0.238856f, 0.864188f }, \r
- { -0.295242f, 0.000000f, 0.955423f }, \r
- { -0.309017f, 0.500000f, 0.809017f }, \r
- { -0.162460f, 0.262866f, 0.951056f }, \r
- { 0.000000f, 0.000000f, 1.000000f },\r
- { 0.000000f, 0.850651f, 0.525731f },\r
- { -0.147621f, 0.716567f, 0.681718f },\r
- { 0.147621f, 0.716567f, 0.681718f }, \r
- { 0.000000f, 0.525731f, 0.850651f }, \r
- { 0.309017f, 0.500000f, 0.809017f }, \r
- { 0.525731f, 0.000000f, 0.850651f }, \r
- { 0.295242f, 0.000000f, 0.955423f }, \r
- { 0.442863f, 0.238856f, 0.864188f }, \r
- { 0.162460f, 0.262866f, 0.951056f }, \r
- { -0.681718f, 0.147621f, 0.716567f }, \r
- { -0.809017f, 0.309017f, 0.500000f }, \r
- { -0.587785f, 0.425325f, 0.688191f }, \r
- { -0.850651f, 0.525731f, 0.000000f }, \r
- { -0.864188f, 0.442863f, 0.238856f }, \r
- { -0.716567f, 0.681718f, 0.147621f }, \r
- { -0.688191f, 0.587785f, 0.425325f }, \r
- { -0.500000f, 0.809017f, 0.309017f }, \r
- { -0.238856f, 0.864188f, 0.442863f }, \r
- { -0.425325f, 0.688191f, 0.587785f }, \r
- { -0.716567f, 0.681718f, -0.147621f }, \r
- { -0.500000f, 0.809017f, -0.309017f }, \r
- { -0.525731f, 0.850651f, 0.000000f }, \r
- { 0.000000f, 0.850651f, -0.525731f }, \r
- { -0.238856f, 0.864188f, -0.442863f }, \r
- { 0.000000f, 0.955423f, -0.295242f }, \r
- { -0.262866f, 0.951056f, -0.162460f }, \r
- { 0.000000f, 1.000000f, 0.000000f }, \r
- { 0.000000f, 0.955423f, 0.295242f }, \r
- { -0.262866f, 0.951056f, 0.162460f }, \r
- { 0.238856f, 0.864188f, 0.442863f }, \r
- { 0.262866f, 0.951056f, 0.162460f }, \r
- { 0.500000f, 0.809017f, 0.309017f }, \r
- { 0.238856f, 0.864188f, -0.442863f }, \r
- { 0.262866f, 0.951056f, -0.162460f }, \r
- { 0.500000f, 0.809017f, -0.309017f }, \r
- { 0.850651f, 0.525731f, 0.000000f }, \r
- { 0.716567f, 0.681718f, 0.147621f }, \r
- { 0.716567f, 0.681718f, -0.147621f }, \r
- { 0.525731f, 0.850651f, 0.000000f }, \r
- { 0.425325f, 0.688191f, 0.587785f }, \r
- { 0.864188f, 0.442863f, 0.238856f }, \r
- { 0.688191f, 0.587785f, 0.425325f }, \r
- { 0.809017f, 0.309017f, 0.500000f }, \r
- { 0.681718f, 0.147621f, 0.716567f }, \r
- { 0.587785f, 0.425325f, 0.688191f }, \r
- { 0.955423f, 0.295242f, 0.000000f }, \r
- { 1.000000f, 0.000000f, 0.000000f }, \r
- { 0.951056f, 0.162460f, 0.262866f }, \r
- { 0.850651f, -0.525731f, 0.000000f }, \r
- { 0.955423f, -0.295242f, 0.000000f }, \r
- { 0.864188f, -0.442863f, 0.238856f }, \r
- { 0.951056f, -0.162460f, 0.262866f }, \r
- { 0.809017f, -0.309017f, 0.500000f }, \r
- { 0.681718f, -0.147621f, 0.716567f }, \r
- { 0.850651f, 0.000000f, 0.525731f }, \r
- { 0.864188f, 0.442863f, -0.238856f }, \r
- { 0.809017f, 0.309017f, -0.500000f }, \r
- { 0.951056f, 0.162460f, -0.262866f }, \r
- { 0.525731f, 0.000000f, -0.850651f }, \r
- { 0.681718f, 0.147621f, -0.716567f }, \r
- { 0.681718f, -0.147621f, -0.716567f }, \r
- { 0.850651f, 0.000000f, -0.525731f }, \r
- { 0.809017f, -0.309017f, -0.500000f }, \r
- { 0.864188f, -0.442863f, -0.238856f }, \r
- { 0.951056f, -0.162460f, -0.262866f }, \r
- { 0.147621f, 0.716567f, -0.681718f }, \r
- { 0.309017f, 0.500000f, -0.809017f }, \r
- { 0.425325f, 0.688191f, -0.587785f }, \r
- { 0.442863f, 0.238856f, -0.864188f }, \r
- { 0.587785f, 0.425325f, -0.688191f }, \r
- { 0.688191f, 0.587785f, -0.425325f }, \r
- { -0.147621f, 0.716567f, -0.681718f }, \r
- { -0.309017f, 0.500000f, -0.809017f }, \r
- { 0.000000f, 0.525731f, -0.850651f }, \r
- { -0.525731f, 0.000000f, -0.850651f }, \r
- { -0.442863f, 0.238856f, -0.864188f }, \r
- { -0.295242f, 0.000000f, -0.955423f }, \r
- { -0.162460f, 0.262866f, -0.951056f }, \r
- { 0.000000f, 0.000000f, -1.000000f }, \r
- { 0.295242f, 0.000000f, -0.955423f }, \r
- { 0.162460f, 0.262866f, -0.951056f }, \r
- { -0.442863f, -0.238856f, -0.864188f }, \r
- { -0.309017f, -0.500000f, -0.809017f }, \r
- { -0.162460f, -0.262866f, -0.951056f }, \r
- { 0.000000f, -0.850651f, -0.525731f }, \r
- { -0.147621f, -0.716567f, -0.681718f }, \r
- { 0.147621f, -0.716567f, -0.681718f }, \r
- { 0.000000f, -0.525731f, -0.850651f }, \r
- { 0.309017f, -0.500000f, -0.809017f }, \r
- { 0.442863f, -0.238856f, -0.864188f }, \r
- { 0.162460f, -0.262866f, -0.951056f }, \r
- { 0.238856f, -0.864188f, -0.442863f }, \r
- { 0.500000f, -0.809017f, -0.309017f }, \r
- { 0.425325f, -0.688191f, -0.587785f }, \r
- { 0.716567f, -0.681718f, -0.147621f }, \r
- { 0.688191f, -0.587785f, -0.425325f }, \r
- { 0.587785f, -0.425325f, -0.688191f }, \r
- { 0.000000f, -0.955423f, -0.295242f }, \r
- { 0.000000f, -1.000000f, 0.000000f }, \r
- { 0.262866f, -0.951056f, -0.162460f }, \r
- { 0.000000f, -0.850651f, 0.525731f }, \r
- { 0.000000f, -0.955423f, 0.295242f }, \r
- { 0.238856f, -0.864188f, 0.442863f }, \r
- { 0.262866f, -0.951056f, 0.162460f }, \r
- { 0.500000f, -0.809017f, 0.309017f }, \r
- { 0.716567f, -0.681718f, 0.147621f }, \r
- { 0.525731f, -0.850651f, 0.000000f }, \r
- { -0.238856f, -0.864188f, -0.442863f }, \r
- { -0.500000f, -0.809017f, -0.309017f }, \r
- { -0.262866f, -0.951056f, -0.162460f }, \r
- { -0.850651f, -0.525731f, 0.000000f }, \r
- { -0.716567f, -0.681718f, -0.147621f }, \r
- { -0.716567f, -0.681718f, 0.147621f }, \r
- { -0.525731f, -0.850651f, 0.000000f }, \r
- { -0.500000f, -0.809017f, 0.309017f }, \r
- { -0.238856f, -0.864188f, 0.442863f }, \r
- { -0.262866f, -0.951056f, 0.162460f }, \r
- { -0.864188f, -0.442863f, 0.238856f }, \r
- { -0.809017f, -0.309017f, 0.500000f }, \r
- { -0.688191f, -0.587785f, 0.425325f }, \r
- { -0.681718f, -0.147621f, 0.716567f }, \r
- { -0.442863f, -0.238856f, 0.864188f }, \r
- { -0.587785f, -0.425325f, 0.688191f }, \r
- { -0.309017f, -0.500000f, 0.809017f }, \r
- { -0.147621f, -0.716567f, 0.681718f }, \r
- { -0.425325f, -0.688191f, 0.587785f }, \r
- { -0.162460f, -0.262866f, 0.951056f }, \r
- { 0.442863f, -0.238856f, 0.864188f }, \r
- { 0.162460f, -0.262866f, 0.951056f }, \r
- { 0.309017f, -0.500000f, 0.809017f }, \r
- { 0.147621f, -0.716567f, 0.681718f }, \r
- { 0.000000f, -0.525731f, 0.850651f }, \r
- { 0.425325f, -0.688191f, 0.587785f }, \r
- { 0.587785f, -0.425325f, 0.688191f }, \r
- { 0.688191f, -0.587785f, 0.425325f }, \r
- { -0.955423f, 0.295242f, 0.000000f }, \r
- { -0.951056f, 0.162460f, 0.262866f }, \r
- { -1.000000f, 0.000000f, 0.000000f }, \r
- { -0.850651f, 0.000000f, 0.525731f }, \r
- { -0.955423f, -0.295242f, 0.000000f }, \r
- { -0.951056f, -0.162460f, 0.262866f }, \r
- { -0.864188f, 0.442863f, -0.238856f }, \r
- { -0.951056f, 0.162460f, -0.262866f }, \r
- { -0.809017f, 0.309017f, -0.500000f }, \r
- { -0.864188f, -0.442863f, -0.238856f },\r
- { -0.951056f, -0.162460f, -0.262866f }, \r
- { -0.809017f, -0.309017f, -0.500000f }, \r
- { -0.681718f, 0.147621f, -0.716567f }, \r
- { -0.681718f, -0.147621f, -0.716567f }, \r
- { -0.850651f, 0.000000f, -0.525731f }, \r
- { -0.688191f, 0.587785f, -0.425325f }, \r
- { -0.587785f, 0.425325f, -0.688191f }, \r
- { -0.425325f, 0.688191f, -0.587785f }, \r
- { -0.425325f, -0.688191f, -0.587785f }, \r
- { -0.587785f, -0.425325f, -0.688191f }, \r
- { -0.688191f, -0.587785f, -0.425325f }, \r
-};\r
-\r
-\r
-// _md2_canload()\r
-\r
-static int _md2_canload( PM_PARAMS_CANLOAD )\r
-{\r
- md2_t *md2;\r
-\r
- /* to keep the compiler happy */\r
- *fileName = *fileName;\r
-\r
- /* sanity check */\r
- if( bufSize < ( sizeof( *md2 ) * 2) )\r
- return PICO_PMV_ERROR_SIZE;\r
- \r
- /* set as md2 */\r
- md2 = (md2_t*) buffer;\r
- \r
- /* check md2 magic */\r
- if( *((int*) md2->magic) != *((int*) MD2_MAGIC) ) \r
- return PICO_PMV_ERROR_IDENT;\r
- \r
- /* check md2 version */\r
- if( _pico_little_long( md2->version ) != MD2_VERSION )\r
- return PICO_PMV_ERROR_VERSION;\r
-\r
- /* file seems to be a valid md2 */\r
- return PICO_PMV_OK;\r
-}\r
-\r
-\r
-\r
-// _md2_load() loads a quake2 md2 model file.\r
-\r
-\r
-static picoModel_t *_md2_load( PM_PARAMS_LOAD )\r
-{\r
- int i, j, dups, dup_index;\r
- short tot_numVerts;\r
- index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3;\r
- index_DUP_LUT_t *p_index_LUT_DUPS;\r
- md2Triangle_t *p_md2Triangle;\r
-\r
- char skinname[ MD2_MAX_SKINNAME ];\r
- md2_t *md2;\r
- md2St_t *texCoord;\r
- md2Frame_t *frame;\r
- md2Triangle_t *triangle;\r
- md2XyzNormal_t *vertex;\r
-\r
- picoByte_t *bb;\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
- // md2 loading\r
- _pico_printf( PICO_NORMAL, "Loading \"%s\"", fileName );\r
-\r
- /* set as md2 */\r
- bb = (picoByte_t*) buffer;\r
- md2 = (md2_t*) buffer;\r
-\r
- /* check ident and version */\r
- if( *((int*) md2->magic) != *((int*) MD2_MAGIC) || _pico_little_long( md2->version ) != MD2_VERSION )\r
- {\r
- /* not an md2 file (todo: set error) */\r
- _pico_printf( PICO_ERROR, "%s is not an MD2 File!", fileName );\r
- return NULL;\r
- }\r
- \r
- // swap md2\r
- md2->version = _pico_little_long( md2->version );\r
-\r
- md2->skinWidth = _pico_little_long( md2->skinWidth );\r
- md2->skinHeight = _pico_little_long( md2->skinHeight );\r
- md2->frameSize = _pico_little_long( md2->frameSize );\r
-\r
- md2->numSkins = _pico_little_long( md2->numSkins );\r
- md2->numXYZ = _pico_little_long( md2->numXYZ );\r
- md2->numST = _pico_little_long( md2->numST );\r
- md2->numTris = _pico_little_long( md2->numTris );\r
- md2->numGLCmds = _pico_little_long( md2->numGLCmds );\r
- md2->numFrames = _pico_little_long( md2->numFrames );\r
-\r
- md2->ofsSkins = _pico_little_long( md2->ofsSkins );\r
- md2->ofsST = _pico_little_long( md2->ofsST );\r
- md2->ofsTris = _pico_little_long( md2->ofsTris );\r
- md2->ofsFrames = _pico_little_long( md2->ofsFrames );\r
- md2->ofsGLCmds = _pico_little_long( md2->ofsGLCmds );\r
- md2->ofsEnd = _pico_little_long( md2->ofsEnd );\r
-\r
- // do frame check\r
- if( md2->numFrames < 1 )\r
- {\r
- _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );\r
- return NULL;\r
- }\r
- \r
- if( frameNum < 0 || frameNum >= md2->numFrames )\r
- {\r
- _pico_printf( PICO_ERROR, "Invalid or out-of-range MD2 frame specified" );\r
- return NULL;\r
- }\r
-\r
- // Setup Frame\r
- frame = (md2Frame_t *) (bb + md2->ofsFrames + (sizeof(md2Frame_t) * frameNum));\r
-\r
- // swap frame scale and translation\r
- for( i = 0; i < 3; i++ )\r
- {\r
- frame->scale[ i ] = _pico_little_float( frame->scale[ i ] );\r
- frame->translate[ i ] = _pico_little_float( frame->translate[ i ] );\r
- }\r
-\r
- // swap triangles\r
- triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) );\r
- for( i = 0; i < md2->numTris; i++, triangle++ )\r
- {\r
- for( j = 0; j < 3; j++ )\r
- {\r
- triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );\r
- triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );\r
- }\r
- }\r
-\r
- // swap st coords\r
- texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) );\r
- for( i = 0; i < md2->numST; i++, texCoord++ )\r
- {\r
- texCoord->s = _pico_little_short( texCoord->s );\r
- texCoord->t = _pico_little_short( texCoord->t );\r
- }\r
-\r
- // set Skin Name\r
- strncpy(skinname, (bb + md2->ofsSkins), MD2_MAX_SKINNAME );\r
-\r
- // Print out md2 values\r
- _pico_printf(PICO_VERBOSE,"Skins: %d Verts: %d STs: %d Triangles: %d Frames: %d\nSkin Name \"%s\"\n", md2->numSkins, md2->numXYZ, md2->numST, md2->numTris, md2->numFrames, &skinname );\r
-\r
- // detox Skin name\r
- _pico_setfext( skinname, "" );\r
- _pico_unixify( skinname );\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, md2->numFrames ); /* sea */\r
- PicoSetModelName( picoModel, fileName );\r
- PicoSetModelFileName( picoModel, fileName );\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 );\r
- return NULL;\r
- }\r
-\r
-\r
- PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );\r
- PicoSetSurfaceName( picoSurface, frame->name );\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
- PicoSetShaderName( picoShader, skinname );\r
-\r
- // associate current surface with newly created shader\r
- PicoSetSurfaceShader( picoSurface, picoShader );\r
-\r
- // Init LUT for Verts\r
- p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * md2->numXYZ);\r
- for(i=0; i<md2->numXYZ; i++)\r
- {\r
- p_index_LUT[i].Vert = -1;\r
- p_index_LUT[i].ST = -1;\r
- p_index_LUT[i].next = NULL;\r
- }\r
-\r
- // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert.\r
- tot_numVerts = md2->numXYZ;\r
- dups = 0;\r
- for(i=0; i<md2->numTris; i++)\r
- {\r
- p_md2Triangle = (md2Triangle_t *) ( bb + md2->ofsTris + (sizeof(md2Triangle_t)*i));\r
- for(j=0; j<3; j++)\r
- {\r
- if (p_index_LUT[p_md2Triangle->index_xyz[j]].ST == -1) // No Main Entry\r
- p_index_LUT[p_md2Triangle->index_xyz[j]].ST = p_md2Triangle->index_st[j];\r
-\r
- else if (p_md2Triangle->index_st[j] == p_index_LUT[p_md2Triangle->index_xyz[j]].ST ) // Equal to Main Entry\r
- continue;\r
-\r
- else if ( (p_index_LUT[p_md2Triangle->index_xyz[j]].next == NULL) ) // Not equal to Main entry, and no LL entry\r
- { // Add first entry of LL from Main\r
- p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));\r
- if (p_index_LUT2 == NULL)\r
- _pico_printf( PICO_ERROR," Couldn't allocate memory!\n");\r
- p_index_LUT[p_md2Triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2;\r
- p_index_LUT2->Vert = dups;\r
- p_index_LUT2->ST = p_md2Triangle->index_st[j];\r
- p_index_LUT2->next = NULL;\r
- p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk\r
- dups++;\r
- }\r
- else // Try to find in LL from Main Entry\r
- {\r
- p_index_LUT3 = p_index_LUT2 = p_index_LUT[p_md2Triangle->index_xyz[j]].next;\r
- while ( (p_index_LUT2 != NULL) && (p_md2Triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL\r
- {\r
- p_index_LUT3 = p_index_LUT2;\r
- p_index_LUT2 = p_index_LUT2->next;\r
- }\r
- p_index_LUT2 = p_index_LUT3;\r
-\r
- if ( p_md2Triangle->index_st[j] == p_index_LUT2->ST ) // Found it\r
- {\r
- p_md2Triangle->index_xyz[j] = p_index_LUT2->Vert + md2->numXYZ; // Make change in Tri hunk\r
- continue;\r
- }\r
-\r
- if ( p_index_LUT2->next == NULL) // Didn't find it. Add entry to LL.\r
- {\r
- // Add the Entry\r
- p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));\r
- if (p_index_LUT3 == NULL)\r
- _pico_printf( PICO_ERROR," Couldn't allocate memory!\n");\r
- p_index_LUT2->next = (index_LUT_t *)p_index_LUT3;\r
- p_index_LUT3->Vert = p_md2Triangle->index_xyz[j];\r
- p_index_LUT3->ST = p_md2Triangle->index_st[j];\r
- p_index_LUT3->next = NULL;\r
- p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk\r
- dups++;\r
- }\r
- }\r
- }\r
- }\r
-\r
- // malloc and build array for Dup STs\r
- p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups);\r
- if (p_index_LUT_DUPS == NULL)\r
- _pico_printf( PICO_ERROR," Couldn't allocate memory!\n");\r
-\r
- dup_index = 0;\r
- for(i=0; i<md2->numXYZ; i++)\r
- {\r
- p_index_LUT2 = p_index_LUT[i].next;\r
- while (p_index_LUT2 != NULL)\r
- {\r
- p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i;\r
- p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST;\r
- dup_index++;\r
- p_index_LUT2 = p_index_LUT2->next;\r
- }\r
- }\r
-\r
- // Build Picomodel\r
- triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) );\r
- texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) );\r
- vertex = (md2XyzNormal_t*) ((picoByte_t*) (frame->verts) );\r
- for( j = 0; j < md2->numTris; j++, triangle++ )\r
- {\r
- PicoSetSurfaceIndex( picoSurface, j*3 , triangle->index_xyz[0] );\r
- PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] );\r
- PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] );\r
- }\r
-\r
- for(i=0; i< md2->numXYZ; i++, vertex++)\r
- {\r
- /* set vertex origin */\r
- xyz[ 0 ] = vertex->v[0] * frame->scale[0] + frame->translate[0];\r
- xyz[ 1 ] = vertex->v[1] * frame->scale[1] + frame->translate[1];\r
- xyz[ 2 ] = vertex->v[2] * frame->scale[2] + frame->translate[2];\r
- PicoSetSurfaceXYZ( picoSurface, i , xyz );\r
-\r
- /* set normal */\r
- normal[ 0 ] = md2_normals[vertex->lightnormalindex][0];\r
- normal[ 1 ] = md2_normals[vertex->lightnormalindex][1];\r
- normal[ 2 ] = md2_normals[vertex->lightnormalindex][2];\r
- PicoSetSurfaceNormal( picoSurface, i , normal );\r
-\r
- /* set st coords */\r
- st[ 0 ] = ((texCoord[p_index_LUT[i].ST].s) / ((float)md2->skinWidth));\r
- st[ 1 ] = (texCoord[p_index_LUT[i].ST].t / ((float)md2->skinHeight));\r
- PicoSetSurfaceST( picoSurface, 0, i , st );\r
- }\r
-\r
- if (dups)\r
- {\r
- for(i=0; i<dups; i++)\r
- {\r
- j = p_index_LUT_DUPS[i].OldVert;\r
- /* set vertex origin */\r
- xyz[ 0 ] = frame->verts[j].v[0] * frame->scale[0] + frame->translate[0];\r
- xyz[ 1 ] = frame->verts[j].v[1] * frame->scale[1] + frame->translate[1];\r
- xyz[ 2 ] = frame->verts[j].v[2] * frame->scale[2] + frame->translate[2];\r
- PicoSetSurfaceXYZ( picoSurface, i + md2->numXYZ , xyz );\r
-\r
- /* set normal */\r
- normal[ 0 ] = md2_normals[frame->verts[j].lightnormalindex][0];\r
- normal[ 1 ] = md2_normals[frame->verts[j].lightnormalindex][1];\r
- normal[ 2 ] = md2_normals[frame->verts[j].lightnormalindex][2];\r
- PicoSetSurfaceNormal( picoSurface, i + md2->numXYZ , normal );\r
-\r
- /* set st coords */\r
- st[ 0 ] = ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)md2->skinWidth));\r
- st[ 1 ] = (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)md2->skinHeight));\r
- PicoSetSurfaceST( picoSurface, 0, i + md2->numXYZ , st );\r
- }\r
- }\r
-\r
- /* set color */\r
- PicoSetSurfaceColor( picoSurface, 0, 0, color );\r
-\r
- // Free up malloc'ed LL entries\r
- for(i=0; i<md2->numXYZ; i++)\r
- {\r
- if(p_index_LUT[i].next != NULL)\r
- {\r
- p_index_LUT2 = p_index_LUT[i].next;\r
- do {\r
- p_index_LUT3 = p_index_LUT2->next;\r
- _pico_free(p_index_LUT2);\r
- p_index_LUT2 = p_index_LUT3;\r
- dups--;\r
- } while (p_index_LUT2 != NULL);\r
- }\r
- }\r
-\r
- if (dups)\r
- _pico_printf(PICO_WARNING, " Not all LL mallocs freed\n");\r
-\r
- // Free malloc'ed LUTs\r
- _pico_free(p_index_LUT);\r
- _pico_free(p_index_LUT_DUPS);\r
-\r
- /* return the new pico model */\r
- return picoModel;\r
-\r
-}\r
-\r
-\r
-\r
-/* pico file format module definition */\r
-const picoModule_t picoModuleMD2 =\r
-{\r
- "0.875", /* module version string */\r
- "Quake 2 MD2", /* module display name */\r
- "Nurail", /* author's name */\r
- "2003 Nurail", /* module copyright */\r
- {\r
- "md2", NULL, NULL, NULL /* default extensions to use */\r
- },\r
- _md2_canload, /* validation routine */\r
- _md2_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.
+
+----------------------------------------------------------------------------- */
+
+/*
+Nurail: Used pm_md3.c (Randy Reddig) as a template.
+*/
+
+
+/* marker */
+#define PM_MD2_C
+
+/* dependencies */
+#include "picointernal.h"
+
+
+/* md2 model format */
+#define MD2_MAGIC "IDP2"
+#define MD2_VERSION 8
+
+#define MD2_NUMVERTEXNORMALS 162
+#define MD2_MAX_SKINNAME 64
+#define MD2_MAX_TRIANGLES 4096
+#define MD2_MAX_VERTS 2048
+#define MD2_MAX_FRAMES 512
+#define MD2_MAX_MD2SKINS 32
+#define MD2_MAX_SKINNAME 64
+
+#ifndef byte
+ #define byte unsigned char
+#endif
+
+typedef struct index_LUT_s
+{
+ short Vert;
+ short ST;
+ struct index_LUT_s *next;
+
+} index_LUT_t;
+
+typedef struct index_DUP_LUT_s
+{
+ short ST;
+ short OldVert;
+
+} index_DUP_LUT_t;
+
+typedef struct
+{
+ short s;
+ short t;
+} md2St_t;
+
+typedef struct
+{
+ short index_xyz[3];
+ short index_st[3];
+} md2Triangle_t;
+
+typedef struct
+{
+ byte v[3]; // scaled byte to fit in frame mins/maxs
+ byte lightnormalindex;
+} md2XyzNormal_t;
+
+typedef struct md2Frame_s
+{
+ float scale[3]; // multiply byte verts by this
+ float translate[3]; // then add this
+ char name[16]; // frame name from grabbing
+ md2XyzNormal_t verts[1]; // variable sized
+}
+md2Frame_t;
+
+
+/* md2 model file md2 structure */
+typedef struct md2_s
+{
+ char magic[ 4 ];
+ int version;
+
+ int skinWidth;
+ int skinHeight;
+ int frameSize;
+
+ int numSkins;
+ int numXYZ;
+ int numST;
+ int numTris;
+ int numGLCmds;
+ int numFrames;
+
+ int ofsSkins;
+ int ofsST;
+ int ofsTris;
+ int ofsFrames;
+ int ofsGLCmds;
+ int ofsEnd;
+}
+md2_t;
+
+float md2_normals[ MD2_NUMVERTEXNORMALS ][ 3 ] =
+{
+ { -0.525731f, 0.000000f, 0.850651f },
+ { -0.442863f, 0.238856f, 0.864188f },
+ { -0.295242f, 0.000000f, 0.955423f },
+ { -0.309017f, 0.500000f, 0.809017f },
+ { -0.162460f, 0.262866f, 0.951056f },
+ { 0.000000f, 0.000000f, 1.000000f },
+ { 0.000000f, 0.850651f, 0.525731f },
+ { -0.147621f, 0.716567f, 0.681718f },
+ { 0.147621f, 0.716567f, 0.681718f },
+ { 0.000000f, 0.525731f, 0.850651f },
+ { 0.309017f, 0.500000f, 0.809017f },
+ { 0.525731f, 0.000000f, 0.850651f },
+ { 0.295242f, 0.000000f, 0.955423f },
+ { 0.442863f, 0.238856f, 0.864188f },
+ { 0.162460f, 0.262866f, 0.951056f },
+ { -0.681718f, 0.147621f, 0.716567f },
+ { -0.809017f, 0.309017f, 0.500000f },
+ { -0.587785f, 0.425325f, 0.688191f },
+ { -0.850651f, 0.525731f, 0.000000f },
+ { -0.864188f, 0.442863f, 0.238856f },
+ { -0.716567f, 0.681718f, 0.147621f },
+ { -0.688191f, 0.587785f, 0.425325f },
+ { -0.500000f, 0.809017f, 0.309017f },
+ { -0.238856f, 0.864188f, 0.442863f },
+ { -0.425325f, 0.688191f, 0.587785f },
+ { -0.716567f, 0.681718f, -0.147621f },
+ { -0.500000f, 0.809017f, -0.309017f },
+ { -0.525731f, 0.850651f, 0.000000f },
+ { 0.000000f, 0.850651f, -0.525731f },
+ { -0.238856f, 0.864188f, -0.442863f },
+ { 0.000000f, 0.955423f, -0.295242f },
+ { -0.262866f, 0.951056f, -0.162460f },
+ { 0.000000f, 1.000000f, 0.000000f },
+ { 0.000000f, 0.955423f, 0.295242f },
+ { -0.262866f, 0.951056f, 0.162460f },
+ { 0.238856f, 0.864188f, 0.442863f },
+ { 0.262866f, 0.951056f, 0.162460f },
+ { 0.500000f, 0.809017f, 0.309017f },
+ { 0.238856f, 0.864188f, -0.442863f },
+ { 0.262866f, 0.951056f, -0.162460f },
+ { 0.500000f, 0.809017f, -0.309017f },
+ { 0.850651f, 0.525731f, 0.000000f },
+ { 0.716567f, 0.681718f, 0.147621f },
+ { 0.716567f, 0.681718f, -0.147621f },
+ { 0.525731f, 0.850651f, 0.000000f },
+ { 0.425325f, 0.688191f, 0.587785f },
+ { 0.864188f, 0.442863f, 0.238856f },
+ { 0.688191f, 0.587785f, 0.425325f },
+ { 0.809017f, 0.309017f, 0.500000f },
+ { 0.681718f, 0.147621f, 0.716567f },
+ { 0.587785f, 0.425325f, 0.688191f },
+ { 0.955423f, 0.295242f, 0.000000f },
+ { 1.000000f, 0.000000f, 0.000000f },
+ { 0.951056f, 0.162460f, 0.262866f },
+ { 0.850651f, -0.525731f, 0.000000f },
+ { 0.955423f, -0.295242f, 0.000000f },
+ { 0.864188f, -0.442863f, 0.238856f },
+ { 0.951056f, -0.162460f, 0.262866f },
+ { 0.809017f, -0.309017f, 0.500000f },
+ { 0.681718f, -0.147621f, 0.716567f },
+ { 0.850651f, 0.000000f, 0.525731f },
+ { 0.864188f, 0.442863f, -0.238856f },
+ { 0.809017f, 0.309017f, -0.500000f },
+ { 0.951056f, 0.162460f, -0.262866f },
+ { 0.525731f, 0.000000f, -0.850651f },
+ { 0.681718f, 0.147621f, -0.716567f },
+ { 0.681718f, -0.147621f, -0.716567f },
+ { 0.850651f, 0.000000f, -0.525731f },
+ { 0.809017f, -0.309017f, -0.500000f },
+ { 0.864188f, -0.442863f, -0.238856f },
+ { 0.951056f, -0.162460f, -0.262866f },
+ { 0.147621f, 0.716567f, -0.681718f },
+ { 0.309017f, 0.500000f, -0.809017f },
+ { 0.425325f, 0.688191f, -0.587785f },
+ { 0.442863f, 0.238856f, -0.864188f },
+ { 0.587785f, 0.425325f, -0.688191f },
+ { 0.688191f, 0.587785f, -0.425325f },
+ { -0.147621f, 0.716567f, -0.681718f },
+ { -0.309017f, 0.500000f, -0.809017f },
+ { 0.000000f, 0.525731f, -0.850651f },
+ { -0.525731f, 0.000000f, -0.850651f },
+ { -0.442863f, 0.238856f, -0.864188f },
+ { -0.295242f, 0.000000f, -0.955423f },
+ { -0.162460f, 0.262866f, -0.951056f },
+ { 0.000000f, 0.000000f, -1.000000f },
+ { 0.295242f, 0.000000f, -0.955423f },
+ { 0.162460f, 0.262866f, -0.951056f },
+ { -0.442863f, -0.238856f, -0.864188f },
+ { -0.309017f, -0.500000f, -0.809017f },
+ { -0.162460f, -0.262866f, -0.951056f },
+ { 0.000000f, -0.850651f, -0.525731f },
+ { -0.147621f, -0.716567f, -0.681718f },
+ { 0.147621f, -0.716567f, -0.681718f },
+ { 0.000000f, -0.525731f, -0.850651f },
+ { 0.309017f, -0.500000f, -0.809017f },
+ { 0.442863f, -0.238856f, -0.864188f },
+ { 0.162460f, -0.262866f, -0.951056f },
+ { 0.238856f, -0.864188f, -0.442863f },
+ { 0.500000f, -0.809017f, -0.309017f },
+ { 0.425325f, -0.688191f, -0.587785f },
+ { 0.716567f, -0.681718f, -0.147621f },
+ { 0.688191f, -0.587785f, -0.425325f },
+ { 0.587785f, -0.425325f, -0.688191f },
+ { 0.000000f, -0.955423f, -0.295242f },
+ { 0.000000f, -1.000000f, 0.000000f },
+ { 0.262866f, -0.951056f, -0.162460f },
+ { 0.000000f, -0.850651f, 0.525731f },
+ { 0.000000f, -0.955423f, 0.295242f },
+ { 0.238856f, -0.864188f, 0.442863f },
+ { 0.262866f, -0.951056f, 0.162460f },
+ { 0.500000f, -0.809017f, 0.309017f },
+ { 0.716567f, -0.681718f, 0.147621f },
+ { 0.525731f, -0.850651f, 0.000000f },
+ { -0.238856f, -0.864188f, -0.442863f },
+ { -0.500000f, -0.809017f, -0.309017f },
+ { -0.262866f, -0.951056f, -0.162460f },
+ { -0.850651f, -0.525731f, 0.000000f },
+ { -0.716567f, -0.681718f, -0.147621f },
+ { -0.716567f, -0.681718f, 0.147621f },
+ { -0.525731f, -0.850651f, 0.000000f },
+ { -0.500000f, -0.809017f, 0.309017f },
+ { -0.238856f, -0.864188f, 0.442863f },
+ { -0.262866f, -0.951056f, 0.162460f },
+ { -0.864188f, -0.442863f, 0.238856f },
+ { -0.809017f, -0.309017f, 0.500000f },
+ { -0.688191f, -0.587785f, 0.425325f },
+ { -0.681718f, -0.147621f, 0.716567f },
+ { -0.442863f, -0.238856f, 0.864188f },
+ { -0.587785f, -0.425325f, 0.688191f },
+ { -0.309017f, -0.500000f, 0.809017f },
+ { -0.147621f, -0.716567f, 0.681718f },
+ { -0.425325f, -0.688191f, 0.587785f },
+ { -0.162460f, -0.262866f, 0.951056f },
+ { 0.442863f, -0.238856f, 0.864188f },
+ { 0.162460f, -0.262866f, 0.951056f },
+ { 0.309017f, -0.500000f, 0.809017f },
+ { 0.147621f, -0.716567f, 0.681718f },
+ { 0.000000f, -0.525731f, 0.850651f },
+ { 0.425325f, -0.688191f, 0.587785f },
+ { 0.587785f, -0.425325f, 0.688191f },
+ { 0.688191f, -0.587785f, 0.425325f },
+ { -0.955423f, 0.295242f, 0.000000f },
+ { -0.951056f, 0.162460f, 0.262866f },
+ { -1.000000f, 0.000000f, 0.000000f },
+ { -0.850651f, 0.000000f, 0.525731f },
+ { -0.955423f, -0.295242f, 0.000000f },
+ { -0.951056f, -0.162460f, 0.262866f },
+ { -0.864188f, 0.442863f, -0.238856f },
+ { -0.951056f, 0.162460f, -0.262866f },
+ { -0.809017f, 0.309017f, -0.500000f },
+ { -0.864188f, -0.442863f, -0.238856f },
+ { -0.951056f, -0.162460f, -0.262866f },
+ { -0.809017f, -0.309017f, -0.500000f },
+ { -0.681718f, 0.147621f, -0.716567f },
+ { -0.681718f, -0.147621f, -0.716567f },
+ { -0.850651f, 0.000000f, -0.525731f },
+ { -0.688191f, 0.587785f, -0.425325f },
+ { -0.587785f, 0.425325f, -0.688191f },
+ { -0.425325f, 0.688191f, -0.587785f },
+ { -0.425325f, -0.688191f, -0.587785f },
+ { -0.587785f, -0.425325f, -0.688191f },
+ { -0.688191f, -0.587785f, -0.425325f },
+};
+
+
+// _md2_canload()
+
+static int _md2_canload( PM_PARAMS_CANLOAD )
+{
+ md2_t *md2;
+
+ /* to keep the compiler happy */
+ *fileName = *fileName;
+
+ /* sanity check */
+ if( bufSize < ( sizeof( *md2 ) * 2) )
+ return PICO_PMV_ERROR_SIZE;
+
+ /* set as md2 */
+ md2 = (md2_t*) buffer;
+
+ /* check md2 magic */
+ if( *((int*) md2->magic) != *((int*) MD2_MAGIC) )
+ return PICO_PMV_ERROR_IDENT;
+
+ /* check md2 version */
+ if( _pico_little_long( md2->version ) != MD2_VERSION )
+ return PICO_PMV_ERROR_VERSION;
+
+ /* file seems to be a valid md2 */
+ return PICO_PMV_OK;
+}
+
+
+
+// _md2_load() loads a quake2 md2 model file.
+
+
+static picoModel_t *_md2_load( PM_PARAMS_LOAD )
+{
+ int i, j, dups, dup_index;
+ short tot_numVerts;
+ index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3;
+ index_DUP_LUT_t *p_index_LUT_DUPS;
+ md2Triangle_t *p_md2Triangle;
+
+ char skinname[ MD2_MAX_SKINNAME ];
+ md2_t *md2;
+ md2St_t *texCoord;
+ md2Frame_t *frame;
+ md2Triangle_t *triangle;
+ md2XyzNormal_t *vertex;
+
+ picoByte_t *bb;
+ picoModel_t *picoModel;
+ picoSurface_t *picoSurface;
+ picoShader_t *picoShader;
+ picoVec3_t xyz, normal;
+ picoVec2_t st;
+ picoColor_t color;
+
+
+ // md2 loading
+ _pico_printf( PICO_NORMAL, "Loading \"%s\"", fileName );
+
+ /* set as md2 */
+ bb = (picoByte_t*) buffer;
+ md2 = (md2_t*) buffer;
+
+ /* check ident and version */
+ if( *((int*) md2->magic) != *((int*) MD2_MAGIC) || _pico_little_long( md2->version ) != MD2_VERSION )
+ {
+ /* not an md2 file (todo: set error) */
+ _pico_printf( PICO_ERROR, "%s is not an MD2 File!", fileName );
+ return NULL;
+ }
+
+ // swap md2
+ md2->version = _pico_little_long( md2->version );
+
+ md2->skinWidth = _pico_little_long( md2->skinWidth );
+ md2->skinHeight = _pico_little_long( md2->skinHeight );
+ md2->frameSize = _pico_little_long( md2->frameSize );
+
+ md2->numSkins = _pico_little_long( md2->numSkins );
+ md2->numXYZ = _pico_little_long( md2->numXYZ );
+ md2->numST = _pico_little_long( md2->numST );
+ md2->numTris = _pico_little_long( md2->numTris );
+ md2->numGLCmds = _pico_little_long( md2->numGLCmds );
+ md2->numFrames = _pico_little_long( md2->numFrames );
+
+ md2->ofsSkins = _pico_little_long( md2->ofsSkins );
+ md2->ofsST = _pico_little_long( md2->ofsST );
+ md2->ofsTris = _pico_little_long( md2->ofsTris );
+ md2->ofsFrames = _pico_little_long( md2->ofsFrames );
+ md2->ofsGLCmds = _pico_little_long( md2->ofsGLCmds );
+ md2->ofsEnd = _pico_little_long( md2->ofsEnd );
+
+ // do frame check
+ if( md2->numFrames < 1 )
+ {
+ _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );
+ return NULL;
+ }
+
+ if( frameNum < 0 || frameNum >= md2->numFrames )
+ {
+ _pico_printf( PICO_ERROR, "Invalid or out-of-range MD2 frame specified" );
+ return NULL;
+ }
+
+ // Setup Frame
+ frame = (md2Frame_t *) (bb + md2->ofsFrames + (sizeof(md2Frame_t) * frameNum));
+
+ // swap frame scale and translation
+ for( i = 0; i < 3; i++ )
+ {
+ frame->scale[ i ] = _pico_little_float( frame->scale[ i ] );
+ frame->translate[ i ] = _pico_little_float( frame->translate[ i ] );
+ }
+
+ // swap triangles
+ triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) );
+ for( i = 0; i < md2->numTris; i++, triangle++ )
+ {
+ for( j = 0; j < 3; j++ )
+ {
+ triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );
+ triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );
+ }
+ }
+
+ // swap st coords
+ texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) );
+ for( i = 0; i < md2->numST; i++, texCoord++ )
+ {
+ texCoord->s = _pico_little_short( texCoord->s );
+ texCoord->t = _pico_little_short( texCoord->t );
+ }
+
+ // set Skin Name
+ strncpy(skinname, (bb + md2->ofsSkins), MD2_MAX_SKINNAME );
+
+ // Print out md2 values
+ _pico_printf(PICO_VERBOSE,"Skins: %d Verts: %d STs: %d Triangles: %d Frames: %d\nSkin Name \"%s\"\n", md2->numSkins, md2->numXYZ, md2->numST, md2->numTris, md2->numFrames, &skinname );
+
+ // detox Skin name
+ _pico_setfext( skinname, "" );
+ _pico_unixify( skinname );
+
+ /* 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, md2->numFrames ); /* sea */
+ PicoSetModelName( picoModel, fileName );
+ PicoSetModelFileName( picoModel, fileName );
+
+ // allocate new pico surface
+ picoSurface = PicoNewSurface( picoModel );
+ if( picoSurface == NULL )
+ {
+ _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
+ PicoFreeModel( picoModel );
+ return NULL;
+ }
+
+
+ PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
+ PicoSetSurfaceName( picoSurface, frame->name );
+ picoShader = PicoNewShader( picoModel );
+ if( picoShader == NULL )
+ {
+ _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
+ PicoFreeModel( picoModel );
+ return NULL;
+ }
+
+ PicoSetShaderName( picoShader, skinname );
+
+ // associate current surface with newly created shader
+ PicoSetSurfaceShader( picoSurface, picoShader );
+
+ // Init LUT for Verts
+ p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * md2->numXYZ);
+ for(i=0; i<md2->numXYZ; i++)
+ {
+ p_index_LUT[i].Vert = -1;
+ p_index_LUT[i].ST = -1;
+ p_index_LUT[i].next = NULL;
+ }
+
+ // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert.
+ tot_numVerts = md2->numXYZ;
+ dups = 0;
+ for(i=0; i<md2->numTris; i++)
+ {
+ p_md2Triangle = (md2Triangle_t *) ( bb + md2->ofsTris + (sizeof(md2Triangle_t)*i));
+ for(j=0; j<3; j++)
+ {
+ if (p_index_LUT[p_md2Triangle->index_xyz[j]].ST == -1) // No Main Entry
+ p_index_LUT[p_md2Triangle->index_xyz[j]].ST = p_md2Triangle->index_st[j];
+
+ else if (p_md2Triangle->index_st[j] == p_index_LUT[p_md2Triangle->index_xyz[j]].ST ) // Equal to Main Entry
+ continue;
+
+ else if ( (p_index_LUT[p_md2Triangle->index_xyz[j]].next == NULL) ) // Not equal to Main entry, and no LL entry
+ { // Add first entry of LL from Main
+ p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));
+ if (p_index_LUT2 == NULL)
+ _pico_printf( PICO_ERROR," Couldn't allocate memory!\n");
+ p_index_LUT[p_md2Triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2;
+ p_index_LUT2->Vert = dups;
+ p_index_LUT2->ST = p_md2Triangle->index_st[j];
+ p_index_LUT2->next = NULL;
+ p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk
+ dups++;
+ }
+ else // Try to find in LL from Main Entry
+ {
+ p_index_LUT3 = p_index_LUT2 = p_index_LUT[p_md2Triangle->index_xyz[j]].next;
+ while ( (p_index_LUT2 != NULL) && (p_md2Triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL
+ {
+ p_index_LUT3 = p_index_LUT2;
+ p_index_LUT2 = p_index_LUT2->next;
+ }
+ p_index_LUT2 = p_index_LUT3;
+
+ if ( p_md2Triangle->index_st[j] == p_index_LUT2->ST ) // Found it
+ {
+ p_md2Triangle->index_xyz[j] = p_index_LUT2->Vert + md2->numXYZ; // Make change in Tri hunk
+ continue;
+ }
+
+ if ( p_index_LUT2->next == NULL) // Didn't find it. Add entry to LL.
+ {
+ // Add the Entry
+ p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));
+ if (p_index_LUT3 == NULL)
+ _pico_printf( PICO_ERROR," Couldn't allocate memory!\n");
+ p_index_LUT2->next = (index_LUT_t *)p_index_LUT3;
+ p_index_LUT3->Vert = p_md2Triangle->index_xyz[j];
+ p_index_LUT3->ST = p_md2Triangle->index_st[j];
+ p_index_LUT3->next = NULL;
+ p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk
+ dups++;
+ }
+ }
+ }
+ }
+
+ // malloc and build array for Dup STs
+ p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups);
+ if (p_index_LUT_DUPS == NULL)
+ _pico_printf( PICO_ERROR," Couldn't allocate memory!\n");
+
+ dup_index = 0;
+ for(i=0; i<md2->numXYZ; i++)
+ {
+ p_index_LUT2 = p_index_LUT[i].next;
+ while (p_index_LUT2 != NULL)
+ {
+ p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i;
+ p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST;
+ dup_index++;
+ p_index_LUT2 = p_index_LUT2->next;
+ }
+ }
+
+ // Build Picomodel
+ triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) );
+ texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) );
+ vertex = (md2XyzNormal_t*) ((picoByte_t*) (frame->verts) );
+ for( j = 0; j < md2->numTris; j++, triangle++ )
+ {
+ PicoSetSurfaceIndex( picoSurface, j*3 , triangle->index_xyz[0] );
+ PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] );
+ PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] );
+ }
+
+ for(i=0; i< md2->numXYZ; i++, vertex++)
+ {
+ /* set vertex origin */
+ xyz[ 0 ] = vertex->v[0] * frame->scale[0] + frame->translate[0];
+ xyz[ 1 ] = vertex->v[1] * frame->scale[1] + frame->translate[1];
+ xyz[ 2 ] = vertex->v[2] * frame->scale[2] + frame->translate[2];
+ PicoSetSurfaceXYZ( picoSurface, i , xyz );
+
+ /* set normal */
+ normal[ 0 ] = md2_normals[vertex->lightnormalindex][0];
+ normal[ 1 ] = md2_normals[vertex->lightnormalindex][1];
+ normal[ 2 ] = md2_normals[vertex->lightnormalindex][2];
+ PicoSetSurfaceNormal( picoSurface, i , normal );
+
+ /* set st coords */
+ st[ 0 ] = ((texCoord[p_index_LUT[i].ST].s) / ((float)md2->skinWidth));
+ st[ 1 ] = (texCoord[p_index_LUT[i].ST].t / ((float)md2->skinHeight));
+ PicoSetSurfaceST( picoSurface, 0, i , st );
+ }
+
+ if (dups)
+ {
+ for(i=0; i<dups; i++)
+ {
+ j = p_index_LUT_DUPS[i].OldVert;
+ /* set vertex origin */
+ xyz[ 0 ] = frame->verts[j].v[0] * frame->scale[0] + frame->translate[0];
+ xyz[ 1 ] = frame->verts[j].v[1] * frame->scale[1] + frame->translate[1];
+ xyz[ 2 ] = frame->verts[j].v[2] * frame->scale[2] + frame->translate[2];
+ PicoSetSurfaceXYZ( picoSurface, i + md2->numXYZ , xyz );
+
+ /* set normal */
+ normal[ 0 ] = md2_normals[frame->verts[j].lightnormalindex][0];
+ normal[ 1 ] = md2_normals[frame->verts[j].lightnormalindex][1];
+ normal[ 2 ] = md2_normals[frame->verts[j].lightnormalindex][2];
+ PicoSetSurfaceNormal( picoSurface, i + md2->numXYZ , normal );
+
+ /* set st coords */
+ st[ 0 ] = ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)md2->skinWidth));
+ st[ 1 ] = (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)md2->skinHeight));
+ PicoSetSurfaceST( picoSurface, 0, i + md2->numXYZ , st );
+ }
+ }
+
+ /* set color */
+ PicoSetSurfaceColor( picoSurface, 0, 0, color );
+
+ // Free up malloc'ed LL entries
+ for(i=0; i<md2->numXYZ; i++)
+ {
+ if(p_index_LUT[i].next != NULL)
+ {
+ p_index_LUT2 = p_index_LUT[i].next;
+ do {
+ p_index_LUT3 = p_index_LUT2->next;
+ _pico_free(p_index_LUT2);
+ p_index_LUT2 = p_index_LUT3;
+ dups--;
+ } while (p_index_LUT2 != NULL);
+ }
+ }
+
+ if (dups)
+ _pico_printf(PICO_WARNING, " Not all LL mallocs freed\n");
+
+ // Free malloc'ed LUTs
+ _pico_free(p_index_LUT);
+ _pico_free(p_index_LUT_DUPS);
+
+ /* return the new pico model */
+ return picoModel;
+
+}
+
+
+
+/* pico file format module definition */
+const picoModule_t picoModuleMD2 =
+{
+ "0.875", /* module version string */
+ "Quake 2 MD2", /* module display name */
+ "Nurail", /* author's name */
+ "2003 Nurail", /* module copyright */
+ {
+ "md2", NULL, NULL, NULL /* default extensions to use */
+ },
+ _md2_canload, /* validation routine */
+ _md2_load, /* load routine */
+ NULL, /* save validation routine */
+ NULL /* save routine */
+};