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