1 /* -----------------------------------------------------------------------------
5 Copyright (c) 2002, Randy Reddig & seaw0lf
8 Redistribution and use in source and binary forms, with or without modification,
9 are permitted provided that the following conditions are met:
11 Redistributions of source code must retain the above copyright notice, this list
12 of conditions and the following disclaimer.
14 Redistributions in binary form must reproduce the above copyright notice, this
15 list of conditions and the following disclaimer in the documentation and/or
16 other materials provided with the distribution.
18 Neither the names of the copyright holders nor the names of its contributors may
19 be used to endorse or promote products derived from this software without
20 specific prior written permission.
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
26 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 ----------------------------------------------------------------------------- */
36 Nurail: Used pm_md3.c (Randy Reddig) as a template.
42 //#define FM_VERBOSE_DBG 0
46 typedef struct index_LUT_s
50 struct index_LUT_s *next;
54 typedef struct index_DUP_LUT_s
63 static int _fm_canload( PM_PARAMS_CANLOAD ){
65 unsigned char *bb, *bb0;
68 bb0 = bb = (picoByte_t*) _pico_alloc( bufSize );
69 memcpy( bb, buffer, bufSize );
72 fm.fm_header_hdr = (fm_chunk_header_t *) bb;
73 fm_file_pos = sizeof( fm_chunk_header_t ) + fm.fm_header_hdr->size;
75 _pico_printf( PICO_VERBOSE, "IDENT: %s\n", (unsigned char *) fm.fm_header_hdr->ident );
77 if ( ( strcmp( fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME ) ) ) {
79 _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n" );
82 return PICO_PMV_ERROR_IDENT;
86 if ( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) {
88 _pico_printf( PICO_WARNING, "FM Header Version incorrect\n" );
91 return PICO_PMV_ERROR_VERSION;
95 fm.fm_skin_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
96 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_skin_hdr->size;
98 _pico_printf( PICO_VERBOSE, "SKIN: %s\n", (unsigned char *) fm.fm_skin_hdr->ident );
100 if ( ( strcmp( fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME ) ) ) {
102 _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n" );
105 return PICO_PMV_ERROR_IDENT;
109 if ( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) {
111 _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n" );
114 return PICO_PMV_ERROR_VERSION;
118 fm.fm_st_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
119 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_st_hdr->size;
120 #ifdef FM_VERBOSE_DBG
121 _pico_printf( PICO_VERBOSE, "ST: %s\n", (unsigned char *) fm.fm_st_hdr->ident );
123 if ( ( strcmp( fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME ) ) ) {
125 _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n" );
128 return PICO_PMV_ERROR_IDENT;
132 if ( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) {
134 _pico_printf( PICO_WARNING, "FM ST Version incorrect\n" );
137 return PICO_PMV_ERROR_VERSION;
141 fm.fm_tri_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
142 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_tri_hdr->size;
143 #ifdef FM_VERBOSE_DBG
144 _pico_printf( PICO_VERBOSE, "TRI: %s\n", (unsigned char *) fm.fm_tri_hdr->ident );
146 if ( ( strcmp( fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME ) ) ) {
148 _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n" );
151 return PICO_PMV_ERROR_IDENT;
155 if ( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) {
157 _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n" );
160 return PICO_PMV_ERROR_VERSION;
164 fm.fm_frame_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
165 fm_file_pos += sizeof( fm_chunk_header_t );
166 #ifdef FM_VERBOSE_DBG
167 _pico_printf( PICO_VERBOSE, "FRAME: %s\n", (unsigned char *) fm.fm_frame_hdr->ident );
169 if ( ( strcmp( fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME ) ) ) {
171 _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n" );
174 return PICO_PMV_ERROR_IDENT;
178 if ( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) {
180 _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n" );
183 return PICO_PMV_ERROR_VERSION;
186 // file seems to be a valid fm
192 // _fm_load() loads a Heretic 2 model file.
193 static picoModel_t *_fm_load( PM_PARAMS_LOAD ){
194 int i, j, dups, dup_index;
196 index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3;
197 index_DUP_LUT_t *p_index_LUT_DUPS;
199 fm_vert_normal_t *vert;
201 char skinname[FM_SKINPATHSIZE];
203 fm_header_t *fm_head;
205 fm_xyz_st_t *tri_verts;
206 fm_xyz_st_t *triangle;
209 picoByte_t *bb, *bb0;
210 picoModel_t *picoModel;
211 picoSurface_t *picoSurface;
212 picoShader_t *picoShader;
213 picoVec3_t xyz, normal;
218 bb0 = bb = (picoByte_t*) _pico_alloc( bufSize );
219 memcpy( bb, buffer, bufSize );
222 fm.fm_header_hdr = (fm_chunk_header_t *) bb;
223 fm_file_pos = sizeof( fm_chunk_header_t ) + fm.fm_header_hdr->size;
224 if ( ( strcmp( fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME ) ) ) {
225 _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n" );
230 if ( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) {
231 _pico_printf( PICO_WARNING, "FM Header Version incorrect\n" );
237 fm.fm_skin_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
238 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_skin_hdr->size;
239 if ( ( strcmp( fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME ) ) ) {
240 _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n" );
245 if ( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) {
246 _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n" );
252 fm.fm_st_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
253 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_st_hdr->size;
254 if ( ( strcmp( fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME ) ) ) {
255 _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n" );
260 if ( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) {
261 _pico_printf( PICO_WARNING, "FM ST Version incorrect\n" );
267 fm.fm_tri_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
268 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_tri_hdr->size;
269 if ( ( strcmp( fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME ) ) ) {
270 _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n" );
275 if ( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) {
276 _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n" );
282 fm.fm_frame_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
283 fm_file_pos += sizeof( fm_chunk_header_t );
284 if ( ( strcmp( fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME ) ) ) {
285 _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n" );
290 if ( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) {
291 _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n" );
297 fm_file_pos = sizeof( fm_chunk_header_t );
298 fm_head = fm.fm_header = (fm_header_t *) ( bb + fm_file_pos );
299 fm_file_pos += fm.fm_header_hdr->size;
302 fm_file_pos += sizeof( fm_chunk_header_t );
303 fm.fm_skin = (fm_skinpath_t *) ( bb + fm_file_pos );
304 fm_file_pos += fm.fm_skin_hdr->size;
307 fm_file_pos += sizeof( fm_chunk_header_t );
308 texCoord = fm.fm_st = (fm_st_t *) ( bb + fm_file_pos );
309 fm_file_pos += fm.fm_st_hdr->size;
312 fm_file_pos += sizeof( fm_chunk_header_t );
313 tri_verts = fm.fm_tri = (fm_xyz_st_t *) ( bb + fm_file_pos );
314 fm_file_pos += fm.fm_tri_hdr->size;
317 fm_file_pos += sizeof( fm_chunk_header_t );
318 frame = fm.fm_frame = (fm_frame_t *) ( bb + fm_file_pos );
321 if ( fm_head->numFrames < 1 ) {
322 _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );
327 if ( frameNum < 0 || frameNum >= fm_head->numFrames ) {
328 _pico_printf( PICO_ERROR, "Invalid or out-of-range FM frame specified" );
334 fm_head->skinWidth = _pico_little_long( fm_head->skinWidth );
335 fm_head->skinHeight = _pico_little_long( fm_head->skinHeight );
336 fm_head->frameSize = _pico_little_long( fm_head->frameSize );
338 fm_head->numSkins = _pico_little_long( fm_head->numSkins );
339 fm_head->numXYZ = _pico_little_long( fm_head->numXYZ );
340 fm_head->numST = _pico_little_long( fm_head->numST );
341 fm_head->numTris = _pico_little_long( fm_head->numTris );
342 fm_head->numGLCmds = _pico_little_long( fm_head->numGLCmds );
343 fm_head->numFrames = _pico_little_long( fm_head->numFrames );
345 // swap frame scale and translation
346 for ( i = 0; i < 3; i++ )
348 frame->header.scale[ i ] = _pico_little_float( frame->header.scale[ i ] );
349 frame->header.translate[ i ] = _pico_little_float( frame->header.translate[ i ] );
353 triangle = tri_verts;
354 for ( i = 0; i < fm_head->numTris; i++, triangle++ )
356 for ( j = 0; j < 3; j++ )
358 triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );
359 triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );
364 for ( i = 0; i < fm_head->numST; i++ )
366 texCoord->s = _pico_little_short( texCoord[i].s );
367 texCoord->t = _pico_little_short( texCoord[i].t );
370 strncpy( skinname, (const char *) fm.fm_skin, FM_SKINPATHSIZE );
372 #ifdef FM_VERBOSE_DBG
373 // Print out md2 values
374 _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 );
378 _pico_setfext( skinname, "" );
379 _pico_unixify( skinname );
381 /* create new pico model */
382 picoModel = PicoNewModel();
383 if ( picoModel == NULL ) {
384 _pico_printf( PICO_ERROR, "Unable to allocate a new model" );
390 PicoSetModelFrameNum( picoModel, frameNum );
391 PicoSetModelNumFrames( picoModel, fm_head->numFrames ); /* sea */
392 PicoSetModelName( picoModel, fileName );
393 PicoSetModelFileName( picoModel, fileName );
395 // allocate new pico surface
396 picoSurface = PicoNewSurface( picoModel );
397 if ( picoSurface == NULL ) {
398 _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
399 PicoFreeModel( picoModel );
405 PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
406 PicoSetSurfaceName( picoSurface, frame->header.name );
407 picoShader = PicoNewShader( picoModel );
408 if ( picoShader == NULL ) {
409 _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
410 PicoFreeModel( picoModel );
415 PicoSetShaderName( picoShader, skinname );
417 // associate current surface with newly created shader
418 PicoSetSurfaceShader( picoSurface, picoShader );
420 // Init LUT for Verts
421 p_index_LUT = (index_LUT_t *)_pico_alloc( sizeof( index_LUT_t ) * fm_head->numXYZ );
422 for ( i = 0; i < fm_head->numXYZ; i++ )
424 p_index_LUT[i].Vert = -1;
425 p_index_LUT[i].ST = -1;
426 p_index_LUT[i].next = NULL;
429 // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert.
431 triangle = tri_verts;
433 for ( i = 0; i < fm_head->numTris; i++ )
435 for ( j = 0; j < 3; j++ )
437 if ( p_index_LUT[triangle->index_xyz[j]].ST == -1 ) { // No Main Entry
438 p_index_LUT[triangle->index_xyz[j]].ST = triangle->index_st[j];
441 else if ( triangle->index_st[j] == p_index_LUT[triangle->index_xyz[j]].ST ) { // Equal to Main Entry
442 #ifdef FM_VERBOSE_DBG
443 _pico_printf( PICO_NORMAL, "-> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
447 else if ( ( p_index_LUT[triangle->index_xyz[j]].next == NULL ) ) { // Not equal to Main entry, and no LL entry
448 // Add first entry of LL from Main
449 p_index_LUT2 = (index_LUT_t *)_pico_alloc( sizeof( index_LUT_t ) );
450 if ( p_index_LUT2 == NULL ) {
451 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n" );
453 p_index_LUT[triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2;
454 p_index_LUT2->Vert = dups;
455 p_index_LUT2->ST = triangle->index_st[j];
456 p_index_LUT2->next = NULL;
457 #ifdef FM_VERBOSE_DBG
458 _pico_printf( PICO_NORMAL, " ADDING first LL XYZ:%d DUP:%d ST:%d\n", triangle->index_xyz[j], dups, triangle->index_st[j] );
460 triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
463 else // Try to find in LL from Main Entry
465 p_index_LUT3 = p_index_LUT2 = p_index_LUT[triangle->index_xyz[j]].next;
466 while ( ( p_index_LUT2 != NULL ) && ( triangle->index_xyz[j] != p_index_LUT2->Vert ) ) // Walk down LL
468 p_index_LUT3 = p_index_LUT2;
469 p_index_LUT2 = p_index_LUT2->next;
471 p_index_LUT2 = p_index_LUT3;
473 if ( triangle->index_st[j] == p_index_LUT2->ST ) { // Found it
474 triangle->index_xyz[j] = p_index_LUT2->Vert + fm_head->numXYZ; // Make change in Tri hunk
475 #ifdef FM_VERBOSE_DBG
476 _pico_printf( PICO_NORMAL, "--> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
481 if ( p_index_LUT2->next == NULL ) { // Didn't find it. Add entry to LL.
483 p_index_LUT3 = (index_LUT_t *)_pico_alloc( sizeof( index_LUT_t ) );
484 if ( p_index_LUT3 == NULL ) {
485 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n" );
487 p_index_LUT2->next = (index_LUT_t *)p_index_LUT3;
488 p_index_LUT3->Vert = dups;
489 p_index_LUT3->ST = triangle->index_st[j];
490 p_index_LUT3->next = NULL;
491 #ifdef FM_VERBOSE_DBG
492 _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] );
494 triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
498 #ifdef FM_VERBOSE_DBG
499 _pico_printf( PICO_NORMAL, "---> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
505 // malloc and build array for Dup STs
506 p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc( sizeof( index_DUP_LUT_t ) * dups );
507 if ( p_index_LUT_DUPS == NULL ) {
508 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n" );
512 for ( i = 0; i < fm_head->numXYZ; i++ )
514 p_index_LUT2 = p_index_LUT[i].next;
515 while ( p_index_LUT2 != NULL )
517 p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i;
518 p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST;
520 p_index_LUT2 = p_index_LUT2->next;
523 #ifdef FM_VERBOSE_DBG
524 _pico_printf( PICO_NORMAL, " Dups = %d\n", dups );
525 _pico_printf( PICO_NORMAL, " Dup Index = %d\n", dup_index );
527 for ( i = 0; i < fm_head->numXYZ; i++ )
529 #ifdef FM_VERBOSE_DBG
530 _pico_printf( PICO_NORMAL, "Vert: %4d\t%4d",i, p_index_LUT[i].ST );
532 if ( p_index_LUT[i].next != NULL ) {
534 p_index_LUT2 = p_index_LUT[i].next;
536 #ifdef FM_VERBOSE_DBG
537 _pico_printf( PICO_NORMAL, " %4d %4d", p_index_LUT2->Vert, p_index_LUT2->ST );
539 p_index_LUT2 = p_index_LUT2->next;
540 } while ( p_index_LUT2 != NULL );
543 #ifdef FM_VERBOSE_DBG
544 _pico_printf( PICO_NORMAL, "\n" );
549 #ifdef FM_VERBOSE_DBG
550 for ( i = 0; i < dup_index; i++ )
551 _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 );
553 triangle = tri_verts;
554 for ( i = 0; i < fm_head->numTris; i++ )
556 for ( j = 0; j < 3; j++ )
557 _pico_printf( PICO_NORMAL, "Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
558 _pico_printf( PICO_NORMAL, "\n" );
563 triangle = tri_verts;
564 for ( j = 0; j < fm_head->numTris; j++, triangle++ )
566 PicoSetSurfaceIndex( picoSurface, j * 3, triangle->index_xyz[0] );
567 PicoSetSurfaceIndex( picoSurface, j * 3 + 1, triangle->index_xyz[1] );
568 PicoSetSurfaceIndex( picoSurface, j * 3 + 2, triangle->index_xyz[2] );
571 vert = (fm_vert_normal_t*) ( (picoByte_t*) ( frame->verts ) );
572 for ( i = 0; i < fm_head->numXYZ; i++, vert++ )
574 /* set vertex origin */
575 xyz[ 0 ] = vert->v[0] * frame->header.scale[0] + frame->header.translate[0];
576 xyz[ 1 ] = vert->v[1] * frame->header.scale[1] + frame->header.translate[1];
577 xyz[ 2 ] = vert->v[2] * frame->header.scale[2] + frame->header.translate[2];
578 PicoSetSurfaceXYZ( picoSurface, i, xyz );
581 normal[ 0 ] = fm_normals[vert->lightnormalindex][0];
582 normal[ 1 ] = fm_normals[vert->lightnormalindex][1];
583 normal[ 2 ] = fm_normals[vert->lightnormalindex][2];
584 PicoSetSurfaceNormal( picoSurface, i, normal );
587 st[ 0 ] = ( ( texCoord[p_index_LUT[i].ST].s ) / ( (float)fm_head->skinWidth ) );
588 st[ 1 ] = ( texCoord[p_index_LUT[i].ST].t / ( (float)fm_head->skinHeight ) );
589 PicoSetSurfaceST( picoSurface, 0, i, st );
593 for ( i = 0; i < dups; i++ )
595 j = p_index_LUT_DUPS[i].OldVert;
596 /* set vertex origin */
597 xyz[ 0 ] = frame->verts[j].v[0] * frame->header.scale[0] + frame->header.translate[0];
598 xyz[ 1 ] = frame->verts[j].v[1] * frame->header.scale[1] + frame->header.translate[1];
599 xyz[ 2 ] = frame->verts[j].v[2] * frame->header.scale[2] + frame->header.translate[2];
600 PicoSetSurfaceXYZ( picoSurface, i + fm_head->numXYZ, xyz );
603 normal[ 0 ] = fm_normals[frame->verts[j].lightnormalindex][0];
604 normal[ 1 ] = fm_normals[frame->verts[j].lightnormalindex][1];
605 normal[ 2 ] = fm_normals[frame->verts[j].lightnormalindex][2];
606 PicoSetSurfaceNormal( picoSurface, i + fm_head->numXYZ, normal );
609 st[ 0 ] = ( ( texCoord[p_index_LUT_DUPS[i].ST].s ) / ( (float)fm_head->skinWidth ) );
610 st[ 1 ] = ( texCoord[p_index_LUT_DUPS[i].ST].t / ( (float)fm_head->skinHeight ) );
611 PicoSetSurfaceST( picoSurface, 0, i + fm_head->numXYZ, st );
616 PicoSetSurfaceColor( picoSurface, 0, 0, color );
618 // Free up malloc'ed LL entries
619 for ( i = 0; i < fm_head->numXYZ; i++ )
621 if ( p_index_LUT[i].next != NULL ) {
622 p_index_LUT2 = p_index_LUT[i].next;
624 p_index_LUT3 = p_index_LUT2->next;
625 _pico_free( p_index_LUT2 );
626 p_index_LUT2 = p_index_LUT3;
628 } while ( p_index_LUT2 != NULL );
633 _pico_printf( PICO_WARNING, " Not all LL mallocs freed\n" );
636 // Free malloc'ed LUTs
637 _pico_free( p_index_LUT );
638 _pico_free( p_index_LUT_DUPS );
640 /* return the new pico model */
648 /* pico file format module definition */
649 const picoModule_t picoModuleFM =
651 "0.85", /* module version string */
652 "Heretic 2 FM", /* module display name */
653 "Nurail", /* author's name */
654 "2003 Nurail", /* module copyright */
656 "fm", NULL, NULL, NULL /* default extensions to use */
658 _fm_canload, /* validation routine */
659 _fm_load, /* load routine */
660 NULL, /* save validation routine */
661 NULL /* save routine */