-/* -----------------------------------------------------------------------------\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
-/* marker */\r
-#define PM_FM_C\r
-\r
-/* dependencies */\r
-#include "pm_fm.h"\r
-\r
-//#define FM_VERBOSE_DBG 0\r
-#undef FM_VERBOSE_DBG\r
-#undef FM_DBG\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
-\r
-// _fm_canload()\r
-static int _fm_canload( PM_PARAMS_CANLOAD )\r
-{\r
- fm_t fm;\r
- unsigned char *bb;\r
- int fm_file_pos;\r
-\r
- bb = (unsigned char *) buffer;\r
-\r
- // Header\r
- fm.fm_header_hdr = (fm_chunk_header_t *) bb;\r
- fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size;\r
-#ifdef FM_VERBOSE_DBG\r
- _pico_printf( PICO_VERBOSE, "IDENT: %s\n", (unsigned char *) fm.fm_header_hdr->ident );\r
-#endif\r
- if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME)) )\r
- {\r
-#ifdef FM_DBG\r
- _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n");\r
-#endif\r
- return PICO_PMV_ERROR_IDENT;\r
- }\r
-\r
- // check fm\r
- if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER )\r
- {\r
-#ifdef FM_DBG\r
- _pico_printf( PICO_WARNING, "FM Header Version incorrect\n");\r
-#endif\r
- return PICO_PMV_ERROR_VERSION;\r
- }\r
-\r
- // Skin\r
- fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);\r
- fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size;\r
-#ifdef FM_VERBOSE_DBG\r
- _pico_printf( PICO_VERBOSE, "SKIN: %s\n", (unsigned char *) fm.fm_skin_hdr->ident );\r
-#endif\r
- if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) )\r
- {\r
-#ifdef FM_DBG\r
- _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n");\r
-#endif\r
- return PICO_PMV_ERROR_IDENT;\r
- }\r
-\r
- // check fm\r
- if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER )\r
- {\r
-#ifdef FM_DBG\r
- _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n");\r
-#endif\r
- return PICO_PMV_ERROR_VERSION;\r
- }\r
-\r
- // st\r
- fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);\r
- fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size;\r
-#ifdef FM_VERBOSE_DBG\r
- _pico_printf( PICO_VERBOSE, "ST: %s\n", (unsigned char *) fm.fm_st_hdr->ident );\r
-#endif\r
- if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) )\r
- {\r
-#ifdef FM_DBG\r
- _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n");\r
-#endif\r
- return PICO_PMV_ERROR_IDENT;\r
- }\r
-\r
- // check fm\r
- if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER )\r
- {\r
-#ifdef FM_DBG\r
- _pico_printf( PICO_WARNING, "FM ST Version incorrect\n");\r
-#endif\r
- return PICO_PMV_ERROR_VERSION;\r
- }\r
-\r
- // tri\r
- fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);\r
- fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size;\r
-#ifdef FM_VERBOSE_DBG\r
- _pico_printf( PICO_VERBOSE, "TRI: %s\n", (unsigned char *) fm.fm_tri_hdr->ident );\r
-#endif\r
- if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) )\r
- {\r
-#ifdef FM_DBG\r
- _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n");\r
-#endif\r
- return PICO_PMV_ERROR_IDENT;\r
- }\r
-\r
- // check fm\r
- if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER )\r
- {\r
-#ifdef FM_DBG\r
- _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n");\r
-#endif\r
- return PICO_PMV_ERROR_VERSION;\r
- }\r
-\r
- // frame\r
- fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);\r
- fm_file_pos += sizeof(fm_chunk_header_t);\r
-#ifdef FM_VERBOSE_DBG\r
- _pico_printf( PICO_VERBOSE, "FRAME: %s\n", (unsigned char *) fm.fm_frame_hdr->ident );\r
-#endif\r
- if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) )\r
- {\r
-#ifdef FM_DBG\r
- _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n");\r
-#endif\r
- return PICO_PMV_ERROR_IDENT;\r
- }\r
-\r
- // check fm\r
- if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER )\r
- {\r
-#ifdef FM_DBG\r
- _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n");\r
-#endif\r
- return PICO_PMV_ERROR_VERSION;\r
- }\r
-\r
- // file seems to be a valid fm\r
- return PICO_PMV_OK;\r
-}\r
-\r
-\r
-\r
-// _fm_load() loads a Heretic 2 model file.\r
-static picoModel_t *_fm_load( PM_PARAMS_LOAD )\r
-{\r
- int i, j, dups, dup_index;\r
- int fm_file_pos;\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
-\r
- fm_vert_normal_t *vert;\r
-\r
- char skinname[FM_SKINPATHSIZE];\r
- fm_t fm;\r
- fm_header_t *fm_head;\r
- fm_st_t *texCoord;\r
- fm_xyz_st_t *tri_verts;\r
- fm_xyz_st_t *triangle;\r
- fm_frame_t *frame;\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
- // fm loading\r
- _pico_printf( PICO_NORMAL, "Loading \"%s\"", fileName );\r
-\r
- bb = (picoByte_t*) buffer;\r
-\r
- // Header Header\r
- fm.fm_header_hdr = (fm_chunk_header_t *) bb;\r
- fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size;\r
- if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME)) )\r
- {\r
- _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n");\r
- return NULL;\r
- }\r
-\r
- if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER )\r
- {\r
- _pico_printf( PICO_WARNING, "FM Header Version incorrect\n");\r
- return NULL;\r
- }\r
-\r
- // Skin Header\r
- fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);\r
- fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size;\r
- if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) )\r
- {\r
- _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n");\r
- return NULL;\r
- }\r
-\r
- if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER )\r
- {\r
- _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n");\r
- return NULL;\r
- }\r
-\r
- // ST Header\r
- fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);\r
- fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size;\r
- if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) )\r
- {\r
- _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n");\r
- return NULL;\r
- }\r
-\r
- if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER )\r
- {\r
- _pico_printf( PICO_WARNING, "FM ST Version incorrect\n");\r
- return NULL;\r
- }\r
-\r
- // Tris Header\r
- fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);\r
- fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size;\r
- if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) )\r
- {\r
- _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n");\r
- return NULL;\r
- }\r
-\r
- if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER )\r
- {\r
- _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n");\r
- return NULL;\r
- }\r
-\r
- // Frame Header\r
- fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);\r
- fm_file_pos += sizeof(fm_chunk_header_t);\r
- if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) )\r
- {\r
- _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n");\r
- return NULL;\r
- }\r
-\r
- if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER )\r
- {\r
- _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n");\r
- return NULL;\r
- }\r
-\r
- // Header\r
- fm_file_pos = sizeof(fm_chunk_header_t);\r
- fm_head = fm.fm_header = (fm_header_t *) (bb + fm_file_pos);\r
- fm_file_pos += fm.fm_header_hdr->size;\r
-\r
- // Skin\r
- fm_file_pos += sizeof(fm_chunk_header_t);\r
- fm.fm_skin = (fm_skinpath_t *) (bb + fm_file_pos);\r
- fm_file_pos += fm.fm_skin_hdr->size;\r
-\r
- // ST\r
- fm_file_pos += sizeof(fm_chunk_header_t);\r
- texCoord = fm.fm_st = (fm_st_t *) (bb + fm_file_pos);\r
- fm_file_pos += fm.fm_st_hdr->size;\r
-\r
- // Tri\r
- fm_file_pos += sizeof(fm_chunk_header_t);\r
- tri_verts = fm.fm_tri = (fm_xyz_st_t *) (bb + fm_file_pos);\r
- fm_file_pos += fm.fm_tri_hdr->size;\r
-\r
- // Frame\r
- fm_file_pos += sizeof(fm_chunk_header_t);\r
- frame = fm.fm_frame = (fm_frame_t *) (bb + fm_file_pos);\r
-\r
- // do frame check\r
- if( fm_head->numFrames < 1 )\r
- {\r
- _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );\r
- return NULL;\r
- }\r
- \r
- if( frameNum < 0 || frameNum >= fm_head->numFrames )\r
- {\r
- _pico_printf( PICO_ERROR, "Invalid or out-of-range FM frame specified" );\r
- return NULL;\r
- }\r
-\r
- // swap fm\r
- fm_head->skinWidth = _pico_little_long( fm_head->skinWidth );\r
- fm_head->skinHeight = _pico_little_long( fm_head->skinHeight );\r
- fm_head->frameSize = _pico_little_long( fm_head->frameSize );\r
-\r
- fm_head->numSkins = _pico_little_long( fm_head->numSkins );\r
- fm_head->numXYZ = _pico_little_long( fm_head->numXYZ );\r
- fm_head->numST = _pico_little_long( fm_head->numST );\r
- fm_head->numTris = _pico_little_long( fm_head->numTris );\r
- fm_head->numGLCmds = _pico_little_long( fm_head->numGLCmds );\r
- fm_head->numFrames = _pico_little_long( fm_head->numFrames );\r
-\r
- // swap frame scale and translation\r
- for( i = 0; i < 3; i++ )\r
- {\r
- frame->header.scale[ i ] = _pico_little_float( frame->header.scale[ i ] );\r
- frame->header.translate[ i ] = _pico_little_float( frame->header.translate[ i ] );\r
- }\r
-\r
- // swap triangles\r
- triangle = tri_verts;\r
- for( i = 0; i < fm_head->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
- for( i = 0; i < fm_head->numST; i++ )\r
- {\r
- texCoord->s = _pico_little_short( texCoord[i].s );\r
- texCoord->t = _pico_little_short( texCoord[i].t );\r
- }\r
- // set Skin Name\r
- strncpy(skinname, (unsigned char *) fm.fm_skin, FM_SKINPATHSIZE );\r
-\r
-#ifdef FM_VERBOSE_DBG\r
- // Print out md2 values\r
- _pico_printf(PICO_VERBOSE,"numSkins->%d numXYZ->%d numST->%d numTris->%d numFrames->%d\nSkin Name \"%s\"\n", fm_head->numSkins, fm_head->numXYZ, fm_head->numST, fm_head->numTris, fm_head->numFrames, &skinname );\r
-#endif\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, fm_head->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->header.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) * fm_head->numXYZ);\r
- for(i=0; i<fm_head->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 = fm_head->numXYZ;\r
- dups = 0;\r
- triangle = tri_verts;\r
-\r
- for(i=0; i<fm_head->numTris; i++)\r
- {\r
- for(j=0; j<3; j++)\r
- {\r
- if (p_index_LUT[triangle->index_xyz[j]].ST == -1) // No Main Entry\r
- p_index_LUT[triangle->index_xyz[j]].ST = triangle->index_st[j];\r
-\r
- else if (triangle->index_st[j] == p_index_LUT[triangle->index_xyz[j]].ST ) // Equal to Main Entry\r
- {\r
-#ifdef FM_VERBOSE_DBG\r
- _pico_printf( PICO_NORMAL, "-> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);\r
-#endif\r
- continue;\r
- }\r
- else if ( (p_index_LUT[triangle->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_NORMAL, " Couldn't allocate memory!\n");\r
- p_index_LUT[triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2;\r
- p_index_LUT2->Vert = dups;\r
- p_index_LUT2->ST = triangle->index_st[j];\r
- p_index_LUT2->next = NULL;\r
-#ifdef FM_VERBOSE_DBG\r
- _pico_printf( PICO_NORMAL, " ADDING first LL XYZ:%d DUP:%d ST:%d\n", triangle->index_xyz[j], dups, triangle->index_st[j]);\r
-#endif\r
- triangle->index_xyz[j] = dups + fm_head->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[triangle->index_xyz[j]].next;\r
- while ( (p_index_LUT2 != NULL) && (triangle->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 ( triangle->index_st[j] == p_index_LUT2->ST ) // Found it\r
- {\r
- triangle->index_xyz[j] = p_index_LUT2->Vert + fm_head->numXYZ; // Make change in Tri hunk\r
-#ifdef FM_VERBOSE_DBG\r
- _pico_printf( PICO_NORMAL, "--> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);\r
-#endif\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_NORMAL, " Couldn't allocate memory!\n");\r
- p_index_LUT2->next = (index_LUT_t *)p_index_LUT3;\r
- p_index_LUT3->Vert = dups;\r
- p_index_LUT3->ST = triangle->index_st[j];\r
- p_index_LUT3->next = NULL;\r
-#ifdef FM_VERBOSE_DBG\r
- _pico_printf( PICO_NORMAL, " ADDING additional LL XYZ:%d DUP:%d NewXYZ:%d ST:%d\n", triangle->index_xyz[j], dups, dups + (fm_head->numXYZ), triangle->index_st[j]);\r
-#endif\r
- triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk\r
- dups++;\r
- }\r
- }\r
-#ifdef FM_VERBOSE_DBG\r
- _pico_printf( PICO_NORMAL, "---> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);\r
-#endif\r
- }\r
- triangle++;\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_NORMAL, " Couldn't allocate memory!\n");\r
-\r
- dup_index = 0;\r
- for(i=0; i<fm_head->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
-#ifdef FM_VERBOSE_DBG\r
- _pico_printf( PICO_NORMAL, " Dups = %d\n", dups);\r
- _pico_printf( PICO_NORMAL, " Dup Index = %d\n", dup_index);\r
-#endif\r
- for(i=0; i<fm_head->numXYZ; i++)\r
- {\r
-#ifdef FM_VERBOSE_DBG\r
- _pico_printf( PICO_NORMAL, "Vert: %4d\t%4d",i, p_index_LUT[i].ST);\r
-#endif\r
- if (p_index_LUT[i].next != NULL)\r
- {\r
-\r
- p_index_LUT2 = p_index_LUT[i].next;\r
- do {\r
-#ifdef FM_VERBOSE_DBG\r
- _pico_printf( PICO_NORMAL, " %4d %4d", p_index_LUT2->Vert, p_index_LUT2->ST);\r
-#endif\r
- p_index_LUT2 = p_index_LUT2->next;\r
- } while ( p_index_LUT2 != NULL);\r
-\r
- }\r
-#ifdef FM_VERBOSE_DBG\r
- _pico_printf( PICO_NORMAL, "\n");\r
-#endif\r
- }\r
-\r
-\r
-#ifdef FM_VERBOSE_DBG\r
- for(i=0; i<dup_index; i++)\r
- _pico_printf( PICO_NORMAL, " Dup Index #%d OldVert: %d ST: %d\n", i, p_index_LUT_DUPS[i].OldVert, p_index_LUT_DUPS[i].ST);\r
-\r
- triangle = tri_verts;\r
- for(i=0; i<fm_head->numTris; i++)\r
- {\r
- for(j=0; j<3; j++)\r
- _pico_printf( PICO_NORMAL, "Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);\r
- _pico_printf( PICO_NORMAL, "\n");\r
- triangle++;\r
- }\r
-#endif\r
- // Build Picomodel\r
- triangle = tri_verts;\r
- for( j = 0; j < fm_head->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
- vert = (fm_vert_normal_t*) ((picoByte_t*) (frame->verts) );\r
- for(i=0; i< fm_head->numXYZ; i++, vert++)\r
- {\r
- /* set vertex origin */\r
- xyz[ 0 ] = vert->v[0] * frame->header.scale[0] + frame->header.translate[0];\r
- xyz[ 1 ] = vert->v[1] * frame->header.scale[1] + frame->header.translate[1];\r
- xyz[ 2 ] = vert->v[2] * frame->header.scale[2] + frame->header.translate[2];\r
- PicoSetSurfaceXYZ( picoSurface, i , xyz );\r
-\r
- /* set normal */\r
- normal[ 0 ] = fm_normals[vert->lightnormalindex][0];\r
- normal[ 1 ] = fm_normals[vert->lightnormalindex][1];\r
- normal[ 2 ] = fm_normals[vert->lightnormalindex][2];\r
- PicoSetSurfaceNormal( picoSurface, i , normal );\r
-\r
- /* set st coords */\r
- st[ 0 ] = ((texCoord[p_index_LUT[i].ST].s) / ((float)fm_head->skinWidth));\r
- st[ 1 ] = (texCoord[p_index_LUT[i].ST].t / ((float)fm_head->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->header.scale[0] + frame->header.translate[0];\r
- xyz[ 1 ] = frame->verts[j].v[1] * frame->header.scale[1] + frame->header.translate[1];\r
- xyz[ 2 ] = frame->verts[j].v[2] * frame->header.scale[2] + frame->header.translate[2];\r
- PicoSetSurfaceXYZ( picoSurface, i + fm_head->numXYZ , xyz );\r
-\r
- /* set normal */\r
- normal[ 0 ] = fm_normals[frame->verts[j].lightnormalindex][0];\r
- normal[ 1 ] = fm_normals[frame->verts[j].lightnormalindex][1];\r
- normal[ 2 ] = fm_normals[frame->verts[j].lightnormalindex][2];\r
- PicoSetSurfaceNormal( picoSurface, i + fm_head->numXYZ , normal );\r
-\r
- /* set st coords */\r
- st[ 0 ] = ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)fm_head->skinWidth));\r
- st[ 1 ] = (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)fm_head->skinHeight));\r
- PicoSetSurfaceST( picoSurface, 0, i + fm_head->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<fm_head->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 picoModuleFM =\r
-{\r
- "0.85", /* module version string */\r
- "Heretic 2 FM", /* module display name */\r
- "Nurail", /* author's name */\r
- "2003 Nurail", /* module copyright */\r
- {\r
- "fm", NULL, NULL, NULL /* default extensions to use */\r
- },\r
- _fm_canload, /* validation routine */\r
- _fm_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.
+ */
+
+/* dependencies */
+#include "pm_fm.h"
+
+//#define FM_VERBOSE_DBG 0
+#undef FM_VERBOSE_DBG
+#undef FM_DBG
+
+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;
+
+
+// _fm_canload()
+static int _fm_canload( PM_PARAMS_CANLOAD ){
+ fm_t fm;
+ unsigned char *bb, *bb0;
+ int fm_file_pos;
+
+ bb0 = bb = (picoByte_t*) _pico_alloc( bufSize );
+ memcpy( bb, buffer, bufSize );
+
+ // Header
+ fm.fm_header_hdr = (fm_chunk_header_t *) bb;
+ fm_file_pos = sizeof( fm_chunk_header_t ) + fm.fm_header_hdr->size;
+#ifdef FM_VERBOSE_DBG
+ _pico_printf( PICO_VERBOSE, "IDENT: %s\n", (unsigned char *) fm.fm_header_hdr->ident );
+#endif
+ if ( ( strcmp( fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME ) ) ) {
+#ifdef FM_DBG
+ _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n" );
+#endif
+ _pico_free( bb0 );
+ return PICO_PMV_ERROR_IDENT;
+ }
+
+ // check fm
+ if ( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) {
+#ifdef FM_DBG
+ _pico_printf( PICO_WARNING, "FM Header Version incorrect\n" );
+#endif
+ _pico_free( bb0 );
+ return PICO_PMV_ERROR_VERSION;
+ }
+
+ // Skin
+ fm.fm_skin_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
+ fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_skin_hdr->size;
+#ifdef FM_VERBOSE_DBG
+ _pico_printf( PICO_VERBOSE, "SKIN: %s\n", (unsigned char *) fm.fm_skin_hdr->ident );
+#endif
+ if ( ( strcmp( fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME ) ) ) {
+#ifdef FM_DBG
+ _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n" );
+#endif
+ _pico_free( bb0 );
+ return PICO_PMV_ERROR_IDENT;
+ }
+
+ // check fm
+ if ( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) {
+#ifdef FM_DBG
+ _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n" );
+#endif
+ _pico_free( bb0 );
+ return PICO_PMV_ERROR_VERSION;
+ }
+
+ // st
+ fm.fm_st_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
+ fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_st_hdr->size;
+#ifdef FM_VERBOSE_DBG
+ _pico_printf( PICO_VERBOSE, "ST: %s\n", (unsigned char *) fm.fm_st_hdr->ident );
+#endif
+ if ( ( strcmp( fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME ) ) ) {
+#ifdef FM_DBG
+ _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n" );
+#endif
+ _pico_free( bb0 );
+ return PICO_PMV_ERROR_IDENT;
+ }
+
+ // check fm
+ if ( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) {
+#ifdef FM_DBG
+ _pico_printf( PICO_WARNING, "FM ST Version incorrect\n" );
+#endif
+ _pico_free( bb0 );
+ return PICO_PMV_ERROR_VERSION;
+ }
+
+ // tri
+ fm.fm_tri_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
+ fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_tri_hdr->size;
+#ifdef FM_VERBOSE_DBG
+ _pico_printf( PICO_VERBOSE, "TRI: %s\n", (unsigned char *) fm.fm_tri_hdr->ident );
+#endif
+ if ( ( strcmp( fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME ) ) ) {
+#ifdef FM_DBG
+ _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n" );
+#endif
+ _pico_free( bb0 );
+ return PICO_PMV_ERROR_IDENT;
+ }
+
+ // check fm
+ if ( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) {
+#ifdef FM_DBG
+ _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n" );
+#endif
+ _pico_free( bb0 );
+ return PICO_PMV_ERROR_VERSION;
+ }
+
+ // frame
+ fm.fm_frame_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
+ fm_file_pos += sizeof( fm_chunk_header_t );
+#ifdef FM_VERBOSE_DBG
+ _pico_printf( PICO_VERBOSE, "FRAME: %s\n", (unsigned char *) fm.fm_frame_hdr->ident );
+#endif
+ if ( ( strcmp( fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME ) ) ) {
+#ifdef FM_DBG
+ _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n" );
+#endif
+ _pico_free( bb0 );
+ return PICO_PMV_ERROR_IDENT;
+ }
+
+ // check fm
+ if ( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) {
+#ifdef FM_DBG
+ _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n" );
+#endif
+ _pico_free( bb0 );
+ return PICO_PMV_ERROR_VERSION;
+ }
+
+ // file seems to be a valid fm
+ return PICO_PMV_OK;
+}
+
+
+
+// _fm_load() loads a Heretic 2 model file.
+static picoModel_t *_fm_load( PM_PARAMS_LOAD ){
+ int i, j, dups, dup_index;
+ int fm_file_pos;
+ index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3;
+ index_DUP_LUT_t *p_index_LUT_DUPS;
+
+ fm_vert_normal_t *vert;
+
+ char skinname[FM_SKINPATHSIZE];
+ fm_t fm;
+ fm_header_t *fm_head;
+ fm_st_t *texCoord;
+ fm_xyz_st_t *tri_verts;
+ fm_xyz_st_t *triangle;
+ fm_frame_t *frame;
+
+ picoByte_t *bb, *bb0;
+ picoModel_t *picoModel;
+ picoSurface_t *picoSurface;
+ picoShader_t *picoShader;
+ picoVec3_t xyz, normal;
+ picoVec2_t st;
+ picoColor_t color;
+
+
+ bb0 = bb = (picoByte_t*) _pico_alloc( bufSize );
+ memcpy( bb, buffer, bufSize );
+
+ // Header Header
+ fm.fm_header_hdr = (fm_chunk_header_t *) bb;
+ fm_file_pos = sizeof( fm_chunk_header_t ) + fm.fm_header_hdr->size;
+ if ( ( strcmp( fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME ) ) ) {
+ _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n" );
+ _pico_free( bb0 );
+ return NULL;
+ }
+
+ if ( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) {
+ _pico_printf( PICO_WARNING, "FM Header Version incorrect\n" );
+ _pico_free( bb0 );
+ return NULL;
+ }
+
+ // Skin Header
+ fm.fm_skin_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
+ fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_skin_hdr->size;
+ if ( ( strcmp( fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME ) ) ) {
+ _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n" );
+ _pico_free( bb0 );
+ return NULL;
+ }
+
+ if ( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) {
+ _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n" );
+ _pico_free( bb0 );
+ return NULL;
+ }
+
+ // ST Header
+ fm.fm_st_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
+ fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_st_hdr->size;
+ if ( ( strcmp( fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME ) ) ) {
+ _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n" );
+ _pico_free( bb0 );
+ return NULL;
+ }
+
+ if ( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) {
+ _pico_printf( PICO_WARNING, "FM ST Version incorrect\n" );
+ _pico_free( bb0 );
+ return NULL;
+ }
+
+ // Tris Header
+ fm.fm_tri_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
+ fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_tri_hdr->size;
+ if ( ( strcmp( fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME ) ) ) {
+ _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n" );
+ _pico_free( bb0 );
+ return NULL;
+ }
+
+ if ( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) {
+ _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n" );
+ _pico_free( bb0 );
+ return NULL;
+ }
+
+ // Frame Header
+ fm.fm_frame_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
+ fm_file_pos += sizeof( fm_chunk_header_t );
+ if ( ( strcmp( fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME ) ) ) {
+ _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n" );
+ _pico_free( bb0 );
+ return NULL;
+ }
+
+ if ( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) {
+ _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n" );
+ _pico_free( bb0 );
+ return NULL;
+ }
+
+ // Header
+ fm_file_pos = sizeof( fm_chunk_header_t );
+ fm_head = fm.fm_header = (fm_header_t *) ( bb + fm_file_pos );
+ fm_file_pos += fm.fm_header_hdr->size;
+
+ // Skin
+ fm_file_pos += sizeof( fm_chunk_header_t );
+ fm.fm_skin = (fm_skinpath_t *) ( bb + fm_file_pos );
+ fm_file_pos += fm.fm_skin_hdr->size;
+
+ // ST
+ fm_file_pos += sizeof( fm_chunk_header_t );
+ texCoord = fm.fm_st = (fm_st_t *) ( bb + fm_file_pos );
+ fm_file_pos += fm.fm_st_hdr->size;
+
+ // Tri
+ fm_file_pos += sizeof( fm_chunk_header_t );
+ tri_verts = fm.fm_tri = (fm_xyz_st_t *) ( bb + fm_file_pos );
+ fm_file_pos += fm.fm_tri_hdr->size;
+
+ // Frame
+ fm_file_pos += sizeof( fm_chunk_header_t );
+ frame = fm.fm_frame = (fm_frame_t *) ( bb + fm_file_pos );
+
+ // do frame check
+ if ( fm_head->numFrames < 1 ) {
+ _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );
+ _pico_free( bb0 );
+ return NULL;
+ }
+
+ if ( frameNum < 0 || frameNum >= fm_head->numFrames ) {
+ _pico_printf( PICO_ERROR, "Invalid or out-of-range FM frame specified" );
+ _pico_free( bb0 );
+ return NULL;
+ }
+
+ // swap fm
+ fm_head->skinWidth = _pico_little_long( fm_head->skinWidth );
+ fm_head->skinHeight = _pico_little_long( fm_head->skinHeight );
+ fm_head->frameSize = _pico_little_long( fm_head->frameSize );
+
+ fm_head->numSkins = _pico_little_long( fm_head->numSkins );
+ fm_head->numXYZ = _pico_little_long( fm_head->numXYZ );
+ fm_head->numST = _pico_little_long( fm_head->numST );
+ fm_head->numTris = _pico_little_long( fm_head->numTris );
+ fm_head->numGLCmds = _pico_little_long( fm_head->numGLCmds );
+ fm_head->numFrames = _pico_little_long( fm_head->numFrames );
+
+ // swap frame scale and translation
+ for ( i = 0; i < 3; i++ )
+ {
+ frame->header.scale[ i ] = _pico_little_float( frame->header.scale[ i ] );
+ frame->header.translate[ i ] = _pico_little_float( frame->header.translate[ i ] );
+ }
+
+ // swap triangles
+ triangle = tri_verts;
+ for ( i = 0; i < fm_head->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
+ for ( i = 0; i < fm_head->numST; i++ )
+ {
+ texCoord->s = _pico_little_short( texCoord[i].s );
+ texCoord->t = _pico_little_short( texCoord[i].t );
+ }
+ // set Skin Name
+ strncpy( skinname, (const char *) fm.fm_skin, FM_SKINPATHSIZE );
+
+#ifdef FM_VERBOSE_DBG
+ // Print out md2 values
+ _pico_printf( PICO_VERBOSE,"numSkins->%d numXYZ->%d numST->%d numTris->%d numFrames->%d\nSkin Name \"%s\"\n", fm_head->numSkins, fm_head->numXYZ, fm_head->numST, fm_head->numTris, fm_head->numFrames, &skinname );
+#endif
+
+ // 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" );
+ _pico_free( bb0 );
+ return NULL;
+ }
+
+ /* do model setup */
+ PicoSetModelFrameNum( picoModel, frameNum );
+ PicoSetModelNumFrames( picoModel, fm_head->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 );
+ _pico_free( bb0 );
+ return NULL;
+ }
+
+
+ PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
+ PicoSetSurfaceName( picoSurface, frame->header.name );
+ picoShader = PicoNewShader( picoModel );
+ if ( picoShader == NULL ) {
+ _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
+ PicoFreeModel( picoModel );
+ _pico_free( bb0 );
+ 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 ) * fm_head->numXYZ );
+ for ( i = 0; i < fm_head->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.
+ dups = 0;
+ triangle = tri_verts;
+
+ for ( i = 0; i < fm_head->numTris; i++ )
+ {
+ for ( j = 0; j < 3; j++ )
+ {
+ if ( p_index_LUT[triangle->index_xyz[j]].ST == -1 ) { // No Main Entry
+ p_index_LUT[triangle->index_xyz[j]].ST = triangle->index_st[j];
+ }
+
+ else if ( triangle->index_st[j] == p_index_LUT[triangle->index_xyz[j]].ST ) { // Equal to Main Entry
+#ifdef FM_VERBOSE_DBG
+ _pico_printf( PICO_NORMAL, "-> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
+#endif
+ continue;
+ }
+ else if ( ( p_index_LUT[triangle->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_NORMAL, " Couldn't allocate memory!\n" );
+ }
+ p_index_LUT[triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2;
+ p_index_LUT2->Vert = dups;
+ p_index_LUT2->ST = triangle->index_st[j];
+ p_index_LUT2->next = NULL;
+#ifdef FM_VERBOSE_DBG
+ _pico_printf( PICO_NORMAL, " ADDING first LL XYZ:%d DUP:%d ST:%d\n", triangle->index_xyz[j], dups, triangle->index_st[j] );
+#endif
+ triangle->index_xyz[j] = dups + fm_head->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[triangle->index_xyz[j]].next;
+ while ( ( p_index_LUT2 != NULL ) && ( triangle->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 ( triangle->index_st[j] == p_index_LUT2->ST ) { // Found it
+ triangle->index_xyz[j] = p_index_LUT2->Vert + fm_head->numXYZ; // Make change in Tri hunk
+#ifdef FM_VERBOSE_DBG
+ _pico_printf( PICO_NORMAL, "--> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
+#endif
+ 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_NORMAL, " Couldn't allocate memory!\n" );
+ }
+ p_index_LUT2->next = (index_LUT_t *)p_index_LUT3;
+ p_index_LUT3->Vert = dups;
+ p_index_LUT3->ST = triangle->index_st[j];
+ p_index_LUT3->next = NULL;
+#ifdef FM_VERBOSE_DBG
+ _pico_printf( PICO_NORMAL, " ADDING additional LL XYZ:%d DUP:%d NewXYZ:%d ST:%d\n", triangle->index_xyz[j], dups, dups + ( fm_head->numXYZ ), triangle->index_st[j] );
+#endif
+ triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
+ dups++;
+ }
+ }
+#ifdef FM_VERBOSE_DBG
+ _pico_printf( PICO_NORMAL, "---> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
+#endif
+ }
+ triangle++;
+ }
+
+ // 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_NORMAL, " Couldn't allocate memory!\n" );
+ }
+
+ dup_index = 0;
+ for ( i = 0; i < fm_head->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;
+ }
+ }
+#ifdef FM_VERBOSE_DBG
+ _pico_printf( PICO_NORMAL, " Dups = %d\n", dups );
+ _pico_printf( PICO_NORMAL, " Dup Index = %d\n", dup_index );
+#endif
+ for ( i = 0; i < fm_head->numXYZ; i++ )
+ {
+#ifdef FM_VERBOSE_DBG
+ _pico_printf( PICO_NORMAL, "Vert: %4d\t%4d",i, p_index_LUT[i].ST );
+#endif
+ if ( p_index_LUT[i].next != NULL ) {
+
+ p_index_LUT2 = p_index_LUT[i].next;
+ do {
+#ifdef FM_VERBOSE_DBG
+ _pico_printf( PICO_NORMAL, " %4d %4d", p_index_LUT2->Vert, p_index_LUT2->ST );
+#endif
+ p_index_LUT2 = p_index_LUT2->next;
+ } while ( p_index_LUT2 != NULL );
+
+ }
+#ifdef FM_VERBOSE_DBG
+ _pico_printf( PICO_NORMAL, "\n" );
+#endif
+ }
+
+
+#ifdef FM_VERBOSE_DBG
+ for ( i = 0; i < dup_index; i++ )
+ _pico_printf( PICO_NORMAL, " Dup Index #%d OldVert: %d ST: %d\n", i, p_index_LUT_DUPS[i].OldVert, p_index_LUT_DUPS[i].ST );
+
+ triangle = tri_verts;
+ for ( i = 0; i < fm_head->numTris; i++ )
+ {
+ for ( j = 0; j < 3; j++ )
+ _pico_printf( PICO_NORMAL, "Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
+ _pico_printf( PICO_NORMAL, "\n" );
+ triangle++;
+ }
+#endif
+ // Build Picomodel
+ triangle = tri_verts;
+ for ( j = 0; j < fm_head->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] );
+ }
+
+ vert = (fm_vert_normal_t*) ( (picoByte_t*) ( frame->verts ) );
+ for ( i = 0; i < fm_head->numXYZ; i++, vert++ )
+ {
+ /* set vertex origin */
+ xyz[ 0 ] = vert->v[0] * frame->header.scale[0] + frame->header.translate[0];
+ xyz[ 1 ] = vert->v[1] * frame->header.scale[1] + frame->header.translate[1];
+ xyz[ 2 ] = vert->v[2] * frame->header.scale[2] + frame->header.translate[2];
+ PicoSetSurfaceXYZ( picoSurface, i, xyz );
+
+ /* set normal */
+ normal[ 0 ] = fm_normals[vert->lightnormalindex][0];
+ normal[ 1 ] = fm_normals[vert->lightnormalindex][1];
+ normal[ 2 ] = fm_normals[vert->lightnormalindex][2];
+ PicoSetSurfaceNormal( picoSurface, i, normal );
+
+ /* set st coords */
+ st[ 0 ] = ( ( texCoord[p_index_LUT[i].ST].s ) / ( (float)fm_head->skinWidth ) );
+ st[ 1 ] = ( texCoord[p_index_LUT[i].ST].t / ( (float)fm_head->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->header.scale[0] + frame->header.translate[0];
+ xyz[ 1 ] = frame->verts[j].v[1] * frame->header.scale[1] + frame->header.translate[1];
+ xyz[ 2 ] = frame->verts[j].v[2] * frame->header.scale[2] + frame->header.translate[2];
+ PicoSetSurfaceXYZ( picoSurface, i + fm_head->numXYZ, xyz );
+
+ /* set normal */
+ normal[ 0 ] = fm_normals[frame->verts[j].lightnormalindex][0];
+ normal[ 1 ] = fm_normals[frame->verts[j].lightnormalindex][1];
+ normal[ 2 ] = fm_normals[frame->verts[j].lightnormalindex][2];
+ PicoSetSurfaceNormal( picoSurface, i + fm_head->numXYZ, normal );
+
+ /* set st coords */
+ st[ 0 ] = ( ( texCoord[p_index_LUT_DUPS[i].ST].s ) / ( (float)fm_head->skinWidth ) );
+ st[ 1 ] = ( texCoord[p_index_LUT_DUPS[i].ST].t / ( (float)fm_head->skinHeight ) );
+ PicoSetSurfaceST( picoSurface, 0, i + fm_head->numXYZ, st );
+ }
+ }
+
+ /* set color */
+ PicoSetSurfaceColor( picoSurface, 0, 0, color );
+
+ // Free up malloc'ed LL entries
+ for ( i = 0; i < fm_head->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 */
+ _pico_free( bb0 );
+ return picoModel;
+
+}
+
+
+
+/* pico file format module definition */
+const picoModule_t picoModuleFM =
+{
+ "0.85", /* module version string */
+ "Heretic 2 FM", /* module display name */
+ "Nurail", /* author's name */
+ "2003 Nurail", /* module copyright */
+ {
+ "fm", NULL, NULL, NULL /* default extensions to use */
+ },
+ _fm_canload, /* validation routine */
+ _fm_load, /* load routine */
+ NULL, /* save validation routine */
+ NULL /* save routine */
+};