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