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