]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/picomodel/pm_fm.c
merge branch work back into trunk
[xonotic/netradiant.git] / libs / picomodel / pm_fm.c
1 /* -----------------------------------------------------------------------------
2
3 PicoModel Library
4
5 Copyright (c) 2002, Randy Reddig & seaw0lf
6 All rights reserved.
7
8 Redistribution and use in source and binary forms, with or without modification,
9 are permitted provided that the following conditions are met:
10
11 Redistributions of source code must retain the above copyright notice, this list
12 of conditions and the following disclaimer.
13
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.
17
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.
21
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.
32
33 ----------------------------------------------------------------------------- */
34
35 /*
36 Nurail: Used pm_md3.c (Randy Reddig) as a template.
37 */
38
39 /* marker */
40 #define PM_FM_C
41
42 /* dependencies */
43 #include "pm_fm.h"
44
45 //#define FM_VERBOSE_DBG        0
46 #undef FM_VERBOSE_DBG
47 #undef FM_DBG
48
49 typedef struct index_LUT_s
50 {
51         short   Vert;
52         short   ST;
53         struct  index_LUT_s     *next;
54
55 } index_LUT_t;
56
57 typedef struct index_DUP_LUT_s
58 {
59         short                   ST;
60         short                   OldVert;
61
62 } index_DUP_LUT_t;
63
64
65 // _fm_canload()
66 static int _fm_canload( PM_PARAMS_CANLOAD )
67 {
68         fm_t            fm;
69         unsigned char   *bb;
70         int             fm_file_pos;
71
72         bb = (unsigned char *) buffer;
73
74         // Header
75         fm.fm_header_hdr = (fm_chunk_header_t *) bb;
76         fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size;
77 #ifdef FM_VERBOSE_DBG
78         _pico_printf( PICO_VERBOSE, "IDENT: %s\n", (unsigned char *) fm.fm_header_hdr->ident );
79 #endif
80         if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME))  )
81         {
82 #ifdef FM_DBG
83                 _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n");
84 #endif
85                 return PICO_PMV_ERROR_IDENT;
86         }
87
88         // check fm
89         if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER )
90         {
91 #ifdef FM_DBG
92                 _pico_printf( PICO_WARNING, "FM Header Version incorrect\n");
93 #endif
94                 return PICO_PMV_ERROR_VERSION;
95         }
96
97         // Skin
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 );
102 #endif
103         if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) )
104         {
105 #ifdef FM_DBG
106                 _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n");
107 #endif
108                 return PICO_PMV_ERROR_IDENT;
109         }
110
111         // check fm
112         if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER )
113         {
114 #ifdef FM_DBG
115                 _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n");
116 #endif
117                 return PICO_PMV_ERROR_VERSION;
118         }
119
120         // st
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 );
125 #endif
126         if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) )
127         {
128 #ifdef FM_DBG
129                 _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n");
130 #endif
131                 return PICO_PMV_ERROR_IDENT;
132         }
133
134         // check fm
135         if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER )
136         {
137 #ifdef FM_DBG
138                 _pico_printf( PICO_WARNING, "FM ST Version incorrect\n");
139 #endif
140                 return PICO_PMV_ERROR_VERSION;
141         }
142
143         // tri
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 );
148 #endif
149         if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) )
150         {
151 #ifdef FM_DBG
152                 _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n");
153 #endif
154                 return PICO_PMV_ERROR_IDENT;
155         }
156
157         // check fm
158         if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER )
159         {
160 #ifdef FM_DBG
161                 _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n");
162 #endif
163                 return PICO_PMV_ERROR_VERSION;
164         }
165
166         // frame
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 );
171 #endif
172         if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) )
173         {
174 #ifdef FM_DBG
175                 _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n");
176 #endif
177                 return PICO_PMV_ERROR_IDENT;
178         }
179
180         // check fm
181         if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER )
182         {
183 #ifdef FM_DBG
184                 _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n");
185 #endif
186                 return PICO_PMV_ERROR_VERSION;
187         }
188
189         // file seems to be a valid fm
190         return PICO_PMV_OK;
191 }
192
193
194
195 // _fm_load() loads a Heretic 2 model file.
196 static picoModel_t *_fm_load( PM_PARAMS_LOAD )
197 {
198         int                             i, j, dups, dup_index;
199         int                             fm_file_pos;
200         short                   tot_numVerts;
201         index_LUT_t             *p_index_LUT, *p_index_LUT2, *p_index_LUT3;
202         index_DUP_LUT_t *p_index_LUT_DUPS;
203
204         fm_vert_normal_t        *vert;
205
206         char                    skinname[FM_SKINPATHSIZE];
207         fm_t                    fm;
208         fm_header_t             *fm_head;
209         fm_st_t                 *texCoord;
210         fm_xyz_st_t             *tri_verts;
211         fm_xyz_st_t             *triangle;
212         fm_frame_t              *frame;
213
214         picoByte_t      *bb;
215         picoModel_t     *picoModel;
216         picoSurface_t   *picoSurface;
217         picoShader_t    *picoShader;
218         picoVec3_t      xyz, normal;
219         picoVec2_t      st;
220         picoColor_t     color;
221         
222
223         // fm loading
224         _pico_printf( PICO_NORMAL, "Loading \"%s\"", fileName );
225
226         bb = (picoByte_t*) buffer;
227
228         // Header Header
229         fm.fm_header_hdr = (fm_chunk_header_t *) bb;
230         fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size;
231         if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME))  )
232         {
233                 _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n");
234                 return NULL;
235         }
236
237         if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER )
238         {
239                 _pico_printf( PICO_WARNING, "FM Header Version incorrect\n");
240                 return NULL;
241         }
242
243         // Skin Header
244         fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
245         fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size;
246         if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) )
247         {
248                 _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n");
249                 return NULL;
250         }
251
252         if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER )
253         {
254                 _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n");
255                 return NULL;
256         }
257
258         // ST Header
259         fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
260         fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size;
261         if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) )
262         {
263                 _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n");
264                 return NULL;
265         }
266
267         if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER )
268         {
269                 _pico_printf( PICO_WARNING, "FM ST Version incorrect\n");
270                 return NULL;
271         }
272
273         // Tris Header
274         fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
275         fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size;
276         if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) )
277         {
278                 _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n");
279                 return NULL;
280         }
281
282         if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER )
283         {
284                 _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n");
285                 return NULL;
286         }
287
288         // Frame Header
289         fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
290         fm_file_pos += sizeof(fm_chunk_header_t);
291         if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) )
292         {
293                 _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n");
294                 return NULL;
295         }
296
297         if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER )
298         {
299                 _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n");
300                 return NULL;
301         }
302
303         // Header
304         fm_file_pos = sizeof(fm_chunk_header_t);
305         fm_head = fm.fm_header = (fm_header_t *) (bb + fm_file_pos);
306         fm_file_pos += fm.fm_header_hdr->size;
307
308         // Skin
309         fm_file_pos += sizeof(fm_chunk_header_t);
310         fm.fm_skin = (fm_skinpath_t *) (bb + fm_file_pos);
311         fm_file_pos += fm.fm_skin_hdr->size;
312
313         // ST
314         fm_file_pos += sizeof(fm_chunk_header_t);
315         texCoord = fm.fm_st = (fm_st_t *) (bb + fm_file_pos);
316         fm_file_pos += fm.fm_st_hdr->size;
317
318         // Tri
319         fm_file_pos += sizeof(fm_chunk_header_t);
320         tri_verts = fm.fm_tri = (fm_xyz_st_t *) (bb + fm_file_pos);
321         fm_file_pos += fm.fm_tri_hdr->size;
322
323         // Frame
324         fm_file_pos += sizeof(fm_chunk_header_t);
325         frame = fm.fm_frame = (fm_frame_t *) (bb + fm_file_pos);
326
327         // do frame check
328         if( fm_head->numFrames < 1 )
329         {
330                 _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );
331                 return NULL;
332         }
333         
334         if( frameNum < 0 || frameNum >= fm_head->numFrames )
335         {
336                 _pico_printf( PICO_ERROR, "Invalid or out-of-range FM frame specified" );
337                 return NULL;
338         }
339
340         // swap fm
341         fm_head->skinWidth = _pico_little_long( fm_head->skinWidth );
342         fm_head->skinHeight = _pico_little_long( fm_head->skinHeight );
343         fm_head->frameSize = _pico_little_long( fm_head->frameSize );
344
345         fm_head->numSkins = _pico_little_long( fm_head->numSkins );
346         fm_head->numXYZ = _pico_little_long( fm_head->numXYZ );
347         fm_head->numST = _pico_little_long( fm_head->numST );
348         fm_head->numTris = _pico_little_long( fm_head->numTris );
349         fm_head->numGLCmds = _pico_little_long( fm_head->numGLCmds );
350         fm_head->numFrames = _pico_little_long( fm_head->numFrames );
351
352         // swap frame scale and translation
353         for( i = 0; i < 3; i++ )
354         {
355                 frame->header.scale[ i ] = _pico_little_float( frame->header.scale[ i ] );
356                 frame->header.translate[ i ] = _pico_little_float( frame->header.translate[ i ] );
357         }
358
359         // swap triangles
360         triangle = tri_verts;
361         for( i = 0; i < fm_head->numTris; i++, triangle++ )
362         {
363                 for( j = 0; j < 3; j++ )
364                 {
365                         triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );
366                         triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );
367                 }
368         }
369
370         // swap st coords
371         for( i = 0; i < fm_head->numST; i++ )
372         {
373                 texCoord->s = _pico_little_short( texCoord[i].s );
374                 texCoord->t = _pico_little_short( texCoord[i].t );
375         }
376         // set Skin Name
377         strncpy(skinname, (unsigned char *) fm.fm_skin, FM_SKINPATHSIZE );
378
379 #ifdef FM_VERBOSE_DBG
380         // Print out md2 values
381         _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 );
382 #endif
383
384         // detox Skin name
385         _pico_setfext( skinname, "" );
386         _pico_unixify( skinname );
387
388         /* create new pico model */
389         picoModel = PicoNewModel();
390         if( picoModel == NULL )
391         {
392                 _pico_printf( PICO_ERROR, "Unable to allocate a new model" );
393                 return NULL;
394         }
395
396         /* do model setup */
397         PicoSetModelFrameNum( picoModel, frameNum );
398         PicoSetModelNumFrames( picoModel, fm_head->numFrames ); /* sea */
399         PicoSetModelName( picoModel, fileName );
400         PicoSetModelFileName( picoModel, fileName );
401
402         // allocate new pico surface
403         picoSurface = PicoNewSurface( picoModel );
404         if( picoSurface == NULL )
405         {
406                 _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
407                 PicoFreeModel( picoModel );
408                 return NULL;
409         }
410
411
412         PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
413         PicoSetSurfaceName( picoSurface, frame->header.name );
414         picoShader = PicoNewShader( picoModel );
415         if( picoShader == NULL )
416         {
417                 _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
418                 PicoFreeModel( picoModel );
419                 return NULL;
420         }
421
422         PicoSetShaderName( picoShader, skinname );
423
424         // associate current surface with newly created shader
425         PicoSetSurfaceShader( picoSurface, picoShader );
426
427         // Init LUT for Verts
428         p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * fm_head->numXYZ);
429         for(i=0; i<fm_head->numXYZ; i++)
430         {
431                 p_index_LUT[i].Vert = -1;
432                 p_index_LUT[i].ST = -1;
433                 p_index_LUT[i].next = NULL;
434         }
435
436         // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert.
437         tot_numVerts = fm_head->numXYZ;
438         dups = 0;
439         triangle = tri_verts;
440
441         for(i=0; i<fm_head->numTris; i++)
442         {
443                 for(j=0; j<3; j++)
444                 {
445                         if (p_index_LUT[triangle->index_xyz[j]].ST == -1) // No Main Entry
446                                 p_index_LUT[triangle->index_xyz[j]].ST = triangle->index_st[j];
447
448                         else if (triangle->index_st[j] == p_index_LUT[triangle->index_xyz[j]].ST ) // Equal to Main Entry
449                         {
450 #ifdef FM_VERBOSE_DBG
451                                 _pico_printf( PICO_NORMAL, "-> Tri #%d, Vert %d:\t XYZ:%d   ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
452 #endif
453                                 continue;
454                         }
455                         else if ( (p_index_LUT[triangle->index_xyz[j]].next == NULL) )  // Not equal to Main entry, and no LL entry
456                         {       // Add first entry of LL from Main
457                                 p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));
458                                 if (p_index_LUT2 == NULL)
459                                         _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n");
460                                 p_index_LUT[triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2;
461                                 p_index_LUT2->Vert = dups;
462                                 p_index_LUT2->ST = triangle->index_st[j];
463                                 p_index_LUT2->next = NULL;
464 #ifdef FM_VERBOSE_DBG
465                                 _pico_printf( PICO_NORMAL, " ADDING first LL XYZ:%d DUP:%d ST:%d\n", triangle->index_xyz[j], dups, triangle->index_st[j]);
466 #endif
467                                 triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
468                                 dups++;
469                         }
470                         else // Try to find in LL from Main Entry
471                         {
472                                 p_index_LUT3 = p_index_LUT2 = p_index_LUT[triangle->index_xyz[j]].next;
473                                 while ( (p_index_LUT2 != NULL) && (triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL
474                                 {
475                                         p_index_LUT3 = p_index_LUT2;
476                                         p_index_LUT2 = p_index_LUT2->next;
477                                 }
478                                 p_index_LUT2 = p_index_LUT3;
479
480                                 if ( triangle->index_st[j] == p_index_LUT2->ST ) // Found it
481                                 {
482                                         triangle->index_xyz[j] = p_index_LUT2->Vert + fm_head->numXYZ; // Make change in Tri hunk
483 #ifdef FM_VERBOSE_DBG
484                                         _pico_printf( PICO_NORMAL, "--> Tri #%d, Vert %d:\t XYZ:%d   ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
485 #endif
486                                         continue;
487                                 }
488
489                                 if ( p_index_LUT2->next == NULL)  // Didn't find it. Add entry to LL.
490                                 {
491                                         // Add the Entry
492                                         p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));
493                                         if (p_index_LUT3 == NULL)
494                                                 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n");
495                                         p_index_LUT2->next = (index_LUT_t *)p_index_LUT3;
496                                         p_index_LUT3->Vert = dups;
497                                         p_index_LUT3->ST = triangle->index_st[j];
498                                         p_index_LUT3->next = NULL;
499 #ifdef FM_VERBOSE_DBG
500                                         _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]);
501 #endif
502                                         triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
503                                         dups++;
504                                 }
505                         }
506 #ifdef FM_VERBOSE_DBG
507                         _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 #endif
509                 }
510                 triangle++;
511         }
512
513         // malloc and build array for Dup STs
514         p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups);
515         if (p_index_LUT_DUPS == NULL)
516                 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n");
517
518         dup_index = 0;
519         for(i=0; i<fm_head->numXYZ; i++)
520         {
521                 p_index_LUT2 = p_index_LUT[i].next;
522                 while (p_index_LUT2 != NULL)
523                 {
524                         p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i;
525                         p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST;
526                         dup_index++;
527                         p_index_LUT2 = p_index_LUT2->next;
528                 }
529         }
530 #ifdef FM_VERBOSE_DBG
531         _pico_printf( PICO_NORMAL, " Dups = %d\n", dups);
532         _pico_printf( PICO_NORMAL, " Dup Index = %d\n", dup_index);
533 #endif
534         for(i=0; i<fm_head->numXYZ; i++)
535         {
536 #ifdef FM_VERBOSE_DBG
537                 _pico_printf( PICO_NORMAL, "Vert: %4d\t%4d",i, p_index_LUT[i].ST);
538 #endif
539                 if (p_index_LUT[i].next != NULL)
540                 {
541
542                         p_index_LUT2 = p_index_LUT[i].next;
543                         do {
544 #ifdef FM_VERBOSE_DBG
545                                 _pico_printf( PICO_NORMAL, " %4d %4d", p_index_LUT2->Vert, p_index_LUT2->ST);
546 #endif
547                                 p_index_LUT2 = p_index_LUT2->next;
548                         } while ( p_index_LUT2 != NULL);
549
550                 }
551 #ifdef FM_VERBOSE_DBG
552                 _pico_printf( PICO_NORMAL, "\n");
553 #endif
554         }
555
556
557 #ifdef FM_VERBOSE_DBG
558         for(i=0; i<dup_index; i++)
559                 _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);
560
561         triangle = tri_verts;
562         for(i=0; i<fm_head->numTris; i++)
563         {
564                 for(j=0; j<3; j++)
565                         _pico_printf( PICO_NORMAL, "Tri #%d, Vert %d:\t XYZ:%d   ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
566                 _pico_printf( PICO_NORMAL, "\n");
567                 triangle++;
568         }
569 #endif
570         // Build Picomodel
571         triangle = tri_verts;
572         for( j = 0; j < fm_head->numTris; j++, triangle++ )
573         {
574                 PicoSetSurfaceIndex( picoSurface, j*3   , triangle->index_xyz[0] );
575                 PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] );
576                 PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] );
577         }
578
579         vert = (fm_vert_normal_t*) ((picoByte_t*) (frame->verts) );
580         for(i=0; i< fm_head->numXYZ; i++, vert++)
581         {
582                 /* set vertex origin */
583                 xyz[ 0 ] = vert->v[0] * frame->header.scale[0] + frame->header.translate[0];
584                 xyz[ 1 ] = vert->v[1] * frame->header.scale[1] + frame->header.translate[1];
585                 xyz[ 2 ] = vert->v[2] * frame->header.scale[2] + frame->header.translate[2];
586                 PicoSetSurfaceXYZ( picoSurface, i , xyz );
587
588                 /* set normal */
589                 normal[ 0 ] = fm_normals[vert->lightnormalindex][0];
590                 normal[ 1 ] = fm_normals[vert->lightnormalindex][1];
591                 normal[ 2 ] = fm_normals[vert->lightnormalindex][2];
592                 PicoSetSurfaceNormal( picoSurface, i , normal );
593
594                 /* set st coords */
595                 st[ 0 ] =  ((texCoord[p_index_LUT[i].ST].s) / ((float)fm_head->skinWidth));
596                 st[ 1 ] =  (texCoord[p_index_LUT[i].ST].t / ((float)fm_head->skinHeight));
597                 PicoSetSurfaceST( picoSurface, 0, i , st );
598         }
599
600         if (dups)
601         {
602                 for(i=0; i<dups; i++)
603                 {
604                         j = p_index_LUT_DUPS[i].OldVert;
605                         /* set vertex origin */
606                         xyz[ 0 ] = frame->verts[j].v[0] * frame->header.scale[0] + frame->header.translate[0];
607                         xyz[ 1 ] = frame->verts[j].v[1] * frame->header.scale[1] + frame->header.translate[1];
608                         xyz[ 2 ] = frame->verts[j].v[2] * frame->header.scale[2] + frame->header.translate[2];
609                         PicoSetSurfaceXYZ( picoSurface, i + fm_head->numXYZ , xyz );
610
611                         /* set normal */
612                         normal[ 0 ] = fm_normals[frame->verts[j].lightnormalindex][0];
613                         normal[ 1 ] = fm_normals[frame->verts[j].lightnormalindex][1];
614                         normal[ 2 ] = fm_normals[frame->verts[j].lightnormalindex][2];
615                         PicoSetSurfaceNormal( picoSurface, i + fm_head->numXYZ , normal );
616
617                         /* set st coords */
618                         st[ 0 ] =  ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)fm_head->skinWidth));
619                         st[ 1 ] =  (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)fm_head->skinHeight));
620                         PicoSetSurfaceST( picoSurface, 0, i + fm_head->numXYZ , st );
621                 }
622         }
623
624         /* set color */
625         PicoSetSurfaceColor( picoSurface, 0, 0, color );
626
627         // Free up malloc'ed LL entries
628         for(i=0; i<fm_head->numXYZ; i++)
629         {
630                 if(p_index_LUT[i].next != NULL)
631                 {
632                         p_index_LUT2 = p_index_LUT[i].next;
633                         do {
634                                 p_index_LUT3 = p_index_LUT2->next;
635                                 _pico_free(p_index_LUT2);
636                                 p_index_LUT2 = p_index_LUT3;
637                                 dups--;
638                         } while (p_index_LUT2 != NULL);
639                 }
640         }
641
642         if (dups)
643                 _pico_printf(PICO_WARNING, " Not all LL mallocs freed\n");
644
645         // Free malloc'ed LUTs
646         _pico_free(p_index_LUT);
647         _pico_free(p_index_LUT_DUPS);
648
649         /* return the new pico model */
650         return picoModel;
651
652 }
653
654
655
656 /* pico file format module definition */
657 const picoModule_t picoModuleFM =
658 {
659         "0.85",                                         /* module version string */
660         "Heretic 2 FM",                         /* module display name */
661         "Nurail",                                       /* author's name */
662         "2003 Nurail",                          /* module copyright */
663         {
664                 "fm", NULL, NULL, NULL  /* default extensions to use */
665         },
666         _fm_canload,                            /* validation routine */
667         _fm_load,                                       /* load routine */
668          NULL,                                          /* save validation routine */
669          NULL                                           /* save routine */
670 };