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