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.
45 //#define FM_VERBOSE_DBG 0
49 typedef struct index_LUT_s
53 struct index_LUT_s *next;
57 typedef struct index_DUP_LUT_s
66 static int _fm_canload( PM_PARAMS_CANLOAD ){
68 unsigned char *bb, *bb0;
71 bb0 = bb = (picoByte_t*) _pico_alloc( bufSize );
72 memcpy( bb, buffer, bufSize );
75 fm.fm_header_hdr = (fm_chunk_header_t *) bb;
76 fm_file_pos = sizeof( fm_chunk_header_t ) + fm.fm_header_hdr->size;
78 _pico_printf( PICO_VERBOSE, "IDENT: %s\n", (unsigned char *) fm.fm_header_hdr->ident );
80 if ( ( strcmp( fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME ) ) ) {
82 _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n" );
85 return PICO_PMV_ERROR_IDENT;
89 if ( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) {
91 _pico_printf( PICO_WARNING, "FM Header Version incorrect\n" );
94 return PICO_PMV_ERROR_VERSION;
98 fm.fm_skin_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
99 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_skin_hdr->size;
100 #ifdef FM_VERBOSE_DBG
101 _pico_printf( PICO_VERBOSE, "SKIN: %s\n", (unsigned char *) fm.fm_skin_hdr->ident );
103 if ( ( strcmp( fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME ) ) ) {
105 _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n" );
108 return PICO_PMV_ERROR_IDENT;
112 if ( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) {
114 _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n" );
117 return PICO_PMV_ERROR_VERSION;
121 fm.fm_st_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
122 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_st_hdr->size;
123 #ifdef FM_VERBOSE_DBG
124 _pico_printf( PICO_VERBOSE, "ST: %s\n", (unsigned char *) fm.fm_st_hdr->ident );
126 if ( ( strcmp( fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME ) ) ) {
128 _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n" );
131 return PICO_PMV_ERROR_IDENT;
135 if ( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) {
137 _pico_printf( PICO_WARNING, "FM ST Version incorrect\n" );
140 return PICO_PMV_ERROR_VERSION;
144 fm.fm_tri_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
145 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_tri_hdr->size;
146 #ifdef FM_VERBOSE_DBG
147 _pico_printf( PICO_VERBOSE, "TRI: %s\n", (unsigned char *) fm.fm_tri_hdr->ident );
149 if ( ( strcmp( fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME ) ) ) {
151 _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n" );
154 return PICO_PMV_ERROR_IDENT;
158 if ( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) {
160 _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n" );
163 return PICO_PMV_ERROR_VERSION;
167 fm.fm_frame_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
168 fm_file_pos += sizeof( fm_chunk_header_t );
169 #ifdef FM_VERBOSE_DBG
170 _pico_printf( PICO_VERBOSE, "FRAME: %s\n", (unsigned char *) fm.fm_frame_hdr->ident );
172 if ( ( strcmp( fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME ) ) ) {
174 _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n" );
177 return PICO_PMV_ERROR_IDENT;
181 if ( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) {
183 _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n" );
186 return PICO_PMV_ERROR_VERSION;
189 // file seems to be a valid fm
195 // _fm_load() loads a Heretic 2 model file.
196 static picoModel_t *_fm_load( PM_PARAMS_LOAD ){
197 int i, j, dups, dup_index;
199 index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3;
200 index_DUP_LUT_t *p_index_LUT_DUPS;
202 fm_vert_normal_t *vert;
204 char skinname[FM_SKINPATHSIZE];
206 fm_header_t *fm_head;
208 fm_xyz_st_t *tri_verts;
209 fm_xyz_st_t *triangle;
212 picoByte_t *bb, *bb0;
213 picoModel_t *picoModel;
214 picoSurface_t *picoSurface;
215 picoShader_t *picoShader;
216 picoVec3_t xyz, normal;
221 bb0 = bb = (picoByte_t*) _pico_alloc( bufSize );
222 memcpy( bb, buffer, bufSize );
225 fm.fm_header_hdr = (fm_chunk_header_t *) bb;
226 fm_file_pos = sizeof( fm_chunk_header_t ) + fm.fm_header_hdr->size;
227 if ( ( strcmp( fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME ) ) ) {
228 _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n" );
233 if ( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) {
234 _pico_printf( PICO_WARNING, "FM Header Version incorrect\n" );
240 fm.fm_skin_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
241 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_skin_hdr->size;
242 if ( ( strcmp( fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME ) ) ) {
243 _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n" );
248 if ( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) {
249 _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n" );
255 fm.fm_st_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
256 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_st_hdr->size;
257 if ( ( strcmp( fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME ) ) ) {
258 _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n" );
263 if ( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) {
264 _pico_printf( PICO_WARNING, "FM ST Version incorrect\n" );
270 fm.fm_tri_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
271 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_tri_hdr->size;
272 if ( ( strcmp( fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME ) ) ) {
273 _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n" );
278 if ( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) {
279 _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n" );
285 fm.fm_frame_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
286 fm_file_pos += sizeof( fm_chunk_header_t );
287 if ( ( strcmp( fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME ) ) ) {
288 _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n" );
293 if ( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) {
294 _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n" );
300 fm_file_pos = sizeof( fm_chunk_header_t );
301 fm_head = fm.fm_header = (fm_header_t *) ( bb + fm_file_pos );
302 fm_file_pos += fm.fm_header_hdr->size;
305 fm_file_pos += sizeof( fm_chunk_header_t );
306 fm.fm_skin = (fm_skinpath_t *) ( bb + fm_file_pos );
307 fm_file_pos += fm.fm_skin_hdr->size;
310 fm_file_pos += sizeof( fm_chunk_header_t );
311 texCoord = fm.fm_st = (fm_st_t *) ( bb + fm_file_pos );
312 fm_file_pos += fm.fm_st_hdr->size;
315 fm_file_pos += sizeof( fm_chunk_header_t );
316 tri_verts = fm.fm_tri = (fm_xyz_st_t *) ( bb + fm_file_pos );
317 fm_file_pos += fm.fm_tri_hdr->size;
320 fm_file_pos += sizeof( fm_chunk_header_t );
321 frame = fm.fm_frame = (fm_frame_t *) ( bb + fm_file_pos );
324 if ( fm_head->numFrames < 1 ) {
325 _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );
330 if ( frameNum < 0 || frameNum >= fm_head->numFrames ) {
331 _pico_printf( PICO_ERROR, "Invalid or out-of-range FM frame specified" );
337 fm_head->skinWidth = _pico_little_long( fm_head->skinWidth );
338 fm_head->skinHeight = _pico_little_long( fm_head->skinHeight );
339 fm_head->frameSize = _pico_little_long( fm_head->frameSize );
341 fm_head->numSkins = _pico_little_long( fm_head->numSkins );
342 fm_head->numXYZ = _pico_little_long( fm_head->numXYZ );
343 fm_head->numST = _pico_little_long( fm_head->numST );
344 fm_head->numTris = _pico_little_long( fm_head->numTris );
345 fm_head->numGLCmds = _pico_little_long( fm_head->numGLCmds );
346 fm_head->numFrames = _pico_little_long( fm_head->numFrames );
348 // swap frame scale and translation
349 for ( i = 0; i < 3; i++ )
351 frame->header.scale[ i ] = _pico_little_float( frame->header.scale[ i ] );
352 frame->header.translate[ i ] = _pico_little_float( frame->header.translate[ i ] );
356 triangle = tri_verts;
357 for ( i = 0; i < fm_head->numTris; i++, triangle++ )
359 for ( j = 0; j < 3; j++ )
361 triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );
362 triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );
367 for ( i = 0; i < fm_head->numST; i++ )
369 texCoord->s = _pico_little_short( texCoord[i].s );
370 texCoord->t = _pico_little_short( texCoord[i].t );
373 strncpy( skinname, (const char *) fm.fm_skin, FM_SKINPATHSIZE );
375 #ifdef FM_VERBOSE_DBG
376 // Print out md2 values
377 _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 );
381 _pico_setfext( skinname, "" );
382 _pico_unixify( skinname );
384 /* create new pico model */
385 picoModel = PicoNewModel();
386 if ( picoModel == NULL ) {
387 _pico_printf( PICO_ERROR, "Unable to allocate a new model" );
393 PicoSetModelFrameNum( picoModel, frameNum );
394 PicoSetModelNumFrames( picoModel, fm_head->numFrames ); /* sea */
395 PicoSetModelName( picoModel, fileName );
396 PicoSetModelFileName( picoModel, fileName );
398 // allocate new pico surface
399 picoSurface = PicoNewSurface( picoModel );
400 if ( picoSurface == NULL ) {
401 _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
402 PicoFreeModel( picoModel );
408 PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
409 PicoSetSurfaceName( picoSurface, frame->header.name );
410 picoShader = PicoNewShader( picoModel );
411 if ( picoShader == NULL ) {
412 _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
413 PicoFreeModel( picoModel );
418 PicoSetShaderName( picoShader, skinname );
420 // associate current surface with newly created shader
421 PicoSetSurfaceShader( picoSurface, picoShader );
423 // Init LUT for Verts
424 p_index_LUT = (index_LUT_t *)_pico_alloc( sizeof( index_LUT_t ) * fm_head->numXYZ );
425 for ( i = 0; i < fm_head->numXYZ; i++ )
427 p_index_LUT[i].Vert = -1;
428 p_index_LUT[i].ST = -1;
429 p_index_LUT[i].next = NULL;
432 // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert.
434 triangle = tri_verts;
436 for ( i = 0; i < fm_head->numTris; i++ )
438 for ( j = 0; j < 3; j++ )
440 if ( p_index_LUT[triangle->index_xyz[j]].ST == -1 ) { // No Main Entry
441 p_index_LUT[triangle->index_xyz[j]].ST = triangle->index_st[j];
444 else if ( triangle->index_st[j] == p_index_LUT[triangle->index_xyz[j]].ST ) { // Equal to Main Entry
445 #ifdef FM_VERBOSE_DBG
446 _pico_printf( PICO_NORMAL, "-> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
450 else if ( ( p_index_LUT[triangle->index_xyz[j]].next == NULL ) ) { // Not equal to Main entry, and no LL entry
451 // Add first entry of LL from Main
452 p_index_LUT2 = (index_LUT_t *)_pico_alloc( sizeof( index_LUT_t ) );
453 if ( p_index_LUT2 == NULL ) {
454 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n" );
456 p_index_LUT[triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2;
457 p_index_LUT2->Vert = dups;
458 p_index_LUT2->ST = triangle->index_st[j];
459 p_index_LUT2->next = NULL;
460 #ifdef FM_VERBOSE_DBG
461 _pico_printf( PICO_NORMAL, " ADDING first LL XYZ:%d DUP:%d ST:%d\n", triangle->index_xyz[j], dups, triangle->index_st[j] );
463 triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
466 else // Try to find in LL from Main Entry
468 p_index_LUT3 = p_index_LUT2 = p_index_LUT[triangle->index_xyz[j]].next;
469 while ( ( p_index_LUT2 != NULL ) && ( triangle->index_xyz[j] != p_index_LUT2->Vert ) ) // Walk down LL
471 p_index_LUT3 = p_index_LUT2;
472 p_index_LUT2 = p_index_LUT2->next;
474 p_index_LUT2 = p_index_LUT3;
476 if ( triangle->index_st[j] == p_index_LUT2->ST ) { // Found it
477 triangle->index_xyz[j] = p_index_LUT2->Vert + fm_head->numXYZ; // Make change in Tri hunk
478 #ifdef FM_VERBOSE_DBG
479 _pico_printf( PICO_NORMAL, "--> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
484 if ( p_index_LUT2->next == NULL ) { // Didn't find it. Add entry to LL.
486 p_index_LUT3 = (index_LUT_t *)_pico_alloc( sizeof( index_LUT_t ) );
487 if ( p_index_LUT3 == NULL ) {
488 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n" );
490 p_index_LUT2->next = (index_LUT_t *)p_index_LUT3;
491 p_index_LUT3->Vert = dups;
492 p_index_LUT3->ST = triangle->index_st[j];
493 p_index_LUT3->next = NULL;
494 #ifdef FM_VERBOSE_DBG
495 _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] );
497 triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
501 #ifdef FM_VERBOSE_DBG
502 _pico_printf( PICO_NORMAL, "---> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
508 // malloc and build array for Dup STs
509 p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc( sizeof( index_DUP_LUT_t ) * dups );
510 if ( p_index_LUT_DUPS == NULL ) {
511 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n" );
515 for ( i = 0; i < fm_head->numXYZ; i++ )
517 p_index_LUT2 = p_index_LUT[i].next;
518 while ( p_index_LUT2 != NULL )
520 p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i;
521 p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST;
523 p_index_LUT2 = p_index_LUT2->next;
526 #ifdef FM_VERBOSE_DBG
527 _pico_printf( PICO_NORMAL, " Dups = %d\n", dups );
528 _pico_printf( PICO_NORMAL, " Dup Index = %d\n", dup_index );
530 for ( i = 0; i < fm_head->numXYZ; i++ )
532 #ifdef FM_VERBOSE_DBG
533 _pico_printf( PICO_NORMAL, "Vert: %4d\t%4d",i, p_index_LUT[i].ST );
535 if ( p_index_LUT[i].next != NULL ) {
537 p_index_LUT2 = p_index_LUT[i].next;
539 #ifdef FM_VERBOSE_DBG
540 _pico_printf( PICO_NORMAL, " %4d %4d", p_index_LUT2->Vert, p_index_LUT2->ST );
542 p_index_LUT2 = p_index_LUT2->next;
543 } while ( p_index_LUT2 != NULL );
546 #ifdef FM_VERBOSE_DBG
547 _pico_printf( PICO_NORMAL, "\n" );
552 #ifdef FM_VERBOSE_DBG
553 for ( i = 0; i < dup_index; i++ )
554 _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 );
556 triangle = tri_verts;
557 for ( i = 0; i < fm_head->numTris; i++ )
559 for ( j = 0; j < 3; j++ )
560 _pico_printf( PICO_NORMAL, "Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
561 _pico_printf( PICO_NORMAL, "\n" );
566 triangle = tri_verts;
567 for ( j = 0; j < fm_head->numTris; j++, triangle++ )
569 PicoSetSurfaceIndex( picoSurface, j * 3, triangle->index_xyz[0] );
570 PicoSetSurfaceIndex( picoSurface, j * 3 + 1, triangle->index_xyz[1] );
571 PicoSetSurfaceIndex( picoSurface, j * 3 + 2, triangle->index_xyz[2] );
574 vert = (fm_vert_normal_t*) ( (picoByte_t*) ( frame->verts ) );
575 for ( i = 0; i < fm_head->numXYZ; i++, vert++ )
577 /* set vertex origin */
578 xyz[ 0 ] = vert->v[0] * frame->header.scale[0] + frame->header.translate[0];
579 xyz[ 1 ] = vert->v[1] * frame->header.scale[1] + frame->header.translate[1];
580 xyz[ 2 ] = vert->v[2] * frame->header.scale[2] + frame->header.translate[2];
581 PicoSetSurfaceXYZ( picoSurface, i, xyz );
584 normal[ 0 ] = fm_normals[vert->lightnormalindex][0];
585 normal[ 1 ] = fm_normals[vert->lightnormalindex][1];
586 normal[ 2 ] = fm_normals[vert->lightnormalindex][2];
587 PicoSetSurfaceNormal( picoSurface, i, normal );
590 st[ 0 ] = ( ( texCoord[p_index_LUT[i].ST].s ) / ( (float)fm_head->skinWidth ) );
591 st[ 1 ] = ( texCoord[p_index_LUT[i].ST].t / ( (float)fm_head->skinHeight ) );
592 PicoSetSurfaceST( picoSurface, 0, i, st );
596 for ( i = 0; i < dups; i++ )
598 j = p_index_LUT_DUPS[i].OldVert;
599 /* set vertex origin */
600 xyz[ 0 ] = frame->verts[j].v[0] * frame->header.scale[0] + frame->header.translate[0];
601 xyz[ 1 ] = frame->verts[j].v[1] * frame->header.scale[1] + frame->header.translate[1];
602 xyz[ 2 ] = frame->verts[j].v[2] * frame->header.scale[2] + frame->header.translate[2];
603 PicoSetSurfaceXYZ( picoSurface, i + fm_head->numXYZ, xyz );
606 normal[ 0 ] = fm_normals[frame->verts[j].lightnormalindex][0];
607 normal[ 1 ] = fm_normals[frame->verts[j].lightnormalindex][1];
608 normal[ 2 ] = fm_normals[frame->verts[j].lightnormalindex][2];
609 PicoSetSurfaceNormal( picoSurface, i + fm_head->numXYZ, normal );
612 st[ 0 ] = ( ( texCoord[p_index_LUT_DUPS[i].ST].s ) / ( (float)fm_head->skinWidth ) );
613 st[ 1 ] = ( texCoord[p_index_LUT_DUPS[i].ST].t / ( (float)fm_head->skinHeight ) );
614 PicoSetSurfaceST( picoSurface, 0, i + fm_head->numXYZ, st );
619 PicoSetSurfaceColor( picoSurface, 0, 0, color );
621 // Free up malloc'ed LL entries
622 for ( i = 0; i < fm_head->numXYZ; i++ )
624 if ( p_index_LUT[i].next != NULL ) {
625 p_index_LUT2 = p_index_LUT[i].next;
627 p_index_LUT3 = p_index_LUT2->next;
628 _pico_free( p_index_LUT2 );
629 p_index_LUT2 = p_index_LUT3;
631 } while ( p_index_LUT2 != NULL );
636 _pico_printf( PICO_WARNING, " Not all LL mallocs freed\n" );
639 // Free malloc'ed LUTs
640 _pico_free( p_index_LUT );
641 _pico_free( p_index_LUT_DUPS );
643 /* return the new pico model */
651 /* pico file format module definition */
652 const picoModule_t picoModuleFM =
654 "0.85", /* module version string */
655 "Heretic 2 FM", /* module display name */
656 "Nurail", /* author's name */
657 "2003 Nurail", /* module copyright */
659 "fm", NULL, NULL, NULL /* default extensions to use */
661 _fm_canload, /* validation routine */
662 _fm_load, /* load routine */
663 NULL, /* save validation routine */
664 NULL /* save routine */