]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/qdata_heretic2/models.c
Remove -Wno-sign-compare
[xonotic/netradiant.git] / tools / quake2 / qdata_heretic2 / models.c
1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22
23 #include "qdata.h"
24 #include <assert.h>
25 #include "jointed.h"
26 #include "fmodel.h"
27
28 //=================================================================
29
30 typedef struct
31 {
32         int numnormals;
33         vec3_t normalsum;
34 } vertexnormals_t;
35
36 typedef struct
37 {
38         vec3_t v;
39         int lightnormalindex;
40 } trivert_t;
41
42 typedef struct
43 {
44         vec3_t mins, maxs;
45         char name[16];
46         trivert_t v[MAX_VERTS];
47         QDataJoint_t joints[NUM_CLUSTERS];    // ,this
48 } frame_t;
49
50 // ,and all of this should get out of here, need to use new stuff in fmodels instead
51
52 typedef struct IntListNode_s
53 {
54         int data;
55         struct IntListNode_s *next;
56 } IntListNode_t;  // gaak
57
58 typedef struct
59 {
60         float scale[3];         // multiply byte verts by this
61         float translate[3];         // then add this
62 } PartialAliasFrame_t;
63
64 int jointed;
65 int clustered;
66
67 int *clusters[NUM_CLUSTERS];
68 IntListNode_t *vertLists[NUM_CLUSTERS];
69 int num_verts[NUM_CLUSTERS + 1];
70 int new_num_verts[NUM_CLUSTERS + 1];
71
72 // end that
73
74 //================================================================
75
76 frame_t g_frames[MAX_FRAMES];
77 //frame_t               *g_frames;
78
79 static dmdl_t model;
80
81
82 float scale_up;                 // set by $scale
83 vec3_t adjust;                  // set by $origin
84 int g_fixedwidth, g_fixedheight;            // set by $skinsize
85
86
87 //
88 // base frame info
89 //
90 dstvert_t base_st[MAX_VERTS];
91 dtriangle_t triangles[MAX_TRIANGLES];
92
93 static int triangle_st[MAX_TRIANGLES][3][2];
94
95 // the command list holds counts, s/t values, and xyz indexes
96 // that are valid for every frame
97 int commands[16384];
98 int numcommands;
99 int numglverts;
100 int used[MAX_TRIANGLES];
101
102 char g_skins[MAX_MD2SKINS][64];
103
104 char cdarchive[1024];
105 char cdpartial[1024];
106 char cddir[1024];
107
108 char modelname[64];         // empty unless $modelname issued (players)
109
110 extern char        *g_outputDir;
111
112 #define NUMVERTEXNORMALS    162
113
114 float avertexnormals[NUMVERTEXNORMALS][3] =
115 {
116         #include "anorms.h"
117 };
118
119 unsigned char pic[SKINPAGE_HEIGHT * SKINPAGE_WIDTH], pic_palette[768];
120
121 FILE    *headerouthandle = NULL;
122
123 //==============================================================
124
125 /*
126    ===============
127    ClearModel
128    ===============
129  */
130 static void ClearModel( void ){
131         memset( &model, 0, sizeof( model ) );
132
133         modelname[0] = 0;
134         jointed = NOT_JOINTED;
135         clustered = 0;
136         scale_up = 1.0;
137         VectorCopy( vec3_origin, adjust );
138         g_fixedwidth = g_fixedheight = 0;
139         g_skipmodel = false;
140 }
141
142
143 void H_printf( char *fmt, ... ){
144         va_list argptr;
145         char name[1024];
146
147         if ( !headerouthandle ) {
148                 sprintf( name, "%s/tris.h", cddir );
149                 headerouthandle = SafeOpenWrite( name );
150                 fprintf( headerouthandle, "// %s\n\n", cddir );
151                 fprintf( headerouthandle, "// This file generated by qdata - Do NOT Modify\n\n" );
152         }
153
154         va_start( argptr, fmt );
155         vfprintf( headerouthandle, fmt, argptr );
156         va_end( argptr );
157 }
158
159 #if 1
160 /*
161    ============
162    WriteModelFile
163    ============
164  */
165 void WriteCommonModelFile( FILE *modelouthandle, PartialAliasFrame_t *outFrames ){
166         int i;
167         dmdl_t modeltemp;
168         int j, k;
169         frame_t         *in;
170         daliasframe_t   *out;
171         byte buffer[MAX_VERTS * 4 + 128];
172         float v;
173         int c_on, c_off;
174
175         model.version = ALIAS_VERSION;
176         model.framesize = (int)&( (daliasframe_t *)0 )->verts[model.num_xyz];
177         model.num_glcmds = numcommands;
178         model.ofs_skins = sizeof( dmdl_t );
179         model.ofs_st = model.ofs_skins + model.num_skins * MAX_SKINNAME;
180         model.ofs_tris = model.ofs_st + model.num_st * sizeof( dstvert_t );
181         model.ofs_frames = model.ofs_tris + model.num_tris * sizeof( dtriangle_t );
182         model.ofs_glcmds = model.ofs_frames + model.num_frames * model.framesize;
183         model.ofs_end = model.ofs_glcmds + model.num_glcmds * sizeof( int );
184         //
185         // write out the model header
186         //
187         for ( i = 0 ; i < sizeof( dmdl_t ) / 4 ; i++ )
188                 ( (int *)&modeltemp )[i] = LittleLong( ( (int *)&model )[i] );
189
190         SafeWrite( modelouthandle, &modeltemp, sizeof( modeltemp ) );
191
192         //
193         // write out the skin names
194         //
195         SafeWrite( modelouthandle, g_skins, model.num_skins * MAX_SKINNAME );
196
197         //
198         // write out the texture coordinates
199         //
200         c_on = c_off = 0;
201         for ( i = 0 ; i < model.num_st ; i++ )
202         {
203                 base_st[i].s = LittleShort( base_st[i].s );
204                 base_st[i].t = LittleShort( base_st[i].t );
205         }
206
207         SafeWrite( modelouthandle, base_st, model.num_st * sizeof( base_st[0] ) );
208
209         //
210         // write out the triangles
211         //
212         for ( i = 0 ; i < model.num_tris ; i++ )
213         {
214                 int j;
215                 dtriangle_t tri;
216
217                 for ( j = 0 ; j < 3 ; j++ )
218                 {
219                         tri.index_xyz[j] = LittleShort( triangles[i].index_xyz[j] );
220                         tri.index_st[j] = LittleShort( triangles[i].index_st[j] );
221                 }
222
223                 SafeWrite( modelouthandle, &tri, sizeof( tri ) );
224         }
225
226         //
227         // write out the frames
228         //
229         for ( i = 0 ; i < model.num_frames ; i++ )
230         {
231                 in = &g_frames[i];
232                 out = (daliasframe_t *)buffer;
233
234                 strcpy( out->name, in->name );
235                 for ( j = 0 ; j < 3 ; j++ )
236                 {
237                         out->scale[j] = ( in->maxs[j] - in->mins[j] ) / 255;
238                         out->translate[j] = in->mins[j];
239
240                         if ( outFrames ) {
241                                 outFrames[i].scale[j] = out->scale[j];
242                                 outFrames[i].translate[j] = out->translate[j];
243                         }
244                 }
245
246                 for ( j = 0 ; j < model.num_xyz ; j++ )
247                 {
248                         // all of these are byte values, so no need to deal with endianness
249                         out->verts[j].lightnormalindex = in->v[j].lightnormalindex;
250
251                         for ( k = 0 ; k < 3 ; k++ )
252                         {
253                                 // scale to byte values & min/max check
254                                 v = Q_rint( ( in->v[j].v[k] - out->translate[k] ) / out->scale[k] );
255
256                                 // clamp, so rounding doesn't wrap from 255.6 to 0
257                                 if ( v > 255.0 ) {
258                                         v = 255.0;
259                                 }
260                                 if ( v < 0 ) {
261                                         v = 0;
262                                 }
263                                 out->verts[j].v[k] = v;
264                         }
265                 }
266
267                 for ( j = 0 ; j < 3 ; j++ )
268                 {
269                         out->scale[j] = LittleFloat( out->scale[j] );
270                         out->translate[j] = LittleFloat( out->translate[j] );
271                 }
272
273                 SafeWrite( modelouthandle, out, model.framesize );
274         }
275
276         //
277         // write out glcmds
278         //
279         SafeWrite( modelouthandle, commands, numcommands * 4 );
280 }
281
282 /*
283    ============
284    WriteModelFile
285    ============
286  */
287 void WriteModelFile( FILE *modelouthandle ){
288         model.ident = IDALIASHEADER;
289
290         WriteCommonModelFile( modelouthandle, NULL );
291 }
292
293 /*
294    ============
295    WriteJointedModelFile
296    ============
297  */
298 void WriteJointedModelFile( FILE *modelouthandle ){
299         int i;
300         int j, k;
301         frame_t         *in;
302         float v;
303         IntListNode_t   *current, *toFree;
304         PartialAliasFrame_t outFrames[MAX_FRAMES];
305
306         model.ident = IDJOINTEDALIASHEADER;
307
308         WriteCommonModelFile( modelouthandle, outFrames );
309
310         // Skeletal Type
311         SafeWrite( modelouthandle, &jointed, sizeof( int ) );
312
313         // number of joints
314         SafeWrite( modelouthandle, &numJointsForSkeleton[jointed], sizeof( int ) );
315
316         // number of verts in each cluster
317         SafeWrite( modelouthandle, &new_num_verts[1], sizeof( int ) * numJointsForSkeleton[jointed] );
318
319         // cluster verts
320         for ( i = 0; i < new_num_verts[0]; ++i )
321         {
322                 current = vertLists[i];
323                 while ( current )
324                 {
325                         SafeWrite( modelouthandle, &current->data, sizeof( int ) );
326                         toFree = current;
327                         current = current->next;
328                         free( toFree );  // freeing of memory allocated in ReplaceClusterIndex called in Cmd_Base
329                 }
330         }
331
332         for ( i = 0 ; i < model.num_frames ; i++ )
333         {
334                 in = &g_frames[i];
335
336                 for ( j = 0 ; j < new_num_verts[0]; ++j )
337                 {
338                         for ( k = 0 ; k < 3 ; k++ )
339                         {
340                                 // scale to byte values & min/max check
341                                 v = Q_rint( ( in->joints[j].placement.origin[k] - outFrames[i].translate[k] ) / outFrames[i].scale[k] );
342
343                                 // clamp, so rounding doesn't wrap from 255.6 to 0
344                                 if ( v > 255.0 ) {
345                                         v = 255.0;
346                                 }
347
348                                 if ( v < 0 ) {
349                                         v = 0;
350                                 }
351
352                                 // write out origin as a float (there's only a few per model, so it's not really
353                                 // a size issue)
354                                 SafeWrite( modelouthandle, &v, sizeof( float ) );
355                         }
356
357                         for ( k = 0 ; k < 3 ; k++ )
358                         {
359                                 v = Q_rint( ( in->joints[j].placement.direction[k] - outFrames[i].translate[k] ) / outFrames[i].scale[k] );
360
361                                 // clamp, so rounding doesn't wrap from 255.6 to 0
362                                 if ( v > 255.0 ) {
363                                         v = 255.0;
364                                 }
365
366                                 if ( v < 0 ) {
367                                         v = 0;
368                                 }
369
370                                 // write out origin as a float (there's only a few per model, so it's not really
371                                 // a size issue)
372                                 SafeWrite( modelouthandle, &v, sizeof( float ) );
373                         }
374
375                         for ( k = 0 ; k < 3 ; k++ )
376                         {
377                                 v = Q_rint( ( in->joints[j].placement.up[k] - outFrames[i].translate[k] ) / outFrames[i].scale[k] );
378
379                                 // clamp, so rounding doesn't wrap from 255.6 to 0
380                                 if ( v > 255.0 ) {
381                                         v = 255.0;
382                                 }
383
384                                 if ( v < 0 ) {
385                                         v = 0;
386                                 }
387
388                                 // write out origin as a float (there's only a few per model, so it's not really
389                                 // a size issue)
390                                 SafeWrite( modelouthandle, &v, sizeof( float ) );
391                         }
392                 }
393         }
394 }
395 #else
396 /*
397    ============
398    WriteModelFile
399    ============
400  */
401 static void WriteModelFile( FILE *modelouthandle ){
402         int i;
403         dmdl_t modeltemp;
404         int j, k;
405         frame_t         *in;
406         daliasframe_t   *out;
407         byte buffer[MAX_VERTS * 4 + 128];
408         float v;
409         int c_on, c_off;
410
411         model.ident = IDALIASHEADER;
412         model.version = ALIAS_VERSION;
413         model.framesize = (int)&( (daliasframe_t *)0 )->verts[model.num_xyz];
414         model.num_glcmds = numcommands;
415         model.ofs_skins = sizeof( dmdl_t );
416         model.ofs_st = model.ofs_skins + model.num_skins * MAX_SKINNAME;
417         model.ofs_tris = model.ofs_st + model.num_st * sizeof( dstvert_t );
418         model.ofs_frames = model.ofs_tris + model.num_tris * sizeof( dtriangle_t );
419         model.ofs_glcmds = model.ofs_frames + model.num_frames * model.framesize;
420         model.ofs_end = model.ofs_glcmds + model.num_glcmds * 4;
421
422         //
423         // write out the model header
424         //
425         for ( i = 0 ; i < sizeof( dmdl_t ) / 4 ; i++ )
426                 ( (int *)&modeltemp )[i] = LittleLong( ( (int *)&model )[i] );
427
428         SafeWrite( modelouthandle, &modeltemp, sizeof( modeltemp ) );
429
430         //
431         // write out the skin names
432         //
433         SafeWrite( modelouthandle, g_skins, model.num_skins * MAX_SKINNAME );
434
435         //
436         // write out the texture coordinates
437         //
438         c_on = c_off = 0;
439         for ( i = 0 ; i < model.num_st ; i++ )
440         {
441                 base_st[i].s = LittleShort( base_st[i].s );
442                 base_st[i].t = LittleShort( base_st[i].t );
443         }
444
445         SafeWrite( modelouthandle, base_st, model.num_st * sizeof( base_st[0] ) );
446
447         //
448         // write out the triangles
449         //
450         for ( i = 0 ; i < model.num_tris ; i++ )
451         {
452                 int j;
453                 dtriangle_t tri;
454
455                 for ( j = 0 ; j < 3 ; j++ )
456                 {
457                         tri.index_xyz[j] = LittleShort( triangles[i].index_xyz[j] );
458                         tri.index_st[j] = LittleShort( triangles[i].index_st[j] );
459                 }
460
461                 SafeWrite( modelouthandle, &tri, sizeof( tri ) );
462         }
463
464         //
465         // write out the frames
466         //
467         for ( i = 0 ; i < model.num_frames ; i++ )
468         {
469                 in = &g_frames[i];
470                 out = (daliasframe_t *)buffer;
471
472                 strcpy( out->name, in->name );
473                 for ( j = 0 ; j < 3 ; j++ )
474                 {
475                         out->scale[j] = ( in->maxs[j] - in->mins[j] ) / 255;
476                         out->translate[j] = in->mins[j];
477                 }
478
479                 for ( j = 0 ; j < model.num_xyz ; j++ )
480                 {
481                         // all of these are byte values, so no need to deal with endianness
482                         out->verts[j].lightnormalindex = in->v[j].lightnormalindex;
483
484                         for ( k = 0 ; k < 3 ; k++ )
485                         {
486                                 // scale to byte values & min/max check
487                                 v = Q_rint( ( in->v[j].v[k] - out->translate[k] ) / out->scale[k] );
488
489                                 // clamp, so rounding doesn't wrap from 255.6 to 0
490                                 if ( v > 255.0 ) {
491                                         v = 255.0;
492                                 }
493                                 if ( v < 0 ) {
494                                         v = 0;
495                                 }
496                                 out->verts[j].v[k] = v;
497                         }
498                 }
499
500                 for ( j = 0 ; j < 3 ; j++ )
501                 {
502                         out->scale[j] = LittleFloat( out->scale[j] );
503                         out->translate[j] = LittleFloat( out->translate[j] );
504                 }
505
506                 SafeWrite( modelouthandle, out, model.framesize );
507         }
508
509         //
510         // write out glcmds
511         //
512         SafeWrite( modelouthandle, commands, numcommands * 4 );
513 }
514 #endif
515
516 /*
517    ===============
518    FinishModel
519    ===============
520  */
521 void FinishModel( void ){
522         FILE        *modelouthandle;
523         int i;
524         char name[1024];
525
526         if ( !model.num_frames ) {
527                 return;
528         }
529
530 //
531 // copy to release directory tree if doing a release build
532 //
533         if ( g_release ) {
534                 if ( modelname[0] ) {
535                         sprintf( name, "%s", modelname );
536                 }
537                 else{
538                         sprintf( name, "%s/tris.md2", cdpartial );
539                 }
540                 ReleaseFile( name );
541
542                 for ( i = 0 ; i < model.num_skins ; i++ )
543                 {
544                         ReleaseFile( g_skins[i] );
545                 }
546                 model.num_frames = 0;
547                 return;
548         }
549
550 //
551 // write the model output file
552 //
553         if ( modelname[0] ) {
554                 sprintf( name, "%s%s", g_outputDir, modelname );
555         }
556         else{
557                 sprintf( name, "%s/tris.md2", g_outputDir );
558         }
559         printf( "saving to %s\n", name );
560         CreatePath( name );
561         modelouthandle = SafeOpenWrite( name );
562
563 #if 1
564         if ( jointed != NOT_JOINTED ) {
565                 WriteJointedModelFile( modelouthandle );
566         }
567         else
568 #endif
569         WriteModelFile( modelouthandle );
570
571         printf( "%3dx%3d skin\n", model.skinwidth, model.skinheight );
572         printf( "First frame boundaries:\n" );
573         printf( "       minimum x: %3f\n", g_frames[0].mins[0] );
574         printf( "       maximum x: %3f\n", g_frames[0].maxs[0] );
575         printf( "       minimum y: %3f\n", g_frames[0].mins[1] );
576         printf( "       maximum y: %3f\n", g_frames[0].maxs[1] );
577         printf( "       minimum z: %3f\n", g_frames[0].mins[2] );
578         printf( "       maximum z: %3f\n", g_frames[0].maxs[2] );
579         printf( "%4d vertices\n", model.num_xyz );
580         printf( "%4d triangles\n", model.num_tris );
581         printf( "%4d frame\n", model.num_frames );
582         printf( "%4d glverts\n", numglverts );
583         printf( "%4d glcmd\n", model.num_glcmds );
584         printf( "%4d skins\n", model.num_skins );
585         printf( "file size: %d\n", (int)ftell( modelouthandle ) );
586         printf( "---------------------\n" );
587
588         fclose( modelouthandle );
589
590         // finish writing header file
591         H_printf( "\n" );
592
593         // scale_up is usefull to allow step distances to be adjusted
594         H_printf( "#define MODEL_SCALE\t\t%f\n", scale_up );
595
596         fclose( headerouthandle );
597         headerouthandle = NULL;
598 }
599
600
601 /*
602    =================================================================
603
604    ALIAS MODEL DISPLAY LIST GENERATION
605
606    =================================================================
607  */
608
609 int strip_xyz[128];
610 int strip_st[128];
611 int strip_tris[128];
612 int stripcount;
613
614 /*
615    ================
616    StripLength
617    ================
618  */
619 static int  StripLength( int starttri, int startv ){
620         int m1, m2;
621         int st1, st2;
622         int j;
623         dtriangle_t *last, *check;
624         int k;
625
626         used[starttri] = 2;
627
628         last = &triangles[starttri];
629
630         strip_xyz[0] = last->index_xyz[( startv ) % 3];
631         strip_xyz[1] = last->index_xyz[( startv + 1 ) % 3];
632         strip_xyz[2] = last->index_xyz[( startv + 2 ) % 3];
633         strip_st[0] = last->index_st[( startv ) % 3];
634         strip_st[1] = last->index_st[( startv + 1 ) % 3];
635         strip_st[2] = last->index_st[( startv + 2 ) % 3];
636
637         strip_tris[0] = starttri;
638         stripcount = 1;
639
640         m1 = last->index_xyz[( startv + 2 ) % 3];
641         st1 = last->index_st[( startv + 2 ) % 3];
642         m2 = last->index_xyz[( startv + 1 ) % 3];
643         st2 = last->index_st[( startv + 1 ) % 3];
644
645         // look for a matching triangle
646 nexttri:
647         for ( j = starttri + 1, check = &triangles[starttri + 1]
648                   ; j < model.num_tris ; j++, check++ )
649         {
650                 for ( k = 0 ; k < 3 ; k++ )
651                 {
652                         if ( check->index_xyz[k] != m1 ) {
653                                 continue;
654                         }
655                         if ( check->index_st[k] != st1 ) {
656                                 continue;
657                         }
658                         if ( check->index_xyz[ ( k + 1 ) % 3 ] != m2 ) {
659                                 continue;
660                         }
661                         if ( check->index_st[ ( k + 1 ) % 3 ] != st2 ) {
662                                 continue;
663                         }
664
665                         // this is the next part of the fan
666
667                         // if we can't use this triangle, this tristrip is done
668                         if ( used[j] ) {
669                                 goto done;
670                         }
671
672                         // the new edge
673                         if ( stripcount & 1 ) {
674                                 m2 = check->index_xyz[ ( k + 2 ) % 3 ];
675                                 st2 = check->index_st[ ( k + 2 ) % 3 ];
676                         }
677                         else
678                         {
679                                 m1 = check->index_xyz[ ( k + 2 ) % 3 ];
680                                 st1 = check->index_st[ ( k + 2 ) % 3 ];
681                         }
682
683                         strip_xyz[stripcount + 2] = check->index_xyz[ ( k + 2 ) % 3 ];
684                         strip_st[stripcount + 2] = check->index_st[ ( k + 2 ) % 3 ];
685                         strip_tris[stripcount] = j;
686                         stripcount++;
687
688                         used[j] = 2;
689                         goto nexttri;
690                 }
691         }
692 done:
693
694         // clear the temp used flags
695         for ( j = starttri + 1 ; j < model.num_tris ; j++ )
696                 if ( used[j] == 2 ) {
697                         used[j] = 0;
698                 }
699
700         return stripcount;
701 }
702
703
704 /*
705    ===========
706    FanLength
707    ===========
708  */
709 static int  FanLength( int starttri, int startv ){
710         int m1, m2;
711         int st1, st2;
712         int j;
713         dtriangle_t *last, *check;
714         int k;
715
716         used[starttri] = 2;
717
718         last = &triangles[starttri];
719
720         strip_xyz[0] = last->index_xyz[( startv ) % 3];
721         strip_xyz[1] = last->index_xyz[( startv + 1 ) % 3];
722         strip_xyz[2] = last->index_xyz[( startv + 2 ) % 3];
723         strip_st[0] = last->index_st[( startv ) % 3];
724         strip_st[1] = last->index_st[( startv + 1 ) % 3];
725         strip_st[2] = last->index_st[( startv + 2 ) % 3];
726
727         strip_tris[0] = starttri;
728         stripcount = 1;
729
730         m1 = last->index_xyz[( startv + 0 ) % 3];
731         st1 = last->index_st[( startv + 0 ) % 3];
732         m2 = last->index_xyz[( startv + 2 ) % 3];
733         st2 = last->index_st[( startv + 2 ) % 3];
734
735
736         // look for a matching triangle
737 nexttri:
738         for ( j = starttri + 1, check = &triangles[starttri + 1]
739                   ; j < model.num_tris ; j++, check++ )
740         {
741                 for ( k = 0 ; k < 3 ; k++ )
742                 {
743                         if ( check->index_xyz[k] != m1 ) {
744                                 continue;
745                         }
746                         if ( check->index_st[k] != st1 ) {
747                                 continue;
748                         }
749                         if ( check->index_xyz[ ( k + 1 ) % 3 ] != m2 ) {
750                                 continue;
751                         }
752                         if ( check->index_st[ ( k + 1 ) % 3 ] != st2 ) {
753                                 continue;
754                         }
755
756                         // this is the next part of the fan
757
758                         // if we can't use this triangle, this tristrip is done
759                         if ( used[j] ) {
760                                 goto done;
761                         }
762
763                         // the new edge
764                         m2 = check->index_xyz[ ( k + 2 ) % 3 ];
765                         st2 = check->index_st[ ( k + 2 ) % 3 ];
766
767                         strip_xyz[stripcount + 2] = m2;
768                         strip_st[stripcount + 2] = st2;
769                         strip_tris[stripcount] = j;
770                         stripcount++;
771
772                         used[j] = 2;
773                         goto nexttri;
774                 }
775         }
776 done:
777
778         // clear the temp used flags
779         for ( j = starttri + 1 ; j < model.num_tris ; j++ )
780                 if ( used[j] == 2 ) {
781                         used[j] = 0;
782                 }
783
784         return stripcount;
785 }
786
787
788
789 /*
790    ================
791    BuildGlCmds
792
793    Generate a list of trifans or strips
794    for the model, which holds for all frames
795    ================
796  */
797 static void BuildGlCmds( void ){
798         int i, j, k;
799         int startv;
800         float s, t;
801         int len, bestlen, besttype;
802         int best_xyz[1024];
803         int best_st[1024];
804         int best_tris[1024];
805         int type;
806
807         //
808         // build tristrips
809         //
810         numcommands = 0;
811         numglverts = 0;
812         memset( used, 0, sizeof( used ) );
813         for ( i = 0 ; i < model.num_tris ; i++ )
814         {
815                 // pick an unused triangle and start the trifan
816                 if ( used[i] ) {
817                         continue;
818                 }
819
820                 bestlen = 0;
821                 for ( type = 0 ; type < 2 ; type++ )
822 //      type = 1;
823                 {
824                         for ( startv = 0 ; startv < 3 ; startv++ )
825                         {
826                                 if ( type == 1 ) {
827                                         len = StripLength( i, startv );
828                                 }
829                                 else{
830                                         len = FanLength( i, startv );
831                                 }
832                                 if ( len > bestlen ) {
833                                         besttype = type;
834                                         bestlen = len;
835                                         for ( j = 0 ; j < bestlen + 2 ; j++ )
836                                         {
837                                                 best_st[j] = strip_st[j];
838                                                 best_xyz[j] = strip_xyz[j];
839                                         }
840                                         for ( j = 0 ; j < bestlen ; j++ )
841                                                 best_tris[j] = strip_tris[j];
842                                 }
843                         }
844                 }
845
846                 // mark the tris on the best strip/fan as used
847                 for ( j = 0 ; j < bestlen ; j++ )
848                         used[best_tris[j]] = 1;
849
850                 if ( besttype == 1 ) {
851                         commands[numcommands++] = ( bestlen + 2 );
852                 }
853                 else{
854                         commands[numcommands++] = -( bestlen + 2 );
855                 }
856
857                 numglverts += bestlen + 2;
858
859                 for ( j = 0 ; j < bestlen + 2 ; j++ )
860                 {
861                         // emit a vertex into the reorder buffer
862                         k = best_st[j];
863
864                         // emit s/t coords into the commands stream
865                         s = base_st[k].s;
866                         t = base_st[k].t;
867
868                         s = ( s + 0.5 ) / model.skinwidth;
869                         t = ( t + 0.5 ) / model.skinheight;
870
871                         *(float *)&commands[numcommands++] = s;
872                         *(float *)&commands[numcommands++] = t;
873                         *(int *)&commands[numcommands++] = best_xyz[j];
874                 }
875         }
876
877         commands[numcommands++] = 0;        // end of list marker
878 }
879
880
881 /*
882    ===============================================================
883
884    BASE FRAME SETUP
885
886    ===============================================================
887  */
888
889 /*
890    ============
891    BuildST
892
893    Builds the triangle_st array for the base frame and
894    model.skinwidth / model.skinheight
895
896    FIXME: allow this to be loaded from a file for
897    arbitrary mappings
898    ============
899  */
900 #if 0
901 static void OldBuildST( triangle_t *ptri, int numtri ){
902         int i, j;
903         int width, height, iwidth, iheight, swidth;
904         float basex, basey;
905         float s_scale, t_scale;
906         float scale;
907         vec3_t mins, maxs;
908         float       *pbasevert;
909         vec3_t vtemp1, vtemp2, normal;
910
911         //
912         // find bounds of all the verts on the base frame
913         //
914         ClearBounds( mins, maxs );
915
916         for ( i = 0 ; i < numtri ; i++ )
917                 for ( j = 0 ; j < 3 ; j++ )
918                         AddPointToBounds( ptri[i].verts[j], mins, maxs );
919
920         for ( i = 0 ; i < 3 ; i++ )
921         {
922                 mins[i] = floor( mins[i] );
923                 maxs[i] = ceil( maxs[i] );
924         }
925
926         width = maxs[0] - mins[0];
927         height = maxs[2] - mins[2];
928
929         if ( !g_fixedwidth ) { // old style
930                 scale = 8;
931                 if ( width * scale >= 150 ) {
932                         scale = 150.0 / width;
933                 }
934                 if ( height * scale >= 190 ) {
935                         scale = 190.0 / height;
936                 }
937
938                 s_scale = t_scale = scale;
939
940                 iwidth = ceil( width * s_scale );
941                 iheight = ceil( height * t_scale );
942
943                 iwidth += 4;
944                 iheight += 4;
945         }
946         else
947         {   // new style
948                 iwidth = g_fixedwidth / 2;
949                 iheight = g_fixedheight;
950
951                 s_scale = (float)( iwidth - 4 ) / width;
952                 t_scale = (float)( iheight - 4 ) / height;
953         }
954
955 //
956 // determine which side of each triangle to map the texture to
957 //
958         for ( i = 0 ; i < numtri ; i++ )
959         {
960                 VectorSubtract( ptri[i].verts[0], ptri[i].verts[1], vtemp1 );
961                 VectorSubtract( ptri[i].verts[2], ptri[i].verts[1], vtemp2 );
962                 CrossProduct( vtemp1, vtemp2, normal );
963
964                 if ( normal[1] > 0 ) {
965                         basex = iwidth + 2;
966                 }
967                 else
968                 {
969                         basex = 2;
970                 }
971                 basey = 2;
972
973                 for ( j = 0 ; j < 3 ; j++ )
974                 {
975                         pbasevert = ptri[i].verts[j];
976
977                         triangle_st[i][j][0] = Q_rint( ( pbasevert[0] - mins[0] ) * s_scale + basex );
978                         triangle_st[i][j][1] = Q_rint( ( maxs[2] - pbasevert[2] ) * t_scale + basey );
979                 }
980         }
981
982 // make the width a multiple of 4; some hardware requires this, and it ensures
983 // dword alignment for each scan
984         swidth = iwidth * 2;
985         model.skinwidth = ( swidth + 3 ) & ~3;
986         model.skinheight = iheight;
987 }
988 #endif
989
990 //==========================================================================
991 //
992 // DrawScreen
993 //
994 //==========================================================================
995
996 void DrawScreen( float s_scale, float t_scale, float iwidth, float iheight ){
997         int i;
998         byte *scrpos;
999         char buffer[256];
1000
1001         // Divider
1002         scrpos = &pic[( INFO_Y - 2 ) * SKINPAGE_WIDTH];
1003         for ( i = 0; i < SKINPAGE_WIDTH; i++ )
1004         {
1005                 *scrpos++ = 255;
1006         }
1007
1008         sprintf( buffer, "GENSKIN:  " );
1009         DrawTextChar( 16, INFO_Y, buffer );
1010
1011         sprintf( buffer, "( %03d * %03d )   SCALE %f %f, SKINWIDTH %d,"
1012                                          " SKINHEIGHT %d", (int)ScaleWidth, (int)ScaleHeight, s_scale, t_scale, (int)iwidth * 2, (int)iheight );
1013         DrawTextChar( 80, INFO_Y, buffer );
1014 }
1015
1016 /*
1017    ============
1018    BuildST
1019
1020    Builds the triangle_st array for the base frame and
1021    model.skinwidth / model.skinheight
1022
1023    FIXME: allow this to be loaded from a file for
1024    arbitrary mappings
1025    ============
1026  */
1027 void BuildST( triangle_t *ptri, int numtri, qboolean DrawSkin ){
1028         int i, j;
1029         int width, height, iwidth, iheight, swidth;
1030         float basex, basey;
1031         float scale;
1032         vec3_t mins, maxs;
1033         float       *pbasevert;
1034         vec3_t vtemp1, vtemp2, normal;
1035         float s_scale, t_scale;
1036         float scWidth;
1037         float scHeight;
1038
1039         //
1040         // find bounds of all the verts on the base frame
1041         //
1042         ClearBounds( mins, maxs );
1043
1044         for ( i = 0 ; i < numtri ; i++ )
1045                 for ( j = 0 ; j < 3 ; j++ )
1046                         AddPointToBounds( ptri[i].verts[j], mins, maxs );
1047
1048         for ( i = 0 ; i < 3 ; i++ )
1049         {
1050                 mins[i] = floor( mins[i] );
1051                 maxs[i] = ceil( maxs[i] );
1052         }
1053
1054         width = maxs[0] - mins[0];
1055         height = maxs[2] - mins[2];
1056
1057
1058         scWidth = ( ScaleWidth / 2 ) * SCALE_ADJUST_FACTOR;
1059         scHeight = ScaleHeight * SCALE_ADJUST_FACTOR;
1060
1061         scale = scWidth / width;
1062
1063         if ( height * scale >= scHeight ) {
1064                 scale = scHeight / height;
1065         }
1066
1067         iwidth = ceil( width * scale ) + 4;
1068         iheight = ceil( height * scale ) + 4;
1069
1070         s_scale = (float)( iwidth - 4 ) / width;
1071         t_scale = (float)( iheight - 4 ) / height;
1072         t_scale = s_scale;
1073
1074         if ( DrawSkin ) {
1075                 DrawScreen( s_scale, t_scale, iwidth, iheight );
1076         }
1077
1078
1079 /*      if (!g_fixedwidth)
1080     {   // old style
1081         scale = 8;
1082         if (width*scale >= 150)
1083             scale = 150.0 / width;
1084         if (height*scale >= 190)
1085             scale = 190.0 / height;
1086
1087         s_scale = t_scale = scale;
1088
1089         iwidth = ceil(width*s_scale);
1090         iheight = ceil(height*t_scale);
1091
1092         iwidth += 4;
1093         iheight += 4;
1094     }
1095     else
1096     {   // new style
1097         iwidth = g_fixedwidth / 2;
1098         iheight = g_fixedheight;
1099
1100         s_scale = (float)(iwidth-4) / width;
1101         t_scale = (float)(iheight-4) / height;
1102     }*/
1103
1104 //
1105 // determine which side of each triangle to map the texture to
1106 //
1107         for ( i = 0 ; i < numtri ; i++ )
1108         {
1109                 if ( ptri[i].HasUV ) {
1110                         for ( j = 0 ; j < 3 ; j++ )
1111                         {
1112                                 triangle_st[i][j][0] = Q_rint( ptri[i].uv[j][0] * iwidth );
1113                                 triangle_st[i][j][1] = Q_rint( ( 1.0f - ptri[i].uv[j][1] ) * iheight );
1114                         }
1115                 }
1116                 else
1117                 {
1118                         VectorSubtract( ptri[i].verts[0], ptri[i].verts[1], vtemp1 );
1119                         VectorSubtract( ptri[i].verts[2], ptri[i].verts[1], vtemp2 );
1120                         CrossProduct( vtemp1, vtemp2, normal );
1121
1122                         if ( normal[1] > 0 ) {
1123                                 basex = iwidth + 2;
1124                         }
1125                         else
1126                         {
1127                                 basex = 2;
1128                         }
1129                         basey = 2;
1130
1131                         for ( j = 0 ; j < 3 ; j++ )
1132                         {
1133                                 pbasevert = ptri[i].verts[j];
1134
1135                                 triangle_st[i][j][0] = Q_rint( ( pbasevert[0] - mins[0] ) * s_scale + basex );
1136                                 triangle_st[i][j][1] = Q_rint( ( maxs[2] - pbasevert[2] ) * t_scale + basey );
1137                         }
1138                 }
1139
1140                 DrawLine( triangle_st[i][0][0], triangle_st[i][0][1],
1141                                   triangle_st[i][1][0], triangle_st[i][1][1] );
1142                 DrawLine( triangle_st[i][1][0], triangle_st[i][1][1],
1143                                   triangle_st[i][2][0], triangle_st[i][2][1] );
1144                 DrawLine( triangle_st[i][2][0], triangle_st[i][2][1],
1145                                   triangle_st[i][0][0], triangle_st[i][0][1] );
1146         }
1147
1148 // make the width a multiple of 4; some hardware requires this, and it ensures
1149 // dword alignment for each scan
1150
1151         swidth = iwidth * 2;
1152         model.skinwidth = ( swidth + 3 ) & ~3;
1153         model.skinheight = iheight;
1154 }
1155
1156
1157 static void ReplaceClusterIndex( int newIndex, int oldindex, int **clusters,
1158                                                                  IntListNode_t **vertLists, int *num_verts, int *new_num_verts ){
1159         int i, j;
1160         IntListNode_t *next;
1161
1162         for ( j = 0; j < num_verts[0]; ++j )
1163         {
1164                 for ( i = 0; i < num_verts[j + 1]; ++i )
1165                 {
1166                         if ( clusters[j][i] == oldindex ) {
1167                                 ++new_num_verts[j + 1];
1168
1169                                 next = vertLists[j];
1170
1171                                 vertLists[j] = (IntListNode_t *) SafeMalloc( sizeof( IntListNode_t ), "ReplaceClusterIndex" );
1172                                 // Currently freed in WriteJointedModelFile only
1173
1174                                 vertLists[j]->data = newIndex;
1175                                 vertLists[j]->next = next;
1176                         }
1177                 }
1178         }
1179 }
1180
1181 /*
1182    =================
1183    Cmd_Base
1184    =================
1185  */
1186 void Cmd_Base( void ){
1187         vec3_t base_xyz[MAX_VERTS];
1188         triangle_t  *ptri;
1189         int i, j, k;
1190 #if 1
1191 #else
1192         int time1;
1193 #endif
1194         char file1[1024];
1195         char file2[1024];
1196
1197         GetScriptToken( false );
1198
1199         if ( g_skipmodel || g_release || g_archive ) {
1200                 return;
1201         }
1202
1203         printf( "---------------------\n" );
1204 #if 1
1205         sprintf( file1, "%s/%s", cdpartial, token );
1206         printf( "%s  ", file1 );
1207
1208         ExpandPathAndArchive( file1 );
1209
1210         sprintf( file1, "%s/%s", cddir, token );
1211 #else
1212         sprintf( file1, "%s/%s.%s", cdarchive, token, trifileext );
1213         printf( "%s\n", file1 );
1214
1215         ExpandPathAndArchive( file1 );
1216
1217         sprintf( file1, "%s/%s.%s", cddir, token, trifileext );
1218
1219         time1 = FileTime( file1 );
1220         if ( time1 == -1 ) {
1221                 Error( "%s doesn't exist", file1 );
1222         }
1223 #endif
1224 //
1225 // load the base triangles
1226 //
1227         if ( do3ds ) {
1228                 Load3DSTriangleList( file1, &ptri, &model.num_tris, NULL, NULL );
1229         }
1230         else{
1231                 LoadTriangleList( file1, &ptri, &model.num_tris, NULL, NULL );
1232         }
1233
1234
1235         GetScriptToken( false );
1236         sprintf( file2, "%s/%s.pcx", cddir, token );
1237 //      sprintf (trans_file, "%s/!%s_a.pcx", cddir, token);
1238
1239         printf( "skin: %s\n", file2 );
1240         Load256Image( file2, &BasePixels, &BasePalette, &BaseWidth, &BaseHeight );
1241
1242         if ( BaseWidth != SKINPAGE_WIDTH || BaseHeight != SKINPAGE_HEIGHT ) {
1243                 if ( g_allow_newskin ) {
1244                         ScaleWidth = BaseWidth;
1245                         ScaleHeight = BaseHeight;
1246                 }
1247                 else
1248                 {
1249                         Error( "Invalid skin page size: (%d,%d) should be (%d,%d)",
1250                                    BaseWidth,BaseHeight,SKINPAGE_WIDTH,SKINPAGE_HEIGHT );
1251                 }
1252         }
1253         else
1254         {
1255                 ScaleWidth = (float)ExtractNumber( BasePixels, ENCODED_WIDTH_X,
1256                                                                                    ENCODED_WIDTH_Y );
1257                 ScaleHeight = (float)ExtractNumber( BasePixels, ENCODED_HEIGHT_X,
1258                                                                                         ENCODED_HEIGHT_Y );
1259         }
1260
1261 //
1262 // get the ST values
1263 //
1264         BuildST( ptri, model.num_tris,false );
1265
1266 //
1267 // run through all the base triangles, storing each unique vertex in the
1268 // base vertex list and setting the indirect triangles to point to the base
1269 // vertices
1270 //
1271         for ( i = 0 ; i < model.num_tris ; i++ )
1272         {
1273                 for ( j = 0 ; j < 3 ; j++ )
1274                 {
1275                         // get the xyz index
1276                         for ( k = 0 ; k < model.num_xyz ; k++ )
1277                                 if ( VectorCompare( ptri[i].verts[j], base_xyz[k] ) ) {
1278                                         break;
1279                                 }           // this vertex is already in the base vertex list
1280
1281                         if ( k == model.num_xyz ) { // new index
1282                                 VectorCopy( ptri[i].verts[j], base_xyz[model.num_xyz] );
1283
1284                                 if ( clustered ) {
1285                                         ReplaceClusterIndex( k, ptri[i].indicies[j], (int **)&clusters, (IntListNode_t **)&vertLists, (int *)&num_verts, (int *)&new_num_verts );
1286                                 }
1287
1288                                 model.num_xyz++;
1289                         }
1290
1291                         triangles[i].index_xyz[j] = k;
1292
1293                         // get the st index
1294                         for ( k = 0 ; k < model.num_st ; k++ )
1295                                 if ( triangle_st[i][j][0] == base_st[k].s
1296                                          && triangle_st[i][j][1] == base_st[k].t ) {
1297                                         break;
1298                                 }           // this vertex is already in the base vertex list
1299
1300                         if ( k == model.num_st ) { // new index
1301                                 base_st[model.num_st].s = triangle_st[i][j][0];
1302                                 base_st[model.num_st].t = triangle_st[i][j][1];
1303                                 model.num_st++;
1304                         }
1305
1306                         triangles[i].index_st[j] = k;
1307                 }
1308         }
1309
1310         // build triangle strips / fans
1311         BuildGlCmds();
1312 }
1313
1314 //===============================================================
1315
1316 char    *FindFrameFile( char *frame ){
1317         int time1;
1318         char file1[1024];
1319         static char retname[1024];
1320         char base[32];
1321         char suffix[32];
1322         char            *s;
1323
1324         if ( strstr( frame, "." ) ) {
1325                 return frame;       // allready in dot format
1326
1327         }
1328         // split 'run1' into 'run' and '1'
1329         s = frame + strlen( frame ) - 1;
1330
1331         while ( s != frame && *s >= '0' && *s <= '9' )
1332                 s--;
1333
1334         strcpy( suffix, s + 1 );
1335         strcpy( base, frame );
1336         base[s - frame + 1] = 0;
1337
1338         sprintf( file1, "%s/%s%s.%s",cddir, base, suffix, "hrc" );
1339         time1 = FileTime( file1 );
1340         if ( time1 != -1 ) {
1341                 sprintf( retname, "%s%s.%s", base, suffix, "hrc" );
1342                 return retname;
1343         }
1344
1345         sprintf( file1, "%s/%s%s.%s",cddir, base, suffix, "asc" );
1346         time1 = FileTime( file1 );
1347         if ( time1 != -1 ) {
1348                 sprintf( retname, "%s%s.%s", base, suffix, "asc" );
1349                 return retname;
1350         }
1351
1352         sprintf( file1, "%s/%s%s.%s",cddir, base, suffix, "tri" );
1353         time1 = FileTime( file1 );
1354         if ( time1 != -1 ) {
1355                 sprintf( retname, "%s%s.%s", base, suffix, "tri" );
1356                 return retname;
1357         }
1358
1359         sprintf( file1, "%s/%s%s.%s",cddir, base, suffix, "3ds" );
1360         time1 = FileTime( file1 );
1361         if ( time1 != -1 ) {
1362                 sprintf( retname, "%s%s.%s", base, suffix, "3ds" );
1363                 return retname;
1364         }
1365
1366         sprintf( file1, "%s/%s%s.%s",cddir, base, suffix, "htr" );
1367         time1 = FileTime( file1 );
1368         if ( time1 != -1 ) {
1369                 sprintf( retname, "%s%s.%s", base, suffix, "htr" );
1370                 return retname;
1371         }
1372
1373         // check for 'run.1'
1374         sprintf( file1, "%s/%s.%s",cddir, base, suffix );
1375         time1 = FileTime( file1 );
1376         if ( time1 != -1 ) {
1377                 sprintf( retname, "%s.%s", base, suffix );
1378                 return retname;
1379         }
1380
1381         Error( "frame %s could not be found",frame );
1382         return NULL;
1383 }
1384
1385 /*
1386    ===============
1387    GrabFrame
1388    ===============
1389  */
1390 static void GrabFrame( char *frame ){
1391         triangle_t      *ptri;
1392         int i, j;
1393         trivert_t       *ptrivert;
1394         int num_tris;
1395         char file1[1024];
1396         frame_t         *fr;
1397         vertexnormals_t vnorms[MAX_VERTS];
1398         int index_xyz;
1399         char            *framefile;
1400
1401         // the frame 'run1' will be looked for as either
1402         // run.1 or run1.tri, so the new alias sequence save
1403         // feature an be used
1404         framefile = FindFrameFile( frame );
1405
1406         sprintf( file1, "%s/%s", cdarchive, framefile );
1407         ExpandPathAndArchive( file1 );
1408
1409         sprintf( file1, "%s/%s",cddir, framefile );
1410
1411         printf( "grabbing %s  ", file1 );
1412
1413         if ( model.num_frames >= MAX_FRAMES ) {
1414                 Error( "model.num_frames >= MAX_FRAMES" );
1415         }
1416         fr = &g_frames[model.num_frames];
1417         model.num_frames++;
1418
1419         strcpy( fr->name, frame );
1420
1421 //
1422 // load the frame
1423 //
1424         if ( do3ds ) {
1425                 Load3DSTriangleList( file1, &ptri, &num_tris, NULL, NULL );
1426         }
1427         else{
1428                 LoadTriangleList( file1, &ptri, &num_tris, NULL, NULL );
1429         }
1430
1431         if ( num_tris != model.num_tris ) {
1432                 Error( "%s: number of triangles doesn't match base frame\n", file1 );
1433         }
1434
1435 //
1436 // allocate storage for the frame's vertices
1437 //
1438         ptrivert = fr->v;
1439
1440         for ( i = 0 ; i < model.num_xyz ; i++ )
1441         {
1442                 vnorms[i].numnormals = 0;
1443                 VectorClear( vnorms[i].normalsum );
1444         }
1445         ClearBounds( fr->mins, fr->maxs );
1446
1447 //
1448 // store the frame's vertices in the same order as the base. This assumes the
1449 // triangles and vertices in this frame are in exactly the same order as in the
1450 // base
1451 //
1452         for ( i = 0 ; i < num_tris ; i++ )
1453         {
1454                 vec3_t vtemp1, vtemp2, normal;
1455                 float ftemp;
1456
1457                 VectorSubtract( ptri[i].verts[0], ptri[i].verts[1], vtemp1 );
1458                 VectorSubtract( ptri[i].verts[2], ptri[i].verts[1], vtemp2 );
1459                 CrossProduct( vtemp1, vtemp2, normal );
1460
1461                 VectorNormalize( normal, normal );
1462
1463                 // rotate the normal so the model faces down the positive x axis
1464                 ftemp = normal[0];
1465                 normal[0] = -normal[1];
1466                 normal[1] = ftemp;
1467
1468                 for ( j = 0 ; j < 3 ; j++ )
1469                 {
1470                         index_xyz = triangles[i].index_xyz[j];
1471
1472                         // rotate the vertices so the model faces down the positive x axis
1473                         // also adjust the vertices to the desired origin
1474                         ptrivert[index_xyz].v[0] = ( ( -ptri[i].verts[j][1] ) * scale_up ) +
1475                                                                            adjust[0];
1476                         ptrivert[index_xyz].v[1] = ( ptri[i].verts[j][0] * scale_up ) +
1477                                                                            adjust[1];
1478                         ptrivert[index_xyz].v[2] = ( ptri[i].verts[j][2] * scale_up ) +
1479                                                                            adjust[2];
1480
1481                         AddPointToBounds( ptrivert[index_xyz].v, fr->mins, fr->maxs );
1482
1483                         VectorAdd( vnorms[index_xyz].normalsum, normal, vnorms[index_xyz].normalsum );
1484                         vnorms[index_xyz].numnormals++;
1485                 }
1486         }
1487
1488 //
1489 // calculate the vertex normals, match them to the template list, and store the
1490 // index of the best match
1491 //
1492         for ( i = 0 ; i < model.num_xyz ; i++ )
1493         {
1494                 int j;
1495                 vec3_t v;
1496                 float maxdot;
1497                 int maxdotindex;
1498                 int c;
1499
1500                 c = vnorms[i].numnormals;
1501                 if ( !c ) {
1502                         Error( "Vertex with no triangles attached" );
1503                 }
1504
1505                 VectorScale( vnorms[i].normalsum, 1.0 / c, v );
1506                 VectorNormalize( v, v );
1507
1508                 maxdot = -999999.0;
1509                 maxdotindex = -1;
1510
1511                 for ( j = 0 ; j < NUMVERTEXNORMALS ; j++ )
1512                 {
1513                         float dot;
1514
1515                         dot = DotProduct( v, avertexnormals[j] );
1516                         if ( dot > maxdot ) {
1517                                 maxdot = dot;
1518                                 maxdotindex = j;
1519                         }
1520                 }
1521
1522                 ptrivert[i].lightnormalindex = maxdotindex;
1523         }
1524
1525         free( ptri );
1526 }
1527
1528 /*
1529    ===============
1530    GrabJointedFrame
1531    ===============
1532  */
1533 void GrabJointedFrame( char *frame ){
1534         char file1[1024];
1535         char    *framefile;
1536         frame_t     *fr;
1537
1538         framefile = FindFrameFile( frame );
1539
1540         sprintf( file1, "%s/%s", cdarchive, framefile );
1541         ExpandPathAndArchive( file1 );
1542
1543         sprintf( file1, "%s/%s",cddir, framefile );
1544
1545         printf( "grabbing %s\n", file1 );
1546
1547         fr = &g_frames[model.num_frames - 1]; // last frame read in
1548
1549         LoadJointList( file1, fr->joints, jointed );
1550 }
1551
1552 /*
1553    ===============
1554    GrabGlobals
1555    ===============
1556  */
1557 void GrabGlobals( char *frame ){
1558         char file1[1024];
1559         char    *framefile;
1560         frame_t     *fr;
1561
1562         framefile = FindFrameFile( frame );
1563
1564         sprintf( file1, "%s/%s", cdarchive, framefile );
1565         ExpandPathAndArchive( file1 );
1566
1567         sprintf( file1, "%s/%s",cddir, framefile );
1568
1569         printf( "grabbing %s\n", file1 );
1570
1571         fr = &g_frames[model.num_frames - 1]; // last frame read in
1572
1573         LoadGlobals( file1 );
1574 }
1575
1576 /*
1577    ===============
1578    Cmd_Frame
1579    ===============
1580  */
1581 void Cmd_Frame( void ){
1582         while ( ScriptTokenAvailable() )
1583         {
1584                 GetScriptToken( false );
1585                 if ( g_skipmodel ) {
1586                         continue;
1587                 }
1588                 if ( g_release || g_archive ) {
1589                         model.num_frames = 1;   // don't skip the writeout
1590                         continue;
1591                 }
1592
1593                 H_printf( "#define FRAME_%-16s\t%i\n", token, model.num_frames );
1594
1595                 GrabFrame( token );
1596         }
1597 }
1598
1599 /*
1600    ===============
1601    Cmd_Skin
1602
1603    Skins aren't actually stored in the file, only a reference
1604    is saved out to the header file.
1605    ===============
1606  */
1607 void Cmd_Skin( void ){
1608         byte    *palette;
1609         byte    *pixels;
1610         int width, height;
1611         byte    *cropped;
1612         int y;
1613         char name[1024], savename[1024];
1614
1615         GetScriptToken( false );
1616
1617         if ( model.num_skins == MAX_MD2SKINS ) {
1618                 Error( "model.num_skins == MAX_MD2SKINS" );
1619         }
1620
1621         if ( g_skipmodel ) {
1622                 return;
1623         }
1624
1625 #if 1
1626         sprintf( name, "%s/%s.pcx", cddir, token );
1627         sprintf( savename, "%s/!%s.pcx", g_outputDir, token );
1628         sprintf( g_skins[model.num_skins], "%s/!%s.pcx", cdpartial, token );
1629 #else
1630         sprintf( name, "%s/%s.lbm", cdarchive, token );
1631         strcpy( name, ExpandPathAndArchive( name ) );
1632 //      sprintf (name, "%s/%s.lbm", cddir, token);
1633
1634         if ( ScriptTokenAvailable() ) {
1635                 GetScriptToken( false );
1636                 sprintf( g_skins[model.num_skins], "%s.pcx", token );
1637                 sprintf( savename, "%s%s.pcx", g_outputDir, g_skins[model.num_skins] );
1638         }
1639         else
1640         {
1641                 sprintf( savename, "%s/%s.pcx", g_outputDir, token );
1642                 sprintf( g_skins[model.num_skins], "%s/%s.pcx", cdpartial, token );
1643         }
1644 #endif
1645
1646         model.num_skins++;
1647
1648         if ( g_skipmodel || g_release || g_archive ) {
1649                 return;
1650         }
1651
1652         // load the image
1653         printf( "loading %s\n", name );
1654         Load256Image( name, &pixels, &palette, &width, &height );
1655 //      RemapZero (pixels, palette, width, height);
1656
1657         // crop it to the proper size
1658         cropped = (byte *) SafeMalloc( model.skinwidth * model.skinheight, "Cmd_Skin" );
1659         for ( y = 0 ; y < model.skinheight ; y++ )
1660         {
1661                 memcpy( cropped + y * model.skinwidth,
1662                                 pixels + y * width, model.skinwidth );
1663         }
1664
1665         // save off the new image
1666         printf( "saving %s\n", savename );
1667         CreatePath( savename );
1668         WritePCXfile( savename, cropped, model.skinwidth,
1669                                   model.skinheight, palette );
1670
1671         free( pixels );
1672         free( palette );
1673         free( cropped );
1674 }
1675
1676
1677 /*
1678    =================
1679    Cmd_Origin
1680    =================
1681  */
1682 void Cmd_Origin( void ){
1683         // rotate points into frame of reference so model points down the
1684         // positive x axis
1685         GetScriptToken( false );
1686         adjust[1] = -atof( token );
1687
1688         GetScriptToken( false );
1689         adjust[0] = atof( token );
1690
1691         GetScriptToken( false );
1692         adjust[2] = -atof( token );
1693 }
1694
1695
1696 /*
1697    =================
1698    Cmd_ScaleUp
1699    =================
1700  */
1701 void Cmd_ScaleUp( void ){
1702         GetScriptToken( false );
1703         scale_up = atof( token );
1704         if ( g_skipmodel || g_release || g_archive ) {
1705                 return;
1706         }
1707
1708         printf( "Scale up: %f\n", scale_up );
1709 }
1710
1711
1712 /*
1713    =================
1714    Cmd_Skinsize
1715
1716    Set a skin size other than the default
1717    =================
1718  */
1719 void Cmd_Skinsize( void ){
1720         GetScriptToken( false );
1721         g_fixedwidth = atoi( token );
1722         GetScriptToken( false );
1723         g_fixedheight = atoi( token );
1724 }
1725
1726 /*
1727    =================
1728    Cmd_Modelname
1729
1730    Gives a different name/location for the file, instead of the cddir
1731    =================
1732  */
1733 void Cmd_Modelname( void ){
1734         GetScriptToken( false );
1735         strcpy( modelname, token );
1736 }
1737
1738 /*
1739    ===============
1740    Cmd_Cd
1741    ===============
1742  */
1743 void Cmd_Cd( void ){
1744         char temp[256];
1745
1746         FinishModel();
1747         ClearModel();
1748
1749         GetScriptToken( false );
1750
1751         // this is a silly mess...
1752         sprintf( cdpartial, "models/%s", token );
1753         sprintf( cdarchive, "%smodels/%s", gamedir + strlen( qdir ), token );
1754         sprintf( cddir, "%s%s", gamedir, cdpartial );
1755
1756         // Since we also changed directories on the output side (for mirror) make sure the outputdir is set properly too.
1757         sprintf( temp, "%s%s", g_outputDir, cdpartial );
1758         strcpy( g_outputDir, temp );
1759
1760         // if -only was specified and this cd doesn't match,
1761         // skip the model (you only need to match leading chars,
1762         // so you could regrab all monsters with -only monsters)
1763         if ( !g_only[0] ) {
1764                 return;
1765         }
1766         if ( strncmp( token, g_only, strlen( g_only ) ) ) {
1767                 g_skipmodel = true;
1768                 printf( "skipping %s\n", cdpartial );
1769         }
1770 }
1771
1772 /*
1773    =================
1774    Cmd_Cluster
1775    =================
1776  */
1777 void Cmd_Cluster(){
1778         char file1[1024];
1779
1780         GetScriptToken( false );
1781
1782         printf( "---------------------\n" );
1783         sprintf( file1, "%s/%s", cdpartial, token );
1784         printf( "%s\n", file1 );
1785
1786         ExpandPathAndArchive( file1 );
1787
1788         sprintf( file1, "%s/%s", cddir, token );
1789
1790         LoadClusters( file1, (int **)&clusters, (int *)&num_verts, jointed );
1791
1792         new_num_verts[0] = num_verts[0];
1793
1794         clustered = 1;
1795 }
1796
1797 // Model construction cover functions.
1798 void MODELCMD_Modelname( int modeltype ){
1799         if ( g_forcemodel ) {
1800                 modeltype = g_forcemodel;
1801         }
1802
1803         Cmd_Modelname();
1804 /*
1805     switch(modeltype)
1806     {
1807     case MODEL_MD2:
1808         Cmd_Modelname ();
1809         break;
1810     case MODEL_FM:
1811         Cmd_FMModelname ();
1812         break;
1813     }
1814  */
1815 }
1816
1817 void MODELCMD_Cd( int modeltype ){
1818         if ( g_forcemodel ) {
1819                 modeltype = g_forcemodel;
1820         }
1821
1822         switch ( modeltype )
1823         {
1824         case MODEL_MD2:
1825                 Cmd_Cd();
1826                 break;
1827         case MODEL_FM:
1828                 Cmd_FMCd();
1829                 break;
1830         }
1831 }
1832
1833 void MODELCMD_Origin( int modeltype ){
1834         if ( g_forcemodel ) {
1835                 modeltype = g_forcemodel;
1836         }
1837
1838         Cmd_Origin();
1839 /*      switch(modeltype)
1840     {
1841     case MODEL_MD2:
1842         Cmd_Origin ();
1843         break;
1844     case MODEL_FM:
1845         Cmd_FMOrigin ();
1846         break;
1847     }
1848  */
1849 }
1850
1851 void MODELCMD_Cluster( int modeltype ){
1852         if ( g_forcemodel ) {
1853                 modeltype = g_forcemodel;
1854         }
1855
1856         switch ( modeltype )
1857         {
1858         case MODEL_MD2:
1859                 Cmd_Cluster();
1860                 break;
1861         case MODEL_FM:
1862                 Cmd_FMCluster();
1863                 break;
1864         }
1865 }
1866
1867 void MODELCMD_Base( int modeltype ){
1868         if ( g_forcemodel ) {
1869                 modeltype = g_forcemodel;
1870         }
1871
1872         switch ( modeltype )
1873         {
1874         case MODEL_MD2:
1875                 Cmd_Base();
1876                 break;
1877         case MODEL_FM:
1878                 Cmd_FMBase( false );
1879                 break;
1880         }
1881 }
1882
1883 void MODELCMD_BaseST( int modeltype ){
1884         if ( g_forcemodel ) {
1885                 modeltype = g_forcemodel;
1886         }
1887
1888         switch ( modeltype )
1889         {
1890         case MODEL_MD2:
1891                 Cmd_Base();
1892                 break;
1893         case MODEL_FM:
1894                 Cmd_FMBase( true );
1895                 break;
1896         }
1897 }
1898
1899 void MODELCMD_ScaleUp( int modeltype ){
1900         if ( g_forcemodel ) {
1901                 modeltype = g_forcemodel;
1902         }
1903
1904         Cmd_ScaleUp();
1905 /*      switch(modeltype)
1906     {
1907     case MODEL_MD2:
1908         Cmd_ScaleUp ();
1909         break;
1910     case MODEL_FM:
1911         Cmd_FMScaleUp ();
1912         break;
1913     }
1914  */
1915 }
1916
1917 void MODELCMD_Frame( int modeltype ){
1918         if ( g_forcemodel ) {
1919                 modeltype = g_forcemodel;
1920         }
1921
1922         switch ( modeltype )
1923         {
1924         case MODEL_MD2:
1925                 Cmd_Frame();
1926                 break;
1927         case MODEL_FM:
1928                 Cmd_FMFrame();
1929                 break;
1930         }
1931 }
1932
1933 void MODELCMD_Skin( int modeltype ){
1934         if ( g_forcemodel ) {
1935                 modeltype = g_forcemodel;
1936         }
1937
1938         switch ( modeltype )
1939         {
1940         case MODEL_MD2:
1941                 Cmd_Skin();
1942                 break;
1943         case MODEL_FM:
1944                 Cmd_FMSkin();
1945                 break;
1946         }
1947 }
1948
1949 void MODELCMD_Skinsize( int modeltype ){
1950         if ( g_forcemodel ) {
1951                 modeltype = g_forcemodel;
1952         }
1953
1954         Cmd_Skinsize();
1955 /*
1956     switch(modeltype)
1957     {
1958     case MODEL_MD2:
1959         Cmd_Skinsize ();
1960         break;
1961     case MODEL_FM:
1962         Cmd_FMSkinsize ();
1963         break;
1964     }
1965  */
1966 }
1967
1968 void MODELCMD_Skeleton( int modeltype ){
1969         if ( g_forcemodel ) {
1970                 modeltype = g_forcemodel;
1971         }
1972
1973         switch ( modeltype )
1974         {
1975         case MODEL_MD2:
1976                 break;
1977         case MODEL_FM:
1978                 Cmd_FMSkeleton();
1979                 break;
1980         }
1981 }
1982
1983 void MODELCMD_BeginGroup( int modeltype ){
1984         if ( g_forcemodel ) {
1985                 modeltype = g_forcemodel;
1986         }
1987
1988         switch ( modeltype )
1989         {
1990         case MODEL_MD2:
1991                 break;
1992         case MODEL_FM:
1993                 Cmd_FMBeginGroup();
1994                 break;
1995         }
1996 }
1997
1998 void MODELCMD_EndGroup( int modeltype ){
1999         if ( g_forcemodel ) {
2000                 modeltype = g_forcemodel;
2001         }
2002
2003         switch ( modeltype )
2004         {
2005         case MODEL_MD2:
2006                 break;
2007         case MODEL_FM:
2008                 Cmd_FMEndGroup();
2009                 break;
2010         }
2011 }
2012
2013 void MODELCMD_Referenced( int modeltype ){
2014         if ( g_forcemodel ) {
2015                 modeltype = g_forcemodel;
2016         }
2017
2018         switch ( modeltype )
2019         {
2020         case MODEL_MD2:
2021                 break;
2022         case MODEL_FM:
2023                 Cmd_FMReferenced();
2024                 break;
2025         }
2026 }
2027
2028 void MODELCMD_NodeOrder( int modeltype ){
2029         if ( g_forcemodel ) {
2030                 modeltype = g_forcemodel;
2031         }
2032
2033         switch ( modeltype )
2034         {
2035         case MODEL_MD2:
2036                 break;
2037         case MODEL_FM:
2038                 Cmd_FMNodeOrder();
2039                 break;
2040         }
2041 }