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