]> icculus.org git repositories - divverent/netradiant.git/blob - libs/picomodel/pm_fm.c
more warnings done. Now q3map2 is warning free apart from libpng deprecation problems.
[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         index_LUT_t             *p_index_LUT, *p_index_LUT2, *p_index_LUT3;
212         index_DUP_LUT_t *p_index_LUT_DUPS;
213
214         fm_vert_normal_t        *vert;
215
216         char                    skinname[FM_SKINPATHSIZE];
217         fm_t                    fm;
218         fm_header_t             *fm_head;
219         fm_st_t                 *texCoord;
220         fm_xyz_st_t             *tri_verts;
221         fm_xyz_st_t             *triangle;
222         fm_frame_t              *frame;
223
224         picoByte_t      *bb, *bb0;
225         picoModel_t     *picoModel;
226         picoSurface_t   *picoSurface;
227         picoShader_t    *picoShader;
228         picoVec3_t      xyz, normal;
229         picoVec2_t      st;
230         picoColor_t     color;
231         
232
233         bb0 = bb = (picoByte_t*) _pico_alloc(bufSize);
234         memcpy(bb, buffer, bufSize);
235
236         // Header Header
237         fm.fm_header_hdr = (fm_chunk_header_t *) bb;
238         fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size;
239         if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME))  )
240         {
241                 _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n");
242                 _pico_free(bb0);
243                 return NULL;
244         }
245
246         if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER )
247         {
248                 _pico_printf( PICO_WARNING, "FM Header Version incorrect\n");
249                 _pico_free(bb0);
250                 return NULL;
251         }
252
253         // Skin Header
254         fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
255         fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size;
256         if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) )
257         {
258                 _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n");
259                 _pico_free(bb0);
260                 return NULL;
261         }
262
263         if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER )
264         {
265                 _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n");
266                 _pico_free(bb0);
267                 return NULL;
268         }
269
270         // ST Header
271         fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
272         fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size;
273         if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) )
274         {
275                 _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n");
276                 _pico_free(bb0);
277                 return NULL;
278         }
279
280         if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER )
281         {
282                 _pico_printf( PICO_WARNING, "FM ST Version incorrect\n");
283                 _pico_free(bb0);
284                 return NULL;
285         }
286
287         // Tris Header
288         fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
289         fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size;
290         if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) )
291         {
292                 _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n");
293                 _pico_free(bb0);
294                 return NULL;
295         }
296
297         if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER )
298         {
299                 _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n");
300                 _pico_free(bb0);
301                 return NULL;
302         }
303
304         // Frame Header
305         fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos);
306         fm_file_pos += sizeof(fm_chunk_header_t);
307         if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) )
308         {
309                 _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n");
310                 _pico_free(bb0);
311                 return NULL;
312         }
313
314         if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER )
315         {
316                 _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n");
317                 _pico_free(bb0);
318                 return NULL;
319         }
320
321         // Header
322         fm_file_pos = sizeof(fm_chunk_header_t);
323         fm_head = fm.fm_header = (fm_header_t *) (bb + fm_file_pos);
324         fm_file_pos += fm.fm_header_hdr->size;
325
326         // Skin
327         fm_file_pos += sizeof(fm_chunk_header_t);
328         fm.fm_skin = (fm_skinpath_t *) (bb + fm_file_pos);
329         fm_file_pos += fm.fm_skin_hdr->size;
330
331         // ST
332         fm_file_pos += sizeof(fm_chunk_header_t);
333         texCoord = fm.fm_st = (fm_st_t *) (bb + fm_file_pos);
334         fm_file_pos += fm.fm_st_hdr->size;
335
336         // Tri
337         fm_file_pos += sizeof(fm_chunk_header_t);
338         tri_verts = fm.fm_tri = (fm_xyz_st_t *) (bb + fm_file_pos);
339         fm_file_pos += fm.fm_tri_hdr->size;
340
341         // Frame
342         fm_file_pos += sizeof(fm_chunk_header_t);
343         frame = fm.fm_frame = (fm_frame_t *) (bb + fm_file_pos);
344
345         // do frame check
346         if( fm_head->numFrames < 1 )
347         {
348                 _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName );
349                 _pico_free(bb0);
350                 return NULL;
351         }
352         
353         if( frameNum < 0 || frameNum >= fm_head->numFrames )
354         {
355                 _pico_printf( PICO_ERROR, "Invalid or out-of-range FM frame specified" );
356                 _pico_free(bb0);
357                 return NULL;
358         }
359
360         // swap fm
361         fm_head->skinWidth = _pico_little_long( fm_head->skinWidth );
362         fm_head->skinHeight = _pico_little_long( fm_head->skinHeight );
363         fm_head->frameSize = _pico_little_long( fm_head->frameSize );
364
365         fm_head->numSkins = _pico_little_long( fm_head->numSkins );
366         fm_head->numXYZ = _pico_little_long( fm_head->numXYZ );
367         fm_head->numST = _pico_little_long( fm_head->numST );
368         fm_head->numTris = _pico_little_long( fm_head->numTris );
369         fm_head->numGLCmds = _pico_little_long( fm_head->numGLCmds );
370         fm_head->numFrames = _pico_little_long( fm_head->numFrames );
371
372         // swap frame scale and translation
373         for( i = 0; i < 3; i++ )
374         {
375                 frame->header.scale[ i ] = _pico_little_float( frame->header.scale[ i ] );
376                 frame->header.translate[ i ] = _pico_little_float( frame->header.translate[ i ] );
377         }
378
379         // swap triangles
380         triangle = tri_verts;
381         for( i = 0; i < fm_head->numTris; i++, triangle++ )
382         {
383                 for( j = 0; j < 3; j++ )
384                 {
385                         triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] );
386                         triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] );
387                 }
388         }
389
390         // swap st coords
391         for( i = 0; i < fm_head->numST; i++ )
392         {
393                 texCoord->s = _pico_little_short( texCoord[i].s );
394                 texCoord->t = _pico_little_short( texCoord[i].t );
395         }
396         // set Skin Name
397         strncpy(skinname, (const char *) fm.fm_skin, FM_SKINPATHSIZE );
398
399 #ifdef FM_VERBOSE_DBG
400         // Print out md2 values
401         _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 );
402 #endif
403
404         // detox Skin name
405         _pico_setfext( skinname, "" );
406         _pico_unixify( skinname );
407
408         /* create new pico model */
409         picoModel = PicoNewModel();
410         if( picoModel == NULL )
411         {
412                 _pico_printf( PICO_ERROR, "Unable to allocate a new model" );
413                 _pico_free(bb0);
414                 return NULL;
415         }
416
417         /* do model setup */
418         PicoSetModelFrameNum( picoModel, frameNum );
419         PicoSetModelNumFrames( picoModel, fm_head->numFrames ); /* sea */
420         PicoSetModelName( picoModel, fileName );
421         PicoSetModelFileName( picoModel, fileName );
422
423         // allocate new pico surface
424         picoSurface = PicoNewSurface( picoModel );
425         if( picoSurface == NULL )
426         {
427                 _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" );
428                 PicoFreeModel( picoModel );
429                 _pico_free(bb0);
430                 return NULL;
431         }
432
433
434         PicoSetSurfaceType( picoSurface, PICO_TRIANGLES );
435         PicoSetSurfaceName( picoSurface, frame->header.name );
436         picoShader = PicoNewShader( picoModel );
437         if( picoShader == NULL )
438         {
439                 _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" );
440                 PicoFreeModel( picoModel );
441                 _pico_free(bb0);
442                 return NULL;
443         }
444
445         PicoSetShaderName( picoShader, skinname );
446
447         // associate current surface with newly created shader
448         PicoSetSurfaceShader( picoSurface, picoShader );
449
450         // Init LUT for Verts
451         p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * fm_head->numXYZ);
452         for(i=0; i<fm_head->numXYZ; i++)
453         {
454                 p_index_LUT[i].Vert = -1;
455                 p_index_LUT[i].ST = -1;
456                 p_index_LUT[i].next = NULL;
457         }
458
459         // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert.
460         dups = 0;
461         triangle = tri_verts;
462
463         for(i=0; i<fm_head->numTris; i++)
464         {
465                 for(j=0; j<3; j++)
466                 {
467                         if (p_index_LUT[triangle->index_xyz[j]].ST == -1) // No Main Entry
468                                 p_index_LUT[triangle->index_xyz[j]].ST = triangle->index_st[j];
469
470                         else if (triangle->index_st[j] == p_index_LUT[triangle->index_xyz[j]].ST ) // Equal to Main Entry
471                         {
472 #ifdef FM_VERBOSE_DBG
473                                 _pico_printf( PICO_NORMAL, "-> Tri #%d, Vert %d:\t XYZ:%d   ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
474 #endif
475                                 continue;
476                         }
477                         else if ( (p_index_LUT[triangle->index_xyz[j]].next == NULL) )  // Not equal to Main entry, and no LL entry
478                         {       // Add first entry of LL from Main
479                                 p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));
480                                 if (p_index_LUT2 == NULL)
481                                         _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n");
482                                 p_index_LUT[triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2;
483                                 p_index_LUT2->Vert = dups;
484                                 p_index_LUT2->ST = triangle->index_st[j];
485                                 p_index_LUT2->next = NULL;
486 #ifdef FM_VERBOSE_DBG
487                                 _pico_printf( PICO_NORMAL, " ADDING first LL XYZ:%d DUP:%d ST:%d\n", triangle->index_xyz[j], dups, triangle->index_st[j]);
488 #endif
489                                 triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
490                                 dups++;
491                         }
492                         else // Try to find in LL from Main Entry
493                         {
494                                 p_index_LUT3 = p_index_LUT2 = p_index_LUT[triangle->index_xyz[j]].next;
495                                 while ( (p_index_LUT2 != NULL) && (triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL
496                                 {
497                                         p_index_LUT3 = p_index_LUT2;
498                                         p_index_LUT2 = p_index_LUT2->next;
499                                 }
500                                 p_index_LUT2 = p_index_LUT3;
501
502                                 if ( triangle->index_st[j] == p_index_LUT2->ST ) // Found it
503                                 {
504                                         triangle->index_xyz[j] = p_index_LUT2->Vert + fm_head->numXYZ; // Make change in Tri hunk
505 #ifdef FM_VERBOSE_DBG
506                                         _pico_printf( PICO_NORMAL, "--> Tri #%d, Vert %d:\t XYZ:%d   ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
507 #endif
508                                         continue;
509                                 }
510
511                                 if ( p_index_LUT2->next == NULL)  // Didn't find it. Add entry to LL.
512                                 {
513                                         // Add the Entry
514                                         p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t));
515                                         if (p_index_LUT3 == NULL)
516                                                 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n");
517                                         p_index_LUT2->next = (index_LUT_t *)p_index_LUT3;
518                                         p_index_LUT3->Vert = dups;
519                                         p_index_LUT3->ST = triangle->index_st[j];
520                                         p_index_LUT3->next = NULL;
521 #ifdef FM_VERBOSE_DBG
522                                         _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]);
523 #endif
524                                         triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk
525                                         dups++;
526                                 }
527                         }
528 #ifdef FM_VERBOSE_DBG
529                         _pico_printf( PICO_NORMAL, "---> Tri #%d, Vert %d:\t XYZ:%d   ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
530 #endif
531                 }
532                 triangle++;
533         }
534
535         // malloc and build array for Dup STs
536         p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups);
537         if (p_index_LUT_DUPS == NULL)
538                 _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n");
539
540         dup_index = 0;
541         for(i=0; i<fm_head->numXYZ; i++)
542         {
543                 p_index_LUT2 = p_index_LUT[i].next;
544                 while (p_index_LUT2 != NULL)
545                 {
546                         p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i;
547                         p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST;
548                         dup_index++;
549                         p_index_LUT2 = p_index_LUT2->next;
550                 }
551         }
552 #ifdef FM_VERBOSE_DBG
553         _pico_printf( PICO_NORMAL, " Dups = %d\n", dups);
554         _pico_printf( PICO_NORMAL, " Dup Index = %d\n", dup_index);
555 #endif
556         for(i=0; i<fm_head->numXYZ; i++)
557         {
558 #ifdef FM_VERBOSE_DBG
559                 _pico_printf( PICO_NORMAL, "Vert: %4d\t%4d",i, p_index_LUT[i].ST);
560 #endif
561                 if (p_index_LUT[i].next != NULL)
562                 {
563
564                         p_index_LUT2 = p_index_LUT[i].next;
565                         do {
566 #ifdef FM_VERBOSE_DBG
567                                 _pico_printf( PICO_NORMAL, " %4d %4d", p_index_LUT2->Vert, p_index_LUT2->ST);
568 #endif
569                                 p_index_LUT2 = p_index_LUT2->next;
570                         } while ( p_index_LUT2 != NULL);
571
572                 }
573 #ifdef FM_VERBOSE_DBG
574                 _pico_printf( PICO_NORMAL, "\n");
575 #endif
576         }
577
578
579 #ifdef FM_VERBOSE_DBG
580         for(i=0; i<dup_index; i++)
581                 _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);
582
583         triangle = tri_verts;
584         for(i=0; i<fm_head->numTris; i++)
585         {
586                 for(j=0; j<3; j++)
587                         _pico_printf( PICO_NORMAL, "Tri #%d, Vert %d:\t XYZ:%d   ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]);
588                 _pico_printf( PICO_NORMAL, "\n");
589                 triangle++;
590         }
591 #endif
592         // Build Picomodel
593         triangle = tri_verts;
594         for( j = 0; j < fm_head->numTris; j++, triangle++ )
595         {
596                 PicoSetSurfaceIndex( picoSurface, j*3   , triangle->index_xyz[0] );
597                 PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] );
598                 PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] );
599         }
600
601         vert = (fm_vert_normal_t*) ((picoByte_t*) (frame->verts) );
602         for(i=0; i< fm_head->numXYZ; i++, vert++)
603         {
604                 /* set vertex origin */
605                 xyz[ 0 ] = vert->v[0] * frame->header.scale[0] + frame->header.translate[0];
606                 xyz[ 1 ] = vert->v[1] * frame->header.scale[1] + frame->header.translate[1];
607                 xyz[ 2 ] = vert->v[2] * frame->header.scale[2] + frame->header.translate[2];
608                 PicoSetSurfaceXYZ( picoSurface, i , xyz );
609
610                 /* set normal */
611                 normal[ 0 ] = fm_normals[vert->lightnormalindex][0];
612                 normal[ 1 ] = fm_normals[vert->lightnormalindex][1];
613                 normal[ 2 ] = fm_normals[vert->lightnormalindex][2];
614                 PicoSetSurfaceNormal( picoSurface, i , normal );
615
616                 /* set st coords */
617                 st[ 0 ] =  ((texCoord[p_index_LUT[i].ST].s) / ((float)fm_head->skinWidth));
618                 st[ 1 ] =  (texCoord[p_index_LUT[i].ST].t / ((float)fm_head->skinHeight));
619                 PicoSetSurfaceST( picoSurface, 0, i , st );
620         }
621
622         if (dups)
623         {
624                 for(i=0; i<dups; i++)
625                 {
626                         j = p_index_LUT_DUPS[i].OldVert;
627                         /* set vertex origin */
628                         xyz[ 0 ] = frame->verts[j].v[0] * frame->header.scale[0] + frame->header.translate[0];
629                         xyz[ 1 ] = frame->verts[j].v[1] * frame->header.scale[1] + frame->header.translate[1];
630                         xyz[ 2 ] = frame->verts[j].v[2] * frame->header.scale[2] + frame->header.translate[2];
631                         PicoSetSurfaceXYZ( picoSurface, i + fm_head->numXYZ , xyz );
632
633                         /* set normal */
634                         normal[ 0 ] = fm_normals[frame->verts[j].lightnormalindex][0];
635                         normal[ 1 ] = fm_normals[frame->verts[j].lightnormalindex][1];
636                         normal[ 2 ] = fm_normals[frame->verts[j].lightnormalindex][2];
637                         PicoSetSurfaceNormal( picoSurface, i + fm_head->numXYZ , normal );
638
639                         /* set st coords */
640                         st[ 0 ] =  ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)fm_head->skinWidth));
641                         st[ 1 ] =  (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)fm_head->skinHeight));
642                         PicoSetSurfaceST( picoSurface, 0, i + fm_head->numXYZ , st );
643                 }
644         }
645
646         /* set color */
647         PicoSetSurfaceColor( picoSurface, 0, 0, color );
648
649         // Free up malloc'ed LL entries
650         for(i=0; i<fm_head->numXYZ; i++)
651         {
652                 if(p_index_LUT[i].next != NULL)
653                 {
654                         p_index_LUT2 = p_index_LUT[i].next;
655                         do {
656                                 p_index_LUT3 = p_index_LUT2->next;
657                                 _pico_free(p_index_LUT2);
658                                 p_index_LUT2 = p_index_LUT3;
659                                 dups--;
660                         } while (p_index_LUT2 != NULL);
661                 }
662         }
663
664         if (dups)
665                 _pico_printf(PICO_WARNING, " Not all LL mallocs freed\n");
666
667         // Free malloc'ed LUTs
668         _pico_free(p_index_LUT);
669         _pico_free(p_index_LUT_DUPS);
670
671         /* return the new pico model */
672         _pico_free(bb0);
673         return picoModel;
674
675 }
676
677
678
679 /* pico file format module definition */
680 const picoModule_t picoModuleFM =
681 {
682         "0.85",                                         /* module version string */
683         "Heretic 2 FM",                         /* module display name */
684         "Nurail",                                       /* author's name */
685         "2003 Nurail",                          /* module copyright */
686         {
687                 "fm", NULL, NULL, NULL  /* default extensions to use */
688         },
689         _fm_canload,                            /* validation routine */
690         _fm_load,                                       /* load routine */
691          NULL,                                          /* save validation routine */
692          NULL                                           /* save routine */
693 };