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