]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/qdata/models.c
76713a5bad71fcb8280ab6688f91911fd62f724c
[xonotic/netradiant.git] / tools / quake2 / qdata / models.c
1
2 #include "qdata.h"
3 #include "inout.h"
4
5 //=================================================================
6
7 typedef struct 
8 {
9         int             numnormals;
10         vec3_t  normalsum;
11 } vertexnormals_t;
12
13 typedef struct
14 {
15         vec3_t          v;
16         int                     lightnormalindex;
17 } trivert_t;
18
19 typedef struct
20 {
21         vec3_t          mins, maxs;
22         char            name[16];
23         trivert_t       v[MAX_VERTS];
24 } frame_t;
25
26 //================================================================
27
28 frame_t         g_frames[MAX_FRAMES];
29
30 dmdl_t          model;
31
32
33 float           scale_up;                       // set by $scale
34 vec3_t          adjust;                         // set by $origin
35 int                     g_fixedwidth, g_fixedheight;    // set by $skinsize
36
37
38 //
39 // base frame info
40 //
41 vec3_t          base_xyz[MAX_VERTS];
42 dstvert_t       base_st[MAX_VERTS];
43 dtriangle_t     triangles[MAX_TRIANGLES];
44
45 int                     triangle_st[MAX_TRIANGLES][3][2];
46
47 // the command list holds counts, s/t values, and xyz indexes
48 // that are valid for every frame
49 int                     commands[16384];
50 int                     numcommands;
51 int                     numglverts;
52 int                     used[MAX_TRIANGLES];
53
54 char            g_skins[MAX_MD2SKINS][64];
55
56 char            cdarchive[1024];
57 char            cdpartial[1024];
58 char            cddir[1024];
59
60 char            modelname[64];  // empty unless $modelname issued (players)
61
62 #define NUMVERTEXNORMALS        162
63
64 float   avertexnormals[NUMVERTEXNORMALS][3] = {
65 #include "anorms.h"
66 };
67
68 FILE    *headerouthandle = NULL;
69
70 //==============================================================
71
72 /*
73 ===============
74 ClearModel
75 ===============
76 */
77 void ClearModel (void)
78 {
79         memset (&model, 0, sizeof(model));
80
81         modelname[0] = 0;
82         scale_up = 1.0; 
83         VectorCopy (vec3_origin, adjust);
84         g_fixedwidth = g_fixedheight = 0;
85         g_skipmodel = false;
86 }
87
88
89 void H_printf(char *fmt, ...)
90 {
91         va_list argptr;
92         char    name[1024];
93
94         if (!headerouthandle)
95         {
96                 sprintf (name, "%s/tris.h", cddir);
97                 headerouthandle = SafeOpenWrite (name);
98                 fprintf(headerouthandle, "// %s\n\n", cddir);
99                 fprintf(headerouthandle, "// This file generated by qdata - Do NOT Modify\n\n");
100         }
101
102         va_start (argptr, fmt);
103         vfprintf (headerouthandle, fmt, argptr);
104         va_end (argptr);
105 }
106
107
108 /*
109 ============
110 WriteModelFile
111 ============
112 */
113 void WriteModelFile (FILE *modelouthandle)
114 {
115         int                             i;
116         dmdl_t                  modeltemp;
117         int                             j, k;
118         frame_t                 *in;
119         daliasframe_t   *out;
120         byte                    buffer[MAX_VERTS*4+128];
121         float                   v;
122         int                             c_on, c_off;
123
124         model.ident = IDALIASHEADER;
125         model.version = ALIAS_VERSION;
126         model.framesize = (int)&((daliasframe_t *)0)->verts[model.num_xyz];
127         model.num_glcmds = numcommands;
128         model.ofs_skins = sizeof(dmdl_t);
129         model.ofs_st = model.ofs_skins + model.num_skins * MAX_SKINNAME;
130         model.ofs_tris = model.ofs_st + model.num_st*sizeof(dstvert_t);
131         model.ofs_frames = model.ofs_tris + model.num_tris*sizeof(dtriangle_t);
132         model.ofs_glcmds = model.ofs_frames + model.num_frames*model.framesize;
133         model.ofs_end = model.ofs_glcmds + model.num_glcmds*4;
134
135         //
136         // write out the model header
137         //
138         for (i=0 ; i<sizeof(dmdl_t)/4 ; i++)
139                 ((int *)&modeltemp)[i] = LittleLong (((int *)&model)[i]);
140
141         SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp));
142
143         //
144         // write out the skin names
145         //
146         SafeWrite (modelouthandle, g_skins, model.num_skins * MAX_SKINNAME);
147
148         //
149         // write out the texture coordinates
150         //
151         c_on = c_off = 0;
152         for (i=0 ; i<model.num_st ; i++)
153         {
154                 base_st[i].s = LittleShort (base_st[i].s);
155                 base_st[i].t = LittleShort (base_st[i].t);
156         }
157
158         SafeWrite (modelouthandle, base_st, model.num_st * sizeof(base_st[0]));
159
160         //
161         // write out the triangles
162         //
163         for (i=0 ; i<model.num_tris ; i++)
164         {
165                 int                     j;
166                 dtriangle_t     tri;
167
168                 for (j=0 ; j<3 ; j++)
169                 {
170                         tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]);
171                         tri.index_st[j] = LittleShort (triangles[i].index_st[j]);
172                 }
173
174                 SafeWrite (modelouthandle, &tri, sizeof(tri));
175         }
176
177         //
178         // write out the frames
179         //
180         for (i=0 ; i<model.num_frames ; i++)
181         {
182                 in = &g_frames[i];
183                 out = (daliasframe_t *)buffer;
184
185                 strcpy (out->name, in->name);
186                 for (j=0 ; j<3 ; j++)
187                 {
188                         out->scale[j] = (in->maxs[j] - in->mins[j])/255;
189                         out->translate[j] = in->mins[j];
190                 }
191
192                 for (j=0 ; j<model.num_xyz ; j++)
193                 {
194                 // all of these are byte values, so no need to deal with endianness
195                         out->verts[j].lightnormalindex = in->v[j].lightnormalindex;
196
197                         for (k=0 ; k<3 ; k++)
198                         {
199                         // scale to byte values & min/max check
200                                 v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] );
201
202                         // clamp, so rounding doesn't wrap from 255.6 to 0
203                                 if (v > 255.0)
204                                         v = 255.0;
205                                 if (v < 0)
206                                         v = 0;
207                                 out->verts[j].v[k] = v;
208                         }
209                 }
210
211                 for (j=0 ; j<3 ; j++)
212                 {
213                         out->scale[j] = LittleFloat (out->scale[j]);
214                         out->translate[j] = LittleFloat (out->translate[j]);
215                 }
216
217                 SafeWrite (modelouthandle, out, model.framesize);
218         }
219
220         //
221         // write out glcmds
222         //
223         SafeWrite (modelouthandle, commands, numcommands*4);
224 }
225
226
227 /*
228 ===============
229 FinishModel
230 ===============
231 */
232 void FinishModel (void)
233 {
234         FILE            *modelouthandle;
235         int                     i;
236         char            name[1024];
237         
238         if (!model.num_frames)
239                 return;
240         
241 //
242 // copy to release directory tree if doing a release build
243 //
244         if (g_release)
245         {
246                 if (modelname[0])
247                         sprintf (name, "%s", modelname);
248                 else
249                         sprintf (name, "%s/tris.md2", cdpartial);
250                 ReleaseFile (name);
251
252                 for (i=0 ; i<model.num_skins ; i++)
253                 {
254                         ReleaseFile (g_skins[i]);
255                 }
256                 model.num_frames = 0;
257                 return;
258         }
259         
260 //
261 // write the model output file
262 //
263         if (modelname[0])
264                 sprintf (name, "%s%s", gamedir, modelname);
265         else
266                 sprintf (name, "%s/tris.md2", cddir);
267         printf ("saving to %s\n", name);
268         CreatePath (name);
269         modelouthandle = SafeOpenWrite (name);
270
271         WriteModelFile (modelouthandle);
272         
273         printf ("%3dx%3d skin\n", model.skinwidth, model.skinheight);
274         printf ("%4d vertexes\n", model.num_xyz);
275         printf ("%4d triangles\n", model.num_tris);
276         printf ("%4d frame\n", model.num_frames);
277         printf ("%4d glverts\n", numglverts);
278         printf ("%4d glcmd\n", model.num_glcmds);
279         printf ("%4d skins\n", model.num_skins);
280         printf ("file size: %d\n", (int)ftell (modelouthandle) );
281         printf ("---------------------\n");
282         
283         fclose (modelouthandle);
284
285         // finish writing header file
286         H_printf("\n");
287
288         // scale_up is usefull to allow step distances to be adjusted
289         H_printf("#define MODEL_SCALE\t\t%f\n", scale_up);
290
291         fclose (headerouthandle);
292         headerouthandle = NULL;
293 }
294
295
296 /*
297 =================================================================
298
299 ALIAS MODEL DISPLAY LIST GENERATION
300
301 =================================================================
302 */
303
304 int             strip_xyz[128];
305 int             strip_st[128];
306 int             strip_tris[128];
307 int             stripcount;
308
309 /*
310 ================
311 StripLength
312 ================
313 */
314 int     StripLength (int starttri, int startv)
315 {
316         int                     m1, m2;
317         int                     st1, st2;
318         int                     j;
319         dtriangle_t     *last, *check;
320         int                     k;
321
322         used[starttri] = 2;
323
324         last = &triangles[starttri];
325
326         strip_xyz[0] = last->index_xyz[(startv)%3];
327         strip_xyz[1] = last->index_xyz[(startv+1)%3];
328         strip_xyz[2] = last->index_xyz[(startv+2)%3];
329         strip_st[0] = last->index_st[(startv)%3];
330         strip_st[1] = last->index_st[(startv+1)%3];
331         strip_st[2] = last->index_st[(startv+2)%3];
332
333         strip_tris[0] = starttri;
334         stripcount = 1;
335
336         m1 = last->index_xyz[(startv+2)%3];
337         st1 = last->index_st[(startv+2)%3];
338         m2 = last->index_xyz[(startv+1)%3];
339         st2 = last->index_st[(startv+1)%3];
340
341         // look for a matching triangle
342 nexttri:
343         for (j=starttri+1, check=&triangles[starttri+1]
344                 ; j<model.num_tris ; j++, check++)
345         {
346                 for (k=0 ; k<3 ; k++)
347                 {
348                         if (check->index_xyz[k] != m1)
349                                 continue;
350                         if (check->index_st[k] != st1)
351                                 continue;
352                         if (check->index_xyz[ (k+1)%3 ] != m2)
353                                 continue;
354                         if (check->index_st[ (k+1)%3 ] != st2)
355                                 continue;
356
357                         // this is the next part of the fan
358
359                         // if we can't use this triangle, this tristrip is done
360                         if (used[j])
361                                 goto done;
362
363                         // the new edge
364                         if (stripcount & 1)
365                         {
366                                 m2 = check->index_xyz[ (k+2)%3 ];
367                                 st2 = check->index_st[ (k+2)%3 ];
368                         }
369                         else
370                         {
371                                 m1 = check->index_xyz[ (k+2)%3 ];
372                                 st1 = check->index_st[ (k+2)%3 ];
373                         }
374
375                         strip_xyz[stripcount+2] = check->index_xyz[ (k+2)%3 ];
376                         strip_st[stripcount+2] = check->index_st[ (k+2)%3 ];
377                         strip_tris[stripcount] = j;
378                         stripcount++;
379
380                         used[j] = 2;
381                         goto nexttri;
382                 }
383         }
384 done:
385
386         // clear the temp used flags
387         for (j=starttri+1 ; j<model.num_tris ; j++)
388                 if (used[j] == 2)
389                         used[j] = 0;
390
391         return stripcount;
392 }
393
394
395 /*
396 ===========
397 FanLength
398 ===========
399 */
400 int     FanLength (int starttri, int startv)
401 {
402         int             m1, m2;
403         int             st1, st2;
404         int             j;
405         dtriangle_t     *last, *check;
406         int             k;
407
408         used[starttri] = 2;
409
410         last = &triangles[starttri];
411
412         strip_xyz[0] = last->index_xyz[(startv)%3];
413         strip_xyz[1] = last->index_xyz[(startv+1)%3];
414         strip_xyz[2] = last->index_xyz[(startv+2)%3];
415         strip_st[0] = last->index_st[(startv)%3];
416         strip_st[1] = last->index_st[(startv+1)%3];
417         strip_st[2] = last->index_st[(startv+2)%3];
418
419         strip_tris[0] = starttri;
420         stripcount = 1;
421
422         m1 = last->index_xyz[(startv+0)%3];
423         st1 = last->index_st[(startv+0)%3];
424         m2 = last->index_xyz[(startv+2)%3];
425         st2 = last->index_st[(startv+2)%3];
426
427
428         // look for a matching triangle
429 nexttri:
430         for (j=starttri+1, check=&triangles[starttri+1] 
431                 ; j<model.num_tris ; j++, check++)
432         {
433                 for (k=0 ; k<3 ; k++)
434                 {
435                         if (check->index_xyz[k] != m1)
436                                 continue;
437                         if (check->index_st[k] != st1)
438                                 continue;
439                         if (check->index_xyz[ (k+1)%3 ] != m2)
440                                 continue;
441                         if (check->index_st[ (k+1)%3 ] != st2)
442                                 continue;
443
444                         // this is the next part of the fan
445
446                         // if we can't use this triangle, this tristrip is done
447                         if (used[j])
448                                 goto done;
449
450                         // the new edge
451                         m2 = check->index_xyz[ (k+2)%3 ];
452                         st2 = check->index_st[ (k+2)%3 ];
453
454                         strip_xyz[stripcount+2] = m2;
455                         strip_st[stripcount+2] = st2;
456                         strip_tris[stripcount] = j;
457                         stripcount++;
458
459                         used[j] = 2;
460                         goto nexttri;
461                 }
462         }
463 done:
464
465         // clear the temp used flags
466         for (j=starttri+1 ; j<model.num_tris ; j++)
467                 if (used[j] == 2)
468                         used[j] = 0;
469
470         return stripcount;
471 }
472
473
474
475 /*
476 ================
477 BuildGlCmds
478
479 Generate a list of trifans or strips
480 for the model, which holds for all frames
481 ================
482 */
483 void BuildGlCmds (void)
484 {
485         int             i, j, k;
486         int             startv;
487         float   s, t;
488         int             len, bestlen, besttype;
489         int             best_xyz[1024];
490         int             best_st[1024];
491         int             best_tris[1024];
492         int             type;
493
494         //
495         // build tristrips
496         //
497         numcommands = 0;
498         numglverts = 0;
499         memset (used, 0, sizeof(used));
500         for (i=0 ; i<model.num_tris ; i++)
501         {
502                 // pick an unused triangle and start the trifan
503                 if (used[i])
504                         continue;
505
506                 bestlen = 0;
507                 for (type = 0 ; type < 2 ; type++)
508 //      type = 1;
509                 {
510                         for (startv =0 ; startv < 3 ; startv++)
511                         {
512                                 if (type == 1)
513                                         len = StripLength (i, startv);
514                                 else
515                                         len = FanLength (i, startv);
516                                 if (len > bestlen)
517                                 {
518                                         besttype = type;
519                                         bestlen = len;
520                                         for (j=0 ; j<bestlen+2 ; j++)
521                                         {
522                                                 best_st[j] = strip_st[j];
523                                                 best_xyz[j] = strip_xyz[j];
524                                         }
525                                         for (j=0 ; j<bestlen ; j++)
526                                                 best_tris[j] = strip_tris[j];
527                                 }
528                         }
529                 }
530
531                 // mark the tris on the best strip/fan as used
532                 for (j=0 ; j<bestlen ; j++)
533                         used[best_tris[j]] = 1;
534
535                 if (besttype == 1)
536                         commands[numcommands++] = (bestlen+2);
537                 else
538                         commands[numcommands++] = -(bestlen+2);
539
540                 numglverts += bestlen+2;
541
542                 for (j=0 ; j<bestlen+2 ; j++)
543                 {
544                         // emit a vertex into the reorder buffer
545                         k = best_st[j];
546
547                         // emit s/t coords into the commands stream
548                         s = base_st[k].s;
549                         t = base_st[k].t;
550
551                         s = (s + 0.5) / model.skinwidth;
552                         t = (t + 0.5) / model.skinheight;
553
554                         *(float *)&commands[numcommands++] = s;
555                         *(float *)&commands[numcommands++] = t;
556                         *(int *)&commands[numcommands++] = best_xyz[j];
557                 }
558         }
559
560         commands[numcommands++] = 0;            // end of list marker
561 }
562
563
564 /*
565 ===============================================================
566
567 BASE FRAME SETUP
568
569 ===============================================================
570 */
571
572 /*
573 ============
574 BuildST
575
576 Builds the triangle_st array for the base frame and
577 model.skinwidth / model.skinheight
578
579   FIXME: allow this to be loaded from a file for
580   arbitrary mappings
581 ============
582 */
583 void BuildST (triangle_t *ptri, int numtri)
584 {
585         int                     i, j;
586         int                     width, height, iwidth, iheight, swidth;
587         float           basex, basey;
588         float           s_scale, t_scale;
589         float           scale;
590         vec3_t          mins, maxs;
591         float           *pbasevert;
592         vec3_t          vtemp1, vtemp2, normal;
593
594         //
595         // find bounds of all the verts on the base frame
596         //
597         ClearBounds (mins, maxs);
598         
599         for (i=0 ; i<numtri ; i++)
600                 for (j=0 ; j<3 ; j++)
601                         AddPointToBounds (ptri[i].verts[j], mins, maxs);
602         
603         for (i=0 ; i<3 ; i++)
604         {
605                 mins[i] = floor(mins[i]);
606                 maxs[i] = ceil(maxs[i]);
607         }
608         
609         width = maxs[0] - mins[0];
610         height = maxs[2] - mins[2];
611
612         if (!g_fixedwidth)
613         {       // old style
614                 scale = 8;
615                 if (width*scale >= 150)
616                         scale = 150.0 / width;  
617                 if (height*scale >= 190)
618                         scale = 190.0 / height;
619
620                 s_scale = t_scale = scale;
621
622                 iwidth = ceil(width*s_scale);
623                 iheight = ceil(height*t_scale);
624
625                 iwidth += 4;
626                 iheight += 4;
627         }
628         else
629         {       // new style
630                 iwidth = g_fixedwidth / 2;
631                 iheight = g_fixedheight;
632
633                 s_scale = (float)(iwidth-4) / width;
634                 t_scale = (float)(iheight-4) / height;
635         }
636
637 //
638 // determine which side of each triangle to map the texture to
639 //
640         for (i=0 ; i<numtri ; i++)
641         {
642                 VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);
643                 VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);
644                 CrossProduct (vtemp1, vtemp2, normal);
645
646                 if (normal[1] > 0)
647                 {
648                         basex = iwidth + 2;
649                 }
650                 else
651                 {
652                         basex = 2;
653                 }
654                 basey = 2;
655                 
656                 for (j=0 ; j<3 ; j++)
657                 {
658                         pbasevert = ptri[i].verts[j];
659
660                         triangle_st[i][j][0] = Q_rint((pbasevert[0] - mins[0]) * s_scale + basex);
661                         triangle_st[i][j][1] = Q_rint((maxs[2] - pbasevert[2]) * t_scale + basey);
662                 }
663         }
664
665 // make the width a multiple of 4; some hardware requires this, and it ensures
666 // dword alignment for each scan
667         swidth = iwidth*2;
668         model.skinwidth = (swidth + 3) & ~3;
669         model.skinheight = iheight;
670 }
671
672
673 /*
674 =================
675 Cmd_Base
676 =================
677 */
678 void Cmd_Base (void)
679 {
680         triangle_t      *ptri;
681         int                     i, j, k;
682         int             time1;
683         char    file1[1024];
684
685         GetToken (false);
686
687         if (g_skipmodel || g_release || g_archive)
688                 return;
689
690         printf ("---------------------\n");
691         sprintf (file1, "%s/%s.%s", cdarchive, token, trifileext);
692         printf ("%s\n", file1);
693
694         ExpandPathAndArchive (file1);
695
696         sprintf (file1, "%s/%s.%s", cddir, token, trifileext);
697
698         time1 = FileTime (file1);
699         if (time1 == -1)
700                 Error ("%s doesn't exist", file1);
701
702 //
703 // load the base triangles
704 //
705         if (do3ds)
706                 Load3DSTriangleList (file1, &ptri, &model.num_tris);
707         else
708                 LoadTriangleList (file1, &ptri, &model.num_tris);
709
710 //
711 // get the ST values
712 //
713         BuildST (ptri, model.num_tris);
714
715 //
716 // run through all the base triangles, storing each unique vertex in the
717 // base vertex list and setting the indirect triangles to point to the base
718 // vertices
719 //
720         for (i=0 ; i<model.num_tris ; i++)
721         {
722                 for (j=0 ; j<3 ; j++)
723                 {
724                         // get the xyz index
725                         for (k=0 ; k<model.num_xyz ; k++)
726                                 if (VectorCompare (ptri[i].verts[j], base_xyz[k]))
727                                         break;  // this vertex is already in the base vertex list
728
729                         if (k == model.num_xyz)
730                         { // new index
731                                 VectorCopy (ptri[i].verts[j], base_xyz[model.num_xyz]);
732                                 model.num_xyz++;
733                         }
734
735                         triangles[i].index_xyz[j] = k;
736
737                         // get the st index
738                         for (k=0 ; k<model.num_st ; k++)
739                                 if (triangle_st[i][j][0] == base_st[k].s
740                                 && triangle_st[i][j][1] == base_st[k].t)
741                                         break;  // this vertex is already in the base vertex list
742
743                         if (k == model.num_st)
744                         { // new index
745                                 base_st[model.num_st].s = triangle_st[i][j][0];
746                                 base_st[model.num_st].t = triangle_st[i][j][1];
747                                 model.num_st++;
748                         }
749
750                         triangles[i].index_st[j] = k;
751                 }
752         }
753
754         // build triangle strips / fans
755         BuildGlCmds ();
756 }
757
758 //===============================================================
759
760 char    *FindFrameFile (char *frame)
761 {
762         int                     time1;
763         char    file1[1024];
764         static char     retname[1024];
765         char    base[32];
766         char    suffix[32];
767         char    *s;
768
769         if (strstr (frame, "."))
770                 return frame;           // allready in dot format
771
772         // split 'run1' into 'run' and '1'
773         s = frame + strlen(frame)-1;
774
775         while (s != frame && *s >= '0' && *s <= '9')
776                 s--;
777
778         strcpy (suffix, s+1);
779         strcpy (base, frame);
780         base[s-frame+1] = 0;
781
782         // check for 'run1.tri'
783         sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, trifileext);
784         time1 = FileTime (file1);
785         if (time1 != -1)
786         {
787                 sprintf (retname, "%s%s.%s", base, suffix, trifileext);
788                 return retname;
789         }
790
791         // check for 'run.1'
792         sprintf (file1, "%s/%s.%s",cddir, base, suffix);
793         time1 = FileTime (file1);
794         if (time1 != -1)
795         {
796                 sprintf (retname, "%s.%s", base, suffix);
797                 return retname;
798         }
799
800         Error ("frame %s could not be found",frame);
801         return NULL;
802 }
803
804 /*
805 ===============
806 GrabFrame
807 ===============
808 */
809 void GrabFrame (char *frame)
810 {
811         triangle_t      *ptri;
812         int                     i, j;
813         trivert_t       *ptrivert;
814         int                     num_tris;
815         char            file1[1024];
816         frame_t         *fr;
817         vertexnormals_t vnorms[MAX_VERTS];
818         int             index_xyz;
819         char    *framefile;
820
821         // the frame 'run1' will be looked for as either
822         // run.1 or run1.tri, so the new alias sequence save
823         // feature an be used
824         framefile = FindFrameFile (frame);
825
826         sprintf (file1, "%s/%s", cdarchive, framefile);
827         ExpandPathAndArchive (file1);
828
829         sprintf (file1, "%s/%s",cddir, framefile);
830
831         printf ("grabbing %s\n", file1);
832
833         if (model.num_frames >= MAX_FRAMES)
834                 Error ("model.num_frames >= MAX_FRAMES");
835         fr = &g_frames[model.num_frames];
836         model.num_frames++;
837
838         strcpy (fr->name, frame);
839
840 //
841 // load the frame
842 //
843         if (do3ds)
844                 Load3DSTriangleList (file1, &ptri, &num_tris);
845         else
846                 LoadTriangleList (file1, &ptri, &num_tris);
847
848         if (num_tris != model.num_tris)
849                 Error ("%s: number of triangles doesn't match base frame\n", file1);
850
851 //
852 // allocate storage for the frame's vertices
853 //
854         ptrivert = fr->v;
855
856         for (i=0 ; i<model.num_xyz ; i++)
857         {
858                 vnorms[i].numnormals = 0;
859                 VectorClear (vnorms[i].normalsum);
860         }
861         ClearBounds (fr->mins, fr->maxs);
862
863 //
864 // store the frame's vertices in the same order as the base. This assumes the
865 // triangles and vertices in this frame are in exactly the same order as in the
866 // base
867 //
868         for (i=0 ; i<num_tris ; i++)
869         {
870                 vec3_t  vtemp1, vtemp2, normal;
871                 float   ftemp;
872
873                 VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);
874                 VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);
875                 CrossProduct (vtemp1, vtemp2, normal);
876
877                 VectorNormalize (normal, normal);
878
879         // rotate the normal so the model faces down the positive x axis
880                 ftemp = normal[0];
881                 normal[0] = -normal[1];
882                 normal[1] = ftemp;
883
884                 for (j=0 ; j<3 ; j++)
885                 {
886                         index_xyz = triangles[i].index_xyz[j];
887
888                 // rotate the vertices so the model faces down the positive x axis
889                 // also adjust the vertices to the desired origin
890                         ptrivert[index_xyz].v[0] = ((-ptri[i].verts[j][1]) * scale_up) +
891                                                                                 adjust[0];
892                         ptrivert[index_xyz].v[1] = (ptri[i].verts[j][0] * scale_up) +
893                                                                                 adjust[1];
894                         ptrivert[index_xyz].v[2] = (ptri[i].verts[j][2] * scale_up) +
895                                                                                 adjust[2];
896
897                         AddPointToBounds (ptrivert[index_xyz].v, fr->mins, fr->maxs);
898
899                         VectorAdd (vnorms[index_xyz].normalsum, normal, vnorms[index_xyz].normalsum);
900                         vnorms[index_xyz].numnormals++;
901                 }
902         }
903
904 //
905 // calculate the vertex normals, match them to the template list, and store the
906 // index of the best match
907 //
908         for (i=0 ; i<model.num_xyz ; i++)
909         {
910                 int             j;
911                 vec3_t  v;
912                 float   maxdot;
913                 int             maxdotindex;
914                 int             c;
915
916                 c = vnorms[i].numnormals;
917                 if (!c)
918                         Error ("Vertex with no triangles attached");
919
920                 VectorScale (vnorms[i].normalsum, 1.0/c, v);
921                 VectorNormalize (v, v);
922
923                 maxdot = -999999.0;
924                 maxdotindex = -1;
925
926                 for (j=0 ; j<NUMVERTEXNORMALS ; j++)
927                 {
928                         float   dot;
929
930                         dot = DotProduct (v, avertexnormals[j]);
931                         if (dot > maxdot)
932                         {
933                                 maxdot = dot;
934                                 maxdotindex = j;
935                         }
936                 }
937
938                 ptrivert[i].lightnormalindex = maxdotindex;
939         }
940
941         free (ptri);
942 }
943
944 /*
945 ===============
946 Cmd_Frame       
947 ===============
948 */
949 void Cmd_Frame (void)
950 {
951         while (TokenAvailable())
952         {
953                 GetToken (false);
954                 if (g_skipmodel)
955                         continue;
956                 if (g_release || g_archive)
957                 {
958                         model.num_frames = 1;   // don't skip the writeout
959                         continue;
960                 }
961
962                 H_printf("#define FRAME_%-16s\t%i\n", token, model.num_frames);
963
964                 GrabFrame (token);
965         }
966 }
967
968
969 /*
970 ===============
971 Cmd_Skin
972
973 Skins aren't actually stored in the file, only a reference
974 is saved out to the header file.
975 ===============
976 */
977 void Cmd_Skin (void)
978 {
979         byte    *palette;
980         byte    *pixels;
981         int             width, height;
982         byte    *cropped;
983         int             y;
984         char    name[1024], savename[1024];
985
986         GetToken (false);
987
988         if (model.num_skins == MAX_MD2SKINS)
989                 Error ("model.num_skins == MAX_MD2SKINS");
990
991         if (g_skipmodel)
992                 return;
993
994         sprintf (name, "%s/%s.lbm", cdarchive, token);
995         strcpy (name, ExpandPathAndArchive( name ) );
996 //      sprintf (name, "%s/%s.lbm", cddir, token);
997
998         if (TokenAvailable())
999         {
1000                 GetToken (false);
1001                 sprintf (g_skins[model.num_skins], "%s.pcx", token);
1002                 sprintf (savename, "%s%s.pcx", gamedir, g_skins[model.num_skins]);
1003         }
1004         else
1005         {
1006                 sprintf (savename, "%s/%s.pcx", cddir, token);
1007                 sprintf (g_skins[model.num_skins], "%s/%s.pcx", cdpartial, token);
1008         }
1009
1010         model.num_skins++;
1011
1012         if (g_skipmodel || g_release || g_archive)
1013                 return;
1014
1015         // load the image
1016         printf ("loading %s\n", name);
1017         Load256Image (name, &pixels, &palette, &width, &height);
1018         RemapZero (pixels, palette, width, height);
1019
1020         // crop it to the proper size
1021         cropped = malloc (model.skinwidth*model.skinheight);
1022         for (y=0 ; y<model.skinheight ; y++)
1023         {
1024                 memcpy (cropped+y*model.skinwidth,
1025                         pixels+y*width, model.skinwidth);
1026         }
1027
1028         // save off the new image
1029         printf ("saving %s\n", savename);
1030         CreatePath (savename);
1031         WritePCXfile (savename, cropped, model.skinwidth,
1032                 model.skinheight, palette);
1033
1034         free (pixels);
1035         free (palette);
1036         free (cropped);
1037 }
1038
1039
1040 /*
1041 =================
1042 Cmd_Origin
1043 =================
1044 */
1045 void Cmd_Origin (void)
1046 {
1047         // rotate points into frame of reference so model points down the
1048         // positive x axis
1049         GetToken (false);
1050         adjust[1] = -atof (token);
1051
1052         GetToken (false);
1053         adjust[0] = atof (token);
1054
1055         GetToken (false);
1056         adjust[2] = -atof (token);
1057 }
1058
1059
1060 /*
1061 =================
1062 Cmd_ScaleUp
1063 =================
1064 */
1065 void Cmd_ScaleUp (void)
1066 {
1067         GetToken (false);
1068         scale_up = atof (token);
1069         if (g_skipmodel || g_release || g_archive)
1070                 return;
1071
1072         printf ("Scale up: %f\n", scale_up);
1073 }
1074
1075
1076 /*
1077 =================
1078 Cmd_Skinsize
1079
1080 Set a skin size other than the default
1081 =================
1082 */
1083 void Cmd_Skinsize (void)
1084 {
1085         GetToken (false);
1086         g_fixedwidth = atoi(token);
1087         GetToken (false);
1088         g_fixedheight = atoi(token);
1089 }
1090
1091 /*
1092 =================
1093 Cmd_Modelname
1094
1095 Gives a different name/location for the file, instead of the cddir
1096 =================
1097 */
1098 void Cmd_Modelname (void)
1099 {
1100         GetToken (false);
1101         strcpy (modelname, token);
1102 }
1103
1104 /*
1105 ===============
1106 Cmd_Cd
1107 ===============
1108 */
1109 void Cmd_Cd (void)
1110 {
1111         FinishModel ();
1112         ClearModel ();
1113
1114         GetToken (false);
1115
1116         // this is a silly mess...
1117         sprintf (cdpartial, "models/%s", token); 
1118         sprintf (cdarchive, "%smodels/%s", gamedir+strlen(qdir), token); 
1119         sprintf (cddir, "%s%s", gamedir, cdpartial);
1120
1121         // if -only was specified and this cd doesn't match,
1122         // skip the model (you only need to match leading chars,
1123         // so you could regrab all monsters with -only monsters)
1124         if (!g_only[0])
1125                 return;
1126         if (strncmp(token, g_only, strlen(g_only)))
1127         {
1128                 g_skipmodel = true;
1129                 printf ("skipping %s\n", cdpartial);
1130         }
1131 }
1132