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 ){
71 bb = (unsigned char *) buffer;
74 fm.fm_header_hdr = (fm_chunk_header_t *) bb;
75 fm_file_pos = sizeof( fm_chunk_header_t ) + fm.fm_header_hdr->size;
77 _pico_printf( PICO_VERBOSE, "IDENT: %s\n", (unsigned char *) fm.fm_header_hdr->ident );
79 if ( ( strcmp( fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME ) ) ) {
81 _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n" );
83 return PICO_PMV_ERROR_IDENT;
87 if ( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) {
89 _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" );
104 return PICO_PMV_ERROR_IDENT;
108 if ( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) {
110 _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n" );
112 return PICO_PMV_ERROR_VERSION;
116 fm.fm_st_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
117 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_st_hdr->size;
118 #ifdef FM_VERBOSE_DBG
119 _pico_printf( PICO_VERBOSE, "ST: %s\n", (unsigned char *) fm.fm_st_hdr->ident );
121 if ( ( strcmp( fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME ) ) ) {
123 _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n" );
125 return PICO_PMV_ERROR_IDENT;
129 if ( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) {
131 _pico_printf( PICO_WARNING, "FM ST Version incorrect\n" );
133 return PICO_PMV_ERROR_VERSION;
137 fm.fm_tri_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
138 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_tri_hdr->size;
139 #ifdef FM_VERBOSE_DBG
140 _pico_printf( PICO_VERBOSE, "TRI: %s\n", (unsigned char *) fm.fm_tri_hdr->ident );
142 if ( ( strcmp( fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME ) ) ) {
144 _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n" );
146 return PICO_PMV_ERROR_IDENT;
150 if ( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) {
152 _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n" );
154 return PICO_PMV_ERROR_VERSION;
158 fm.fm_frame_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
159 fm_file_pos += sizeof( fm_chunk_header_t );
160 #ifdef FM_VERBOSE_DBG
161 _pico_printf( PICO_VERBOSE, "FRAME: %s\n", (unsigned char *) fm.fm_frame_hdr->ident );
163 if ( ( strcmp( fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME ) ) ) {
165 _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n" );
167 return PICO_PMV_ERROR_IDENT;
171 if ( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) {
173 _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n" );
175 return PICO_PMV_ERROR_VERSION;
178 // file seems to be a valid fm
184 // _fm_load() loads a Heretic 2 model file.
185 static picoModel_t *_fm_load( PM_PARAMS_LOAD ){
186 int i, j, dups, dup_index;
189 index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3;
190 index_DUP_LUT_t *p_index_LUT_DUPS;
192 fm_vert_normal_t *vert;
194 char skinname[FM_SKINPATHSIZE];
196 fm_header_t *fm_head;
198 fm_xyz_st_t *tri_verts;
199 fm_xyz_st_t *triangle;
203 picoModel_t *picoModel;
204 picoSurface_t *picoSurface;
205 picoShader_t *picoShader;
206 picoVec3_t xyz, normal;
212 _pico_printf( PICO_NORMAL, "Loading \"%s\"", fileName );
214 bb = (picoByte_t*) buffer;
217 fm.fm_header_hdr = (fm_chunk_header_t *) bb;
218 fm_file_pos = sizeof( fm_chunk_header_t ) + fm.fm_header_hdr->size;
219 if ( ( strcmp( fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME ) ) ) {
220 _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n" );
224 if ( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) {
225 _pico_printf( PICO_WARNING, "FM Header Version incorrect\n" );
230 fm.fm_skin_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
231 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_skin_hdr->size;
232 if ( ( strcmp( fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME ) ) ) {
233 _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n" );
237 if ( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) {
238 _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n" );
243 fm.fm_st_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
244 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_st_hdr->size;
245 if ( ( strcmp( fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME ) ) ) {
246 _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n" );
250 if ( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) {
251 _pico_printf( PICO_WARNING, "FM ST Version incorrect\n" );
256 fm.fm_tri_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
257 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_tri_hdr->size;
258 if ( ( strcmp( fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME ) ) ) {
259 _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n" );
263 if ( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) {
264 _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n" );
269 fm.fm_frame_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
270 fm_file_pos += sizeof( fm_chunk_header_t );
271 if ( ( strcmp( fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME ) ) ) {
272 _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n" );
276 if ( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) {
277 _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n" );
282 fm_file_pos = sizeof( fm_chunk_header_t );
283 fm_head = fm.fm_header = (fm_header_t *) ( bb + fm_file_pos );
284 fm_file_pos += fm.fm_header_hdr->size;
287 fm_file_pos += sizeof( fm_chunk_header_t );
288 fm.fm_skin = (fm_skinpath_t *) ( bb + fm_file_pos );
289 fm_file_pos += fm.fm_skin_hdr->size;
292 fm_file_pos += sizeof( fm_chunk_header_t );
293 texCoord = fm.fm_st = (fm_st_t *) ( bb + fm_file_pos );
294 fm_file_pos += fm.fm_st_hdr->size;
297 fm_file_pos += sizeof( fm_chunk_header_t );
298 tri_verts = fm.fm_tri = (fm_xyz_st_t *) ( bb + fm_file_pos );
299 fm_file_pos += fm.fm_tri_hdr->size;
302 fm_file_pos += sizeof( fm_chunk_header_t );
303 frame = fm.fm_frame = (fm_frame_t *) ( bb + fm_file_pos );
306 if ( fm_head->numFrames < 1 ) {
307 _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );
311 if ( frameNum < 0 || frameNum >= fm_head->numFrames ) {
312 _pico_printf( PICO_ERROR, "Invalid or out-of-range FM frame specified" );
317 fm_head->skinWidth = _pico_little_long( fm_head->skinWidth );
318 fm_head->skinHeight = _pico_little_long( fm_head->skinHeight );
319 fm_head->frameSize = _pico_little_long( fm_head->frameSize );
321 fm_head->numSkins = _pico_little_long( fm_head->numSkins );
322 fm_head->numXYZ = _pico_little_long( fm_head->numXYZ );
323 fm_head->numST = _pico_little_long( fm_head->numST );
324 fm_head->numTris = _pico_little_long( fm_head->numTris );
325 fm_head->numGLCmds = _pico_little_long( fm_head->numGLCmds );
326 fm_head->numFrames = _pico_little_long( fm_head->numFrames );
328 // swap frame scale and translation
329 for ( i = 0; i < 3; i++ )
331 frame->header.scale[ i ] = _pico_little_float( frame->header.scale[ i ] );
332 frame->header.translate[ i ] = _pico_little_float( frame->header.translate[ i ] );
336 triangle = tri_verts;
337 for ( i = 0; i < fm_head->numTris; i++, triangle++ )
339 for ( j = 0; j < 3; j++ )
341 triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );
342 triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );
347 for ( i = 0; i < fm_head->numST; i++ )
349 texCoord->s = _pico_little_short( texCoord[i].s );
350 texCoord->t = _pico_little_short( texCoord[i].t );
353 strncpy( skinname, (unsigned char *) fm.fm_skin, FM_SKINPATHSIZE );
355 #ifdef FM_VERBOSE_DBG
356 // Print out md2 values
357 _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 );
361 _pico_setfext( skinname, "" );
362 _pico_unixify( skinname );
364 /* create new pico model */
365 picoModel = PicoNewModel();
366 if ( picoModel == NULL ) {
367 _pico_printf( PICO_ERROR, "Unable to allocate a new model" );
372 PicoSetModelFrameNum( picoModel, frameNum );
373 PicoSetModelNumFrames( picoModel, fm_head->numFrames ); /* sea */
374 PicoSetModelName( picoModel, fileName );
375 PicoSetModelFileName( picoModel, fileName );
377 // allocate new pico surface
378 picoSurface = PicoNewSurface( picoModel );
379 if ( picoSurface == NULL ) {
380 _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
381 PicoFreeModel( picoModel );
386 PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
387 PicoSetSurfaceName( picoSurface, frame->header.name );
388 picoShader = PicoNewShader( picoModel );
389 if ( picoShader == NULL ) {
390 _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
391 PicoFreeModel( picoModel );
395 PicoSetShaderName( picoShader, skinname );
397 // associate current surface with newly created shader
398 PicoSetSurfaceShader( picoSurface, picoShader );
400 // Init LUT for Verts
401 p_index_LUT = (index_LUT_t *)_pico_alloc( sizeof( index_LUT_t ) * fm_head->numXYZ );
402 for ( i = 0; i < fm_head->numXYZ; i++ )
404 p_index_LUT[i].Vert = -1;
405 p_index_LUT[i].ST = -1;
406 p_index_LUT[i].next = NULL;
409 // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert.
410 tot_numVerts = fm_head->numXYZ;
412 triangle = tri_verts;
414 for ( i = 0; i < fm_head->numTris; i++ )
416 for ( j = 0; j < 3; j++ )
418 if ( p_index_LUT[triangle->index_xyz[j]].ST == -1 ) { // No Main Entry
419 p_index_LUT[triangle->index_xyz[j]].ST = triangle->index_st[j];
422 else if ( triangle->index_st[j] == p_index_LUT[triangle->index_xyz[j]].ST ) { // Equal to Main Entry
423 #ifdef FM_VERBOSE_DBG
424 _pico_printf( PICO_NORMAL, "-> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
428 else if ( ( p_index_LUT[triangle->index_xyz[j]].next == NULL ) ) { // Not equal to Main entry, and no LL entry
429 // Add first entry of LL from Main
430 p_index_LUT2 = (index_LUT_t *)_pico_alloc( sizeof( index_LUT_t ) );
431 if ( p_index_LUT2 == NULL ) {
432 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n" );
434 p_index_LUT[triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2;
435 p_index_LUT2->Vert = dups;
436 p_index_LUT2->ST = triangle->index_st[j];
437 p_index_LUT2->next = NULL;
438 #ifdef FM_VERBOSE_DBG
439 _pico_printf( PICO_NORMAL, " ADDING first LL XYZ:%d DUP:%d ST:%d\n", triangle->index_xyz[j], dups, triangle->index_st[j] );
441 triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
444 else // Try to find in LL from Main Entry
446 p_index_LUT3 = p_index_LUT2 = p_index_LUT[triangle->index_xyz[j]].next;
447 while ( ( p_index_LUT2 != NULL ) && ( triangle->index_xyz[j] != p_index_LUT2->Vert ) ) // Walk down LL
449 p_index_LUT3 = p_index_LUT2;
450 p_index_LUT2 = p_index_LUT2->next;
452 p_index_LUT2 = p_index_LUT3;
454 if ( triangle->index_st[j] == p_index_LUT2->ST ) { // Found it
455 triangle->index_xyz[j] = p_index_LUT2->Vert + fm_head->numXYZ; // Make change in Tri hunk
456 #ifdef FM_VERBOSE_DBG
457 _pico_printf( PICO_NORMAL, "--> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
462 if ( p_index_LUT2->next == NULL ) { // Didn't find it. Add entry to LL.
464 p_index_LUT3 = (index_LUT_t *)_pico_alloc( sizeof( index_LUT_t ) );
465 if ( p_index_LUT3 == NULL ) {
466 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n" );
468 p_index_LUT2->next = (index_LUT_t *)p_index_LUT3;
469 p_index_LUT3->Vert = dups;
470 p_index_LUT3->ST = triangle->index_st[j];
471 p_index_LUT3->next = NULL;
472 #ifdef FM_VERBOSE_DBG
473 _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] );
475 triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
479 #ifdef FM_VERBOSE_DBG
480 _pico_printf( PICO_NORMAL, "---> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
486 // malloc and build array for Dup STs
487 p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc( sizeof( index_DUP_LUT_t ) * dups );
488 if ( p_index_LUT_DUPS == NULL ) {
489 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n" );
493 for ( i = 0; i < fm_head->numXYZ; i++ )
495 p_index_LUT2 = p_index_LUT[i].next;
496 while ( p_index_LUT2 != NULL )
498 p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i;
499 p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST;
501 p_index_LUT2 = p_index_LUT2->next;
504 #ifdef FM_VERBOSE_DBG
505 _pico_printf( PICO_NORMAL, " Dups = %d\n", dups );
506 _pico_printf( PICO_NORMAL, " Dup Index = %d\n", dup_index );
508 for ( i = 0; i < fm_head->numXYZ; i++ )
510 #ifdef FM_VERBOSE_DBG
511 _pico_printf( PICO_NORMAL, "Vert: %4d\t%4d",i, p_index_LUT[i].ST );
513 if ( p_index_LUT[i].next != NULL ) {
515 p_index_LUT2 = p_index_LUT[i].next;
517 #ifdef FM_VERBOSE_DBG
518 _pico_printf( PICO_NORMAL, " %4d %4d", p_index_LUT2->Vert, p_index_LUT2->ST );
520 p_index_LUT2 = p_index_LUT2->next;
521 } while ( p_index_LUT2 != NULL );
524 #ifdef FM_VERBOSE_DBG
525 _pico_printf( PICO_NORMAL, "\n" );
530 #ifdef FM_VERBOSE_DBG
531 for ( i = 0; i < dup_index; i++ )
532 _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 );
534 triangle = tri_verts;
535 for ( i = 0; i < fm_head->numTris; i++ )
537 for ( j = 0; j < 3; j++ )
538 _pico_printf( PICO_NORMAL, "Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
539 _pico_printf( PICO_NORMAL, "\n" );
544 triangle = tri_verts;
545 for ( j = 0; j < fm_head->numTris; j++, triangle++ )
547 PicoSetSurfaceIndex( picoSurface, j * 3, triangle->index_xyz[0] );
548 PicoSetSurfaceIndex( picoSurface, j * 3 + 1, triangle->index_xyz[1] );
549 PicoSetSurfaceIndex( picoSurface, j * 3 + 2, triangle->index_xyz[2] );
552 vert = (fm_vert_normal_t*) ( (picoByte_t*) ( frame->verts ) );
553 for ( i = 0; i < fm_head->numXYZ; i++, vert++ )
555 /* set vertex origin */
556 xyz[ 0 ] = vert->v[0] * frame->header.scale[0] + frame->header.translate[0];
557 xyz[ 1 ] = vert->v[1] * frame->header.scale[1] + frame->header.translate[1];
558 xyz[ 2 ] = vert->v[2] * frame->header.scale[2] + frame->header.translate[2];
559 PicoSetSurfaceXYZ( picoSurface, i, xyz );
562 normal[ 0 ] = fm_normals[vert->lightnormalindex][0];
563 normal[ 1 ] = fm_normals[vert->lightnormalindex][1];
564 normal[ 2 ] = fm_normals[vert->lightnormalindex][2];
565 PicoSetSurfaceNormal( picoSurface, i, normal );
568 st[ 0 ] = ( ( texCoord[p_index_LUT[i].ST].s ) / ( (float)fm_head->skinWidth ) );
569 st[ 1 ] = ( texCoord[p_index_LUT[i].ST].t / ( (float)fm_head->skinHeight ) );
570 PicoSetSurfaceST( picoSurface, 0, i, st );
574 for ( i = 0; i < dups; i++ )
576 j = p_index_LUT_DUPS[i].OldVert;
577 /* set vertex origin */
578 xyz[ 0 ] = frame->verts[j].v[0] * frame->header.scale[0] + frame->header.translate[0];
579 xyz[ 1 ] = frame->verts[j].v[1] * frame->header.scale[1] + frame->header.translate[1];
580 xyz[ 2 ] = frame->verts[j].v[2] * frame->header.scale[2] + frame->header.translate[2];
581 PicoSetSurfaceXYZ( picoSurface, i + fm_head->numXYZ, xyz );
584 normal[ 0 ] = fm_normals[frame->verts[j].lightnormalindex][0];
585 normal[ 1 ] = fm_normals[frame->verts[j].lightnormalindex][1];
586 normal[ 2 ] = fm_normals[frame->verts[j].lightnormalindex][2];
587 PicoSetSurfaceNormal( picoSurface, i + fm_head->numXYZ, normal );
590 st[ 0 ] = ( ( texCoord[p_index_LUT_DUPS[i].ST].s ) / ( (float)fm_head->skinWidth ) );
591 st[ 1 ] = ( texCoord[p_index_LUT_DUPS[i].ST].t / ( (float)fm_head->skinHeight ) );
592 PicoSetSurfaceST( picoSurface, 0, i + fm_head->numXYZ, st );
597 PicoSetSurfaceColor( picoSurface, 0, 0, color );
599 // Free up malloc'ed LL entries
600 for ( i = 0; i < fm_head->numXYZ; i++ )
602 if ( p_index_LUT[i].next != NULL ) {
603 p_index_LUT2 = p_index_LUT[i].next;
605 p_index_LUT3 = p_index_LUT2->next;
606 _pico_free( p_index_LUT2 );
607 p_index_LUT2 = p_index_LUT3;
609 } while ( p_index_LUT2 != NULL );
614 _pico_printf( PICO_WARNING, " Not all LL mallocs freed\n" );
617 // Free malloc'ed LUTs
618 _pico_free( p_index_LUT );
619 _pico_free( p_index_LUT_DUPS );
621 /* return the new pico model */
628 /* pico file format module definition */
629 const picoModule_t picoModuleFM =
631 "0.85", /* module version string */
632 "Heretic 2 FM", /* module display name */
633 "Nurail", /* author's name */
634 "2003 Nurail", /* module copyright */
636 "fm", NULL, NULL, NULL /* default extensions to use */
638 _fm_canload, /* validation routine */
639 _fm_load, /* load routine */
640 NULL, /* save validation routine */
641 NULL /* save routine */