]> icculus.org git repositories - divverent/netradiant.git/blob - libs/picomodel/pm_fm.c
1065160e64792f4bb15d37b768a24abc0b05e1c9
[divverent/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, *bb0;
70         int             fm_file_pos;
71
72         bb0 = bb = (picoByte_t*) _pico_alloc(bufSize);
73         memcpy(bb, buffer, bufSize);
74
75         // Header
76         fm.fm_header_hdr = (fm_chunk_header_t *) bb;
77         fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size;
78 #ifdef FM_VERBOSE_DBG
79         _pico_printf( PICO_VERBOSE, "IDENT: %s\n", (unsigned char *) fm.fm_header_hdr->ident );
80 #endif
81         if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME))  )
82         {
83 #ifdef FM_DBG
84                 _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n");
85 #endif
86                 _pico_free(bb0);
87                 return PICO_PMV_ERROR_IDENT;
88         }
89
90         // check fm
91         if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER )
92         {
93 #ifdef FM_DBG
94                 _pico_printf( PICO_WARNING, "FM Header Version incorrect\n");
95 #endif
96                 _pico_free(bb0);
97                 return PICO_PMV_ERROR_VERSION;
98         }
99
100         // Skin
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 );
105 #endif
106         if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) )
107         {
108 #ifdef FM_DBG
109                 _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n");
110 #endif
111                 _pico_free(bb0);
112                 return PICO_PMV_ERROR_IDENT;
113         }
114
115         // check fm
116         if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER )
117         {
118 #ifdef FM_DBG
119                 _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n");
120 #endif
121                 _pico_free(bb0);
122                 return PICO_PMV_ERROR_VERSION;
123         }
124
125         // st
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 );
130 #endif
131         if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) )
132         {
133 #ifdef FM_DBG
134                 _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n");
135 #endif
136                 _pico_free(bb0);
137                 return PICO_PMV_ERROR_IDENT;
138         }
139
140         // check fm
141         if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER )
142         {
143 #ifdef FM_DBG
144                 _pico_printf( PICO_WARNING, "FM ST Version incorrect\n");
145 #endif
146                 _pico_free(bb0);
147                 return PICO_PMV_ERROR_VERSION;
148         }
149
150         // tri
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 );
155 #endif
156         if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) )
157         {
158 #ifdef FM_DBG
159                 _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n");
160 #endif
161                 _pico_free(bb0);
162                 return PICO_PMV_ERROR_IDENT;
163         }
164
165         // check fm
166         if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER )
167         {
168 #ifdef FM_DBG
169                 _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n");
170 #endif
171                 _pico_free(bb0);
172                 return PICO_PMV_ERROR_VERSION;
173         }
174
175         // frame
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 );
180 #endif
181         if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) )
182         {
183 #ifdef FM_DBG
184                 _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n");
185 #endif
186                 _pico_free(bb0);
187                 return PICO_PMV_ERROR_IDENT;
188         }
189
190         // check fm
191         if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER )
192         {
193 #ifdef FM_DBG
194                 _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n");
195 #endif
196                 _pico_free(bb0);
197                 return PICO_PMV_ERROR_VERSION;
198         }
199
200         // file seems to be a valid fm
201         return PICO_PMV_OK;
202 }
203
204
205
206 // _fm_load() loads a Heretic 2 model file.
207 static picoModel_t *_fm_load( PM_PARAMS_LOAD )
208 {
209         int                             i, j, dups, dup_index;
210         int                             fm_file_pos;
211         short                   tot_numVerts;
212         index_LUT_t             *p_index_LUT, *p_index_LUT2, *p_index_LUT3;
213         index_DUP_LUT_t *p_index_LUT_DUPS;
214
215         fm_vert_normal_t        *vert;
216
217         char                    skinname[FM_SKINPATHSIZE];
218         fm_t                    fm;
219         fm_header_t             *fm_head;
220         fm_st_t                 *texCoord;
221         fm_xyz_st_t             *tri_verts;
222         fm_xyz_st_t             *triangle;
223         fm_frame_t              *frame;
224
225         picoByte_t      *bb, *bb0;
226         picoModel_t     *picoModel;
227         picoSurface_t   *picoSurface;
228         picoShader_t    *picoShader;
229         picoVec3_t      xyz, normal;
230         picoVec2_t      st;
231         picoColor_t     color;
232         
233
234         bb0 = bb = (picoByte_t*) _pico_alloc(bufSize);
235         memcpy(bb, buffer, bufSize);
236
237         // Header Header
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))  )
241         {
242                 _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n");
243                 _pico_free(bb0);
244                 return NULL;
245         }
246
247         if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER )
248         {
249                 _pico_printf( PICO_WARNING, "FM Header Version incorrect\n");
250                 _pico_free(bb0);
251                 return NULL;
252         }
253
254         // Skin Header
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)) )
258         {
259                 _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n");
260                 _pico_free(bb0);
261                 return NULL;
262         }
263
264         if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER )
265         {
266                 _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n");
267                 _pico_free(bb0);
268                 return NULL;
269         }
270
271         // ST Header
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)) )
275         {
276                 _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n");
277                 _pico_free(bb0);
278                 return NULL;
279         }
280
281         if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER )
282         {
283                 _pico_printf( PICO_WARNING, "FM ST Version incorrect\n");
284                 _pico_free(bb0);
285                 return NULL;
286         }
287
288         // Tris Header
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)) )
292         {
293                 _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n");
294                 _pico_free(bb0);
295                 return NULL;
296         }
297
298         if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER )
299         {
300                 _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n");
301                 _pico_free(bb0);
302                 return NULL;
303         }
304
305         // Frame Header
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)) )
309         {
310                 _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n");
311                 _pico_free(bb0);
312                 return NULL;
313         }
314
315         if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER )
316         {
317                 _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n");
318                 _pico_free(bb0);
319                 return NULL;
320         }
321
322         // Header
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;
326
327         // Skin
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;
331
332         // ST
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;
336
337         // Tri
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;
341
342         // Frame
343         fm_file_pos += sizeof(fm_chunk_header_t);
344         frame = fm.fm_frame = (fm_frame_t *) (bb + fm_file_pos);
345
346         // do frame check
347         if( fm_head->numFrames < 1 )
348         {
349                 _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );
350                 _pico_free(bb0);
351                 return NULL;
352         }
353         
354         if( frameNum < 0 || frameNum >= fm_head->numFrames )
355         {
356                 _pico_printf( PICO_ERROR, "Invalid or out-of-range FM frame specified" );
357                 _pico_free(bb0);
358                 return NULL;
359         }
360
361         // swap fm
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 );
365
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 );
372
373         // swap frame scale and translation
374         for( i = 0; i < 3; i++ )
375         {
376                 frame->header.scale[ i ] = _pico_little_float( frame->header.scale[ i ] );
377                 frame->header.translate[ i ] = _pico_little_float( frame->header.translate[ i ] );
378         }
379
380         // swap triangles
381         triangle = tri_verts;
382         for( i = 0; i < fm_head->numTris; i++, triangle++ )
383         {
384                 for( j = 0; j < 3; j++ )
385                 {
386                         triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );
387                         triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );
388                 }
389         }
390
391         // swap st coords
392         for( i = 0; i < fm_head->numST; i++ )
393         {
394                 texCoord->s = _pico_little_short( texCoord[i].s );
395                 texCoord->t = _pico_little_short( texCoord[i].t );
396         }
397         // set Skin Name
398         strncpy(skinname, (const char *) fm.fm_skin, FM_SKINPATHSIZE );
399
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 );
403 #endif
404
405         // detox Skin name
406         _pico_setfext( skinname, "" );
407         _pico_unixify( skinname );
408
409         /* create new pico model */
410         picoModel = PicoNewModel();
411         if( picoModel == NULL )
412         {
413                 _pico_printf( PICO_ERROR, "Unable to allocate a new model" );
414                 _pico_free(bb0);
415                 return NULL;
416         }
417
418         /* do model setup */
419         PicoSetModelFrameNum( picoModel, frameNum );
420         PicoSetModelNumFrames( picoModel, fm_head->numFrames ); /* sea */
421         PicoSetModelName( picoModel, fileName );
422         PicoSetModelFileName( picoModel, fileName );
423
424         // allocate new pico surface
425         picoSurface = PicoNewSurface( picoModel );
426         if( picoSurface == NULL )
427         {
428                 _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
429                 PicoFreeModel( picoModel );
430                 _pico_free(bb0);
431                 return NULL;
432         }
433
434
435         PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
436         PicoSetSurfaceName( picoSurface, frame->header.name );
437         picoShader = PicoNewShader( picoModel );
438         if( picoShader == NULL )
439         {
440                 _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
441                 PicoFreeModel( picoModel );
442                 _pico_free(bb0);
443                 return NULL;
444         }
445
446         PicoSetShaderName( picoShader, skinname );
447
448         // associate current surface with newly created shader
449         PicoSetSurfaceShader( picoSurface, picoShader );
450
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++)
454         {
455                 p_index_LUT[i].Vert = -1;
456                 p_index_LUT[i].ST = -1;
457                 p_index_LUT[i].next = NULL;
458         }
459
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;
462         dups = 0;
463         triangle = tri_verts;
464
465         for(i=0; i<fm_head->numTris; i++)
466         {
467                 for(j=0; j<3; j++)
468                 {
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];
471
472                         else if (triangle->index_st[j] == p_index_LUT[triangle->index_xyz[j]].ST ) // Equal to Main Entry
473                         {
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]);
476 #endif
477                                 continue;
478                         }
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]);
490 #endif
491                                 triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
492                                 dups++;
493                         }
494                         else // Try to find in LL from Main Entry
495                         {
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
498                                 {
499                                         p_index_LUT3 = p_index_LUT2;
500                                         p_index_LUT2 = p_index_LUT2->next;
501                                 }
502                                 p_index_LUT2 = p_index_LUT3;
503
504                                 if ( triangle->index_st[j] == p_index_LUT2->ST ) // Found it
505                                 {
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]);
509 #endif
510                                         continue;
511                                 }
512
513                                 if ( p_index_LUT2->next == NULL)  // Didn't find it. Add entry to LL.
514                                 {
515                                         // Add the Entry
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]);
525 #endif
526                                         triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
527                                         dups++;
528                                 }
529                         }
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]);
532 #endif
533                 }
534                 triangle++;
535         }
536
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");
541
542         dup_index = 0;
543         for(i=0; i<fm_head->numXYZ; i++)
544         {
545                 p_index_LUT2 = p_index_LUT[i].next;
546                 while (p_index_LUT2 != NULL)
547                 {
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;
550                         dup_index++;
551                         p_index_LUT2 = p_index_LUT2->next;
552                 }
553         }
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);
557 #endif
558         for(i=0; i<fm_head->numXYZ; i++)
559         {
560 #ifdef FM_VERBOSE_DBG
561                 _pico_printf( PICO_NORMAL, "Vert: %4d\t%4d",i, p_index_LUT[i].ST);
562 #endif
563                 if (p_index_LUT[i].next != NULL)
564                 {
565
566                         p_index_LUT2 = p_index_LUT[i].next;
567                         do {
568 #ifdef FM_VERBOSE_DBG
569                                 _pico_printf( PICO_NORMAL, " %4d %4d", p_index_LUT2->Vert, p_index_LUT2->ST);
570 #endif
571                                 p_index_LUT2 = p_index_LUT2->next;
572                         } while ( p_index_LUT2 != NULL);
573
574                 }
575 #ifdef FM_VERBOSE_DBG
576                 _pico_printf( PICO_NORMAL, "\n");
577 #endif
578         }
579
580
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);
584
585         triangle = tri_verts;
586         for(i=0; i<fm_head->numTris; i++)
587         {
588                 for(j=0; j<3; j++)
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");
591                 triangle++;
592         }
593 #endif
594         // Build Picomodel
595         triangle = tri_verts;
596         for( j = 0; j < fm_head->numTris; j++, triangle++ )
597         {
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] );
601         }
602
603         vert = (fm_vert_normal_t*) ((picoByte_t*) (frame->verts) );
604         for(i=0; i< fm_head->numXYZ; i++, vert++)
605         {
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 );
611
612                 /* set normal */
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 );
617
618                 /* set st coords */
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 );
622         }
623
624         if (dups)
625         {
626                 for(i=0; i<dups; i++)
627                 {
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 );
634
635                         /* set normal */
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 );
640
641                         /* set st coords */
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 );
645                 }
646         }
647
648         /* set color */
649         PicoSetSurfaceColor( picoSurface, 0, 0, color );
650
651         // Free up malloc'ed LL entries
652         for(i=0; i<fm_head->numXYZ; i++)
653         {
654                 if(p_index_LUT[i].next != NULL)
655                 {
656                         p_index_LUT2 = p_index_LUT[i].next;
657                         do {
658                                 p_index_LUT3 = p_index_LUT2->next;
659                                 _pico_free(p_index_LUT2);
660                                 p_index_LUT2 = p_index_LUT3;
661                                 dups--;
662                         } while (p_index_LUT2 != NULL);
663                 }
664         }
665
666         if (dups)
667                 _pico_printf(PICO_WARNING, " Not all LL mallocs freed\n");
668
669         // Free malloc'ed LUTs
670         _pico_free(p_index_LUT);
671         _pico_free(p_index_LUT_DUPS);
672
673         /* return the new pico model */
674         _pico_free(bb0);
675         return picoModel;
676
677 }
678
679
680
681 /* pico file format module definition */
682 const picoModule_t picoModuleFM =
683 {
684         "0.85",                                         /* module version string */
685         "Heretic 2 FM",                         /* module display name */
686         "Nurail",                                       /* author's name */
687         "2003 Nurail",                          /* module copyright */
688         {
689                 "fm", NULL, NULL, NULL  /* default extensions to use */
690         },
691         _fm_canload,                            /* validation routine */
692         _fm_load,                                       /* load routine */
693          NULL,                                          /* save validation routine */
694          NULL                                           /* save routine */
695 };