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 )
69 unsigned char *bb, *bb0;
72 bb0 = bb = (picoByte_t*) _pico_alloc(bufSize);
73 memcpy(bb, buffer, bufSize);
76 fm.fm_header_hdr = (fm_chunk_header_t *) bb;
77 fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size;
79 _pico_printf( PICO_VERBOSE, "IDENT: %s\n", (unsigned char *) fm.fm_header_hdr->ident );
81 if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME)) )
84 _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n");
87 return PICO_PMV_ERROR_IDENT;
91 if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER )
94 _pico_printf( PICO_WARNING, "FM Header Version incorrect\n");
97 return PICO_PMV_ERROR_VERSION;
101 fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
102 fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size;
103 #ifdef FM_VERBOSE_DBG
104 _pico_printf( PICO_VERBOSE, "SKIN: %s\n", (unsigned char *) fm.fm_skin_hdr->ident );
106 if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) )
109 _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n");
112 return PICO_PMV_ERROR_IDENT;
116 if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER )
119 _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n");
122 return PICO_PMV_ERROR_VERSION;
126 fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
127 fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size;
128 #ifdef FM_VERBOSE_DBG
129 _pico_printf( PICO_VERBOSE, "ST: %s\n", (unsigned char *) fm.fm_st_hdr->ident );
131 if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) )
134 _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n");
137 return PICO_PMV_ERROR_IDENT;
141 if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER )
144 _pico_printf( PICO_WARNING, "FM ST Version incorrect\n");
147 return PICO_PMV_ERROR_VERSION;
151 fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
152 fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size;
153 #ifdef FM_VERBOSE_DBG
154 _pico_printf( PICO_VERBOSE, "TRI: %s\n", (unsigned char *) fm.fm_tri_hdr->ident );
156 if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) )
159 _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n");
162 return PICO_PMV_ERROR_IDENT;
166 if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER )
169 _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n");
172 return PICO_PMV_ERROR_VERSION;
176 fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
177 fm_file_pos += sizeof(fm_chunk_header_t);
178 #ifdef FM_VERBOSE_DBG
179 _pico_printf( PICO_VERBOSE, "FRAME: %s\n", (unsigned char *) fm.fm_frame_hdr->ident );
181 if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) )
184 _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n");
187 return PICO_PMV_ERROR_IDENT;
191 if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER )
194 _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n");
197 return PICO_PMV_ERROR_VERSION;
200 // file seems to be a valid fm
206 // _fm_load() loads a Heretic 2 model file.
207 static picoModel_t *_fm_load( PM_PARAMS_LOAD )
209 int i, j, dups, dup_index;
212 index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3;
213 index_DUP_LUT_t *p_index_LUT_DUPS;
215 fm_vert_normal_t *vert;
217 char skinname[FM_SKINPATHSIZE];
219 fm_header_t *fm_head;
221 fm_xyz_st_t *tri_verts;
222 fm_xyz_st_t *triangle;
225 picoByte_t *bb, *bb0;
226 picoModel_t *picoModel;
227 picoSurface_t *picoSurface;
228 picoShader_t *picoShader;
229 picoVec3_t xyz, normal;
234 bb0 = bb = (picoByte_t*) _pico_alloc(bufSize);
235 memcpy(bb, buffer, bufSize);
238 fm.fm_header_hdr = (fm_chunk_header_t *) bb;
239 fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size;
240 if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME)) )
242 _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n");
247 if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER )
249 _pico_printf( PICO_WARNING, "FM Header Version incorrect\n");
255 fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
256 fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size;
257 if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) )
259 _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n");
264 if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER )
266 _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n");
272 fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
273 fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size;
274 if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) )
276 _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n");
281 if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER )
283 _pico_printf( PICO_WARNING, "FM ST Version incorrect\n");
289 fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
290 fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size;
291 if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) )
293 _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n");
298 if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER )
300 _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n");
306 fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
307 fm_file_pos += sizeof(fm_chunk_header_t);
308 if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) )
310 _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n");
315 if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER )
317 _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n");
323 fm_file_pos = sizeof(fm_chunk_header_t);
324 fm_head = fm.fm_header = (fm_header_t *) (bb + fm_file_pos);
325 fm_file_pos += fm.fm_header_hdr->size;
328 fm_file_pos += sizeof(fm_chunk_header_t);
329 fm.fm_skin = (fm_skinpath_t *) (bb + fm_file_pos);
330 fm_file_pos += fm.fm_skin_hdr->size;
333 fm_file_pos += sizeof(fm_chunk_header_t);
334 texCoord = fm.fm_st = (fm_st_t *) (bb + fm_file_pos);
335 fm_file_pos += fm.fm_st_hdr->size;
338 fm_file_pos += sizeof(fm_chunk_header_t);
339 tri_verts = fm.fm_tri = (fm_xyz_st_t *) (bb + fm_file_pos);
340 fm_file_pos += fm.fm_tri_hdr->size;
343 fm_file_pos += sizeof(fm_chunk_header_t);
344 frame = fm.fm_frame = (fm_frame_t *) (bb + fm_file_pos);
347 if( fm_head->numFrames < 1 )
349 _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );
354 if( frameNum < 0 || frameNum >= fm_head->numFrames )
356 _pico_printf( PICO_ERROR, "Invalid or out-of-range FM frame specified" );
362 fm_head->skinWidth = _pico_little_long( fm_head->skinWidth );
363 fm_head->skinHeight = _pico_little_long( fm_head->skinHeight );
364 fm_head->frameSize = _pico_little_long( fm_head->frameSize );
366 fm_head->numSkins = _pico_little_long( fm_head->numSkins );
367 fm_head->numXYZ = _pico_little_long( fm_head->numXYZ );
368 fm_head->numST = _pico_little_long( fm_head->numST );
369 fm_head->numTris = _pico_little_long( fm_head->numTris );
370 fm_head->numGLCmds = _pico_little_long( fm_head->numGLCmds );
371 fm_head->numFrames = _pico_little_long( fm_head->numFrames );
373 // swap frame scale and translation
374 for( i = 0; i < 3; i++ )
376 frame->header.scale[ i ] = _pico_little_float( frame->header.scale[ i ] );
377 frame->header.translate[ i ] = _pico_little_float( frame->header.translate[ i ] );
381 triangle = tri_verts;
382 for( i = 0; i < fm_head->numTris; i++, triangle++ )
384 for( j = 0; j < 3; j++ )
386 triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );
387 triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );
392 for( i = 0; i < fm_head->numST; i++ )
394 texCoord->s = _pico_little_short( texCoord[i].s );
395 texCoord->t = _pico_little_short( texCoord[i].t );
398 strncpy(skinname, (const char *) fm.fm_skin, FM_SKINPATHSIZE );
400 #ifdef FM_VERBOSE_DBG
401 // Print out md2 values
402 _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 );
406 _pico_setfext( skinname, "" );
407 _pico_unixify( skinname );
409 /* create new pico model */
410 picoModel = PicoNewModel();
411 if( picoModel == NULL )
413 _pico_printf( PICO_ERROR, "Unable to allocate a new model" );
419 PicoSetModelFrameNum( picoModel, frameNum );
420 PicoSetModelNumFrames( picoModel, fm_head->numFrames ); /* sea */
421 PicoSetModelName( picoModel, fileName );
422 PicoSetModelFileName( picoModel, fileName );
424 // allocate new pico surface
425 picoSurface = PicoNewSurface( picoModel );
426 if( picoSurface == NULL )
428 _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
429 PicoFreeModel( picoModel );
435 PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
436 PicoSetSurfaceName( picoSurface, frame->header.name );
437 picoShader = PicoNewShader( picoModel );
438 if( picoShader == NULL )
440 _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
441 PicoFreeModel( picoModel );
446 PicoSetShaderName( picoShader, skinname );
448 // associate current surface with newly created shader
449 PicoSetSurfaceShader( picoSurface, picoShader );
451 // Init LUT for Verts
452 p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * fm_head->numXYZ);
453 for(i=0; i<fm_head->numXYZ; i++)
455 p_index_LUT[i].Vert = -1;
456 p_index_LUT[i].ST = -1;
457 p_index_LUT[i].next = NULL;
460 // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert.
461 tot_numVerts = fm_head->numXYZ;
463 triangle = tri_verts;
465 for(i=0; i<fm_head->numTris; i++)
469 if (p_index_LUT[triangle->index_xyz[j]].ST == -1) // No Main Entry
470 p_index_LUT[triangle->index_xyz[j]].ST = triangle->index_st[j];
472 else if (triangle->index_st[j] == p_index_LUT[triangle->index_xyz[j]].ST ) // Equal to Main Entry
474 #ifdef FM_VERBOSE_DBG
475 _pico_printf( PICO_NORMAL, "-> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
479 else if ( (p_index_LUT[triangle->index_xyz[j]].next == NULL) ) // Not equal to Main entry, and no LL entry
480 { // Add first entry of LL from Main
481 p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));
482 if (p_index_LUT2 == NULL)
483 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n");
484 p_index_LUT[triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2;
485 p_index_LUT2->Vert = dups;
486 p_index_LUT2->ST = triangle->index_st[j];
487 p_index_LUT2->next = NULL;
488 #ifdef FM_VERBOSE_DBG
489 _pico_printf( PICO_NORMAL, " ADDING first LL XYZ:%d DUP:%d ST:%d\n", triangle->index_xyz[j], dups, triangle->index_st[j]);
491 triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
494 else // Try to find in LL from Main Entry
496 p_index_LUT3 = p_index_LUT2 = p_index_LUT[triangle->index_xyz[j]].next;
497 while ( (p_index_LUT2 != NULL) && (triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL
499 p_index_LUT3 = p_index_LUT2;
500 p_index_LUT2 = p_index_LUT2->next;
502 p_index_LUT2 = p_index_LUT3;
504 if ( triangle->index_st[j] == p_index_LUT2->ST ) // Found it
506 triangle->index_xyz[j] = p_index_LUT2->Vert + fm_head->numXYZ; // Make change in Tri hunk
507 #ifdef FM_VERBOSE_DBG
508 _pico_printf( PICO_NORMAL, "--> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
513 if ( p_index_LUT2->next == NULL) // Didn't find it. Add entry to LL.
516 p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));
517 if (p_index_LUT3 == NULL)
518 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n");
519 p_index_LUT2->next = (index_LUT_t *)p_index_LUT3;
520 p_index_LUT3->Vert = dups;
521 p_index_LUT3->ST = triangle->index_st[j];
522 p_index_LUT3->next = NULL;
523 #ifdef FM_VERBOSE_DBG
524 _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]);
526 triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
530 #ifdef FM_VERBOSE_DBG
531 _pico_printf( PICO_NORMAL, "---> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
537 // malloc and build array for Dup STs
538 p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups);
539 if (p_index_LUT_DUPS == NULL)
540 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n");
543 for(i=0; i<fm_head->numXYZ; i++)
545 p_index_LUT2 = p_index_LUT[i].next;
546 while (p_index_LUT2 != NULL)
548 p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i;
549 p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST;
551 p_index_LUT2 = p_index_LUT2->next;
554 #ifdef FM_VERBOSE_DBG
555 _pico_printf( PICO_NORMAL, " Dups = %d\n", dups);
556 _pico_printf( PICO_NORMAL, " Dup Index = %d\n", dup_index);
558 for(i=0; i<fm_head->numXYZ; i++)
560 #ifdef FM_VERBOSE_DBG
561 _pico_printf( PICO_NORMAL, "Vert: %4d\t%4d",i, p_index_LUT[i].ST);
563 if (p_index_LUT[i].next != NULL)
566 p_index_LUT2 = p_index_LUT[i].next;
568 #ifdef FM_VERBOSE_DBG
569 _pico_printf( PICO_NORMAL, " %4d %4d", p_index_LUT2->Vert, p_index_LUT2->ST);
571 p_index_LUT2 = p_index_LUT2->next;
572 } while ( p_index_LUT2 != NULL);
575 #ifdef FM_VERBOSE_DBG
576 _pico_printf( PICO_NORMAL, "\n");
581 #ifdef FM_VERBOSE_DBG
582 for(i=0; i<dup_index; i++)
583 _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);
585 triangle = tri_verts;
586 for(i=0; i<fm_head->numTris; i++)
589 _pico_printf( PICO_NORMAL, "Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
590 _pico_printf( PICO_NORMAL, "\n");
595 triangle = tri_verts;
596 for( j = 0; j < fm_head->numTris; j++, triangle++ )
598 PicoSetSurfaceIndex( picoSurface, j*3 , triangle->index_xyz[0] );
599 PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] );
600 PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] );
603 vert = (fm_vert_normal_t*) ((picoByte_t*) (frame->verts) );
604 for(i=0; i< fm_head->numXYZ; i++, vert++)
606 /* set vertex origin */
607 xyz[ 0 ] = vert->v[0] * frame->header.scale[0] + frame->header.translate[0];
608 xyz[ 1 ] = vert->v[1] * frame->header.scale[1] + frame->header.translate[1];
609 xyz[ 2 ] = vert->v[2] * frame->header.scale[2] + frame->header.translate[2];
610 PicoSetSurfaceXYZ( picoSurface, i , xyz );
613 normal[ 0 ] = fm_normals[vert->lightnormalindex][0];
614 normal[ 1 ] = fm_normals[vert->lightnormalindex][1];
615 normal[ 2 ] = fm_normals[vert->lightnormalindex][2];
616 PicoSetSurfaceNormal( picoSurface, i , normal );
619 st[ 0 ] = ((texCoord[p_index_LUT[i].ST].s) / ((float)fm_head->skinWidth));
620 st[ 1 ] = (texCoord[p_index_LUT[i].ST].t / ((float)fm_head->skinHeight));
621 PicoSetSurfaceST( picoSurface, 0, i , st );
626 for(i=0; i<dups; i++)
628 j = p_index_LUT_DUPS[i].OldVert;
629 /* set vertex origin */
630 xyz[ 0 ] = frame->verts[j].v[0] * frame->header.scale[0] + frame->header.translate[0];
631 xyz[ 1 ] = frame->verts[j].v[1] * frame->header.scale[1] + frame->header.translate[1];
632 xyz[ 2 ] = frame->verts[j].v[2] * frame->header.scale[2] + frame->header.translate[2];
633 PicoSetSurfaceXYZ( picoSurface, i + fm_head->numXYZ , xyz );
636 normal[ 0 ] = fm_normals[frame->verts[j].lightnormalindex][0];
637 normal[ 1 ] = fm_normals[frame->verts[j].lightnormalindex][1];
638 normal[ 2 ] = fm_normals[frame->verts[j].lightnormalindex][2];
639 PicoSetSurfaceNormal( picoSurface, i + fm_head->numXYZ , normal );
642 st[ 0 ] = ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)fm_head->skinWidth));
643 st[ 1 ] = (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)fm_head->skinHeight));
644 PicoSetSurfaceST( picoSurface, 0, i + fm_head->numXYZ , st );
649 PicoSetSurfaceColor( picoSurface, 0, 0, color );
651 // Free up malloc'ed LL entries
652 for(i=0; i<fm_head->numXYZ; i++)
654 if(p_index_LUT[i].next != NULL)
656 p_index_LUT2 = p_index_LUT[i].next;
658 p_index_LUT3 = p_index_LUT2->next;
659 _pico_free(p_index_LUT2);
660 p_index_LUT2 = p_index_LUT3;
662 } while (p_index_LUT2 != NULL);
667 _pico_printf(PICO_WARNING, " Not all LL mallocs freed\n");
669 // Free malloc'ed LUTs
670 _pico_free(p_index_LUT);
671 _pico_free(p_index_LUT_DUPS);
673 /* return the new pico model */
681 /* pico file format module definition */
682 const picoModule_t picoModuleFM =
684 "0.85", /* module version string */
685 "Heretic 2 FM", /* module display name */
686 "Nurail", /* author's name */
687 "2003 Nurail", /* module copyright */
689 "fm", NULL, NULL, NULL /* default extensions to use */
691 _fm_canload, /* validation routine */
692 _fm_load, /* load routine */
693 NULL, /* save validation routine */
694 NULL /* save routine */