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