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;
217 bb0 = bb = (picoByte_t*) _pico_alloc( bufSize );
218 memcpy( bb, buffer, bufSize );
221 fm.fm_header_hdr = (fm_chunk_header_t *) bb;
222 fm_file_pos = sizeof( fm_chunk_header_t ) + fm.fm_header_hdr->size;
223 if ( ( strcmp( fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME ) ) ) {
224 _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n" );
229 if ( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) {
230 _pico_printf( PICO_WARNING, "FM Header Version incorrect\n" );
236 fm.fm_skin_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
237 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_skin_hdr->size;
238 if ( ( strcmp( fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME ) ) ) {
239 _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n" );
244 if ( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) {
245 _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n" );
251 fm.fm_st_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
252 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_st_hdr->size;
253 if ( ( strcmp( fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME ) ) ) {
254 _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n" );
259 if ( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) {
260 _pico_printf( PICO_WARNING, "FM ST Version incorrect\n" );
266 fm.fm_tri_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
267 fm_file_pos += sizeof( fm_chunk_header_t ) + fm.fm_tri_hdr->size;
268 if ( ( strcmp( fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME ) ) ) {
269 _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n" );
274 if ( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) {
275 _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n" );
281 fm.fm_frame_hdr = (fm_chunk_header_t *) ( bb + fm_file_pos );
282 fm_file_pos += sizeof( fm_chunk_header_t );
283 if ( ( strcmp( fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME ) ) ) {
284 _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n" );
289 if ( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) {
290 _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n" );
296 fm_file_pos = sizeof( fm_chunk_header_t );
297 fm_head = fm.fm_header = (fm_header_t *) ( bb + fm_file_pos );
298 fm_file_pos += fm.fm_header_hdr->size;
301 fm_file_pos += sizeof( fm_chunk_header_t );
302 fm.fm_skin = (fm_skinpath_t *) ( bb + fm_file_pos );
303 fm_file_pos += fm.fm_skin_hdr->size;
306 fm_file_pos += sizeof( fm_chunk_header_t );
307 texCoord = fm.fm_st = (fm_st_t *) ( bb + fm_file_pos );
308 fm_file_pos += fm.fm_st_hdr->size;
311 fm_file_pos += sizeof( fm_chunk_header_t );
312 tri_verts = fm.fm_tri = (fm_xyz_st_t *) ( bb + fm_file_pos );
313 fm_file_pos += fm.fm_tri_hdr->size;
316 fm_file_pos += sizeof( fm_chunk_header_t );
317 frame = fm.fm_frame = (fm_frame_t *) ( bb + fm_file_pos );
320 if ( fm_head->numFrames < 1 ) {
321 _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );
326 if ( frameNum < 0 || frameNum >= fm_head->numFrames ) {
327 _pico_printf( PICO_ERROR, "Invalid or out-of-range FM frame specified" );
333 fm_head->skinWidth = _pico_little_long( fm_head->skinWidth );
334 fm_head->skinHeight = _pico_little_long( fm_head->skinHeight );
335 fm_head->frameSize = _pico_little_long( fm_head->frameSize );
337 fm_head->numSkins = _pico_little_long( fm_head->numSkins );
338 fm_head->numXYZ = _pico_little_long( fm_head->numXYZ );
339 fm_head->numST = _pico_little_long( fm_head->numST );
340 fm_head->numTris = _pico_little_long( fm_head->numTris );
341 fm_head->numGLCmds = _pico_little_long( fm_head->numGLCmds );
342 fm_head->numFrames = _pico_little_long( fm_head->numFrames );
344 // swap frame scale and translation
345 for ( i = 0; i < 3; i++ )
347 frame->header.scale[ i ] = _pico_little_float( frame->header.scale[ i ] );
348 frame->header.translate[ i ] = _pico_little_float( frame->header.translate[ i ] );
352 triangle = tri_verts;
353 for ( i = 0; i < fm_head->numTris; i++, triangle++ )
355 for ( j = 0; j < 3; j++ )
357 triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );
358 triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );
363 for ( i = 0; i < fm_head->numST; i++ )
365 texCoord->s = _pico_little_short( texCoord[i].s );
366 texCoord->t = _pico_little_short( texCoord[i].t );
369 strncpy( skinname, (const char *) fm.fm_skin, FM_SKINPATHSIZE );
371 #ifdef FM_VERBOSE_DBG
372 // Print out md2 values
373 _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 );
377 _pico_setfext( skinname, NULL );
378 _pico_unixify( skinname );
380 /* create new pico model */
381 picoModel = PicoNewModel();
382 if ( picoModel == NULL ) {
383 _pico_printf( PICO_ERROR, "Unable to allocate a new model" );
389 PicoSetModelFrameNum( picoModel, frameNum );
390 PicoSetModelNumFrames( picoModel, fm_head->numFrames ); /* sea */
391 PicoSetModelName( picoModel, fileName );
392 PicoSetModelFileName( picoModel, fileName );
394 // allocate new pico surface
395 picoSurface = PicoNewSurface( picoModel );
396 if ( picoSurface == NULL ) {
397 _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
398 PicoFreeModel( picoModel );
404 PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
405 PicoSetSurfaceName( picoSurface, frame->header.name );
406 picoShader = PicoNewShader( picoModel );
407 if ( picoShader == NULL ) {
408 _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
409 PicoFreeModel( picoModel );
414 PicoSetShaderName( picoShader, skinname );
416 // associate current surface with newly created shader
417 PicoSetSurfaceShader( picoSurface, picoShader );
419 // Init LUT for Verts
420 p_index_LUT = (index_LUT_t *)_pico_alloc( sizeof( index_LUT_t ) * fm_head->numXYZ );
421 for ( i = 0; i < fm_head->numXYZ; i++ )
423 p_index_LUT[i].Vert = -1;
424 p_index_LUT[i].ST = -1;
425 p_index_LUT[i].next = NULL;
428 // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert.
430 triangle = tri_verts;
432 for ( i = 0; i < fm_head->numTris; i++ )
434 for ( j = 0; j < 3; j++ )
436 if ( p_index_LUT[triangle->index_xyz[j]].ST == -1 ) { // No Main Entry
437 p_index_LUT[triangle->index_xyz[j]].ST = triangle->index_st[j];
440 else if ( triangle->index_st[j] == p_index_LUT[triangle->index_xyz[j]].ST ) { // Equal to Main Entry
441 #ifdef FM_VERBOSE_DBG
442 _pico_printf( PICO_NORMAL, "-> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
446 else if ( ( p_index_LUT[triangle->index_xyz[j]].next == NULL ) ) { // Not equal to Main entry, and no LL entry
447 // Add first entry of LL from Main
448 p_index_LUT2 = (index_LUT_t *)_pico_alloc( sizeof( index_LUT_t ) );
449 if ( p_index_LUT2 == NULL ) {
450 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n" );
452 p_index_LUT[triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2;
453 p_index_LUT2->Vert = dups;
454 p_index_LUT2->ST = triangle->index_st[j];
455 p_index_LUT2->next = NULL;
456 #ifdef FM_VERBOSE_DBG
457 _pico_printf( PICO_NORMAL, " ADDING first LL XYZ:%d DUP:%d ST:%d\n", triangle->index_xyz[j], dups, triangle->index_st[j] );
459 triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
462 else // Try to find in LL from Main Entry
464 p_index_LUT3 = p_index_LUT2 = p_index_LUT[triangle->index_xyz[j]].next;
465 while ( ( p_index_LUT2 != NULL ) && ( triangle->index_xyz[j] != p_index_LUT2->Vert ) ) // Walk down LL
467 p_index_LUT3 = p_index_LUT2;
468 p_index_LUT2 = p_index_LUT2->next;
470 p_index_LUT2 = p_index_LUT3;
472 if ( triangle->index_st[j] == p_index_LUT2->ST ) { // Found it
473 triangle->index_xyz[j] = p_index_LUT2->Vert + fm_head->numXYZ; // Make change in Tri hunk
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] );
480 if ( p_index_LUT2->next == NULL ) { // Didn't find it. Add entry to LL.
482 p_index_LUT3 = (index_LUT_t *)_pico_alloc( sizeof( index_LUT_t ) );
483 if ( p_index_LUT3 == NULL ) {
484 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n" );
486 p_index_LUT2->next = (index_LUT_t *)p_index_LUT3;
487 p_index_LUT3->Vert = dups;
488 p_index_LUT3->ST = triangle->index_st[j];
489 p_index_LUT3->next = NULL;
490 #ifdef FM_VERBOSE_DBG
491 _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] );
493 triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
497 #ifdef FM_VERBOSE_DBG
498 _pico_printf( PICO_NORMAL, "---> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
504 // malloc and build array for Dup STs
505 p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc( sizeof( index_DUP_LUT_t ) * dups );
506 if ( p_index_LUT_DUPS == NULL ) {
507 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n" );
511 for ( i = 0; i < fm_head->numXYZ; i++ )
513 p_index_LUT2 = p_index_LUT[i].next;
514 while ( p_index_LUT2 != NULL )
516 p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i;
517 p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST;
519 p_index_LUT2 = p_index_LUT2->next;
522 #ifdef FM_VERBOSE_DBG
523 _pico_printf( PICO_NORMAL, " Dups = %d\n", dups );
524 _pico_printf( PICO_NORMAL, " Dup Index = %d\n", dup_index );
526 for ( i = 0; i < fm_head->numXYZ; i++ )
528 #ifdef FM_VERBOSE_DBG
529 _pico_printf( PICO_NORMAL, "Vert: %4d\t%4d",i, p_index_LUT[i].ST );
531 if ( p_index_LUT[i].next != NULL ) {
533 p_index_LUT2 = p_index_LUT[i].next;
535 #ifdef FM_VERBOSE_DBG
536 _pico_printf( PICO_NORMAL, " %4d %4d", p_index_LUT2->Vert, p_index_LUT2->ST );
538 p_index_LUT2 = p_index_LUT2->next;
539 } while ( p_index_LUT2 != NULL );
542 #ifdef FM_VERBOSE_DBG
543 _pico_printf( PICO_NORMAL, "\n" );
548 #ifdef FM_VERBOSE_DBG
549 for ( i = 0; i < dup_index; i++ )
550 _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 );
552 triangle = tri_verts;
553 for ( i = 0; i < fm_head->numTris; i++ )
555 for ( j = 0; j < 3; j++ )
556 _pico_printf( PICO_NORMAL, "Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j] );
557 _pico_printf( PICO_NORMAL, "\n" );
562 triangle = tri_verts;
563 for ( j = 0; j < fm_head->numTris; j++, triangle++ )
565 PicoSetSurfaceIndex( picoSurface, j * 3, triangle->index_xyz[0] );
566 PicoSetSurfaceIndex( picoSurface, j * 3 + 1, triangle->index_xyz[1] );
567 PicoSetSurfaceIndex( picoSurface, j * 3 + 2, triangle->index_xyz[2] );
570 vert = (fm_vert_normal_t*) ( (picoByte_t*) ( frame->verts ) );
571 for ( i = 0; i < fm_head->numXYZ; i++, vert++ )
573 /* set vertex origin */
574 xyz[ 0 ] = vert->v[0] * frame->header.scale[0] + frame->header.translate[0];
575 xyz[ 1 ] = vert->v[1] * frame->header.scale[1] + frame->header.translate[1];
576 xyz[ 2 ] = vert->v[2] * frame->header.scale[2] + frame->header.translate[2];
577 PicoSetSurfaceXYZ( picoSurface, i, xyz );
580 normal[ 0 ] = fm_normals[vert->lightnormalindex][0];
581 normal[ 1 ] = fm_normals[vert->lightnormalindex][1];
582 normal[ 2 ] = fm_normals[vert->lightnormalindex][2];
583 PicoSetSurfaceNormal( picoSurface, i, normal );
586 st[ 0 ] = ( ( texCoord[p_index_LUT[i].ST].s ) / ( (float)fm_head->skinWidth ) );
587 st[ 1 ] = ( texCoord[p_index_LUT[i].ST].t / ( (float)fm_head->skinHeight ) );
588 PicoSetSurfaceST( picoSurface, 0, i, st );
591 PicoSetSurfaceColor( picoSurface, 0, i, picoColor_white );
595 for ( i = 0; i < dups; i++ )
597 j = p_index_LUT_DUPS[i].OldVert;
598 /* set vertex origin */
599 xyz[ 0 ] = frame->verts[j].v[0] * frame->header.scale[0] + frame->header.translate[0];
600 xyz[ 1 ] = frame->verts[j].v[1] * frame->header.scale[1] + frame->header.translate[1];
601 xyz[ 2 ] = frame->verts[j].v[2] * frame->header.scale[2] + frame->header.translate[2];
602 PicoSetSurfaceXYZ( picoSurface, i + fm_head->numXYZ, xyz );
605 normal[ 0 ] = fm_normals[frame->verts[j].lightnormalindex][0];
606 normal[ 1 ] = fm_normals[frame->verts[j].lightnormalindex][1];
607 normal[ 2 ] = fm_normals[frame->verts[j].lightnormalindex][2];
608 PicoSetSurfaceNormal( picoSurface, i + fm_head->numXYZ, normal );
611 st[ 0 ] = ( ( texCoord[p_index_LUT_DUPS[i].ST].s ) / ( (float)fm_head->skinWidth ) );
612 st[ 1 ] = ( texCoord[p_index_LUT_DUPS[i].ST].t / ( (float)fm_head->skinHeight ) );
613 PicoSetSurfaceST( picoSurface, 0, i + fm_head->numXYZ, st );
616 PicoSetSurfaceColor( picoSurface, 0, i + fm_head->numXYZ, picoColor_white );
620 // Free up malloc'ed LL entries
621 for ( i = 0; i < fm_head->numXYZ; i++ )
623 if ( p_index_LUT[i].next != NULL ) {
624 p_index_LUT2 = p_index_LUT[i].next;
626 p_index_LUT3 = p_index_LUT2->next;
627 _pico_free( p_index_LUT2 );
628 p_index_LUT2 = p_index_LUT3;
630 } while ( p_index_LUT2 != NULL );
635 _pico_printf( PICO_WARNING, " Not all LL mallocs freed\n" );
638 // Free malloc'ed LUTs
639 _pico_free( p_index_LUT );
640 _pico_free( p_index_LUT_DUPS );
642 /* return the new pico model */
650 /* pico file format module definition */
651 const picoModule_t picoModuleFM =
653 "0.85", /* module version string */
654 "Heretic 2 FM", /* module display name */
655 "Nurail", /* author's name */
656 "2003 Nurail", /* module copyright */
658 "fm", NULL, NULL, NULL /* default extensions to use */
660 _fm_canload, /* validation routine */
661 _fm_load, /* load routine */
662 NULL, /* save validation routine */
663 NULL /* save routine */