]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/qdata_heretic2/fmodels.c
my own uncrustify run
[xonotic/netradiant.git] / tools / quake2 / qdata_heretic2 / fmodels.c
1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 #include "qd_fmodel.h"
23 #include "animcomp.h"
24 #include "qd_skeletons.h"
25 #include "skeletons.h"
26 #include "qdata.h"
27 #include "flex.h"
28 #include "reference.h"
29
30 #include <assert.h>
31
32 /*
33    ========================================================================
34
35    .FM triangle flexible model file format
36
37    ========================================================================
38  */
39
40 //=================================================================
41
42 #define NUMVERTEXNORMALS    162
43
44 extern float avertexnormals[NUMVERTEXNORMALS][3];
45
46 #define MAX_GROUPS  128
47
48 typedef struct
49 {
50         triangle_t triangle;
51         int group;
52 } trigroup_t;
53
54 #define TRIVERT_DIST    .1
55
56 typedef struct
57 {
58         int start_frame;
59         int num_frames;
60         int degrees;
61         char *mat;
62         char *ccomp;
63         char *cbase;
64         float *cscale;
65         float *coffset;
66         float trans[3];
67         float scale[3];
68         float bmin[3];
69         float bmax[3];
70 } fmgroup_t;
71
72 //================================================================
73
74 // Initial
75 fmheader_t fmheader;
76
77 // Skin
78 extern char g_skins[MAX_FM_SKINS][64];
79
80 // ST Coord
81 extern fmstvert_t base_st[MAX_FM_VERTS];
82
83 // Triangles
84 extern fmtriangle_t triangles[MAX_FM_TRIANGLES];
85
86 // Frames
87 fmframe_t g_frames[MAX_FM_FRAMES];
88 //fmframe_t     *g_FMframes;
89
90 // GL Commands
91 extern int commands[16384];
92 extern int numcommands;
93
94
95 //
96 // varibles set by commands
97 //
98 extern float scale_up;                              // set by $scale
99 extern vec3_t adjust;                               // set by $origin
100 extern int g_fixedwidth, g_fixedheight;             // set by $skinsize
101 extern char modelname[64];                          // set by $modelname
102
103
104 extern char        *g_outputDir;
105
106
107 // Mesh Nodes
108 mesh_node_t *pmnodes = NULL;
109 fmmeshnode_t mesh_nodes[MAX_FM_MESH_NODES];
110
111 fmgroup_t groups[MAX_GROUPS];
112 int num_groups;
113 int frame_to_group[MAX_FM_FRAMES];
114
115 //
116 // variables set by command line arguments
117 //
118 qboolean g_no_opimizations = false;
119
120
121 //
122 // base frame info
123 //
124 static int triangle_st[MAX_FM_TRIANGLES][3][2];
125
126
127 // number of gl vertices
128 extern int numglverts;
129 // indicates if a triangle has already been used in a glcmd
130 extern int used[MAX_FM_TRIANGLES];
131 // indicates if a triangle has translucency in it or not
132 static qboolean translucent[MAX_FM_TRIANGLES];
133
134 // main output file handle
135 extern FILE         *headerouthandle;
136 // output sizes of buildst()
137 static int skin_width, skin_height;
138
139
140 // statistics
141 static int total_skin_pixels;
142 static int skin_pixels_used;
143
144 int ShareVertex( trigroup_t trione, trigroup_t tritwo );
145 float DistBetween( vec3_t point1, vec3_t point2 );
146 int GetNumTris( trigroup_t *tris, int group );
147 void GetOneGroup( trigroup_t *tris, int grp, triangle_t* triangles );
148 void ScaleTris( vec3_t min, vec3_t max, int Width, int Height, float* u, float* v, int verts );
149 void NewDrawLine( int x1, int y1, int x2, int y2, unsigned char* picture, int width, int height );
150
151 #ifndef _WIN32
152
153 void strupr( char *string ){
154         int i;
155
156         for ( i = 0 ; i < strlen( string ); i++ )
157                 toupper( string[i] );
158
159         return;
160 }
161
162 #endif
163 //==============================================================
164
165 /*
166    ===============
167    ClearModel
168    ===============
169  */
170 static void ClearModel( void ){
171         memset( &fmheader, 0, sizeof( fmheader ) );
172
173         modelname[0] = 0;
174         scale_up = 1.0;
175         VectorCopy( vec3_origin, adjust );
176         g_fixedwidth = g_fixedheight = 0;
177         g_skipmodel = false;
178         num_groups = 0;
179
180         if ( pmnodes ) {
181                 free( pmnodes );
182                 pmnodes = NULL;
183         }
184
185         ClearSkeletalModel();
186 }
187
188
189 extern void H_printf( char *fmt, ... );
190
191
192 void WriteHeader( FILE *FH, char *Ident, int Version, int Size, void *Data ){
193         header_t header;
194         static long pos = -1;
195         long CurrentPos;
196
197         if ( Size == 0 ) { // Don't write out empty packets
198                 return;
199         }
200
201         if ( pos != -1 ) {
202                 CurrentPos = ftell( FH );
203                 Size = CurrentPos - pos + sizeof( header_t );
204                 fseek( FH, pos, SEEK_SET );
205                 pos = -2;
206         }
207         else if ( Size == -1 ) {
208                 pos = ftell( FH );
209         }
210
211         memset( &header,0,sizeof( header ) );
212         strcpy( header.ident,Ident );
213         header.version = Version;
214         header.size = Size;
215
216         SafeWrite( FH, &header, sizeof( header ) );
217
218         if ( Data ) {
219                 SafeWrite( FH, Data, Size );
220         }
221
222         if ( pos == -2 ) {
223                 pos = -1;
224                 fseek( FH, 0, SEEK_END );
225         }
226 }
227
228 /*
229    ============
230    WriteModelFile
231    ============
232  */
233 static void WriteModelFile( FILE *modelouthandle ){
234         int i;
235         int j, k;
236         fmframe_t       *in;
237         fmaliasframe_t  *out;
238         byte buffer[MAX_FM_VERTS * 4 + 128];
239         float v;
240         int c_on, c_off;
241         IntListNode_t   *current, *toFree;
242         qboolean framesWritten = false;
243         size_t temp,size = 0;
244
245         // probably should do this dynamically one of these days
246         struct
247         {
248                 float scale[3];         // multiply byte verts by this
249                 float translate[3];         // then add this
250         } outFrames[MAX_FM_FRAMES];
251
252 #define DATA_SIZE 0x60000       // 384K had better be enough, particularly for the reference points
253         byte data[DATA_SIZE];
254         byte data2[DATA_SIZE];
255
256         fmheader.num_glcmds = numcommands;
257         fmheader.framesize = (int)&( (fmaliasframe_t *)0 )->verts[fmheader.num_xyz];
258
259         WriteHeader( modelouthandle, FM_HEADER_NAME, FM_HEADER_VER, sizeof( fmheader ), &fmheader );
260
261         //
262         // write out the skin names
263         //
264
265         WriteHeader( modelouthandle, FM_SKIN_NAME, FM_SKIN_VER, fmheader.num_skins * MAX_FM_SKINNAME, g_skins );
266
267         //
268         // write out the texture coordinates
269         //
270         c_on = c_off = 0;
271         for ( i = 0 ; i < fmheader.num_st ; i++ )
272         {
273                 base_st[i].s = LittleShort( base_st[i].s );
274                 base_st[i].t = LittleShort( base_st[i].t );
275         }
276
277         WriteHeader( modelouthandle, FM_ST_NAME, FM_ST_VER, fmheader.num_st * sizeof( base_st[0] ), base_st );
278
279         //
280         // write out the triangles
281         //
282         WriteHeader( modelouthandle, FM_TRI_NAME, FM_TRI_VER, fmheader.num_tris * sizeof( fmtriangle_t ), NULL );
283
284         for ( i = 0 ; i < fmheader.num_tris ; i++ )
285         {
286                 int j;
287                 fmtriangle_t tri;
288
289                 for ( j = 0 ; j < 3 ; j++ )
290                 {
291                         tri.index_xyz[j] = LittleShort( triangles[i].index_xyz[j] );
292                         tri.index_st[j] = LittleShort( triangles[i].index_st[j] );
293                 }
294
295                 SafeWrite( modelouthandle, &tri, sizeof( tri ) );
296         }
297
298         if ( !num_groups ) {
299                 //
300                 // write out the frames
301                 //
302                 WriteHeader( modelouthandle, FM_FRAME_NAME, FM_FRAME_VER, fmheader.num_frames * fmheader.framesize, NULL );
303                 //      WriteHeader(modelouthandle, FM_FRAME_NAME, FM_FRAME_VER, -1, NULL);
304
305                 for ( i = 0 ; i < fmheader.num_frames ; i++ )
306                 {
307                         in = &g_frames[i];
308                         out = (fmaliasframe_t *)buffer;
309
310                         strcpy( out->name, in->name );
311                         for ( j = 0 ; j < 3 ; j++ )
312                         {
313                                 out->scale[j] = ( in->maxs[j] - in->mins[j] ) / 255;
314                                 out->translate[j] = in->mins[j];
315
316                                 outFrames[i].scale[j] = out->scale[j];
317                                 outFrames[i].translate[j] = out->translate[j];
318                         }
319
320                         for ( j = 0 ; j < fmheader.num_xyz ; j++ )
321                         {
322                                 // all of these are byte values, so no need to deal with endianness
323                                 out->verts[j].lightnormalindex = in->v[j].lightnormalindex;
324
325                                 for ( k = 0 ; k < 3 ; k++ )
326                                 {
327                                         // scale to byte values & min/max check
328                                         v = Q_rint( ( in->v[j].v[k] - out->translate[k] ) / out->scale[k] );
329
330                                         // clamp, so rounding doesn't wrap from 255.6 to 0
331                                         if ( v > 255.0 ) {
332                                                 v = 255.0;
333                                         }
334                                         if ( v < 0 ) {
335                                                 v = 0;
336                                         }
337                                         out->verts[j].v[k] = v;
338                                 }
339                         }
340
341                         for ( j = 0 ; j < 3 ; j++ )
342                         {
343                                 out->scale[j] = LittleFloat( out->scale[j] );
344                                 out->translate[j] = LittleFloat( out->translate[j] );
345                         }
346
347                         SafeWrite( modelouthandle, out, fmheader.framesize );
348                 }
349
350                 // Go back and finish the header
351                 //      WriteHeader(modelouthandle, FM_FRAME_NAME, FM_FRAME_VER, -1, NULL);
352         }
353         else
354         {
355                 WriteHeader( modelouthandle, FM_SHORT_FRAME_NAME, FM_SHORT_FRAME_VER,FRAME_NAME_LEN * fmheader.num_frames, NULL );
356                 for ( i = 0 ; i < fmheader.num_frames ; i++ )
357                 {
358                         in = &g_frames[i];
359                         SafeWrite( modelouthandle,in->name,FRAME_NAME_LEN );
360                 }
361                 WriteHeader( modelouthandle, FM_NORMAL_NAME, FM_NORMAL_VER,fmheader.num_xyz, NULL );
362                 in = &g_frames[0];
363                 for ( j = 0 ; j < fmheader.num_xyz ; j++ )
364                         SafeWrite( modelouthandle,&in->v[j].lightnormalindex,1 );
365         }
366
367         //
368         // write out glcmds
369         //
370         WriteHeader( modelouthandle, FM_GLCMDS_NAME, FM_GLCMDS_VER, numcommands * 4, commands );
371
372         //
373         // write out mesh nodes
374         //
375         for ( i = 0; i < fmheader.num_mesh_nodes; i++ )
376         {
377                 memcpy( mesh_nodes[i].tris, pmnodes[i].tris, sizeof( mesh_nodes[i].tris ) );
378                 memcpy( mesh_nodes[i].verts, pmnodes[i].verts, sizeof( mesh_nodes[i].verts ) );
379                 mesh_nodes[i].start_glcmds = LittleShort( (short)pmnodes[i].start_glcmds );
380                 mesh_nodes[i].num_glcmds = LittleShort( (short)pmnodes[i].num_glcmds );
381         }
382
383         WriteHeader( modelouthandle, FM_MESH_NAME, FM_MESH_VER, sizeof( fmmeshnode_t ) * fmheader.num_mesh_nodes, mesh_nodes );
384
385         if ( num_groups ) {
386
387 /*
388    typedef struct
389    {
390     int                 start_frame;
391     int                 num_frames;
392     int                 degrees;
393     char *mat; fmheader.num_xyz*3*g->degrees*sizeof(char)
394     char *ccomp; g->num_frames*g->degrees*sizeof(char)
395     char *cbase; fmheader.num_xyz*3*sizeof(unsigned char)
396     float *cscale; g->degrees*sizeof(float)
397     float *coffset; g->degrees*sizeof(float)
398     float trans[3]; 3*sizeof(float)
399     float scale[3]; 3*sizeof(float)
400    } fmgroup_t;
401  */
402                 int tmp,k;
403                 fmgroup_t *g;
404                 size = sizeof( int ) + fmheader.num_frames * sizeof( int );
405                 for ( k = 0; k < num_groups; k++ )
406                 {
407                         g = &groups[k];
408                         size += sizeof( int ) * 3;
409                         size += fmheader.num_xyz * 3 * g->degrees * sizeof( char );
410                         size += g->num_frames * g->degrees * sizeof( char );
411                         size += fmheader.num_xyz * 3 * sizeof( unsigned char );
412                         size += g->degrees * sizeof( float );
413                         size += g->degrees * sizeof( float );
414                         size += 12 * sizeof( float );
415                 }
416                 WriteHeader( modelouthandle, FM_COMP_NAME, FM_COMP_VER,size, NULL );
417                 SafeWrite( modelouthandle,&num_groups,sizeof( int ) );
418                 SafeWrite( modelouthandle,frame_to_group,sizeof( int ) * fmheader.num_frames );
419
420                 for ( k = 0; k < num_groups; k++ )
421                 {
422                         g = &groups[k];
423                         tmp = LittleLong( g->start_frame );
424                         SafeWrite( modelouthandle,&tmp,sizeof( int ) );
425                         tmp = LittleLong( g->num_frames );
426                         SafeWrite( modelouthandle,&tmp,sizeof( int ) );
427                         tmp = LittleLong( g->degrees );
428                         SafeWrite( modelouthandle,&tmp,sizeof( int ) );
429
430                         SafeWrite( modelouthandle,g->mat,fmheader.num_xyz * 3 * g->degrees * sizeof( char ) );
431                         SafeWrite( modelouthandle,g->ccomp,g->num_frames * g->degrees * sizeof( char ) );
432                         SafeWrite( modelouthandle,g->cbase,fmheader.num_xyz * 3 * sizeof( unsigned char ) );
433                         SafeWrite( modelouthandle,g->cscale,g->degrees * sizeof( float ) );
434                         SafeWrite( modelouthandle,g->coffset,g->degrees * sizeof( float ) );
435                         SafeWrite( modelouthandle,g->trans,3 * sizeof( float ) );
436                         SafeWrite( modelouthandle,g->scale,3 * sizeof( float ) );
437                         SafeWrite( modelouthandle,g->bmin,3 * sizeof( float ) );
438                         SafeWrite( modelouthandle,g->bmax,3 * sizeof( float ) );
439                         free( g->mat );
440                         free( g->ccomp );
441                         free( g->cbase );
442                         free( g->cscale );
443                         free( g->coffset );
444                 }
445         }
446
447         // write the skeletal info
448         if ( g_skelModel.type != SKEL_NULL ) {
449                 size = 0;
450
451                 temp = sizeof( int );     // change this to a byte
452                 memcpy( data + size, &g_skelModel.type, temp );
453                 size += temp;
454
455                 // number of joints
456                 temp = sizeof( int );     // change this to a byte
457                 memcpy( data + size, &numJointsInSkeleton[g_skelModel.type], temp );
458                 size += temp;
459
460                 // number of verts in each joint cluster
461                 temp = sizeof( int ) * numJointsInSkeleton[g_skelModel.type]; // change this to shorts
462                 memcpy( data + size, &g_skelModel.new_num_verts[1], temp );
463                 size += temp;
464
465                 // cluster verts
466                 for ( i = 0; i < numJointsInSkeleton[g_skelModel.type]; ++i )
467                 {
468                         current = g_skelModel.vertLists[i];
469                         while ( current )
470                         {
471                                 temp = sizeof( int ); // change this to a short
472                                 memcpy( data + size, &current->data, temp );
473                                 size += temp;
474                                 toFree = current;
475                                 current = current->next;
476                                 free( toFree );  // freeing of memory allocated in ReplaceClusterIndex called in Cmd_Base
477                         }
478                 }
479
480                 if ( !num_groups ) { // joints are stored with regular verts for compressed models
481                         framesWritten = true;
482
483                         temp = sizeof( int ); // change this to a byte
484                         memcpy( data + size, &framesWritten, temp );
485                         size += temp;
486
487                         for ( i = 0; i < fmheader.num_frames; ++i )
488                         {
489                                 in = &g_frames[i];
490
491                                 for ( j = 0 ; j < numJointsInSkeleton[g_skelModel.type]; ++j )
492                                 {
493                                         for ( k = 0 ; k < 3 ; k++ )
494                                         {
495                                                 // scale to byte values & min/max check
496                                                 v = Q_rint( ( in->joints[j].placement.origin[k] - outFrames[i].translate[k] ) / outFrames[i].scale[k] );
497
498                                                 // write out origin as a float since they arn't clamped
499                                                 temp = sizeof( float );   // change this to a short
500                                                 assert( size + temp < DATA_SIZE );
501                                                 memcpy( data + size, &v, temp );
502                                                 size += temp;
503                                         }
504
505                                         for ( k = 0 ; k < 3 ; k++ )
506                                         {
507                                                 v = Q_rint( ( in->joints[j].placement.direction[k] - outFrames[i].translate[k] ) / outFrames[i].scale[k] );
508
509                                                 // write out origin as a float since they arn't clamped
510                                                 temp = sizeof( float );   // change this to a short
511                                                 assert( size + temp < DATA_SIZE );
512                                                 memcpy( data + size, &v, temp );
513                                                 size += temp;
514                                         }
515
516                                         for ( k = 0 ; k < 3 ; k++ )
517                                         {
518                                                 v = Q_rint( ( in->joints[j].placement.up[k] - outFrames[i].translate[k] ) / outFrames[i].scale[k] );
519
520                                                 // write out origin as a float since they arn't clamped
521                                                 temp = sizeof( float );   // change this to a short
522                                                 assert( size + temp < DATA_SIZE );
523                                                 memcpy( data + size, &v, temp );
524                                                 size += temp;
525                                         }
526                                 }
527                         }
528
529                 }
530                 else
531                 {
532                         temp = sizeof( int ); // change this to a byte
533                         memcpy( data + size, &framesWritten, temp );
534                         size += temp;
535                 }
536
537                 WriteHeader( modelouthandle, FM_SKELETON_NAME, FM_SKELETON_VER, size, data );
538         }
539
540         if ( g_skelModel.references != REF_NULL ) {
541                 int refnum;
542
543                 size = 0;
544                 if ( RefPointNum <= 0 ) { // Hard-coded labels
545                         refnum = numReferences[g_skelModel.references];
546                 }
547                 else
548                 {   // Labels indicated in QDT
549                         refnum = RefPointNum;
550                 }
551
552                 temp = sizeof( int ); // change this to a byte
553                 memcpy( data2 + size, &g_skelModel.references, temp );
554                 size += temp;
555
556                 if ( !num_groups ) {
557                         framesWritten = true;
558
559                         temp = sizeof( int ); // change this to a byte
560                         memcpy( data2 + size, &framesWritten, temp );
561                         size += temp;
562
563                         for ( i = 0; i < fmheader.num_frames; ++i )
564                         {
565                                 in = &g_frames[i];
566
567                                 for ( j = 0 ; j < refnum; ++j )
568                                 {
569                                         for ( k = 0 ; k < 3 ; k++ )
570                                         {
571                                                 // scale to byte values & min/max check
572                                                 v = Q_rint( ( in->references[j].placement.origin[k] - outFrames[i].translate[k] ) / outFrames[i].scale[k] );
573
574                                                 // write out origin as a float since they arn't clamped
575                                                 temp = sizeof( float );   // change this to a short
576                                                 assert( size + temp < DATA_SIZE );
577                                                 memcpy( data2 + size, &v, temp );
578                                                 size += temp;
579                                         }
580
581                                         for ( k = 0 ; k < 3 ; k++ )
582                                         {
583                                                 v = Q_rint( ( in->references[j].placement.direction[k] - outFrames[i].translate[k] ) / outFrames[i].scale[k] );
584
585                                                 // write out origin as a float since they arn't clamped
586                                                 temp = sizeof( float );   // change this to a short
587                                                 assert( size + temp < DATA_SIZE );
588                                                 memcpy( data2 + size, &v, temp );
589                                                 size += temp;
590                                         }
591
592                                         for ( k = 0 ; k < 3 ; k++ )
593                                         {
594                                                 v = Q_rint( ( in->references[j].placement.up[k] - outFrames[i].translate[k] ) / outFrames[i].scale[k] );
595
596                                                 // write out origin as a float since they arn't clamped
597                                                 temp = sizeof( float );   // change this to a short
598                                                 assert( size + temp < DATA_SIZE );
599                                                 memcpy( data2 + size, &v, temp );
600                                                 size += temp;
601                                         }
602                                 }
603                         }
604                 }
605                 else    // FINISH ME: references need to be stored with regular verts for compressed models
606                 {
607                         framesWritten = false;
608
609                         temp = sizeof( int ); // change this to a byte
610                         memcpy( data2 + size, &framesWritten, temp );
611                         size += temp;
612                 }
613
614                 WriteHeader( modelouthandle, FM_REFERENCES_NAME, FM_REFERENCES_VER, size, data2 );
615         }
616 }
617
618 static void CompressFrames(){
619         fmgroup_t *g;
620         int i,j,k;
621         fmframe_t   *in;
622
623         j = 0;
624         for ( i = 0; i < fmheader.num_frames; i++ )
625         {
626                 while ( i >= groups[j].start_frame + groups[j].num_frames && j < num_groups - 1 )
627                         j++;
628                 frame_to_group[i] = j;
629         }
630
631         for ( k = 0; k < num_groups; k++ )
632         {
633                 g = &groups[k];
634
635                 printf( "\nCompressing Frames for group %i...\n", k );
636                 AnimCompressInit( g->num_frames,fmheader.num_xyz,g->degrees );
637                 for ( i = 0; i < g->num_frames; i++ )
638                 {
639                         in = &g_frames[i + g->start_frame];
640                         for ( j = 0; j < fmheader.num_xyz; j++ )
641                                 AnimSetFrame( i,j,in->v[j].v[0],in->v[j].v[1],in->v[j].v[2] );
642                 }
643                 AnimCompressDoit();
644                 g->mat = (char *) SafeMalloc( fmheader.num_xyz * 3 * g->degrees * sizeof( char ), "CompressFrames" );
645                 g->ccomp = (char *) SafeMalloc( g->num_frames * g->degrees * sizeof( char ), "CompressFrames" );
646                 g->cbase = (char *) SafeMalloc( fmheader.num_xyz * 3 * sizeof( unsigned char ), "CompressFrames" );
647                 g->cscale = (float *) SafeMalloc( g->degrees * sizeof( float ), "CompressFrames" );
648                 g->coffset = (float *) SafeMalloc( g->degrees * sizeof( float ), "CompressFrames" );
649                 AnimCompressToBytes( g->trans,g->scale,g->mat,g->ccomp,g->cbase,g->cscale,g->coffset,g->bmin,g->bmax );
650                 AnimCompressEnd();
651         }
652 }
653
654 static void OptimizeVertices( void ){
655         qboolean vert_used[MAX_FM_VERTS];
656         short vert_replacement[MAX_FM_VERTS];
657         int i,j,k,l,pos,bit,set_pos,set_bit;
658         fmframe_t   *in;
659         qboolean Found;
660         int num_unique;
661         static IntListNode_t *newVertLists[NUM_CLUSTERS];
662         static int newNum_verts[NUM_CLUSTERS];
663         IntListNode_t *current, *next;
664
665         printf( "Optimizing vertices..." );
666
667         memset( vert_used, 0, sizeof( vert_used ) );
668
669         if ( g_skelModel.clustered == true ) {
670                 memset( newNum_verts, 0, sizeof( newNum_verts ) );
671                 memset( newVertLists, 0, sizeof( newVertLists ) );
672         }
673
674         num_unique = 0;
675
676         // search for common points among all the frames
677         for ( i = 0 ; i < fmheader.num_frames ; i++ )
678         {
679                 in = &g_frames[i];
680
681                 for ( j = 0; j < fmheader.num_xyz; j++ )
682                 {
683                         for ( k = 0,Found = false; k < j; k++ )
684                         {   // starting from the beginning always ensures vert_replacement points to the first point in the array
685                                 if ( in->v[j].v[0] == in->v[k].v[0] &&
686                                          in->v[j].v[1] == in->v[k].v[1] &&
687                                          in->v[j].v[2] == in->v[k].v[2] ) {
688                                         Found = true;
689                                         vert_replacement[j] = k;
690                                         break;
691                                 }
692
693                         }
694
695                         if ( !Found ) {
696                                 if ( !vert_used[j] ) {
697                                         num_unique++;
698                                 }
699                                 vert_used[j] = true;
700                         }
701                 }
702         }
703
704         // recompute the light normals
705         for ( i = 0 ; i < fmheader.num_frames ; i++ )
706         {
707                 in = &g_frames[i];
708
709                 for ( j = 0; j < fmheader.num_xyz; j++ )
710                 {
711                         if ( !vert_used[j] ) {
712                                 k = vert_replacement[j];
713
714                                 VectorAdd( in->v[j].vnorm.normalsum, in->v[k].vnorm.normalsum, in->v[k].vnorm.normalsum );
715                                 in->v[k].vnorm.numnormals += in->v[j].vnorm.numnormals++;
716                         }
717                 }
718
719                 for ( j = 0 ; j < fmheader.num_xyz ; j++ )
720                 {
721                         vec3_t v;
722                         float maxdot;
723                         int maxdotindex;
724                         int c;
725
726                         c = in->v[j].vnorm.numnormals;
727                         if ( !c ) {
728                                 Error( "Vertex with no triangles attached" );
729                         }
730
731                         VectorScale( in->v[j].vnorm.normalsum, 1.0 / c, v );
732                         VectorNormalize( v, v );
733
734                         maxdot = -999999.0;
735                         maxdotindex = -1;
736
737                         for ( k = 0 ; k < NUMVERTEXNORMALS ; k++ )
738                         {
739                                 float dot;
740
741                                 dot = DotProduct( v, avertexnormals[k] );
742                                 if ( dot > maxdot ) {
743                                         maxdot = dot;
744                                         maxdotindex = k;
745                                 }
746                         }
747
748                         in->v[j].lightnormalindex = maxdotindex;
749                 }
750         }
751
752         // create substitution list
753         num_unique = 0;
754         for ( i = 0; i < fmheader.num_xyz; i++ )
755         {
756                 if ( vert_used[i] ) {
757                         vert_replacement[i] = num_unique;
758                         num_unique++;
759                 }
760                 else
761                 {
762                         vert_replacement[i] = vert_replacement[vert_replacement[i]];
763                 }
764
765                 // vert_replacement[i] is the new index, i is the old index
766                 // need to add the new index to the cluster list if old index was in it
767                 if ( g_skelModel.clustered == true ) {
768                         for ( k = 0; k < numJointsInSkeleton[g_skelModel.type]; ++k )
769                         {
770                                 for ( l = 0, current = g_skelModel.vertLists[k];
771                                           l < g_skelModel.new_num_verts[k + 1]; ++l, current = current->next )
772                                 {
773                                         if ( current->data == i ) {
774                                                 IntListNode_t *current2;
775                                                 int m;
776                                                 qboolean added = false;
777
778                                                 for ( m = 0, current2 = newVertLists[k]; m < newNum_verts[k + 1];
779                                                           ++m, current2 = current2->next )
780                                                 {
781                                                         if ( current2->data == vert_replacement[i] ) {
782                                                                 added = true;
783                                                                 break;
784                                                         }
785                                                 }
786
787                                                 if ( !added ) {
788                                                         ++newNum_verts[k + 1];
789
790                                                         next = newVertLists[k];
791
792                                                         newVertLists[k] = (IntListNode_t *) SafeMalloc( sizeof( IntListNode_t ), "OptimizeVertices" );
793                                                         // freed after model write out
794
795                                                         newVertLists[k]->data = vert_replacement[i];
796                                                         newVertLists[k]->next = next;
797                                                 }
798                                                 break;
799                                         }
800                                 }
801                         }
802                 }
803         }
804
805         // substitute
806         for ( i = 0 ; i < fmheader.num_frames ; i++ )
807         {
808                 in = &g_frames[i];
809
810                 for ( j = 0; j < fmheader.num_xyz; j++ )
811                 {
812                         in->v[vert_replacement[j]] = in->v[j];
813                 }
814
815         }
816
817         for ( i = 0; i < numJointsInSkeleton[g_skelModel.type]; ++i )
818         {
819                 IntListNode_t *toFree;
820                 current = g_skelModel.vertLists[i];
821
822                 while ( current )
823                 {
824                         toFree = current;
825                         current = current->next;
826                         free( toFree );  // freeing of memory allocated in ReplaceClusterIndex called in Cmd_Base
827                 }
828
829                 g_skelModel.vertLists[i] = newVertLists[i];
830                 g_skelModel.new_num_verts[i + 1] = newNum_verts[i + 1];
831         }
832
833 #ifndef NDEBUG
834         for ( k = 0; k < numJointsInSkeleton[g_skelModel.type]; ++k )
835         {
836                 for ( l = 0, current = g_skelModel.vertLists[k];
837                           l < g_skelModel.new_num_verts[k + 1]; ++l, current = current->next )
838                 {
839                         IntListNode_t *current2;
840                         int m;
841
842                         for ( m = l + 1, current2 = current->next; m < newNum_verts[k + 1];
843                                   ++m, current2 = current2->next )
844                         {
845                                 if ( current->data == current2->data ) {
846                                         printf( "Warning duplicate vertex:  %d\n", current->data );
847                                         break;
848                                 }
849                         }
850                 }
851         }
852 #endif
853
854         for ( i = 0; i < fmheader.num_mesh_nodes; i++ )
855         {   // reset the vert bits
856                 memset( pmnodes[i].verts,0,sizeof( pmnodes[i].verts ) );
857         }
858
859         // repleace the master triangle list vertex indexes and update the vert bits for each mesh node
860         for ( i = 0 ; i < fmheader.num_tris ; i++ )
861         {
862                 pos = i >> 3;
863                 bit = 1 << ( i & 7 );
864
865                 for ( j = 0 ; j < 3 ; j++ )
866                 {
867                         set_bit = set_pos = triangles[i].index_xyz[j] = vert_replacement[triangles[i].index_xyz[j]];
868
869                         set_pos >>= 3;
870                         set_bit = 1 << ( set_bit & 7 );
871
872                         for ( k = 0; k < fmheader.num_mesh_nodes; k++ )
873                         {
874                                 if ( !( pmnodes[k].tris[pos] & bit ) ) {
875                                         continue;
876                                 }
877                                 pmnodes[k].verts[set_pos] |= set_bit;
878                         }
879                 }
880         }
881
882         for ( i = 0; i < numcommands; i++ )
883         {
884                 j = commands[i];
885                 if ( !j ) {
886                         continue;
887                 }
888
889                 j = abs( j );
890                 for ( i++; j; j--,i += 3 )
891                 {
892                         commands[i + 2] = vert_replacement[commands[i + 2]];
893                 }
894                 i--;
895         }
896
897         printf( "Reduced by %d\n",fmheader.num_xyz - num_unique );
898
899         fmheader.num_xyz = num_unique;
900         if ( num_groups ) {
901                 // tack on the reference verts to the regular verts
902                 if ( g_skelModel.references != REF_NULL ) {
903                         fmframe_t   *in;
904                         int index;
905                         int refnum;
906
907                         if ( RefPointNum <= 0 ) { // Hard-coded labels
908                                 refnum = numReferences[g_skelModel.references];
909                         }
910                         else
911                         {   // Labels indicated in QDT
912                                 refnum = RefPointNum;
913                         }
914
915
916                         for ( i = 0; i < fmheader.num_frames; ++i )
917                         {
918                                 in = &g_frames[i];
919                                 index = fmheader.num_xyz;
920
921                                 for ( j = 0 ; j < refnum; ++j )
922                                 {
923                                         VectorCopy( in->references[j].placement.origin, in->v[index].v );
924                                         index++;
925
926                                         VectorCopy( in->references[j].placement.direction, in->v[index].v );
927                                         index++;
928
929                                         VectorCopy( in->references[j].placement.up, in->v[index].v );
930                                         index++;
931                                 }
932                         }
933
934                         fmheader.num_xyz += refnum * 3;
935                 }
936
937                 // tack on the skeletal joint verts to the regular verts
938                 if ( g_skelModel.type != SKEL_NULL ) {
939                         fmframe_t   *in;
940                         int index;
941
942                         for ( i = 0; i < fmheader.num_frames; ++i )
943                         {
944                                 in = &g_frames[i];
945                                 index = fmheader.num_xyz;
946
947                                 for ( j = 0 ; j < numJointsInSkeleton[g_skelModel.type]; ++j )
948                                 {
949                                         VectorCopy( in->joints[j].placement.origin, in->v[index].v );
950                                         index++;
951
952                                         VectorCopy( in->joints[j].placement.direction, in->v[index].v );
953                                         index++;
954
955                                         VectorCopy( in->joints[j].placement.up, in->v[index].v );
956                                         index++;
957                                 }
958                         }
959
960                         fmheader.num_xyz += numJointsInSkeleton[g_skelModel.type] * 3;
961                 }
962
963                 CompressFrames();
964         }
965 }
966
967
968 /*
969    ===============
970    FinishModel
971    ===============
972  */
973 void FMFinishModel( void ){
974         FILE        *modelouthandle;
975         int i,j,length,tris,verts,bit,pos,total_tris,total_verts;
976         char name[1024];
977         int trans_count;
978
979         if ( !fmheader.num_frames ) {
980                 return;
981         }
982
983 //
984 // copy to release directory tree if doing a release build
985 //
986         if ( g_release ) {
987                 if ( modelname[0] ) {
988                         sprintf( name, "%s", modelname );
989                 }
990                 else{
991                         sprintf( name, "%s/tris.fm", cdpartial );
992                 }
993                 ReleaseFile( name );
994
995                 for ( i = 0 ; i < fmheader.num_skins ; i++ )
996                 {
997                         ReleaseFile( g_skins[i] );
998                 }
999                 fmheader.num_frames = 0;
1000                 return;
1001         }
1002
1003         printf( "\n" );
1004
1005         trans_count = 0;
1006         for ( i = 0; i < fmheader.num_tris; i++ )
1007                 if ( translucent[i] ) {
1008                         trans_count++;
1009                 }
1010
1011         if ( !g_no_opimizations ) {
1012                 OptimizeVertices();
1013         }
1014
1015 //
1016 // write the model output file
1017 //
1018         if ( modelname[0] ) {
1019                 sprintf( name, "%s%s", g_outputDir, modelname );
1020         }
1021         else{
1022                 sprintf( name, "%s/tris.fm", g_outputDir );
1023         }
1024         printf( "saving to %s\n", name );
1025         CreatePath( name );
1026         modelouthandle = SafeOpenWrite( name );
1027
1028         WriteModelFile( modelouthandle );
1029
1030         printf( "%3dx%3d skin\n", fmheader.skinwidth, fmheader.skinheight );
1031         printf( "First frame boundaries:\n" );
1032         printf( "       minimum x: %3f\n", g_frames[0].mins[0] );
1033         printf( "       maximum x: %3f\n", g_frames[0].maxs[0] );
1034         printf( "       minimum y: %3f\n", g_frames[0].mins[1] );
1035         printf( "       maximum y: %3f\n", g_frames[0].maxs[1] );
1036         printf( "       minimum z: %3f\n", g_frames[0].mins[2] );
1037         printf( "       maximum z: %3f\n", g_frames[0].maxs[2] );
1038         printf( "%4d vertices\n", fmheader.num_xyz );
1039         printf( "%4d triangles, %4d of them translucent\n", fmheader.num_tris, trans_count );
1040         printf( "%4d frame\n", fmheader.num_frames );
1041         printf( "%4d glverts\n", numglverts );
1042         printf( "%4d glcmd\n", fmheader.num_glcmds );
1043         printf( "%4d skins\n", fmheader.num_skins );
1044         printf( "%4d mesh nodes\n", fmheader.num_mesh_nodes );
1045         printf( "wasted pixels: %d / %d (%5.2f Percent)\n",total_skin_pixels - skin_pixels_used,
1046                         total_skin_pixels, (double)( total_skin_pixels - skin_pixels_used ) / (double)total_skin_pixels * 100.0 );
1047
1048         printf( "file size: %d\n", (int)ftell( modelouthandle ) );
1049         printf( "---------------------\n" );
1050
1051         if ( g_verbose ) {
1052                 if ( fmheader.num_mesh_nodes ) {
1053                         total_tris = total_verts = 0;
1054                         printf( "Node Name                         Tris Verts\n" );
1055                         printf( "--------------------------------- ---- -----\n" );
1056                         for ( i = 0; i < fmheader.num_mesh_nodes; i++ )
1057                         {
1058                                 tris = 0;
1059                                 verts = 0;
1060                                 for ( j = 0; j < MAXTRIANGLES; j++ )
1061                                 {
1062                                         pos = ( j ) >> 3;
1063                                         bit = 1 << ( ( j ) & 7 );
1064                                         if ( pmnodes[i].tris[pos] & bit ) {
1065                                                 tris++;
1066                                         }
1067                                 }
1068                                 for ( j = 0; j < MAX_FM_VERTS; j++ )
1069                                 {
1070                                         pos = ( j ) >> 3;
1071                                         bit = 1 << ( ( j ) & 7 );
1072                                         if ( pmnodes[i].verts[pos] & bit ) {
1073                                                 verts++;
1074                                         }
1075                                 }
1076
1077                                 printf( "%-33s %4d %5d\n",pmnodes[i].name,tris,verts );
1078
1079                                 total_tris += tris;
1080                                 total_verts += verts;
1081                         }
1082                         printf( "--------------------------------- ---- -----\n" );
1083                         printf( "%-33s %4d %5d\n","TOTALS",total_tris,total_verts );
1084                 }
1085         }
1086         fclose( modelouthandle );
1087
1088         // finish writing header file
1089         H_printf( "\n" );
1090
1091         // scale_up is usefull to allow step distances to be adjusted
1092         H_printf( "#define MODEL_SCALE\t\t%f\n", scale_up );
1093
1094         // mesh nodes
1095         if ( fmheader.num_mesh_nodes ) {
1096                 H_printf( "\n" );
1097                 H_printf( "#define NUM_MESH_NODES\t\t%d\n\n",fmheader.num_mesh_nodes );
1098                 for ( i = 0; i < fmheader.num_mesh_nodes; i++ )
1099                 {
1100                         strcpy( name, pmnodes[i].name );
1101                         strupr( name );
1102                         length = strlen( name );
1103                         for ( j = 0; j < length; j++ )
1104                         {
1105                                 if ( name[j] == ' ' ) {
1106                                         name[j] = '_';
1107                                 }
1108                         }
1109                         H_printf( "#define MESH_%s\t\t%d\n", name, i );
1110                 }
1111         }
1112
1113         fclose( headerouthandle );
1114         headerouthandle = NULL;
1115         free( pmnodes );
1116 }
1117
1118
1119 /*
1120    =================================================================
1121
1122    ALIAS MODEL DISPLAY LIST GENERATION
1123
1124    =================================================================
1125  */
1126
1127 extern int strip_xyz[128];
1128 extern int strip_st[128];
1129 extern int strip_tris[128];
1130 extern int stripcount;
1131
1132 /*
1133    ================
1134    StripLength
1135    ================
1136  */
1137 static int  StripLength( int starttri, int startv, int num_tris, int node ){
1138         int m1, m2;
1139         int st1, st2;
1140         int j;
1141         fmtriangle_t    *last, *check;
1142         int k;
1143         int pos, bit;
1144
1145         used[starttri] = 2;
1146
1147         last = &triangles[starttri];
1148
1149         strip_xyz[0] = last->index_xyz[( startv ) % 3];
1150         strip_xyz[1] = last->index_xyz[( startv + 1 ) % 3];
1151         strip_xyz[2] = last->index_xyz[( startv + 2 ) % 3];
1152         strip_st[0] = last->index_st[( startv ) % 3];
1153         strip_st[1] = last->index_st[( startv + 1 ) % 3];
1154         strip_st[2] = last->index_st[( startv + 2 ) % 3];
1155
1156         strip_tris[0] = starttri;
1157         stripcount = 1;
1158
1159         m1 = last->index_xyz[( startv + 2 ) % 3];
1160         st1 = last->index_st[( startv + 2 ) % 3];
1161         m2 = last->index_xyz[( startv + 1 ) % 3];
1162         st2 = last->index_st[( startv + 1 ) % 3];
1163
1164         // look for a matching triangle
1165 nexttri:
1166         for ( j = starttri + 1, check = &triangles[starttri + 1]
1167                   ; j < num_tris ; j++, check++ )
1168         {
1169                 pos = j >> 3;
1170                 bit = 1 << ( j & 7 );
1171                 if ( !( pmnodes[node].tris[pos] & bit ) ) {
1172                         continue;
1173                 }
1174                 for ( k = 0 ; k < 3 ; k++ )
1175                 {
1176                         if ( check->index_xyz[k] != m1 ) {
1177                                 continue;
1178                         }
1179                         if ( check->index_st[k] != st1 ) {
1180                                 continue;
1181                         }
1182                         if ( check->index_xyz[ ( k + 1 ) % 3 ] != m2 ) {
1183                                 continue;
1184                         }
1185                         if ( check->index_st[ ( k + 1 ) % 3 ] != st2 ) {
1186                                 continue;
1187                         }
1188
1189                         // this is the next part of the fan
1190
1191                         // if we can't use this triangle, this tristrip is done
1192                         if ( used[j] || translucent[j] != translucent[starttri] ) {
1193                                 goto done;
1194                         }
1195
1196                         // the new edge
1197                         if ( stripcount & 1 ) {
1198                                 m2 = check->index_xyz[ ( k + 2 ) % 3 ];
1199                                 st2 = check->index_st[ ( k + 2 ) % 3 ];
1200                         }
1201                         else
1202                         {
1203                                 m1 = check->index_xyz[ ( k + 2 ) % 3 ];
1204                                 st1 = check->index_st[ ( k + 2 ) % 3 ];
1205                         }
1206
1207                         strip_xyz[stripcount + 2] = check->index_xyz[ ( k + 2 ) % 3 ];
1208                         strip_st[stripcount + 2] = check->index_st[ ( k + 2 ) % 3 ];
1209                         strip_tris[stripcount] = j;
1210                         stripcount++;
1211
1212                         used[j] = 2;
1213                         goto nexttri;
1214                 }
1215         }
1216 done:
1217
1218         // clear the temp used flags
1219         for ( j = starttri + 1 ; j < num_tris ; j++ )
1220                 if ( used[j] == 2 ) {
1221                         used[j] = 0;
1222                 }
1223
1224         return stripcount;
1225 }
1226
1227
1228 /*
1229    ===========
1230    FanLength
1231    ===========
1232  */
1233 static int  FanLength( int starttri, int startv, int num_tris, int node ){
1234         int m1, m2;
1235         int st1, st2;
1236         int j;
1237         fmtriangle_t    *last, *check;
1238         int k;
1239         int pos, bit;
1240
1241         used[starttri] = 2;
1242
1243         last = &triangles[starttri];
1244
1245         strip_xyz[0] = last->index_xyz[( startv ) % 3];
1246         strip_xyz[1] = last->index_xyz[( startv + 1 ) % 3];
1247         strip_xyz[2] = last->index_xyz[( startv + 2 ) % 3];
1248         strip_st[0] = last->index_st[( startv ) % 3];
1249         strip_st[1] = last->index_st[( startv + 1 ) % 3];
1250         strip_st[2] = last->index_st[( startv + 2 ) % 3];
1251
1252         strip_tris[0] = starttri;
1253         stripcount = 1;
1254
1255         m1 = last->index_xyz[( startv + 0 ) % 3];
1256         st1 = last->index_st[( startv + 0 ) % 3];
1257         m2 = last->index_xyz[( startv + 2 ) % 3];
1258         st2 = last->index_st[( startv + 2 ) % 3];
1259
1260
1261         // look for a matching triangle
1262 nexttri:
1263         for ( j = starttri + 1, check = &triangles[starttri + 1]
1264                   ; j < num_tris ; j++, check++ )
1265         {
1266                 pos = j >> 3;
1267                 bit = 1 << ( j & 7 );
1268                 if ( !( pmnodes[node].tris[pos] & bit ) ) {
1269                         continue;
1270                 }
1271                 for ( k = 0 ; k < 3 ; k++ )
1272                 {
1273                         if ( check->index_xyz[k] != m1 ) {
1274                                 continue;
1275                         }
1276                         if ( check->index_st[k] != st1 ) {
1277                                 continue;
1278                         }
1279                         if ( check->index_xyz[ ( k + 1 ) % 3 ] != m2 ) {
1280                                 continue;
1281                         }
1282                         if ( check->index_st[ ( k + 1 ) % 3 ] != st2 ) {
1283                                 continue;
1284                         }
1285
1286                         // this is the next part of the fan
1287
1288                         // if we can't use this triangle, this tristrip is done
1289                         if ( used[j] || translucent[j] != translucent[starttri] ) {
1290                                 goto done;
1291                         }
1292
1293                         // the new edge
1294                         m2 = check->index_xyz[ ( k + 2 ) % 3 ];
1295                         st2 = check->index_st[ ( k + 2 ) % 3 ];
1296
1297                         strip_xyz[stripcount + 2] = m2;
1298                         strip_st[stripcount + 2] = st2;
1299                         strip_tris[stripcount] = j;
1300                         stripcount++;
1301
1302                         used[j] = 2;
1303                         goto nexttri;
1304                 }
1305         }
1306 done:
1307
1308         // clear the temp used flags
1309         for ( j = starttri + 1 ; j < num_tris ; j++ )
1310                 if ( used[j] == 2 ) {
1311                         used[j] = 0;
1312                 }
1313
1314         return stripcount;
1315 }
1316
1317
1318
1319 /*
1320    ================
1321    BuildGlCmds
1322
1323    Generate a list of trifans or strips
1324    for the model, which holds for all frames
1325    ================
1326  */
1327 static void BuildGlCmds( void ){
1328         int i, j, k, l;
1329         int startv;
1330         float s, t;
1331         int len, bestlen, besttype;
1332         int best_xyz[1024];
1333         int best_st[1024];
1334         int best_tris[1024];
1335         int type;
1336         int trans_check;
1337         int bit,pos;
1338
1339         //
1340         // build tristrips
1341         //
1342         numcommands = 0;
1343         numglverts = 0;
1344
1345
1346         for ( l = 0; l < fmheader.num_mesh_nodes; l++ )
1347         {
1348                 memset( used, 0, sizeof( used ) );
1349
1350                 pmnodes[l].start_glcmds = numcommands;
1351
1352                 for ( trans_check = 0; trans_check < 2; trans_check++ )
1353                 {
1354                         for ( i = 0 ; i < fmheader.num_tris ; i++ )
1355                         {
1356                                 pos = i >> 3;
1357                                 bit = 1 << ( i & 7 );
1358                                 if ( !( pmnodes[l].tris[pos] & bit ) ) {
1359                                         continue;
1360                                 }
1361
1362                                 // pick an unused triangle and start the trifan
1363                                 if ( used[i] || trans_check != translucent[i] ) {
1364                                         continue;
1365                                 }
1366
1367                                 bestlen = 0;
1368                                 for ( type = 0 ; type < 2 ; type++ )
1369                                 //      type = 1;
1370                                 {
1371                                         for ( startv = 0 ; startv < 3 ; startv++ )
1372                                         {
1373                                                 if ( type == 1 ) {
1374                                                         len = StripLength( i, startv, fmheader.num_tris, l );
1375                                                 }
1376                                                 else{
1377                                                         len = FanLength( i, startv, fmheader.num_tris, l );
1378                                                 }
1379                                                 if ( len > bestlen ) {
1380                                                         besttype = type;
1381                                                         bestlen = len;
1382                                                         for ( j = 0 ; j < bestlen + 2 ; j++ )
1383                                                         {
1384                                                                 best_st[j] = strip_st[j];
1385                                                                 best_xyz[j] = strip_xyz[j];
1386                                                         }
1387                                                         for ( j = 0 ; j < bestlen ; j++ )
1388                                                                 best_tris[j] = strip_tris[j];
1389                                                 }
1390                                         }
1391                                 }
1392
1393                                 // mark the tris on the best strip/fan as used
1394                                 for ( j = 0 ; j < bestlen ; j++ )
1395                                         used[best_tris[j]] = 1;
1396
1397                                 if ( besttype == 1 ) {
1398                                         commands[numcommands++] = ( bestlen + 2 );
1399                                 }
1400                                 else{
1401                                         commands[numcommands++] = -( bestlen + 2 );
1402                                 }
1403
1404                                 numglverts += bestlen + 2;
1405
1406                                 for ( j = 0 ; j < bestlen + 2 ; j++ )
1407                                 {
1408                                         // emit a vertex into the reorder buffer
1409                                         k = best_st[j];
1410
1411                                         // emit s/t coords into the commands stream
1412                                         s = base_st[k].s;
1413                                         t = base_st[k].t;
1414
1415                                         s = ( s  ) / fmheader.skinwidth;
1416                                         t = ( t  ) / fmheader.skinheight;
1417
1418                                         *(float *)&commands[numcommands++] = s;
1419                                         *(float *)&commands[numcommands++] = t;
1420                                         *(int *)&commands[numcommands++] = best_xyz[j];
1421                                 }
1422                         }
1423                 }
1424                 commands[numcommands++] = 0;        // end of list marker
1425                 pmnodes[l].num_glcmds = numcommands - pmnodes[l].start_glcmds;
1426         }
1427 }
1428
1429
1430 /*
1431    ===============================================================
1432
1433    BASE FRAME SETUP
1434
1435    ===============================================================
1436  */
1437
1438
1439 #define LINE_NORMAL 1
1440 #define LINE_FAT 2
1441 #define LINE_DOTTED 3
1442
1443
1444 #define ASCII_SPACE 32
1445
1446 int LineType = LINE_NORMAL;
1447 extern unsigned char pic[SKINPAGE_HEIGHT * SKINPAGE_WIDTH], pic_palette[768];
1448 unsigned char LineColor = 255;
1449 int ScaleWidth, ScaleHeight;
1450
1451
1452 static char *CharDefs[] =
1453 {
1454         "-------------------------",
1455         "-------------------------", // !
1456         "-------------------------", // "
1457         "-------------------------", // #
1458         "-------------------------", // $
1459         "-------------------------", // %
1460         "-------------------------", // &
1461         "--*----*-----------------", // '
1462         "-*---*----*----*-----*---", // (
1463         "*-----*----*----*---*----", // )
1464         "-----*--*--**---**--*--*-", // *
1465         "-------------------------", // +
1466         "----------------**--**---", // ,
1467         "-------------------------", // -
1468         "----------------**---**--", // .
1469         "-------------------------", // /
1470         " *** *  *** * ***  * *** ", // 0
1471         "   *   **    *    *    * ",
1472         "****     * *** *    *****",
1473         "****     * ***     ***** ",
1474         "  **  * * *  * *****   * ",
1475         "**** *    ****     ***** ",
1476         " *** *    **** *   * *** ",
1477         "*****    *   *   *    *  ",
1478         " *** *   * *** *   * *** ",
1479         " *** *   * ****    * *** ", // 9
1480         "-**---**--------**---**--", // :
1481         "-------------------------", // ;
1482         "-------------------------", // <
1483         "-------------------------", // =
1484         "-------------------------", // >
1485         "-------------------------", // ?
1486         "-------------------------", // @
1487         "-***-*---*******---**---*", // A
1488         "****-*---*****-*---*****-",
1489         "-*****----*----*-----****",
1490         "****-*---**---**---*****-",
1491         "******----****-*----*****",
1492         "******----****-*----*----",
1493         "-*****----*--***---*-****",
1494         "*---**---*******---**---*",
1495         "-***---*----*----*---***-",
1496         "----*----*----**---*-***-",
1497         "-*--*-*-*--**---*-*--*--*",
1498         "-*----*----*----*----****",
1499         "*---***-***-*-**---**---*",
1500         "*---***--**-*-**--***---*",
1501         "-***-*---**---**---*-***-",
1502         "****-*---*****-*----*----",
1503         "-***-*---**---*-***----**",
1504         "****-*---*****-*-*--*--**",
1505         "-*****-----***-----*****-",
1506         "*****--*----*----*----*--",
1507         "*---**---**---**---******",
1508         "*---**---**---*-*-*---*--",
1509         "*---**---**-*-***-***---*",
1510         "*---*-*-*---*---*-*-*---*",
1511         "*---**---*-*-*---*----*--",
1512         "*****---*---*---*---*****" // Z
1513 };
1514
1515 void DrawLine( int x1, int y1, int x2, int y2 ){
1516         int dx, dy;
1517         int adx, ady;
1518         int count;
1519         float xfrac, yfrac, xstep, ystep;
1520         unsigned sx, sy;
1521         float u, v;
1522
1523         dx = x2 - x1;
1524         dy = y2 - y1;
1525         adx = abs( dx );
1526         ady = abs( dy );
1527
1528         count = adx > ady ? adx : ady;
1529         count++;
1530
1531         if ( count > 300 ) {
1532                 printf( "Bad count\n" );
1533                 return; // don't ever hang up on bad data
1534         }
1535
1536         xfrac = x1;
1537         yfrac = y1;
1538
1539         xstep = (float)dx / count;
1540         ystep = (float)dy / count;
1541
1542         switch ( LineType )
1543         {
1544         case LINE_NORMAL:
1545                 do
1546                 {
1547                         if ( xfrac < SKINPAGE_WIDTH && yfrac < SKINPAGE_HEIGHT ) {
1548                                 pic[(int)yfrac * SKINPAGE_WIDTH + (int)xfrac] = LineColor;
1549                         }
1550                         xfrac += xstep;
1551                         yfrac += ystep;
1552                         count--;
1553                 } while ( count > 0 );
1554                 break;
1555         case LINE_FAT:
1556                 do
1557                 {
1558                         for ( u = -0.1 ; u <= 0.9 ; u += 0.999 )
1559                         {
1560                                 for ( v = -0.1 ; v <= 0.9 ; v += 0.999 )
1561                                 {
1562                                         sx = xfrac + u;
1563                                         sy = yfrac + v;
1564                                         if ( sx < SKINPAGE_WIDTH && sy < SKINPAGE_HEIGHT ) {
1565                                                 pic[sy * SKINPAGE_WIDTH + sx] = LineColor;
1566                                         }
1567                                 }
1568                         }
1569                         xfrac += xstep;
1570                         yfrac += ystep;
1571                         count--;
1572                 } while ( count > 0 );
1573                 break;
1574         case LINE_DOTTED:
1575                 do
1576                 {
1577                         if ( count & 1 && xfrac < SKINPAGE_WIDTH &&
1578                                  yfrac < SKINPAGE_HEIGHT ) {
1579                                 pic[(int)yfrac * SKINPAGE_WIDTH + (int)xfrac] = LineColor;
1580                         }
1581                         xfrac += xstep;
1582                         yfrac += ystep;
1583                         count--;
1584                 } while ( count > 0 );
1585                 break;
1586         default:
1587                 Error( "Unknown <linetype> %d.\n", LineType );
1588         }
1589 }
1590
1591 //==========================================================================
1592 //
1593 // DrawCharacter
1594 //
1595 //==========================================================================
1596
1597 static void DrawCharacter( int x, int y, int character ){
1598         int r, c;
1599         char *def;
1600
1601         character = toupper( character );
1602         if ( character < ASCII_SPACE || character > 'Z' ) {
1603                 character = ASCII_SPACE;
1604         }
1605         character -= ASCII_SPACE;
1606         for ( def = CharDefs[character], r = 0; r < 5; r++ )
1607         {
1608                 for ( c = 0; c < 5; c++ )
1609                 {
1610                         pic[( y + r ) * SKINPAGE_WIDTH + x + c] = *def++ == '*' ? 255 : 0;
1611                 }
1612         }
1613 }
1614
1615 //==========================================================================
1616 //
1617 // DrawTextChar
1618 //
1619 //==========================================================================
1620
1621 void DrawTextChar( int x, int y, char *text ){
1622         int c;
1623
1624         while ( ( c = *text++ ) != '\0' )
1625         {
1626                 DrawCharacter( x, y, c );
1627                 x += 6;
1628         }
1629 }
1630
1631
1632 extern void DrawScreen( float s_scale, float t_scale, float iwidth, float iheight );
1633
1634 //==========================================================================
1635 // ExtractDigit
1636
1637 static int ExtractDigit( byte *pic, int x, int y ){
1638         int i;
1639         int r, c;
1640         char digString[32];
1641         char    *buffer;
1642         byte backColor;
1643         char    **DigitDefs;
1644
1645         backColor = pic[( SKINPAGE_HEIGHT - 1 ) * SKINPAGE_WIDTH];
1646         DigitDefs = &CharDefs['0' - ASCII_SPACE];
1647
1648         buffer = digString;
1649         for ( r = 0; r < 5; r++ )
1650         {
1651                 for ( c = 0; c < 5; c++ )
1652                 {
1653                         *buffer++ = ( pic[( y + r ) * SKINPAGE_WIDTH + x + c] == backColor ) ? ' ' : '*';
1654                 }
1655         }
1656         *buffer = '\0';
1657         for ( i = 0; i < 10; i++ )
1658         {
1659                 if ( strcmp( DigitDefs[i], digString ) == 0 ) {
1660                         return i;
1661                 }
1662         }
1663
1664         Error( "Unable to extract scaling info from skin PCX." );
1665         return 0;
1666 }
1667
1668 //==========================================================================
1669 // ExtractNumber
1670
1671 int ExtractNumber( byte *pic, int x, int y ){
1672         return ExtractDigit( pic, x, y ) * 100 + ExtractDigit( pic, x + 6, y ) * 10 + ExtractDigit( pic, x + 12, y );
1673 }
1674
1675
1676
1677
1678
1679 /*
1680    ============
1681    BuildST
1682
1683    Builds the triangle_st array for the base frame and
1684    fmheader.skinwidth / fmheader.skinheight
1685
1686    FIXME: allow this to be loaded from a file for
1687    arbitrary mappings
1688    ============
1689  */
1690 static void BuildST( triangle_t *ptri, int numtri, qboolean DrawSkin ){
1691         int backface_flag;
1692         int i, j;
1693         int width, height, iwidth, iheight, swidth;
1694         float basex, basey;
1695         float scale;
1696         vec3_t mins, maxs;
1697         float       *pbasevert;
1698         vec3_t vtemp1, vtemp2, normal;
1699         float s_scale, t_scale;
1700         float scWidth;
1701         float scHeight;
1702         int skinwidth;
1703         int skinheight;
1704
1705         //
1706         // find bounds of all the verts on the base frame
1707         //
1708         ClearBounds( mins, maxs );
1709         backface_flag = false;
1710
1711         if ( ptri[0].HasUV ) { // if we have the uv already, we don't want to double up or scale
1712                 iwidth = ScaleWidth;
1713                 iheight = ScaleHeight;
1714
1715                 t_scale = s_scale = 1.0;
1716         }
1717         else
1718         {
1719                 for ( i = 0 ; i < numtri ; i++ )
1720                         for ( j = 0 ; j < 3 ; j++ )
1721                                 AddPointToBounds( ptri[i].verts[j], mins, maxs );
1722
1723                 for ( i = 0 ; i < 3 ; i++ )
1724                 {
1725                         mins[i] = floor( mins[i] );
1726                         maxs[i] = ceil( maxs[i] );
1727                 }
1728
1729                 width = maxs[0] - mins[0];
1730                 height = maxs[2] - mins[2];
1731
1732                 for ( i = 0 ; i < numtri ; i++ )
1733                 {
1734                         VectorSubtract( ptri[i].verts[0], ptri[i].verts[1], vtemp1 );
1735                         VectorSubtract( ptri[i].verts[2], ptri[i].verts[1], vtemp2 );
1736                         CrossProduct( vtemp1, vtemp2, normal );
1737
1738                         if ( normal[1] > 0 ) {
1739                                 backface_flag = true;
1740                                 break;
1741                         }
1742                 }
1743                 scWidth = ScaleWidth * SCALE_ADJUST_FACTOR;
1744                 if ( backface_flag ) {  //we are doubling
1745                         scWidth /= 2;
1746                 }
1747
1748                 scHeight = ScaleHeight * SCALE_ADJUST_FACTOR;
1749
1750                 scale = scWidth / width;
1751
1752                 if ( height * scale >= scHeight ) {
1753                         scale = scHeight / height;
1754                 }
1755
1756                 iwidth = ceil( width * scale ) + 4;
1757                 iheight = ceil( height * scale ) + 4;
1758
1759                 s_scale = (float)( iwidth - 4 ) / width;
1760                 t_scale = (float)( iheight - 4 ) / height;
1761                 t_scale = s_scale;
1762         }
1763         if ( DrawSkin ) {
1764                 if ( backface_flag ) {
1765                         DrawScreen( s_scale, t_scale, iwidth * 2, iheight );
1766                 }
1767                 else{
1768                         DrawScreen( s_scale, t_scale, iwidth, iheight );
1769                 }
1770         }
1771         if ( backface_flag ) {
1772                 skinwidth = iwidth * 2;
1773         }
1774         else{
1775                 skinwidth = iwidth;
1776         }
1777         skinheight = iheight;
1778
1779
1780 /*      if (!g_fixedwidth)
1781     {   // old style
1782         scale = 8;
1783         if (width*scale >= 150)
1784             scale = 150.0 / width;
1785         if (height*scale >= 190)
1786             scale = 190.0 / height;
1787
1788         s_scale = t_scale = scale;
1789
1790         iwidth = ceil(width*s_scale);
1791         iheight = ceil(height*t_scale);
1792
1793         iwidth += 4;
1794         iheight += 4;
1795     }
1796     else
1797     {   // new style
1798         iwidth = g_fixedwidth / 2;
1799         iheight = g_fixedheight;
1800
1801         s_scale = (float)(iwidth-4) / width;
1802         t_scale = (float)(iheight-4) / height;
1803     }*/
1804
1805 //
1806 // determine which side of each triangle to map the texture to
1807 //
1808         basey = 2;
1809         for ( i = 0 ; i < numtri ; i++ )
1810         {
1811                 if ( ptri[i].HasUV ) {
1812                         for ( j = 0 ; j < 3 ; j++ )
1813                         {
1814                                 triangle_st[i][j][0] = Q_rint( ptri[i].uv[j][0] * skinwidth );
1815                                 triangle_st[i][j][1] = Q_rint( ( 1.0f - ptri[i].uv[j][1] ) * skinheight );
1816                         }
1817                 }
1818                 else
1819                 {
1820                         VectorSubtract( ptri[i].verts[0], ptri[i].verts[1], vtemp1 );
1821                         VectorSubtract( ptri[i].verts[2], ptri[i].verts[1], vtemp2 );
1822                         CrossProduct( vtemp1, vtemp2, normal );
1823
1824                         if ( normal[1] > 0 ) {
1825                                 basex = iwidth + 2;
1826                         }
1827                         else
1828                         {
1829                                 basex = 2;
1830                         }
1831
1832                         for ( j = 0 ; j < 3 ; j++ )
1833                         {
1834                                 pbasevert = ptri[i].verts[j];
1835
1836                                 triangle_st[i][j][0] = Q_rint( ( pbasevert[0] - mins[0] ) * s_scale + basex );
1837                                 triangle_st[i][j][1] = Q_rint( ( maxs[2] - pbasevert[2] ) * t_scale + basey );
1838                         }
1839                 }
1840
1841                 if ( DrawSkin ) {
1842                         DrawLine( triangle_st[i][0][0], triangle_st[i][0][1],
1843                                           triangle_st[i][1][0], triangle_st[i][1][1] );
1844                         DrawLine( triangle_st[i][1][0], triangle_st[i][1][1],
1845                                           triangle_st[i][2][0], triangle_st[i][2][1] );
1846                         DrawLine( triangle_st[i][2][0], triangle_st[i][2][1],
1847                                           triangle_st[i][0][0], triangle_st[i][0][1] );
1848                 }
1849         }
1850
1851 // make the width a multiple of 4; some hardware requires this, and it ensures
1852 // dword alignment for each scan
1853
1854         swidth = iwidth;
1855         if ( backface_flag ) {
1856                 swidth *= 2;
1857         }
1858         fmheader.skinwidth = ( swidth + 3 ) & ~3;
1859         fmheader.skinheight = iheight;
1860
1861         skin_width = iwidth;
1862         skin_height = iheight;
1863 }
1864
1865
1866 static void BuildNewST( triangle_t *ptri, int numtri, qboolean DrawSkin ){
1867         int i, j;
1868
1869         for ( i = 0 ; i < numtri ; i++ )
1870         {
1871                 if ( ptri[i].HasUV ) {
1872                         for ( j = 0 ; j < 3 ; j++ )
1873                         {
1874                                 triangle_st[i][j][0] = Q_rint( ptri[i].uv[j][0] * ( ScaleWidth - 1 ) );
1875                                 triangle_st[i][j][1] = Q_rint( ( 1.0f - ptri[i].uv[j][1] ) * ( ScaleHeight - 1 ) );
1876                         }
1877                 }
1878
1879                 if ( DrawSkin ) {
1880                         DrawLine( triangle_st[i][0][0], triangle_st[i][0][1],
1881                                           triangle_st[i][1][0], triangle_st[i][1][1] );
1882                         DrawLine( triangle_st[i][1][0], triangle_st[i][1][1],
1883                                           triangle_st[i][2][0], triangle_st[i][2][1] );
1884                         DrawLine( triangle_st[i][2][0], triangle_st[i][2][1],
1885                                           triangle_st[i][0][0], triangle_st[i][0][1] );
1886                 }
1887         }
1888
1889 // make the width a multiple of 4; some hardware requires this, and it ensures
1890 // dword alignment for each scan
1891
1892         fmheader.skinwidth = ( ScaleWidth + 3 ) & ~3;
1893         fmheader.skinheight = ScaleHeight;
1894
1895         skin_width = ScaleWidth;
1896         skin_height = ScaleHeight;
1897 }
1898
1899
1900
1901
1902 byte            *BasePalette;
1903 byte            *BasePixels,*TransPixels;
1904 int BaseWidth, BaseHeight, TransWidth, TransHeight;
1905 qboolean BaseTrueColor;
1906 static qboolean SetPixel = false;
1907
1908 int CheckTransRecursiveTri( int *lp1, int *lp2, int *lp3 ){
1909         int     *temp;
1910         int d;
1911         int new[2];
1912
1913         d = lp2[0] - lp1[0];
1914         if ( d < -1 || d > 1 ) {
1915                 goto split;
1916         }
1917         d = lp2[1] - lp1[1];
1918         if ( d < -1 || d > 1 ) {
1919                 goto split;
1920         }
1921
1922         d = lp3[0] - lp2[0];
1923         if ( d < -1 || d > 1 ) {
1924                 goto split2;
1925         }
1926         d = lp3[1] - lp2[1];
1927         if ( d < -1 || d > 1 ) {
1928                 goto split2;
1929         }
1930
1931         d = lp1[0] - lp3[0];
1932         if ( d < -1 || d > 1 ) {
1933                 goto split3;
1934         }
1935         d = lp1[1] - lp3[1];
1936         if ( d < -1 || d > 1 ) {
1937 split3:
1938                 temp = lp1;
1939                 lp1 = lp3;
1940                 lp3 = lp2;
1941                 lp2 = temp;
1942
1943                 goto split;
1944         }
1945
1946         return 0;           // entire tri is filled
1947
1948 split2:
1949         temp = lp1;
1950         lp1 = lp2;
1951         lp2 = lp3;
1952         lp3 = temp;
1953
1954 split:
1955 // split this edge
1956         new[0] = ( lp1[0] + lp2[0] ) >> 1;
1957         new[1] = ( lp1[1] + lp2[1] ) >> 1;
1958
1959 // draw the point if splitting a leading edge
1960         if ( lp2[1] > lp1[1] ) {
1961                 goto nodraw;
1962         }
1963         if ( ( lp2[1] == lp1[1] ) && ( lp2[0] < lp1[0] ) ) {
1964                 goto nodraw;
1965         }
1966
1967         if ( SetPixel ) {
1968                 assert( ( new[1] * BaseWidth ) + new[0] < BaseWidth * BaseHeight );
1969
1970                 if ( BaseTrueColor ) {
1971                         BasePixels[( ( new[1] * BaseWidth ) + new[0] ) * 4] = 1;
1972                 }
1973                 else
1974                 {
1975                         BasePixels[( new[1] * BaseWidth ) + new[0]] = 1;
1976                 }
1977         }
1978         else
1979         {
1980                 if ( TransPixels ) {
1981                         if ( TransPixels[( new[1] * TransWidth ) + new[0]] != 255 ) {
1982                                 return 1;
1983                         }
1984                 }
1985                 else if ( BaseTrueColor ) {
1986                         if ( BasePixels[( ( ( new[1] * BaseWidth ) + new[0] ) * 4 ) + 3] != 255 ) {
1987                                 return 1;
1988                         }
1989                 }
1990                 else
1991                 {
1992 //                      pixel = BasePixels[(new[1]*BaseWidth) + new[0]];
1993                 }
1994         }
1995
1996 nodraw:
1997 // recursively continue
1998         if ( CheckTransRecursiveTri( lp3, lp1, new ) ) {
1999                 return 1;
2000         }
2001
2002         return CheckTransRecursiveTri( lp3, new, lp2 );
2003 }
2004
2005 static void ReplaceClusterIndex( int newIndex, int oldindex, int **clusters,
2006                                                                  IntListNode_t **vertLists, int *num_verts, int *new_num_verts ){
2007         int i, j;
2008         IntListNode_t *next;
2009
2010         for ( j = 0; j < numJointsInSkeleton[g_skelModel.type]; ++j )
2011         {
2012                 if ( !clusters[j] ) {
2013                         continue;
2014                 }
2015
2016                 for ( i = 0; i < num_verts[j + 1]; ++i )
2017                 {
2018                         if ( clusters[j][i] == oldindex ) {
2019                                 ++new_num_verts[j + 1];
2020
2021                                 next = vertLists[j];
2022
2023                                 vertLists[j] = (IntListNode_t *) SafeMalloc( sizeof( IntListNode_t ), "ReplaceClusterIndex" );
2024                                 // Currently freed in WriteJointedModelFile only
2025
2026                                 vertLists[j]->data = newIndex;
2027                                 vertLists[j]->next = next;
2028                         }
2029                 }
2030         }
2031 }
2032
2033 #define FUDGE_EPSILON   0.002
2034
2035 qboolean VectorFudgeCompare( vec3_t v1, vec3_t v2 ){
2036         int i;
2037
2038         for ( i = 0 ; i < 3 ; i++ )
2039                 if ( fabs( v1[i] - v2[i] ) > FUDGE_EPSILON ) {
2040                         return false;
2041                 }
2042
2043         return true;
2044 }
2045
2046 /*
2047    =================
2048    Cmd_Base
2049    =================
2050  */
2051 void Cmd_FMBase( qboolean GetST ){
2052         triangle_t  *ptri, *st_tri;
2053         int num_st_tris;
2054         int i, j, k, l;
2055         int x,y,z;
2056 //      int                     time1;
2057         char file1[1024],file2[1024],trans_file[1024], stfile[1024], extension[256];
2058         vec3_t base_xyz[MAX_FM_VERTS];
2059         FILE        *FH;
2060         int pos,bit;
2061         qboolean NewSkin;
2062
2063         GetScriptToken( false );
2064
2065         if ( g_skipmodel || g_release || g_archive ) {
2066                 return;
2067         }
2068
2069         printf( "---------------------\n" );
2070         sprintf( file1, "%s/%s.%s", cdarchive, token, trifileext );
2071         printf( "%s ", file1 );
2072
2073         ExpandPathAndArchive( file1 );
2074
2075         // Use the input filepath for this one.
2076         sprintf( file1, "%s/%s", cddir, token );
2077
2078 //      time1 = FileTime (file1);
2079 //      if (time1 == -1)
2080 //              Error ("%s doesn't exist", file1);
2081
2082 //
2083 // load the base triangles
2084 //
2085         if ( do3ds ) {
2086                 Load3DSTriangleList( file1, &ptri, &fmheader.num_tris, &pmnodes, &fmheader.num_mesh_nodes );
2087         }
2088         else{
2089                 LoadTriangleList( file1, &ptri, &fmheader.num_tris, &pmnodes, &fmheader.num_mesh_nodes );
2090         }
2091
2092         if ( g_ignoreTriUV ) {
2093                 for ( i = 0; i < fmheader.num_tris; i++ )
2094                 {
2095                         ptri[i].HasUV = 0;
2096                 }
2097         }
2098
2099         GetScriptToken( false );
2100         sprintf( file2, "%s/%s", cddir, token );
2101         sprintf( trans_file, "%s/!%s_a.pcx", cddir, token );
2102
2103         ExtractFileExtension( file2, extension );
2104         if ( extension[0] == 0 ) {
2105                 strcat( file2, ".pcx" );
2106         }
2107         printf( "skin: %s\n", file2 );
2108
2109         BaseTrueColor = LoadAnyImage( file2, &BasePixels, &BasePalette, &BaseWidth, &BaseHeight );
2110
2111         NewSkin = false;
2112         if ( BaseWidth != SKINPAGE_WIDTH || BaseHeight != SKINPAGE_HEIGHT ) {
2113                 if ( g_allow_newskin ) {
2114                         ScaleWidth = BaseWidth;
2115                         ScaleHeight = BaseHeight;
2116                         NewSkin = true;
2117                 }
2118                 else
2119                 {
2120                         Error( "Invalid skin page size: (%d,%d) should be (%d,%d)",
2121                                    BaseWidth,BaseHeight,SKINPAGE_WIDTH,SKINPAGE_HEIGHT );
2122                 }
2123         }
2124         else if ( !BaseTrueColor ) {
2125                 ScaleWidth = (float)ExtractNumber( BasePixels, ENCODED_WIDTH_X,
2126                                                                                    ENCODED_WIDTH_Y );
2127                 ScaleHeight = (float)ExtractNumber( BasePixels, ENCODED_HEIGHT_X,
2128                                                                                         ENCODED_HEIGHT_Y );
2129         }
2130         else
2131         {
2132                 Error( "Texture coordinates not supported on true color image" );
2133         }
2134
2135         if ( GetST ) {
2136                 GetScriptToken( false );
2137
2138                 sprintf( stfile, "%s/%s.%s", cdarchive, token, trifileext );
2139                 printf( "ST: %s ", stfile );
2140
2141                 sprintf( stfile, "%s/%s", cddir, token );
2142
2143                 if ( do3ds ) {
2144                         Load3DSTriangleList( stfile, &st_tri, &num_st_tris, NULL, NULL );
2145                 }
2146                 else{
2147                         LoadTriangleList( stfile, &st_tri, &num_st_tris, NULL, NULL );
2148                 }
2149
2150                 if ( num_st_tris != fmheader.num_tris ) {
2151                         Error( "num st tris mismatch: st %d / base %d", num_st_tris, fmheader.num_tris );
2152                 }
2153
2154                 printf( "   matching triangles...\n" );
2155                 for ( i = 0; i < fmheader.num_tris; i++ )
2156                 {
2157                         k = -1;
2158                         for ( j = 0; j < num_st_tris; j++ )
2159                         {
2160                                 for ( x = 0; x < 3; x++ )
2161                                 {
2162                                         for ( y = 0; y < 3; y++ )
2163                                         {
2164                                                 if ( x == y ) {
2165                                                         continue;
2166                                                 }
2167                                                 for ( z = 0; z < 3; z++ )
2168                                                 {
2169                                                         if ( z == x || z == y ) {
2170                                                                 continue;
2171                                                         }
2172
2173                                                         if ( VectorFudgeCompare( ptri[i].verts[0], st_tri[j].verts[x] ) &&
2174                                                                  VectorFudgeCompare( ptri[i].verts[1], st_tri[j].verts[y] ) &&
2175                                                                  VectorFudgeCompare( ptri[i].verts[2], st_tri[j].verts[z] ) ) {
2176                                                                 if ( k == -1 ) {
2177                                                                         k = j;
2178                                                                         ptri[i].HasUV = st_tri[k].HasUV;
2179                                                                         ptri[i].uv[0][0] = st_tri[k].uv[x][0];
2180                                                                         ptri[i].uv[0][1] = st_tri[k].uv[x][1];
2181                                                                         ptri[i].uv[1][0] = st_tri[k].uv[y][0];
2182                                                                         ptri[i].uv[1][1] = st_tri[k].uv[y][1];
2183                                                                         ptri[i].uv[2][0] = st_tri[k].uv[z][0];
2184                                                                         ptri[i].uv[2][1] = st_tri[k].uv[z][1];
2185                                                                         x = y = z = 999;
2186                                                                 }
2187                                                                 else if ( k != j ) {
2188                                                                         printf( "Duplicate triangle %d found in st file: %d and %d\n",i,k,j );
2189                                                                         printf( "   (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f)\n",
2190                                                                                         ptri[i].verts[0][0],ptri[i].verts[0][1],ptri[i].verts[0][2],
2191                                                                                         ptri[i].verts[1][0],ptri[i].verts[1][1],ptri[i].verts[1][2],
2192                                                                                         ptri[i].verts[2][0],ptri[i].verts[2][1],ptri[i].verts[2][2] );
2193                                                                         printf( "   (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f)\n",
2194                                                                                         st_tri[k].verts[0][0],st_tri[k].verts[0][1],st_tri[k].verts[0][2],
2195                                                                                         st_tri[k].verts[1][0],st_tri[k].verts[1][1],st_tri[k].verts[1][2],
2196                                                                                         st_tri[k].verts[2][0],st_tri[k].verts[2][1],st_tri[k].verts[2][2] );
2197                                                                         printf( "   (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f)\n",
2198                                                                                         st_tri[j].verts[0][0],st_tri[j].verts[0][1],st_tri[j].verts[0][2],
2199                                                                                         st_tri[j].verts[1][0],st_tri[j].verts[1][1],st_tri[j].verts[1][2],
2200                                                                                         st_tri[j].verts[2][0],st_tri[j].verts[2][1],st_tri[j].verts[2][2] );
2201                                                                 }
2202                                                         }
2203                                                 }
2204                                         }
2205                                 }
2206                         }
2207                         if ( k == -1 ) {
2208                                 printf( "No matching triangle %d\n",i );
2209                         }
2210                 }
2211                 free( st_tri );
2212         }
2213
2214 //
2215 // get the ST values
2216 //
2217         if ( ptri && ptri[0].HasUV ) {
2218                 if ( !NewSkin ) {
2219                         Error( "Base has UVs with old style skin page\nMaybe you want to use -ignoreUV" );
2220                 }
2221                 else
2222                 {
2223                         BuildNewST( ptri, fmheader.num_tris, false );
2224                 }
2225         }
2226         else
2227         {
2228                 if ( NewSkin ) {
2229                         Error( "Base has new style skin without UVs" );
2230                 }
2231                 else
2232                 {
2233                         BuildST( ptri, fmheader.num_tris, false );
2234                 }
2235         }
2236
2237         TransPixels = NULL;
2238         if ( !BaseTrueColor ) {
2239                 FH = fopen( trans_file,"rb" );
2240                 if ( FH ) {
2241                         fclose( FH );
2242                         Load256Image( trans_file, &TransPixels, NULL, &TransWidth, &TransHeight );
2243                         if ( TransWidth != fmheader.skinwidth || TransHeight != fmheader.skinheight ) {
2244                                 Error( "source image %s dimensions (%d,%d) are not the same as alpha image (%d,%d)\n",file2,fmheader.skinwidth,fmheader.skinheight,TransWidth,TransHeight );
2245                         }
2246                 }
2247         }
2248
2249 //
2250 // run through all the base triangles, storing each unique vertex in the
2251 // base vertex list and setting the indirect triangles to point to the base
2252 // vertices
2253 //
2254         for ( l = 0; l < fmheader.num_mesh_nodes; l++ )
2255         {
2256                 for ( i = 0 ; i < fmheader.num_tris ; i++ )
2257                 {
2258                         pos = i >> 3;
2259                         bit = 1 << ( i & 7 );
2260                         if ( !( pmnodes[l].tris[pos] & bit ) ) {
2261                                 continue;
2262                         }
2263
2264                         for ( j = 0 ; j < 3 ; j++ )
2265                         {
2266                                 // get the xyz index
2267                                 for ( k = 0 ; k < fmheader.num_xyz ; k++ )
2268                                 {
2269                                         if ( VectorCompare( ptri[i].verts[j], base_xyz[k] ) ) {
2270                                                 break;  // this vertex is already in the base vertex list
2271                                         }
2272                                 }
2273
2274                                 if ( k == fmheader.num_xyz ) { // new index
2275                                         VectorCopy( ptri[i].verts[j], base_xyz[fmheader.num_xyz] );
2276
2277                                         if ( pmnodes[l].clustered == true ) {
2278                                                 ReplaceClusterIndex( k, ptri[i].indicies[j], (int **)&pmnodes[l].clusters, (IntListNode_t **)&g_skelModel.vertLists, (int *)&pmnodes[l].num_verts, (int *)&g_skelModel.new_num_verts );
2279                                         }
2280
2281                                         fmheader.num_xyz++;
2282                                 }
2283
2284                                 pos = k >> 3;
2285                                 bit = 1 << ( k & 7 );
2286                                 pmnodes[l].verts[pos] |= bit;
2287
2288                                 triangles[i].index_xyz[j] = k;
2289
2290                                 // get the st index
2291                                 for ( k = 0 ; k < fmheader.num_st ; k++ )
2292                                 {
2293                                         if ( triangle_st[i][j][0] == base_st[k].s
2294                                                  && triangle_st[i][j][1] == base_st[k].t ) {
2295                                                 break;  // this vertex is already in the base vertex list
2296                                         }
2297                                 }
2298
2299                                 if ( k == fmheader.num_st ) { // new index
2300                                         base_st[fmheader.num_st].s = triangle_st[i][j][0];
2301                                         base_st[fmheader.num_st].t = triangle_st[i][j][1];
2302                                         fmheader.num_st++;
2303                                 }
2304
2305                                 triangles[i].index_st[j] = k;
2306                         }
2307
2308                         if ( TransPixels || BaseTrueColor ) {
2309                                 translucent[i] = CheckTransRecursiveTri( triangle_st[i][0], triangle_st[i][1], triangle_st[i][2] );
2310                         }
2311                         else
2312                         {
2313                                 translucent[i] = false;
2314                         }
2315                 }
2316         }
2317
2318         if ( !BaseTrueColor ) {
2319                 SetPixel = true;
2320                 memset( BasePixels,0,BaseWidth * BaseHeight );
2321                 for ( i = 0 ; i < fmheader.num_tris ; i++ )
2322                 {
2323                         CheckTransRecursiveTri( triangle_st[i][0], triangle_st[i][1], triangle_st[i][2] );
2324                 }
2325                 SetPixel = false;
2326
2327                 skin_pixels_used = 0;
2328                 for ( i = 0; i < fmheader.skinheight; i++ )
2329                 {
2330                         for ( j = 0; j < fmheader.skinwidth; j++ )
2331                         {
2332                                 skin_pixels_used += BasePixels[( i * BaseWidth ) + j];
2333                         }
2334                 }
2335                 total_skin_pixels = fmheader.skinheight * fmheader.skinwidth;
2336         }
2337         else
2338         {
2339                 SetPixel = true;
2340                 memset( BasePixels,0,BaseWidth * BaseHeight * 4 );
2341                 for ( i = 0 ; i < fmheader.num_tris ; i++ )
2342                 {
2343                         CheckTransRecursiveTri( triangle_st[i][0], triangle_st[i][1], triangle_st[i][2] );
2344                 }
2345                 SetPixel = false;
2346
2347                 skin_pixels_used = 0;
2348                 for ( i = 0; i < fmheader.skinheight; i++ )
2349                 {
2350                         for ( j = 0; j < fmheader.skinwidth; j++ )
2351                         {
2352                                 skin_pixels_used += BasePixels[( ( i * BaseWidth ) + j ) * 4];
2353                         }
2354                 }
2355                 total_skin_pixels = fmheader.skinheight * fmheader.skinwidth;
2356         }
2357
2358         // build triangle strips / fans
2359         BuildGlCmds();
2360
2361         if ( TransPixels ) {
2362                 free( TransPixels );
2363         }
2364         free( BasePixels );
2365         if ( BasePalette ) {
2366                 free( BasePalette );
2367         }
2368         free( ptri );
2369 }
2370
2371 void Cmd_FMNodeOrder( void ){
2372         mesh_node_t *newnodes, *pos;
2373         int i,j;
2374
2375         if ( !pmnodes ) {
2376                 Error( "Base has not been established yet" );
2377         }
2378
2379         pos = newnodes = malloc( sizeof( mesh_node_t ) * fmheader.num_mesh_nodes );
2380
2381         for ( i = 0; i < fmheader.num_mesh_nodes; i++ )
2382         {
2383                 GetScriptToken( false );
2384
2385                 for ( j = 0; j < fmheader.num_mesh_nodes; j++ )
2386                 {
2387                         if ( strcmpi( pmnodes[j].name, token ) == 0 ) {
2388                                 *pos = pmnodes[j];
2389                                 pos++;
2390                                 break;
2391                         }
2392                 }
2393                 if ( j >= fmheader.num_mesh_nodes ) {
2394                         Error( "Node '%s' not in base list!\n", token );
2395                 }
2396         }
2397
2398         free( pmnodes );
2399         pmnodes = newnodes;
2400 }
2401
2402 //===============================================================
2403
2404 extern char *FindFrameFile( char *frame );
2405
2406
2407 /*
2408    ===============
2409    GrabFrame
2410    ===============
2411  */
2412 void GrabFrame( char *frame ){
2413         triangle_t      *ptri;
2414         int i, j;
2415         fmtrivert_t     *ptrivert;
2416         int num_tris;
2417         char file1[1024];
2418         fmframe_t       *fr;
2419         int index_xyz;
2420         char            *framefile;
2421
2422         // the frame 'run1' will be looked for as either
2423         // run.1 or run1.tri, so the new alias sequence save
2424         // feature an be used
2425         framefile = FindFrameFile( frame );
2426
2427         sprintf( file1, "%s/%s", cdarchive, framefile );
2428         ExpandPathAndArchive( file1 );
2429
2430         sprintf( file1, "%s/%s",cddir, framefile );
2431
2432         printf( "grabbing %s  ", file1 );
2433
2434         if ( fmheader.num_frames >= MAX_FM_FRAMES ) {
2435                 Error( "fmheader.num_frames >= MAX_FM_FRAMES" );
2436         }
2437         fr = &g_frames[fmheader.num_frames];
2438         fmheader.num_frames++;
2439
2440         strcpy( fr->name, frame );
2441
2442 //
2443 // load the frame
2444 //
2445         if ( do3ds ) {
2446                 Load3DSTriangleList( file1, &ptri, &num_tris, NULL, NULL );
2447         }
2448         else{
2449                 LoadTriangleList( file1, &ptri, &num_tris, NULL, NULL );
2450         }
2451
2452         if ( num_tris != fmheader.num_tris ) {
2453                 Error( "%s: number of triangles (%d) doesn't match base frame (%d)\n", file1, num_tris, fmheader.num_tris );
2454         }
2455
2456 //
2457 // allocate storage for the frame's vertices
2458 //
2459         ptrivert = fr->v;
2460
2461         for ( i = 0 ; i < fmheader.num_xyz ; i++ )
2462         {
2463                 ptrivert[i].vnorm.numnormals = 0;
2464                 VectorClear( ptrivert[i].vnorm.normalsum );
2465         }
2466         ClearBounds( fr->mins, fr->maxs );
2467
2468 //
2469 // store the frame's vertices in the same order as the base. This assumes the
2470 // triangles and vertices in this frame are in exactly the same order as in the
2471 // base
2472 //
2473         for ( i = 0 ; i < num_tris ; i++ )
2474         {
2475                 vec3_t vtemp1, vtemp2, normal;
2476                 float ftemp;
2477
2478                 VectorSubtract( ptri[i].verts[0], ptri[i].verts[1], vtemp1 );
2479                 VectorSubtract( ptri[i].verts[2], ptri[i].verts[1], vtemp2 );
2480                 CrossProduct( vtemp1, vtemp2, normal );
2481
2482                 VectorNormalize( normal, normal );
2483
2484                 // rotate the normal so the model faces down the positive x axis
2485                 ftemp = normal[0];
2486                 normal[0] = -normal[1];
2487                 normal[1] = ftemp;
2488
2489                 for ( j = 0 ; j < 3 ; j++ )
2490                 {
2491                         index_xyz = triangles[i].index_xyz[j];
2492
2493                         // rotate the vertices so the model faces down the positive x axis
2494                         // also adjust the vertices to the desired origin
2495                         ptrivert[index_xyz].v[0] = ( ( -ptri[i].verts[j][1] ) * scale_up ) +
2496                                                                            adjust[0];
2497                         ptrivert[index_xyz].v[1] = ( ptri[i].verts[j][0] * scale_up ) +
2498                                                                            adjust[1];
2499                         ptrivert[index_xyz].v[2] = ( ptri[i].verts[j][2] * scale_up ) +
2500                                                                            adjust[2];
2501
2502                         AddPointToBounds( ptrivert[index_xyz].v, fr->mins, fr->maxs );
2503
2504                         VectorAdd( ptrivert[index_xyz].vnorm.normalsum, normal, ptrivert[index_xyz].vnorm.normalsum );
2505                         ptrivert[index_xyz].vnorm.numnormals++;
2506                 }
2507         }
2508
2509 //
2510 // calculate the vertex normals, match them to the template list, and store the
2511 // index of the best match
2512 //
2513         for ( i = 0 ; i < fmheader.num_xyz ; i++ )
2514         {
2515                 int j;
2516                 vec3_t v;
2517                 float maxdot;
2518                 int maxdotindex;
2519                 int c;
2520
2521                 c = ptrivert[i].vnorm.numnormals;
2522                 if ( !c ) {
2523                         Error( "Vertex with no triangles attached" );
2524                 }
2525
2526                 VectorScale( ptrivert[i].vnorm.normalsum, 1.0 / c, v );
2527                 VectorNormalize( v, v );
2528
2529                 maxdot = -999999.0;
2530                 maxdotindex = -1;
2531
2532                 for ( j = 0 ; j < NUMVERTEXNORMALS ; j++ )
2533                 {
2534                         float dot;
2535
2536                         dot = DotProduct( v, avertexnormals[j] );
2537                         if ( dot > maxdot ) {
2538                                 maxdot = dot;
2539                                 maxdotindex = j;
2540                         }
2541                 }
2542
2543                 ptrivert[i].lightnormalindex = maxdotindex;
2544         }
2545
2546         free( ptri );
2547 }
2548
2549 /*
2550    ===============
2551    Cmd_Frame
2552    ===============
2553  */
2554 void Cmd_FMFrame( void ){
2555         while ( ScriptTokenAvailable() )
2556         {
2557                 GetScriptToken( false );
2558                 if ( g_skipmodel ) {
2559                         continue;
2560                 }
2561                 if ( g_release || g_archive ) {
2562                         fmheader.num_frames = 1;    // don't skip the writeout
2563                         continue;
2564                 }
2565
2566                 H_printf( "#define FRAME_%-16s\t%i\n", token, fmheader.num_frames );
2567
2568                 if ( ( g_skelModel.type != SKEL_NULL ) || ( g_skelModel.references != REF_NULL ) ) {
2569                         GrabModelTransform( token );
2570                 }
2571
2572                 GrabFrame( token );
2573
2574                 if ( g_skelModel.type != SKEL_NULL ) {
2575                         GrabSkeletalFrame( token );
2576                 }
2577
2578                 if ( g_skelModel.references != REF_NULL ) {
2579                         GrabReferencedFrame( token );
2580                 }
2581
2582                 // need to add the up and dir points to the frame bounds here
2583                 // using AddPointToBounds (ptrivert[index_xyz].v, fr->mins, fr->maxs);
2584                 // then remove fudge in determining scale on frame write out
2585         }
2586 }
2587
2588 /*
2589    ===============
2590    Cmd_Skin
2591
2592    Skins aren't actually stored in the file, only a reference
2593    is saved out to the header file.
2594    ===============
2595  */
2596 void Cmd_FMSkin( void ){
2597         byte        *palette;
2598         byte        *pixels;
2599         int width, height;
2600         byte        *cropped;
2601         int y;
2602         char name[1024], savename[1024], transname[1024], extension[256];
2603         miptex32_t  *qtex32;
2604         int size;
2605         FILE        *FH;
2606         qboolean TrueColor;
2607
2608         GetScriptToken( false );
2609
2610         if ( fmheader.num_skins == MAX_FM_SKINS ) {
2611                 Error( "fmheader.num_skins == MAX_FM_SKINS" );
2612         }
2613
2614         if ( g_skipmodel ) {
2615                 return;
2616         }
2617
2618         sprintf( name, "%s/%s", cdarchive, token );
2619         strcpy( name, ExpandPathAndArchive( name ) );
2620 //      sprintf (name, "%s/%s.lbm", cddir, token);
2621
2622         if ( ScriptTokenAvailable() ) {
2623                 GetScriptToken( false );
2624                 sprintf( g_skins[fmheader.num_skins], "!%s", token );
2625                 sprintf( savename, "%s!%s", g_outputDir, token );
2626                 sprintf( transname, "%s!%s_a.pcx", gamedir, token );
2627         }
2628         else
2629         {
2630                 sprintf( g_skins[fmheader.num_skins], "%s/!%s", cdpartial, token );
2631                 sprintf( savename, "%s/!%s", g_outputDir, token );
2632                 sprintf( transname, "%s/!%s_a.pcx", cddir, token );
2633         }
2634
2635         fmheader.num_skins++;
2636
2637         if ( g_skipmodel || g_release || g_archive ) {
2638                 return;
2639         }
2640
2641         // load the image
2642         printf( "loading %s\n", name );
2643         ExtractFileExtension( name, extension );
2644         if ( extension[0] == 0 ) {
2645                 strcat( name, ".pcx" );
2646         }
2647
2648
2649         TrueColor = LoadAnyImage( name, &pixels, &palette, &width, &height );
2650 //      RemapZero (pixels, palette, width, height);
2651
2652         // crop it to the proper size
2653
2654         if ( !TrueColor ) {
2655                 cropped = (byte *) SafeMalloc( fmheader.skinwidth * fmheader.skinheight, "Cmd_FMSkin" );
2656                 for ( y = 0 ; y < fmheader.skinheight ; y++ )
2657                 {
2658                         memcpy( cropped + y * fmheader.skinwidth,
2659                                         pixels + y * width, fmheader.skinwidth );
2660                 }
2661
2662                 TransPixels = NULL;
2663                 FH = fopen( transname,"rb" );
2664                 if ( FH ) {
2665                         fclose( FH );
2666
2667                         strcat( g_skins[fmheader.num_skins - 1],".pcx" );
2668                         strcat( savename,".pcx" );
2669
2670                         // save off the new image
2671                         printf( "saving %s\n", savename );
2672                         CreatePath( savename );
2673                         WritePCXfile( savename, cropped, fmheader.skinwidth, fmheader.skinheight, palette );
2674                 }
2675                 else
2676                 {
2677         #if 1
2678                         miptex_t    *qtex;
2679                         qtex = CreateMip( cropped, fmheader.skinwidth, fmheader.skinheight, palette, &size, true );
2680
2681                         strcat( g_skins[fmheader.num_skins - 1],".m8" );
2682                         strcat( savename,".m8" );
2683
2684                         printf( "saving %s\n", savename );
2685                         CreatePath( savename );
2686                         SaveFile( savename, (byte *)qtex, size );
2687                         free( qtex );
2688         #else
2689                         strcat( g_skins[fmheader.num_skins - 1],".pcx" );
2690                         strcat( savename,".pcx" );
2691
2692                         // save off the new image
2693                         printf( "saving %s\n", savename );
2694                         CreatePath( savename );
2695                         WritePCXfile( savename, cropped, fmheader.skinwidth, fmheader.skinheight, palette );
2696         #endif
2697                 }
2698         }
2699         else
2700         {
2701                 cropped = (byte *) SafeMalloc( fmheader.skinwidth * fmheader.skinheight * 4, "Cmd_FMSkin" );
2702                 for ( y = 0 ; y < fmheader.skinheight ; y++ )
2703                 {
2704                         memcpy( cropped + ( ( y * fmheader.skinwidth ) * 4 ), pixels + ( y * width * 4 ), fmheader.skinwidth * 4 );
2705                 }
2706
2707                 qtex32 = CreateMip32( (unsigned *)cropped, fmheader.skinwidth, fmheader.skinheight, &size, true );
2708
2709                 StripExtension( g_skins[fmheader.num_skins - 1] );
2710                 strcat( g_skins[fmheader.num_skins - 1],".m32" );
2711                 StripExtension( savename );
2712                 strcat( savename,".m32" );
2713
2714                 printf( "saving %s\n", savename );
2715                 CreatePath( savename );
2716                 SaveFile( savename, (byte *)qtex32, size );
2717         }
2718
2719         free( pixels );
2720         if ( palette ) {
2721                 free( palette );
2722         }
2723         free( cropped );
2724 }
2725
2726
2727 /*
2728    ===============
2729    Cmd_Cd
2730    ===============
2731  */
2732 void Cmd_FMCd( void ){
2733         char temp[256];
2734
2735         FinishModel();
2736         ClearModel();
2737
2738         GetScriptToken( false );
2739
2740         // this is a silly mess...
2741         sprintf( cdpartial, "models/%s", token );
2742         sprintf( cdarchive, "%smodels/%s", gamedir + strlen( qdir ), token );
2743         sprintf( cddir, "%s%s", gamedir, cdpartial );
2744
2745         // Since we also changed directories on the output side (for mirror) make sure the outputdir is set properly too.
2746         sprintf( temp, "%s%s", g_outputDir, cdpartial );
2747         strcpy( g_outputDir, temp );
2748
2749         // if -only was specified and this cd doesn't match,
2750         // skip the model (you only need to match leading chars,
2751         // so you could regrab all monsters with -only monsters)
2752         if ( !g_only[0] ) {
2753                 return;
2754         }
2755         if ( strncmp( token, g_only, strlen( g_only ) ) ) {
2756                 g_skipmodel = true;
2757                 printf( "skipping %s\n", cdpartial );
2758         }
2759 }
2760
2761
2762 /*
2763
2764    //=======================
2765    //           NEW GEN
2766    //=======================
2767
2768    void NewGen (char *ModelFile, char *OutputName, int width, int height)
2769    {
2770     trigroup_t  *triangles;
2771     triangle_t  *ptri;
2772     triangle_t  *grouptris;
2773     mesh_node_t *pmnodes;
2774
2775     vec3_t              *vertices;
2776     vec3_t              *uvs;
2777     vec3_t              aveNorm, crossvect;
2778     vec3_t              diffvect1, diffvect2;
2779     vec3_t              v0, v1, v2;
2780     vec3_t              n, u, v;
2781     vec3_t              base, zaxis, yaxis;
2782     vec3_t              uvwMin, uvwMax;
2783     vec3_t              groupMin, groupMax;
2784     vec3_t              uvw;
2785
2786     float               *uFinal, *vFinal;
2787     unsigned char       *newpic;
2788
2789     int                 finalstart = 0, finalcount = 0;
2790     int                 xbase = 0, xwidth = 0, ywidth = 0;
2791     int                 *todo, *done, finished;
2792     int                 i, j, k, l; //counters
2793     int                 groupnum, numtris, numverts, num;
2794     int                 count;
2795     FILE                *grpfile;
2796     long                datasize;
2797
2798     for ( i = 0; i<3; i++)
2799     {
2800         aveNorm[i] = 0;
2801         uvwMin[i] = 1e30f;
2802         uvwMax[i] = -1e30f;
2803     }
2804
2805     pmnodes = NULL;
2806     ptri = NULL;
2807     triangles = NULL;
2808
2809     zaxis[0] = 0;
2810     zaxis[1] = 0;
2811     zaxis[2] = 1;
2812
2813     yaxis[0] = 0;
2814     yaxis[1] = 1;
2815     yaxis[2] = 0;
2816
2817     LoadTriangleList (ModelFile, &ptri, &fmheader.num_tris, &pmnodes, &fmheader.num_mesh_nodes);
2818
2819     todo = (int*)SafeMalloc(fmheader.num_tris*sizeof(int), "NewGen");
2820     done = (int*)SafeMalloc(fmheader.num_tris*sizeof(int), "NewGen");
2821     triangles = (trigroup_t*)SafeMalloc(fmheader.num_tris*sizeof(trigroup_t), "NewGen");
2822
2823     for ( i=0; i < fmheader.num_tris; i++)
2824     {
2825         todo[i] = false;
2826         done[i] = false;
2827         triangles[i].triangle = ptri[i];
2828         triangles[i].group = 0;
2829     }
2830
2831     groupnum = 0;
2832
2833    //  transitive closure algorithm follows
2834    //  put all triangles who transitively share vertices into separate groups
2835
2836     while (1)
2837     {
2838         for ( i = 0; i < fmheader.num_tris; i++)
2839         {
2840             if (!done[i])
2841             {
2842                 break;
2843             }
2844         }
2845         if ( i == fmheader.num_tris)
2846         {
2847             break;
2848         }
2849         finished = false;
2850         todo[i] = true;
2851         while (!finished)
2852         {
2853             finished = true;
2854             for ( i = 0; i < fmheader.num_tris; i++)
2855             {
2856                 if (todo[i])
2857                 {
2858                     done[i] = true;
2859                     triangles[i].group = groupnum;
2860                     todo[i] = false;
2861                     for ( j = 0; j < fmheader.num_tris; j++)
2862                     {
2863                         if ((!done[j]) && (ShareVertex(triangles[i],triangles[j])))
2864                         {
2865                             todo[j] = true;
2866                             finished = false;
2867                         }
2868                     }
2869                 }
2870             }
2871         }
2872         groupnum++;
2873     }
2874         uFinal = (float*)SafeMalloc(3*fmheader.num_tris*sizeof(float), "NewGen");
2875         vFinal = (float*)SafeMalloc(3*fmheader.num_tris*sizeof(float), "NewGen");
2876
2877     grpfile = fopen("grpdebug.txt","w");
2878
2879
2880     for (i = 0; i < groupnum; i++)
2881     {
2882
2883         fprintf(grpfile,"Group Number: %d\n", i);
2884
2885         numtris = GetNumTris(triangles, i); // number of triangles in group i
2886         numverts = numtris * 3;
2887
2888         fprintf(grpfile,"%d triangles.\n", numtris);
2889
2890         vertices = (vec3_t*)SafeMalloc(numverts*sizeof(vec3_t), "NewGen");
2891         uvs = (vec3_t*)SafeMalloc(numverts*sizeof(vec3_t), "NewGen");
2892         grouptris = (triangle_t*)SafeMalloc(numtris*sizeof(triangle_t), "NewGen");
2893
2894         for (count = 0; count < fmheader.num_tris; count++)
2895         {
2896             if (triangles[count].group == i)
2897             {
2898                 fprintf(grpfile,"Triangle %d\n", count);
2899             }
2900         }
2901         fprintf(grpfile,"\n");
2902
2903
2904
2905
2906         GetOneGroup(triangles, i, grouptris);
2907
2908         num = 0;
2909         for (j = 0; j < numtris; j++)
2910         {
2911             VectorCopy(grouptris[j].verts[0], v0);
2912             VectorCopy(grouptris[j].verts[1], v1);
2913             VectorCopy(grouptris[j].verts[2], v2);
2914             VectorSubtract(v1, v0, diffvect1);
2915             VectorSubtract(v2, v1, diffvect2);
2916             CrossProduct( diffvect1, diffvect2, crossvect);
2917             VectorAdd(aveNorm, crossvect, aveNorm);
2918             VectorCopy(v0,vertices[num]);
2919             num++;                                      //  FIXME
2920             VectorCopy(v1,vertices[num]);
2921             num++;                                      //  add routine to add only verts that
2922             VectorCopy(v2,vertices[num]);
2923             num++;                                      // have not already been added
2924         }
2925
2926         assert (num >= 3);
2927    // figure out the best plane projections
2928         DOsvdPlane ((float*)vertices, num, (float *)&n, (float *)&base);
2929
2930         if (DotProduct(aveNorm,n) < 0.0f)
2931         {
2932             VectorScale(n, -1.0f, n);
2933         }
2934         VectorNormalize(n,n);
2935         if (fabs(n[2]) < .57)
2936         {
2937             CrossProduct( zaxis, n, crossvect);
2938             VectorCopy(crossvect, u);
2939         }
2940         else
2941         {
2942             CrossProduct( yaxis, n, crossvect);
2943             VectorCopy(crossvect, u);
2944         }
2945         VectorNormalize(u,u);
2946         CrossProduct( n, u, crossvect);
2947         VectorCopy(crossvect, v);
2948         VectorNormalize(v,v);
2949
2950         num = 0;
2951
2952         for ( j = 0; j < 3; j++)
2953         {
2954             groupMin[j] = 1e30f;
2955             groupMax[j] = -1e30f;
2956         }
2957
2958         for ( j = 0; j < numtris; j++)
2959         {
2960             for ( k = 0; k < 3; k++)
2961             {
2962                 VectorCopy(grouptris[j].verts[k],v0);
2963                 VectorSubtract(v0, base, v0);
2964                 uvw[0] = DotProduct(v0, u);
2965                 uvw[1] = DotProduct(v0, v);
2966                 uvw[2] = DotProduct(v0, n);
2967                 VectorCopy(uvw,uvs[num]);
2968                 num++;
2969                 for ( l = 0; l < 3; l++)
2970                 {
2971                     if (uvw[l] < groupMin[l])
2972                     {
2973                         groupMin[l] = uvw[l];
2974                     }
2975                     if (uvw[l] > groupMax[l])
2976                     {
2977                         groupMax[l] = uvw[l];
2978                     }
2979                 }
2980             }
2981         }
2982
2983         xwidth = ceil(0 - groupMin[0]) + 2; // move right of origin and avoid overlap
2984         ywidth = ceil(0 - groupMin[1]) + 2; // move "above" origin
2985
2986         for ( j=0; j < numverts; j++)
2987         {
2988             uFinal[finalcount] = uvs[j][0] + xwidth + xbase;
2989             vFinal[finalcount] = uvs[j][1] + ywidth;
2990             if (uFinal[finalcount] < uvwMin[0])
2991             {
2992                 uvwMin[0] = uFinal[finalcount];
2993             }
2994             if (uFinal[finalcount] > uvwMax[0])
2995             {
2996                 uvwMax[0] = uFinal[finalcount];
2997             }
2998             if (vFinal[finalcount] < uvwMin[1])
2999             {
3000                 uvwMin[1] = vFinal[finalcount];
3001             }
3002             if (vFinal[finalcount] > uvwMax[1])
3003             {
3004                 uvwMax[1] = vFinal[finalcount];
3005             }
3006             finalcount++;
3007         }
3008
3009         fprintf(grpfile,"svdPlaned Group min: ( %f , %f )\n",groupMin[0] + xwidth + xbase, groupMin[1] + ywidth);
3010         fprintf(grpfile,"svdPlaned Group max: ( %f , %f )\n",groupMax[0] + xwidth + xbase, groupMax[1] + ywidth);
3011
3012         finalcount = finalstart;
3013
3014         for ( count = 0; count < numverts; count++)
3015         {
3016             fprintf(grpfile,"Vertex %d: ( %f , %f , %f )\n",count,vertices[count][0],vertices[count][1],vertices[count][2]);
3017             fprintf(grpfile,"svdPlaned: ( %f , %f )\n",uFinal[finalcount],vFinal[finalcount++]);
3018         }
3019
3020         finalstart = finalcount;
3021
3022         fprintf(grpfile,"\n");
3023
3024         free(vertices);
3025         free(uvs);
3026         free(grouptris);
3027
3028         xbase += ceil(groupMax[0] - groupMin[0]) + 2;
3029
3030     }
3031
3032     fprintf(grpfile,"Global Min ( %f , %f )\n",uvwMin[0],uvwMin[1]);
3033     fprintf(grpfile,"Global Max ( %f , %f )\n",uvwMax[0],uvwMax[1]);
3034
3035
3036     ScaleTris(uvwMin, uvwMax, width, height, uFinal, vFinal, finalcount);
3037
3038     for (k = 0; k < finalcount; k++)
3039     {
3040         fprintf(grpfile, "scaled vertex %d: ( %f , %f )\n",k,uFinal[k],vFinal[k]);
3041     }
3042
3043     //  i've got the array of vertices in uFinal and vFinal.  Now I need to write them and draw lines
3044
3045     datasize = width * height*sizeof(unsigned char);
3046     newpic = (unsigned char*)SafeMalloc(datasize, "NewGen");
3047     memset(newpic,0,datasize);
3048     memset(pic_palette,0,sizeof(pic_palette));
3049     pic_palette[767] = pic_palette[766] = pic_palette[765] = 255;
3050
3051     k = 0;
3052     while (k < finalcount)
3053     {
3054         NewDrawLine(uFinal[k], vFinal[k], uFinal[k+1], vFinal[k+1], newpic, width, height);
3055         k++;
3056         NewDrawLine(uFinal[k], vFinal[k], uFinal[k+1], vFinal[k+1], newpic, width, height);
3057         k++;
3058         NewDrawLine(uFinal[k], vFinal[k], uFinal[k-2], vFinal[k-2], newpic, width, height);
3059         k++;
3060         fprintf(grpfile, "output tri with verts %d, %d, %d", k-2, k-1, k);
3061     }
3062
3063     WritePCXfile (OutputName, newpic, width, height, pic_palette);
3064
3065     fclose(grpfile);
3066
3067     free(todo);
3068     free(done);
3069     free(triangles);
3070     free(newpic);
3071     return;
3072    }
3073    void NewDrawLine(int x1, int y1, int x2, int y2, unsigned char* picture, int width, int height)
3074    {
3075     long dx, dy;
3076     long adx, ady;
3077     long count;
3078     float xfrac, yfrac, xstep, ystep;
3079     unsigned long sx, sy;
3080     float u, v;
3081
3082     dx = x2 - x1;
3083     dy = y2 - y1;
3084     adx = abs(dx);
3085     ady = abs(dy);
3086
3087     count = adx > ady ? adx : ady;
3088     count++;
3089
3090     if(count > 300)
3091     {
3092         printf("Bad count\n");
3093         return; // don't ever hang up on bad data
3094     }
3095
3096     xfrac = x1;
3097     yfrac = y1;
3098
3099     xstep = (float)dx/count;
3100     ystep = (float)dy/count;
3101
3102     switch(LineType)
3103     {
3104         case LINE_NORMAL:
3105             do
3106             {
3107                 if(xfrac < width && yfrac < height)
3108                 {
3109                     picture[(long)yfrac*width+(long)xfrac] = LineColor;
3110                 }
3111                 xfrac += xstep;
3112                 yfrac += ystep;
3113                 count--;
3114             } while (count > 0);
3115             break;
3116         case LINE_FAT:
3117             do
3118             {
3119                 for (u=-0.1 ; u<=0.9 ; u+=0.999)
3120                 {
3121                     for (v=-0.1 ; v<=0.9 ; v+=0.999)
3122                     {
3123                         sx = xfrac+u;
3124                         sy = yfrac+v;
3125                         if(sx < width && sy < height)
3126                         {
3127                             picture[sy*width+sx] = LineColor;
3128                         }
3129                     }
3130                 }
3131                 xfrac += xstep;
3132                 yfrac += ystep;
3133                 count--;
3134             } while (count > 0);
3135             break;
3136         case LINE_DOTTED:
3137             do
3138             {
3139                 if(count&1 && xfrac < width &&
3140                     yfrac < height)
3141                 {
3142                     picture[(long)yfrac*width+(long)xfrac] = LineColor;
3143                 }
3144                 xfrac += xstep;
3145                 yfrac += ystep;
3146                 count--;
3147             } while (count > 0);
3148             break;
3149         default:
3150             Error("Unknown <linetype> %d.\n", LineType);
3151     }
3152    }
3153  */
3154 void ScaleTris( vec3_t min, vec3_t max, int Width, int Height, float* u, float* v, int verts ){
3155
3156         int i;
3157         float hscale, vscale;
3158         float scale;
3159
3160         hscale = max[0];
3161         vscale = max[1];
3162
3163         hscale = ( Width - 2 ) / max[0];
3164         vscale = ( Height - 2 ) / max[1];
3165
3166         scale = hscale;
3167         if ( scale > vscale ) {
3168                 scale = vscale;
3169         }
3170         for ( i = 0; i < verts; i++ )
3171         {
3172                 u[i] *= scale;
3173                 v[i] *= scale;
3174         }
3175         return;
3176 }
3177
3178
3179 void GetOneGroup( trigroup_t *tris, int grp, triangle_t* triangles ){
3180         int i;
3181         int j;
3182
3183         j = 0;
3184         for ( i = 0; i < fmheader.num_tris; i++ )
3185         {
3186                 if ( tris[i].group == grp ) {
3187                         triangles[j++] = tris[i].triangle;
3188                 }
3189         }
3190         return;
3191 }
3192
3193
3194 int GetNumTris( trigroup_t *tris, int grp ){
3195         int i;
3196         int verts;
3197
3198         verts = 0;
3199         for ( i = 0; i < fmheader.num_tris; i++ )
3200         {
3201                 if ( tris[i].group == grp ) {
3202                         verts++;
3203                 }
3204         }
3205         return verts;
3206 }
3207
3208
3209 int ShareVertex( trigroup_t trione, trigroup_t tritwo ){
3210         int i;
3211         int j;
3212
3213         i = 1;
3214         j = 1;
3215         for ( i = 0; i < 3; i++ )
3216         {
3217                 for ( j = 0; j < 3; j++ )
3218                 {
3219                         if ( DistBetween( trione.triangle.verts[i],tritwo.triangle.verts[j] ) < TRIVERT_DIST ) {
3220                                 return true;
3221                         }
3222                 }
3223         }
3224         return false;
3225 }
3226
3227
3228 float DistBetween( vec3_t point1, vec3_t point2 ){
3229         float dist;
3230
3231         dist = ( point1[0] - point2[0] );
3232         dist *= dist;
3233         dist += ( point1[1] - point2[1] ) * ( point1[1] - point2[1] );
3234         dist += ( point1[2] - point2[2] ) * ( point1[2] - point2[2] );
3235         dist = sqrt( dist );
3236         return dist;
3237 }
3238
3239
3240 void GenSkin( char *ModelFile, char *OutputName, int Width, int Height ){
3241         triangle_t  *ptri;
3242         mesh_node_t *pmnodes;
3243         int i;
3244
3245         pmnodes = NULL;
3246         ptri = NULL;
3247
3248         LoadTriangleList( ModelFile, &ptri, &fmheader.num_tris, &pmnodes, &fmheader.num_mesh_nodes );
3249         if ( g_ignoreTriUV ) {
3250                 for ( i = 0; i < fmheader.num_tris; i++ )
3251                 {
3252                         ptri[i].HasUV = 0;
3253                 }
3254         }
3255
3256         memset( pic,0,sizeof( pic ) );
3257         memset( pic_palette,0,sizeof( pic_palette ) );
3258         pic_palette[767] = pic_palette[766] = pic_palette[765] = 255;
3259
3260         ScaleWidth = Width;
3261         ScaleHeight = Height;
3262
3263         BuildST( ptri, fmheader.num_tris, true );
3264
3265         WritePCXfile( OutputName, pic, SKINPAGE_WIDTH, SKINPAGE_HEIGHT, pic_palette );
3266
3267         printf( "Gen Skin Stats:\n" );
3268         printf( "   Input Base: %s\n",ModelFile );
3269         printf( "   Input Dimensions: %d,%d\n",Width,Height );
3270         printf( "\n" );
3271         printf( "   Output File: %s\n",OutputName );
3272         printf( "   Output Dimensions: %d,%d\n",ScaleWidth,ScaleHeight );
3273
3274         if ( fmheader.num_mesh_nodes ) {
3275                 printf( "\nNodes:\n" );
3276                 for ( i = 0; i < fmheader.num_mesh_nodes; i++ )
3277                 {
3278                         printf( "   %s\n",pmnodes[i].name );
3279                 }
3280         }
3281
3282         free( ptri );
3283         free( pmnodes );
3284 }
3285
3286
3287 void Cmd_FMBeginGroup( void ){
3288         GetScriptToken( false );
3289
3290         g_no_opimizations = false;
3291
3292         groups[num_groups].start_frame = fmheader.num_frames;
3293         groups[num_groups].num_frames = 0;
3294
3295         groups[num_groups].degrees = atol( token );
3296         if ( groups[num_groups].degrees < 1 || groups[num_groups].degrees > 32 ) {
3297                 Error( "Degrees of freedom out of range: %d",groups[num_groups].degrees );
3298         }
3299 }
3300
3301 void Cmd_FMEndGroup( void ){
3302         groups[num_groups].num_frames = fmheader.num_frames - groups[num_groups].start_frame;
3303
3304         if ( num_groups < MAX_GROUPS - 1 ) {
3305                 num_groups++;
3306         }
3307         else
3308         {
3309                 Error( "Number of compression groups exceded: %i\n", MAX_GROUPS );
3310         }
3311 }