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