1 /*
2 * genmodel.c
3 * $Id: genmodel.c,v 1.16 2009-01-24 23:41:28 sezero Exp $
4 *
5 * Generates a .mdl file from a base frame, a texture bitmap,
6 * and a series of frames.
7 *
8 * Copyright (C) 1996-1997 Id Software, Inc.
9 * Copyright (C) 1997-1998 Raven Software Corp.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or (at
14 * your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 */
26
27 #ifdef _MSC_VER
28 #pragma warning(disable: 4244)
29 #endif
30
31 // HEADER FILES ------------------------------------------------------------
32
33 #include "q_stdinc.h"
34 #include "compiler.h"
35 #include "arch_def.h"
36 #include "cmdlib.h"
37 #include "util_io.h"
38 #include "pathutil.h"
39 #include "scriplib.h"
40 #include "mathlib.h"
41 #include "q_endian.h"
42 #include "byteordr.h"
43 #include "loadtri.h"
44 #include "genmodel.h"
45 #include "qdir.h"
46
47 // MACROS ------------------------------------------------------------------
48
49 #define VERSION_TEXT "1.18"
50
51 #define MAXVERTS 2048
52 #define MAXFRAMES 512
53 #define MAXSKINS 100
54
55 #define NUMVERTEXNORMALS 162
56
57 #define SKINPAGE_WIDTH 640
58 #define SKINPAGE_HEIGHT 480
59 #define SKINPAGE_SIZE (SKINPAGE_WIDTH*SKINPAGE_HEIGHT)
60
61 // Must match definitions in genskin.c
62 #define SCALE_ADJUST_FACTOR 0.96
63 #define ENCODED_WIDTH_X 192
64 #define ENCODED_WIDTH_Y 475
65 #define ENCODED_HEIGHT_X 228
66 #define ENCODED_HEIGHT_Y 475
67
68 // TYPES -------------------------------------------------------------------
69
70 typedef struct {
71 aliasframetype_t type; // single frame or group of frames
72 void *pdata; // either a daliasframe_t or group info
73 float interval; // only used for frames in groups
74 int numgroupframes; // only used by group headers
75 char name[16];
76 } aliaspackage_t;
77
78 typedef struct {
79 aliasskintype_t type; // single skin or group of skiins
80 void *pdata; // either a daliasskinframe_t or group info
81 float interval; // only used for skins in groups
82 int numgroupskins; // only used by group headers
83 } aliasskinpackage_t;
84
85 typedef struct {
86 int numnormals;
87 float normals[40][3];
88 } vertexnormals;
89
90 typedef struct {
91 vec3_t v;
92 int lightnormalindex;
93 } trivert_t;
94
95 typedef struct
96 {
97 byte tag;
98 byte version;
99 byte encoding;
100 byte pixelBits;
101 signed short xMin;
102 signed short yMin;
103 signed short xMax;
104 signed short yMax;
105 signed short horzRes;
106 signed short vertRes;
107 byte palette[48];
108 byte pad;
109 byte planes;
110 signed short lineBytes;
111 signed short palType;
112 unsigned short vidSizeX;
113 unsigned short vidSizeY;
114 byte reserved[54];
115 byte data;
116 } pcx_t;
117
118 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
119
120 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
121
122 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
123
124 static void ClearModel(void);
125 static void WriteModel(void);
126 static void ReadModel(const char *FileName);
127 static void ParseScript(void);
128 static void LoadPCXSkin(const char *filename, byte **buffer);
129 static int ExtractNumber(byte *pic, int x, int y);
130 static int ExtractDigit(byte *pic, int x, int y);
131
132 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
133
134 // PUBLIC DATA DEFINITIONS -------------------------------------------------
135
136 // PRIVATE DATA DEFINITIONS ------------------------------------------------
137
138 static trivert_t verts[MAXFRAMES][MAXVERTS];
139 static newmdl_t model;
140
141 static char file1[1024];
142 static char file2[1024];
143 static char skinname[1024];
144 static char qbasename[1024];
145 static float scale, scale_up = 1.0;
146
147 static float ScaleWidth;
148 static float ScaleHeight;
149
150 static vec3_t mins, maxs;
151 static vec3_t framesmins, framesmaxs;
152 static vec3_t adjust;
153
154 static aliaspackage_t frames[MAXFRAMES];
155 static aliasskinpackage_t skins[MAXSKINS];
156
157 static vec3_t baseverts[MAXVERTS];
158 static stvert_t stverts[MAXVERTS];
159 static dnewtriangle_t triangles[MAXTRIANGLES];
160 static int degenerate[MAXTRIANGLES];
161
162 static char cdpartial[256];
163 static char cddir[256];
164
165 static int framecount, skincount;
166 static qboolean cdset;
167 static int degeneratetris;
168 static int firstframe = 1;
169 static float totsize, averagesize;
170
171 static qboolean DoOpts = false;
172 static qboolean ModelReadIn = false;
173 static int original_size = 0;
174
175 static vertexnormals vnorms[MAXVERTS];
176
177 static double avertexnormals[NUMVERTEXNORMALS][3] =
178 {
179 #include "anorms.h"
180 };
181
182 static trivertx_t tarray[MAXVERTS];
183
184 static char outname[1024];
185
186 // Must match definitions in genskin.c
187 static const char *DigitDefs[] =
188 {
189 " *** * *** * *** * *** ",
190 " * ** * * * ",
191 "**** * *** * *****",
192 "**** * *** ***** ",
193 " ** * * * * ***** * ",
194 "**** * **** ***** ",
195 " *** * **** * * *** ",
196 "***** * * * * ",
197 " *** * * *** * * *** ",
198 " *** * * **** * *** "
199 };
200
201 // CODE --------------------------------------------------------------------
202
203 //==========================================================================
204 //
205 // main
206 //
207 //==========================================================================
208
usage(void)209 FUNC_NORETURN static void usage (void) {
210 printf("usage: genmodel [-opt] [-archive path] model.hc\n");
211 exit(1);
212 }
213
main(int argc,char ** argv)214 int main(int argc, char **argv)
215 {
216 int i, j;
217 char path[1024], bakname[1024];
218
219 printf("GENMODEL Version " VERSION_TEXT " (" __DATE__ ")\n\n");
220
221 if (argc == 1)
222 usage ();
223
224 ValidateByteorder ();
225
226 path[0] = 0;
227
228 myargc = argc;
229 myargv = argv;
230
231 i = CheckParm("-archive");
232 if (i != 0)
233 {
234 if (i >= argc - 1) usage ();
235 archive = true;
236 q_strlcpy(archivedir, argv[++i], sizeof(archivedir));
237 printf("Archiving source to: %s\n", archivedir);
238 }
239 j = CheckParm("-opt");
240 if (j != 0)
241 DoOpts = true;
242 if (i < j) i = j;
243 if (i + 1 > argc - 1)
244 usage ();
245
246 q_strlcpy(path, argv[i + 1], sizeof(path));
247 SetQdirFromPath(""); /* (path); */
248
249 // Init
250 for (i = 0; i < 3; i++)
251 {
252 framesmins[i] = 9999999;
253 framesmaxs[i] = -9999999;
254 }
255 ClearModel();
256
257 q_strlcpy(outname, path, sizeof(outname));
258
259 i = strlen(path);
260 if (i > 4 && q_strcasecmp(&path[i - 4],".mdl") == 0)
261 {
262 q_strlcpy(outname, path, sizeof(outname));
263 ReadModel(path);
264
265 q_strlcpy(bakname, path, sizeof(bakname));
266 bakname[i - 4] = 0;
267 DefaultExtension(bakname, ".bak", sizeof(bakname));
268 if (Q_rename(path, bakname))
269 COM_Error("Could not rename file!\n");
270 }
271 else
272 {
273 DefaultExtension(path, ".hc", sizeof(path));
274 // Load the .hc script file
275 LoadScriptFile(path);
276
277 // Parse it
278 ParseScript();
279 }
280
281 WriteModel();
282
283 return 0;
284 }
285
286 //==========================================================================
287 //
288 // ClearModel
289 //
290 //==========================================================================
291
ClearModel(void)292 static void ClearModel(void)
293 {
294 memset(&model, 0, sizeof(model));
295 model.synctype = ST_RAND; // default
296 framecount = skincount = 0;
297
298 scale = 0;
299 scale_up = 1.0;
300
301 VectorClear (adjust);
302 VectorClear (mins);
303 VectorClear (maxs);
304 VectorClear (framesmins);
305 VectorClear (framesmaxs);
306
307 degeneratetris = 0;
308 cdset = false;
309 firstframe = 1;
310 totsize = 0.0;
311 }
312
313 //==========================================================================
314 //
315 // ReadFrame
316 //
317 //==========================================================================
318
ReadFrame(FILE * FH,int framenum)319 static void ReadFrame (FILE *FH, int framenum)
320 {
321 int j, k;
322 trivert_t *pframe;
323 daliasframe_t aframe;
324
325 SafeRead (FH, &aframe, sizeof (aframe));
326 SafeRead (FH, &tarray[0], model.numverts * sizeof(tarray[0]));
327
328 pframe = verts[framenum];
329 memcpy (frames[framenum].name, aframe.name, sizeof(aframe.name));
330 frames[framenum].pdata = pframe;
331
332 for (j = 0 ; j < model.numverts ; j++)
333 {
334 // all of these are byte values, so no need to deal with endianness
335 pframe[j].lightnormalindex = tarray[j].lightnormalindex;
336
337 for (k = 0 ; k < 3 ; k++)
338 { // scale to byte values & min/max check
339 // float v;
340 // byte b;
341
342 pframe[j].v[k] = (tarray[j].v[k] * model.scale[k]) + model.scale_origin[k] + 0.001;
343
344 // v = (pframe[j].v[k] - model.scale_origin[k]) / model.scale[k];
345 // b = v;
346 }
347 }
348 }
349
350 //==========================================================================
351 //
352 // WriteFrame
353 //
354 //==========================================================================
355
WriteFrame(FILE * modelouthandle,int framenum)356 static void WriteFrame (FILE *modelouthandle, int framenum)
357 {
358 int j, k;
359 trivert_t *pframe;
360 daliasframe_t aframe;
361 float v;
362
363 pframe = verts[framenum];
364
365 memcpy (aframe.name, frames[framenum].name, sizeof(aframe.name));
366
367 for (j = 0 ; j < 3 ; j++)
368 {
369 aframe.bboxmin.v[j] = 255;
370 aframe.bboxmax.v[j] = 0;
371 }
372
373 for (j = 0 ; j < model.numverts ; j++)
374 {
375 // all of these are byte values, so no need to deal with endianness
376 tarray[j].lightnormalindex = pframe[j].lightnormalindex;
377
378 if (tarray[j].lightnormalindex > NUMVERTEXNORMALS)
379 COM_Error ("invalid lightnormalindex %d\n", tarray[j].lightnormalindex);
380
381 for (k = 0 ; k < 3 ; k++)
382 {
383 // scale to byte values & min/max check
384 v = (pframe[j].v[k] - model.scale_origin[k]) / model.scale[k];
385
386 tarray[j].v[k] = v;
387
388 if (tarray[j].v[k] < aframe.bboxmin.v[k])
389 {
390 aframe.bboxmin.v[k] = tarray[j].v[k];
391 }
392 if (tarray[j].v[k] > aframe.bboxmax.v[k])
393 {
394 aframe.bboxmax.v[k] = tarray[j].v[k];
395 }
396 }
397 }
398
399 SafeWrite (modelouthandle, &aframe, sizeof (aframe));
400 SafeWrite (modelouthandle, &tarray[0], model.numverts * sizeof(tarray[0]));
401 }
402
403 //==========================================================================
404 //
405 // WriteGroupBBox
406 //
407 //==========================================================================
408
WriteGroupBBox(FILE * modelouthandle,int numframes,int curframe)409 static void WriteGroupBBox (FILE *modelouthandle, int numframes, int curframe)
410 {
411 int i, j, k;
412 daliasgroup_t dagroup;
413 trivert_t *pframe;
414
415 dagroup.numframes = LittleLong (numframes);
416
417 for (i = 0 ; i < 3 ; i++)
418 {
419 dagroup.bboxmin.v[i] = 255;
420 dagroup.bboxmax.v[i] = 0;
421 }
422
423 for (i = 0 ; i < numframes ; i++)
424 {
425 pframe = (trivert_t *)frames[curframe].pdata;
426
427 for (j = 0 ; j < model.numverts ; j++)
428 {
429 for (k = 0 ; k < 3 ; k++)
430 {
431 // scale to byte values & min/max check
432 tarray[j].v[k] = (pframe[j].v[k] - model.scale_origin[k]) / model.scale[k];
433 if (tarray[j].v[k] < dagroup.bboxmin.v[k])
434 dagroup.bboxmin.v[k] = tarray[j].v[k];
435 if (tarray[j].v[k] > dagroup.bboxmax.v[k])
436 dagroup.bboxmax.v[k] = tarray[j].v[k];
437 }
438 }
439
440 curframe++;
441 }
442
443 SafeWrite (modelouthandle, &dagroup, sizeof(dagroup));
444 }
445
446 //==========================================================================
447 //
448 // WriteModelFile
449 //
450 //==========================================================================
451
WriteModelFile(FILE * modelouthandle)452 static void WriteModelFile (FILE *modelouthandle)
453 {
454 int i, curframe, curskin;
455 float dist[3];
456 mdl_t modeltemp;
457 newmdl_t newmodeltemp;
458
459 // Calculate the bounding box for this model
460 if (!ModelReadIn)
461 {
462 for (i = 0 ; i < 3 ; i++)
463 {
464 printf ("framesmins[%d]: %f, framesmaxs[%d]: %f\n", i, framesmins[i], i, framesmaxs[i]);
465 if (fabs (framesmins[i]) > fabs (framesmaxs[i]))
466 dist[i] = framesmins[i];
467 else
468 dist[i] = framesmaxs[i];
469
470 model.scale[i] = (framesmaxs[i] - framesmins[i]) / 255.9;
471 model.scale_origin[i] = framesmins[i];
472 }
473
474 model.boundingradius = sqrt(dist[0] * dist[0] +
475 dist[1] * dist[1] +
476 dist[2] * dist[2]);
477 }
478
479 //
480 // write out the model header
481 //
482 modeltemp.ident = LittleLong (IDPOLYHEADER);
483 modeltemp.version = LittleLong (ALIAS_VERSION);
484 newmodeltemp.ident = LittleLong (RAPOLYHEADER);
485 newmodeltemp.version = LittleLong (ALIAS_NEWVERSION);
486 newmodeltemp.boundingradius = modeltemp.boundingradius = LittleFloat (model.boundingradius);
487
488 for (i = 0 ; i < 3 ; i++)
489 {
490 newmodeltemp.scale[i] = modeltemp.scale[i] = LittleFloat (model.scale[i]);
491 newmodeltemp.scale_origin[i] = modeltemp.scale_origin[i] = LittleFloat (model.scale_origin[i]);
492 newmodeltemp.eyeposition[i] = modeltemp.eyeposition[i] = LittleFloat (model.eyeposition[i] + adjust[i]);
493 }
494
495 newmodeltemp.flags = modeltemp.flags = LittleLong (model.flags);
496 newmodeltemp.numskins = modeltemp.numskins = LittleLong (model.numskins);
497 newmodeltemp.skinwidth = modeltemp.skinwidth = LittleLong (model.skinwidth);
498 newmodeltemp.skinheight = modeltemp.skinheight = LittleLong (model.skinheight);
499 newmodeltemp.numverts = modeltemp.numverts = LittleLong (model.numverts);
500 newmodeltemp.numtris = modeltemp.numtris = LittleLong (model.numtris - degeneratetris);
501 newmodeltemp.numframes = modeltemp.numframes = LittleLong (model.numframes);
502 newmodeltemp.synctype = modeltemp.synctype = (synctype_t) LittleLong (model.synctype);
503
504 if (!ModelReadIn)
505 {
506 averagesize = totsize / model.numtris;
507 }
508 else
509 {
510 averagesize = model.size;
511 }
512 newmodeltemp.size = modeltemp.size = LittleFloat (averagesize);
513
514 // new stuff
515 newmodeltemp.num_st_verts = LittleLong (model.num_st_verts);
516
517 if (DoOpts)
518 {
519 SafeWrite (modelouthandle, &newmodeltemp, sizeof(newmodeltemp));
520 }
521 else
522 {
523 SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp));
524 }
525 //
526 // write out the skins
527 //
528 curskin = 0;
529
530 for (i = 0 ; i < model.numskins ; i++)
531 {
532 SafeWrite (modelouthandle, &skins[curskin].type, sizeof(skins[curskin].type));
533 SafeWrite (modelouthandle, skins[curskin].pdata, model.skinwidth * model.skinheight);
534
535 curskin++;
536 }
537
538 //
539 // write out the base model (the s & t coordinates for the vertices)
540 //
541 for (i = 0 ; i < model.num_st_verts ; i++)
542 {
543 if (stverts[i].onseam == 3)
544 {
545 stverts[i].onseam = LittleLong (ALIAS_ONSEAM);
546 }
547 else
548 {
549 stverts[i].onseam = LittleLong (0);
550 }
551
552 stverts[i].s = LittleLong (stverts[i].s);
553 stverts[i].t = LittleLong (stverts[i].t);
554 }
555
556 SafeWrite (modelouthandle, stverts, model.num_st_verts * sizeof(stverts[0]));
557
558 //
559 // write out the triangles
560 //
561 if (DoOpts)
562 {
563 for (i = 0 ; i < model.numtris ; i++)
564 {
565 int j;
566 dnewtriangle_t tri;
567
568 if (!degenerate[i])
569 {
570 tri.facesfront = LittleLong (triangles[i].facesfront);
571
572 for (j = 0 ; j < 3 ; j++)
573 {
574 tri.vertindex[j] = LittleShort (triangles[i].vertindex[j]);
575 tri.stindex[j] = LittleShort (triangles[i].stindex[j]);
576 }
577
578 SafeWrite (modelouthandle, &tri, sizeof(tri));
579 }
580 }
581 }
582 else
583 {
584 for (i = 0 ; i < model.numtris ; i++)
585 {
586 int j;
587 dtriangle_t tri;
588
589 if (!degenerate[i])
590 {
591 tri.facesfront = LittleLong (triangles[i].facesfront);
592
593 for (j = 0 ; j < 3 ; j++)
594 {
595 tri.vertindex[j] = LittleLong (triangles[i].vertindex[j]);
596 }
597
598 SafeWrite (modelouthandle,&tri,sizeof(tri));
599 }
600 }
601 }
602 //
603 // write out the frames
604 //
605 curframe = 0;
606
607 for (i = 0 ; i < model.numframes ; i++)
608 {
609 SafeWrite (modelouthandle, &frames[curframe].type, sizeof(frames[curframe].type));
610
611 if (frames[curframe].type == ALIAS_SINGLE)
612 {
613 //
614 // single (non-grouped) frame
615 //
616 WriteFrame (modelouthandle, curframe);
617 curframe++;
618 }
619 else
620 {
621 int j, numframes, groupframe;
622 float totinterval;
623
624 groupframe = curframe;
625 curframe++;
626 numframes = frames[groupframe].numgroupframes;
627
628 //
629 // set and write the group header
630 //
631 WriteGroupBBox (modelouthandle, numframes, curframe);
632
633 //
634 // write the interval array
635 //
636 totinterval = 0.0;
637
638 for (j = 0 ; j < numframes ; j++)
639 {
640 daliasinterval_t temp;
641
642 totinterval += frames[groupframe+1+j].interval;
643 temp.interval = LittleFloat (totinterval);
644
645 SafeWrite (modelouthandle, &temp, sizeof(temp));
646 }
647
648 for (j = 0 ; j < numframes ; j++)
649 {
650 WriteFrame (modelouthandle, curframe);
651 curframe++;
652 }
653 }
654 }
655 }
656
OptimizeVertices(void)657 static void OptimizeVertices(void)
658 {
659 qboolean vert_used[MAXVERTS];
660 short vert_replacement[MAXVERTS];
661 int i, j, k;
662 trivert_t *in;
663 qboolean Found;
664 int num_unique;
665
666 printf("Optimizing vertices...");
667
668 memset(vert_used, 0, sizeof(vert_used));
669 memset(vert_replacement, 0, sizeof(vert_replacement)); // make static analyzers happy
670 num_unique = 0;
671
672 // search for common points among all the frames
673 for (i = 0 ; i < model.numframes ; i++)
674 {
675 in = (trivert_t *) frames[i].pdata;
676
677 for (j = 0; j < model.numverts; j++)
678 {
679 for (k = 0, Found = false; k < j; k++)
680 {
681 // starting from the beginning always ensures
682 // vert_replacement points to the first point
683 // in the array
684 if (in[j].v[0] == in[k].v[0] &&
685 in[j].v[1] == in[k].v[1] &&
686 in[j].v[2] == in[k].v[2])
687 {
688 Found = true;
689 vert_replacement[j] = k;
690 break;
691 }
692 }
693
694 if (!Found)
695 {
696 if (!vert_used[j])
697 {
698 num_unique++;
699 }
700 vert_used[j] = true;
701 }
702 }
703 }
704
705 #if 0 /* this is a dead loop because of the commented out code. */
706 // recompute the light normals
707 for (i = 0 ; i < model.numframes ; i++)
708 {
709 in = (trivert_t *) frames[i].pdata;
710
711 for (j = 0; j < model.numverts; j++)
712 {
713 if (!vert_used[j])
714 {
715 k = vert_replacement[j];
716
717 // VectorAdd (inv[j].vnorm.normalsum, in->v[k].vnorm.normalsum, in->v[k].vnorm.normalsum);
718 // in->v[k].vnorm.numnormals += in->v[j].vnorm.numnormals++;
719 }
720 }
721
722 /* for (j = 0 ; j < model.numverts ; j++)
723 {
724 vec3_t v;
725 float maxdot;
726 int maxdotindex;
727 int c;
728
729 c = in->v[j].vnorm.numnormals;
730 if (!c)
731 COM_Error ("Vertex with no triangles attached");
732
733 VectorScale (in->v[j].vnorm.normalsum, 1.0/c, v);
734 VectorNormalize (v, v);
735
736 maxdot = -999999.0;
737 maxdotindex = -1;
738
739 for (k = 0 ; k < NUMVERTEXNORMALS ; k++)
740 {
741 float dot;
742
743 dot = DotProduct (v, avertexnormals[k]);
744 if (dot > maxdot)
745 {
746 maxdot = dot;
747 maxdotindex = k;
748 }
749 }
750
751 in->v[j].lightnormalindex = maxdotindex;
752 }*/
753 }
754 #endif
755
756 // create substitution list
757 num_unique = 0;
758 for (i = 0; i < model.numverts; i++)
759 {
760 if (vert_used[i])
761 {
762 vert_replacement[i] = num_unique;
763 num_unique++;
764 }
765 else
766 {
767 vert_replacement[i] = vert_replacement[vert_replacement[i]];
768 }
769 }
770
771 // substitute
772 for (i = 0 ; i < model.numframes ; i++)
773 {
774 in = (trivert_t *) frames[i].pdata;
775
776 for (j = 0; j < model.numverts; j++)
777 {
778 in[vert_replacement[j]] = in[j];
779 }
780 }
781
782 for (i = 0 ; i < model.numtris ; i++)
783 {
784 for (j = 0 ; j < 3 ; j++)
785 {
786 triangles[i].vertindex[j] = vert_replacement[triangles[i].vertindex[j]];
787 }
788 }
789
790 /* for (i = 0; i < numcommands; i++)
791 {
792 j = commands[i];
793 if (!j)
794 continue;
795
796 j = abs(j);
797 for (i++; j; j--, i+=3)
798 {
799 commands[i+2] = vert_replacement[commands[i+2]];
800 }
801 i--;
802 }
803 */
804 printf("Reduced by %d\n",model.numverts - num_unique);
805
806 model.numverts = num_unique;
807 }
808
809 //==========================================================================
810 //
811 // WriteModel
812 //
813 //==========================================================================
814
WriteModel(void)815 static void WriteModel (void)
816 {
817 FILE *modelouthandle;
818 //
819 // write the model output file
820 //
821 if (!framecount)
822 {
823 printf ("no frames grabbed, no file generated\n");
824 return;
825 }
826
827 if (!skincount)
828 COM_Error ("frames with no skins\n");
829
830 StripExtension (outname);
831 q_strlcat(outname, ".mdl", sizeof(outname));
832
833 if (DoOpts)
834 {
835 OptimizeVertices();
836 }
837
838 printf ("---------------------\n");
839 printf ("writing %s:\n", outname);
840 modelouthandle = SafeOpenWrite (outname);
841
842 WriteModelFile (modelouthandle);
843
844 printf ("%4d frame(s)\n", model.numframes);
845 printf ("%4d ungrouped frame(s), including group headers\n", framecount);
846 printf ("%4d skin(s)\n", model.numskins);
847 printf ("%4d degenerate triangles(s) removed\n", degeneratetris);
848 printf ("%4d triangles emitted\n", model.numtris - degeneratetris);
849 printf ("pixels per triangle %f\n", averagesize);
850 printf ("%4d numverts\n", model.numverts);
851
852 if (ModelReadIn)
853 {
854 printf ("file size: %d (Saved %d)\n", (int)ftell (modelouthandle), (int)(original_size - ftell(modelouthandle)) );
855 }
856 else
857 {
858 printf ("file size: %d\n", (int)ftell (modelouthandle) );
859 }
860 printf ("---------------------\n");
861
862 fclose (modelouthandle);
863
864 ClearModel ();
865 }
866
ReadModel(const char * FileName)867 static void ReadModel(const char *FileName)
868 {
869 FILE *FH;
870 mdl_t mdl;
871 int i, curframe;
872
873 FH = fopen(FileName,"rb");
874 if (!FH)
875 COM_Error ("Could not open model %s\n",FileName);
876
877 SafeRead(FH, (void *)&mdl, sizeof(mdl));
878
879 if (mdl.ident != LittleLong (IDPOLYHEADER) ||
880 mdl.version != LittleLong (ALIAS_VERSION))
881 {
882 COM_Error ("Invalid model version for file %s\n",FileName);
883 }
884
885 model.boundingradius = LittleFloat (mdl.boundingradius);
886
887 for (i = 0 ; i < 3 ; i++)
888 {
889 model.scale[i] = LittleFloat (mdl.scale[i]);
890 model.scale_origin[i] = LittleFloat (mdl.scale_origin[i]);
891
892 // rjr - adjust will default to 0
893 model.eyeposition[i] = LittleFloat (mdl.eyeposition[i] - adjust[i]);
894 }
895
896 model.flags = LittleLong (mdl.flags);
897 skincount = model.numskins = LittleLong (mdl.numskins);
898 model.skinwidth = LittleLong (mdl.skinwidth);
899 model.skinheight = LittleLong (mdl.skinheight);
900 model.numverts = LittleLong (mdl.numverts);
901 model.numtris = LittleLong (mdl.numtris - degeneratetris);
902 framecount = model.numframes = LittleLong (mdl.numframes);
903 model.synctype = (synctype_t) LittleLong (mdl.synctype);
904
905 model.size = LittleFloat (mdl.size);
906
907 model.num_st_verts = model.numverts;
908
909 // read in the skins
910 for (i = 0 ; i < model.numskins ; i++)
911 {
912 SafeRead (FH, &skins[i].type, sizeof(skins[i].type));
913 skins[i].pdata = SafeMalloc (model.skinwidth * model.skinheight);
914 SafeRead (FH, skins[i].pdata, model.skinwidth * model.skinheight);
915 }
916
917 // read in the st's
918 SafeRead (FH, stverts, model.num_st_verts * sizeof(stverts[0]));
919 for (i = 0 ; i < model.num_st_verts ; i++)
920 {
921 if (stverts[i].onseam == ALIAS_ONSEAM)
922 {
923 stverts[i].onseam = 3;
924 }
925 else
926 {
927 stverts[i].onseam = 0;
928 }
929
930 stverts[i].s = LittleLong (stverts[i].s);
931 stverts[i].t = LittleLong (stverts[i].t);
932 }
933
934 // read in the triangles
935 for (i = 0 ; i < model.numtris ; i++)
936 {
937 int j;
938 dtriangle_t tri;
939
940 SafeRead (FH, &tri, sizeof(tri));
941
942 triangles[i].facesfront = LittleLong (tri.facesfront);
943
944 for (j = 0 ; j < 3 ; j++)
945 {
946 triangles[i].vertindex[j] = LittleLong (tri.vertindex[j]);
947 triangles[i].stindex[j] = triangles[i].vertindex[j];
948 }
949 }
950
951 // read in the frames
952 curframe = 0;
953 for (i = 0 ; i < model.numframes ; i++)
954 {
955 SafeRead (FH, &frames[curframe].type, sizeof(frames[curframe].type));
956
957 if (frames[curframe].type == ALIAS_SINGLE)
958 { // single (non-grouped) frame
959 ReadFrame (FH, curframe);
960 curframe++;
961 }
962 else
963 {
964 COM_Error("group frames not implemented");
965
966 /* int j, numframes, groupframe;
967 float totinterval;
968
969 groupframe = curframe;
970 curframe++;
971 numframes = frames[groupframe].numgroupframes;
972
973 //
974 // set and write the group header
975 //
976 WriteGroupBBox (modelouthandle, numframes, curframe);
977
978 //
979 // write the interval array
980 //
981 totinterval = 0.0;
982
983 for (j = 0 ; j < numframes ; j++)
984 {
985 daliasinterval_t temp;
986
987 totinterval += frames[groupframe+1+j].interval;
988 temp.interval = LittleFloat (totinterval);
989
990 SafeWrite (modelouthandle, &temp, sizeof(temp));
991 }
992
993 for (j = 0 ; j < numframes ; j++)
994 {
995 WriteFrame (modelouthandle, curframe);
996 curframe++;
997 }*/
998 }
999 }
1000
1001 ModelReadIn = true;
1002 original_size = ftell(FH);
1003
1004 fclose(FH);
1005 }
1006
1007 //==========================================================================
1008 //
1009 // SetSkinValues
1010 //
1011 // Called for the base frame.
1012 //
1013 //==========================================================================
1014
SetSkinValues(void)1015 static void SetSkinValues (void)
1016 {
1017 int i;
1018 float v;
1019 int width, height, iwidth, iheight, skinwidth;
1020 float basex, basey;
1021 float scw, sch;
1022
1023 for (i = 0 ; i < 3 ; i++)
1024 {
1025 mins[i] = 9999999;
1026 maxs[i] = -9999999;
1027 }
1028
1029 for (i = 0 ; i < model.numverts ; i++)
1030 {
1031 int j;
1032
1033 stverts[i].onseam = 0;
1034
1035 for (j = 0 ; j < 3 ; j++)
1036 {
1037 v = baseverts[i][j];
1038 if (v < mins[j])
1039 mins[j] = v;
1040 if (v > maxs[j])
1041 maxs[j] = v;
1042 }
1043 }
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 printf("width: %i height: %i\n",width, height);
1055
1056 scw = (ScaleWidth/2)*SCALE_ADJUST_FACTOR;
1057 sch = ScaleHeight*SCALE_ADJUST_FACTOR;
1058
1059 scale = scw/width;
1060 if (height*scale >= sch)
1061 {
1062 scale = sch/height;
1063 }
1064
1065 iwidth = ceil(width*scale)+4;
1066 iheight = ceil(height*scale)+4;
1067
1068 printf ("scale: %f\n",scale);
1069 printf ("iwidth: %i iheight: %i\n",iwidth, iheight);
1070
1071 //
1072 // determine which side of each triangle to map the texture to
1073 //
1074 for (i = 0 ; i < model.numtris ; i++)
1075 {
1076 int j;
1077 vec3_t vtemp1, vtemp2, normal;
1078
1079 VectorSubtract (baseverts[triangles[i].vertindex[0]],
1080 baseverts[triangles[i].vertindex[1]], vtemp1);
1081 VectorSubtract (baseverts[triangles[i].vertindex[2]],
1082 baseverts[triangles[i].vertindex[1]], vtemp2);
1083 CrossProduct (vtemp1, vtemp2, normal);
1084
1085 if (normal[1] > 0)
1086 {
1087 basex = iwidth + 2;
1088 triangles[i].facesfront = 0;
1089 }
1090 else
1091 {
1092 basex = 2;
1093 triangles[i].facesfront = 1;
1094 }
1095 basey = 2;
1096
1097 for (j = 0 ; j < 3 ; j++)
1098 {
1099 float *pbasevert;
1100 stvert_t *pstvert;
1101
1102 pbasevert = baseverts[triangles[i].vertindex[j]];
1103 pstvert = &stverts[triangles[i].vertindex[j]];
1104
1105 if (triangles[i].facesfront)
1106 {
1107 pstvert->onseam |= 1;
1108 }
1109 else
1110 {
1111 pstvert->onseam |= 2;
1112 }
1113
1114 if ((triangles[i].facesfront) || ((pstvert->onseam & 1) == 0))
1115 {
1116 // we want the front s value for seam vertices
1117 pstvert->s = Q_rint((pbasevert[0] - mins[0]) * scale + basex);
1118 pstvert->t = Q_rint((maxs[2] - pbasevert[2]) * scale + basey);
1119 }
1120 }
1121 }
1122
1123 // make the width a multiple of 4; some hardware requires this, and it ensures
1124 // dword alignment for each scan
1125 skinwidth = iwidth*2;
1126 model.skinwidth = (skinwidth + 3) & ~3;
1127 model.skinheight = iheight;
1128
1129 printf ("skin width: %i (unpadded width %i) skin height: %i\n",
1130 model.skinwidth, skinwidth, model.skinheight);
1131 }
1132
1133
1134 /*
1135 =================
1136 Cmd_Base
1137 =================
1138 */
Cmd_Base(void)1139 static void Cmd_Base (void)
1140 {
1141 int i, j, k;
1142 triangle_t *ptri;
1143 byte *pskinbitmap;
1144
1145 GetToken(false);
1146 q_strlcpy(qbasename, token, sizeof(qbasename));
1147
1148 //q_snprintf(file1, sizeof(file1), "%s/%s.tri", cdpartial, token);
1149 //ExpandPathAndArchive (file1);
1150
1151 q_snprintf(file1, sizeof(file1), "%s/%s", cddir, token);
1152
1153 // Extract the scaling information from a skin page
1154 GetToken(false);
1155 q_snprintf(file2, sizeof(file2), "%s/%s.pcx", cddir, token);
1156 LoadPCXSkin(file2, &pskinbitmap);
1157 ScaleWidth = (float)ExtractNumber(pskinbitmap, ENCODED_WIDTH_X, ENCODED_WIDTH_Y);
1158 ScaleHeight = (float)ExtractNumber(pskinbitmap, ENCODED_HEIGHT_X, ENCODED_HEIGHT_Y);
1159 free(pskinbitmap);
1160
1161 //
1162 // load the base triangles
1163 //
1164 LoadTriangleList (file1, &ptri, &model.numtris);
1165 printf("Number of triangles (including degenerate triangles): %d\n", model.numtris);
1166
1167 //
1168 // run through all the base triangles, storing each unique vertex in the
1169 // base vertex list and setting the indirect triangles to point to the base
1170 // vertices
1171 //
1172 for (i = 0; i < model.numtris; i++)
1173 {
1174 if (VectorCompare(ptri[i].verts[0], ptri[i].verts[1])
1175 || VectorCompare(ptri[i].verts[1], ptri[i].verts[2])
1176 || VectorCompare(ptri[i].verts[2], ptri[i].verts[0]))
1177 {
1178 degeneratetris++;
1179 degenerate[i] = 1;
1180 }
1181 else
1182 {
1183 degenerate[i] = 0;
1184 }
1185
1186 for (j = 0; j < 3; j++)
1187 {
1188 for (k = 0; k < model.numverts; k++)
1189 {
1190 if (VectorCompare(ptri[i].verts[j], baseverts[k]))
1191 {
1192 // already in the base vertex list
1193 break;
1194 }
1195 }
1196
1197 if (k == model.numverts)
1198 {
1199 // new vertex
1200 VectorCopy(ptri[i].verts[j], baseverts[model.numverts]);
1201 model.numverts++;
1202 model.num_st_verts = model.numverts;
1203 }
1204
1205 triangles[i].vertindex[j] = k;
1206 // Unoptimized vertexes parellel st vertexes
1207 triangles[i].stindex[j] = k;
1208 }
1209 }
1210
1211 printf("Number of vertices: %i\n", model.numverts);
1212
1213 printf("Extracted scaling info: width %d, height %d\n",
1214 (int)ScaleWidth, (int)ScaleHeight);
1215
1216 //
1217 // calculate s & t for each vertex, and set the skin width and height
1218 //
1219 SetSkinValues ();
1220 }
1221
1222
1223 /*
1224 ===============
1225 Cmd_Skin
1226 ===============
1227 */
Cmd_Skin(void)1228 static void Cmd_Skin (void)
1229 {
1230 //byte *ppal;
1231 byte *pskinbitmap;
1232 byte *ptemp1, *ptemp2;
1233 int i;
1234 float scw, sch;
1235
1236 GetToken (false);
1237 q_strlcpy(skinname, token, sizeof(skinname));
1238
1239 //q_snprintf(file1, sizeof(file1), "%s/%s.lbm", cdpartial, token);
1240 //ExpandPathAndArchive (file1);
1241
1242 q_snprintf(file1, sizeof(file1), "%s/%s.pcx", cddir, token);
1243
1244 if (TokenAvailable ())
1245 {
1246 GetToken (false);
1247 skins[skincount].interval = atof (token);
1248 if (skins[skincount].interval <= 0.0)
1249 COM_Error ("Non-positive interval");
1250 }
1251 else
1252 {
1253 skins[skincount].interval = 0.1F;
1254 }
1255
1256 //LoadFile(file1, &pskinbitmap);
1257 LoadPCXSkin(file1, &pskinbitmap);
1258
1259 scw = (float)ExtractNumber(pskinbitmap, ENCODED_WIDTH_X, ENCODED_WIDTH_Y);
1260 sch = (float)ExtractNumber(pskinbitmap, ENCODED_HEIGHT_X, ENCODED_HEIGHT_Y);
1261 if (ScaleWidth != scw || ScaleHeight != sch)
1262 {
1263 COM_Error("Conflicting scale values in %s.\nBase info: %d, %d\n"
1264 "Skin info: %d, %d", file1, (int)ScaleWidth, (int)ScaleHeight,
1265 (int)scw, (int)sch);
1266 }
1267
1268 skins[skincount].pdata = SafeMalloc (model.skinwidth * model.skinheight);
1269
1270 // Copy skinwidth*skinheight, since PCXs are always
1271 // loaded as 640x480 bitmaps
1272 ptemp1 = (byte *) skins[skincount].pdata;
1273 ptemp2 = pskinbitmap;
1274 for (i = 0; i < model.skinheight; i++)
1275 {
1276 memcpy(ptemp1, ptemp2, model.skinwidth);
1277 ptemp1 += model.skinwidth;
1278 ptemp2 += 640;
1279 }
1280
1281 skincount++;
1282
1283 if (skincount > MAXSKINS)
1284 COM_Error ("Too many skins; increase MAXSKINS");
1285 }
1286
1287 //==========================================================================
1288 // ExtractNumber
1289
ExtractNumber(byte * pic,int x,int y)1290 static int ExtractNumber(byte *pic, int x, int y)
1291 {
1292 return ExtractDigit(pic, x, y)*100 + ExtractDigit(pic, x+6, y)*10 + ExtractDigit(pic, x+12, y);
1293 }
1294
1295 //==========================================================================
1296 // ExtractDigit
1297
ExtractDigit(byte * pic,int x,int y)1298 static int ExtractDigit(byte *pic, int x, int y)
1299 {
1300 int i;
1301 int r, c;
1302 char digString[32];
1303 char *buffer;
1304 byte backColor;
1305
1306 backColor = pic[(SKINPAGE_HEIGHT-1)*SKINPAGE_WIDTH];
1307 buffer = digString;
1308 for (r = 0; r < 5; r++)
1309 {
1310 for (c = 0; c < 5; c++)
1311 {
1312 *buffer++ = (pic[(y+r)*SKINPAGE_WIDTH+x+c] == backColor) ? ' ' : '*';
1313 }
1314 }
1315 *buffer = '\0';
1316 for (i = 0; i < 10; i++)
1317 {
1318 if (strcmp(DigitDefs[i], digString) == 0)
1319 {
1320 return i;
1321 }
1322 }
1323 COM_Error("Unable to extract scaling info from skin PCX.");
1324 return -1;
1325 }
1326
1327
1328 /*
1329 ===============
1330 GrabFrame
1331 ===============
1332 */
GrabFrame(const char * frame,int isgroup)1333 static void GrabFrame (const char *frame, int isgroup)
1334 {
1335 triangle_t *ptri;
1336 int i, j;
1337 trivert_t *ptrivert;
1338 int numtris;
1339
1340 //q_snprintf(file1, sizeof(file1), "%s/%s.tri", cdpartial, frame);
1341 //ExpandPathAndArchive (file1);
1342
1343 q_snprintf(file1, sizeof(file1), "%s/%s", cddir, frame);
1344
1345 printf ("grabbing %s\n", file1);
1346 frames[framecount].interval = 0.1F;
1347 q_strlcpy(frames[framecount].name, frame, sizeof(frames[0].name));
1348
1349 //
1350 // load the frame
1351 //
1352 LoadTriangleList (file1, &ptri, &numtris);
1353
1354 if (numtris != model.numtris)
1355 {
1356 COM_Error("Number of triangles doesn't match\n"
1357 "Base frame: %d, frame %s: %d\n",
1358 model.numtris, frame, numtris);
1359 }
1360
1361 // set the intervals
1362 if (isgroup && TokenAvailable ())
1363 {
1364 GetToken (false);
1365 frames[framecount].interval = atof (token);
1366 if (frames[framecount].interval <= 0.0)
1367 COM_Error ("Non-positive interval %s %f", token, frames[framecount].interval);
1368 }
1369 else
1370 {
1371 frames[framecount].interval = 0.1F;
1372 }
1373
1374 //
1375 // allocate storage for the frame's vertices
1376 //
1377 ptrivert = verts[framecount];
1378
1379 frames[framecount].pdata = ptrivert;
1380 frames[framecount].type = ALIAS_SINGLE;
1381
1382 for (i = 0 ; i < model.numverts ; i++)
1383 {
1384 vnorms[i].numnormals = 0;
1385 }
1386
1387 //
1388 // store the frame's vertices in the same order as the base. This assumes the
1389 // triangles and vertices in this frame are in exactly the same order as in the
1390 // base
1391 //
1392 for (i = 0 ; i < numtris ; i++)
1393 {
1394 vec3_t vtemp1, vtemp2, normal;
1395 float ftemp;
1396
1397 if (degenerate[i])
1398 continue;
1399
1400 if (firstframe)
1401 {
1402 VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);
1403 VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);
1404 VectorScale (vtemp1, scale_up, vtemp1);
1405 VectorScale (vtemp2, scale_up, vtemp2);
1406 CrossProduct (vtemp1, vtemp2, normal);
1407
1408 totsize += sqrt (normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]) / 2.0;
1409 }
1410
1411 VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);
1412 VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);
1413 CrossProduct (vtemp1, vtemp2, normal);
1414
1415 VectorNormalize (normal);
1416
1417 // rotate the normal so the model faces down the positive x axis
1418 ftemp = normal[0];
1419 normal[0] = -normal[1];
1420 normal[1] = ftemp;
1421
1422 for (j = 0 ; j < 3 ; j++)
1423 {
1424 int k;
1425 int vertindex;
1426
1427 vertindex = triangles[i].vertindex[j];
1428
1429 // rotate the vertices so the model faces down the positive x axis
1430 // also adjust the vertices to the desired origin
1431
1432 ptrivert[vertindex].v[0] = ((-ptri[i].verts[j][1]) * scale_up) + adjust[0];
1433 ptrivert[vertindex].v[1] = (ptri[i].verts[j][0] * scale_up) + adjust[1];
1434 ptrivert[vertindex].v[2] = (ptri[i].verts[j][2] * scale_up) + adjust[2];
1435
1436 for (k = 0 ; k < 3 ; k++)
1437 {
1438 if (ptrivert[vertindex].v[k] < framesmins[k])
1439 framesmins[k] = ptrivert[vertindex].v[k];
1440
1441 if (ptrivert[vertindex].v[k] > framesmaxs[k])
1442 framesmaxs[k] = ptrivert[vertindex].v[k];
1443 }
1444
1445 VectorCopy (normal, vnorms[vertindex].normals[vnorms[vertindex].numnormals] );
1446
1447 vnorms[vertindex].numnormals++;
1448 }
1449 }
1450
1451 //
1452 // calculate the vertex normals, match them to the template list, and store the
1453 // index of the best match
1454 //
1455 for (i = 0 ; i < model.numverts ; i++)
1456 {
1457 int l;
1458 vec3_t v;
1459 float maxdot;
1460 int maxdotindex;
1461
1462 if (vnorms[i].numnormals > 0)
1463 {
1464 for (l = 0 ; l < 3 ; l++)
1465 {
1466 int m;
1467
1468 v[l] = 0;
1469
1470 for (m = 0 ; m < vnorms[i].numnormals ; m++)
1471 {
1472 v[l] += vnorms[i].normals[m][l];
1473 }
1474
1475 v[l] /= vnorms[i].numnormals;
1476 }
1477 }
1478 else
1479 {
1480 COM_Error ("Vertex with no non-degenerate triangles attached");
1481 }
1482
1483 VectorNormalize (v);
1484
1485 maxdot = -999999.0;
1486 maxdotindex = -1;
1487
1488 for (l = 0 ; l < NUMVERTEXNORMALS ; l++)
1489 {
1490 float dot;
1491
1492 dot = DotProduct (v, avertexnormals[l]);
1493 if (dot > maxdot)
1494 {
1495 maxdot = dot;
1496 maxdotindex = l;
1497 }
1498 }
1499
1500 ptrivert[i].lightnormalindex = maxdotindex;
1501 }
1502
1503 framecount++;
1504
1505 if (framecount >= MAXFRAMES)
1506 COM_Error ("Too many frames; increase MAXFRAMES");
1507
1508 free (ptri);
1509 firstframe = 0;
1510 }
1511
1512
1513 /*
1514 ===============
1515 Cmd_Frame
1516 ===============
1517 */
Cmd_Frame(int isgroup)1518 static void Cmd_Frame (int isgroup)
1519 {
1520 while (TokenAvailable())
1521 {
1522 GetToken (false);
1523 GrabFrame (token, isgroup);
1524
1525 if (!isgroup)
1526 model.numframes++;
1527 }
1528 }
1529
1530 /*
1531 ===============
1532 Cmd_SkinGroupStart
1533 ===============
1534 */
Cmd_SkinGroupStart(void)1535 static void Cmd_SkinGroupStart (void)
1536 {
1537 int groupskin;
1538
1539 groupskin = skincount++;
1540 if (skincount >= MAXFRAMES)
1541 COM_Error ("Too many skins; increase MAXSKINS");
1542
1543 skins[groupskin].type = ALIAS_SKIN_GROUP;
1544 skins[groupskin].numgroupskins = 0;
1545
1546 while (1)
1547 {
1548 GetToken (true);
1549 if (endofscript)
1550 COM_Error ("End of file during group");
1551
1552 if (!strcmp (token, "$skin"))
1553 {
1554 Cmd_Skin ();
1555 skins[groupskin].numgroupskins++;
1556 }
1557 else if (!strcmp (token, "$skingroupend"))
1558 {
1559 break;
1560 }
1561 else
1562 {
1563 COM_Error ("$skin or $skingroupend expected\n");
1564 }
1565 }
1566
1567 if (skins[groupskin].numgroupskins == 0)
1568 COM_Error ("Empty group\n");
1569 }
1570
1571 /*
1572 ===============
1573 Cmd_FrameGroupStart
1574 ===============
1575 */
Cmd_FrameGroupStart(void)1576 static void Cmd_FrameGroupStart (void)
1577 {
1578 int groupframe;
1579
1580 groupframe = framecount++;
1581 if (framecount >= MAXFRAMES)
1582 COM_Error ("Too many frames; increase MAXFRAMES");
1583
1584 frames[groupframe].type = ALIAS_GROUP;
1585 frames[groupframe].numgroupframes = 0;
1586
1587 while (1)
1588 {
1589 GetToken (true);
1590 if (endofscript)
1591 COM_Error ("End of file during group");
1592
1593 if (!strcmp (token, "$frame"))
1594 {
1595 Cmd_Frame (1);
1596 }
1597 else if (!strcmp (token, "$framegroupend"))
1598 {
1599 break;
1600 }
1601 else
1602 {
1603 COM_Error ("$frame or $framegroupend expected\n");
1604 }
1605 }
1606
1607 frames[groupframe].numgroupframes += framecount - groupframe - 1;
1608
1609 if (frames[groupframe].numgroupframes == 0)
1610 COM_Error ("Empty group\n");
1611 }
1612
1613 /*
1614 =================
1615 Cmd_Origin
1616 =================
1617 */
Cmd_Origin(void)1618 static void Cmd_Origin (void)
1619 {
1620
1621 // rotate points into frame of reference so model points down the positive x
1622 // axis
1623 GetToken (false);
1624 adjust[1] = -atof (token);
1625
1626 GetToken (false);
1627 adjust[0] = atof (token);
1628
1629 GetToken (false);
1630 adjust[2] = -atof (token);
1631 }
1632
1633 /*
1634 =================
1635 Cmd_Eyeposition
1636 =================
1637 */
Cmd_Eyeposition(void)1638 static void Cmd_Eyeposition (void)
1639 {
1640
1641 // rotate points into frame of reference so model points down the positive x
1642 // axis
1643 GetToken (false);
1644 model.eyeposition[1] = atof (token);
1645
1646 GetToken (false);
1647 model.eyeposition[0] = -atof (token);
1648
1649 GetToken (false);
1650 model.eyeposition[2] = atof (token);
1651 }
1652
1653 /*
1654 =================
1655 Cmd_ScaleUp
1656 =================
1657 */
Cmd_ScaleUp(void)1658 static void Cmd_ScaleUp (void)
1659 {
1660 GetToken (false);
1661 scale_up = atof (token);
1662 }
1663
1664 /*
1665 =================
1666 Cmd_Flags
1667 =================
1668 */
Cmd_Flags(void)1669 static void Cmd_Flags (void)
1670 {
1671 GetToken (false);
1672 model.flags = atoi (token);
1673 }
1674
1675 /*
1676 =================
1677 Cmd_RotateHTR
1678 =================
1679 */
Cmd_RotateHTR(void)1680 static void Cmd_RotateHTR(void)
1681 {
1682 GetToken(false);
1683 FixHTRRotateX = atof(token);
1684
1685 GetToken(false);
1686 FixHTRRotateY = atof(token);
1687
1688 GetToken(false);
1689 FixHTRRotateZ = atof(token);
1690 }
1691
1692 /*
1693 =================
1694 Cmd_TranslateHTR
1695 =================
1696 */
Cmd_TranslateHTR(void)1697 static void Cmd_TranslateHTR(void)
1698 {
1699 GetToken(false);
1700 FixHTRTranslateX = atof(token);
1701
1702 GetToken(false);
1703 FixHTRTranslateY = atof(token);
1704
1705 GetToken(false);
1706 FixHTRTranslateZ = atof(token);
1707 }
1708
1709 /*
1710 =================
1711 Cmd_Modelname
1712 =================
1713 */
Cmd_Modelname(void)1714 static void Cmd_Modelname (void)
1715 {
1716 WriteModel ();
1717 GetToken (false);
1718 q_strlcpy(outname, token, sizeof(outname));
1719 }
1720
1721 /*
1722 ===============
1723 ParseScript
1724 ===============
1725 */
ParseScript(void)1726 static void ParseScript (void)
1727 {
1728 while (1)
1729 {
1730 do
1731 { // look for a line starting with a $ command
1732 GetToken (true);
1733 if (endofscript)
1734 return;
1735 if (token[0] == '$')
1736 break;
1737 while (TokenAvailable())
1738 GetToken (false);
1739 } while (1);
1740
1741 if (!strcmp (token, "$modelname"))
1742 {
1743 Cmd_Modelname ();
1744 }
1745 else if (!strcmp (token, "$base"))
1746 {
1747 Cmd_Base ();
1748 }
1749 else if (!strcmp (token, "$cd"))
1750 {
1751 if (cdset)
1752 COM_Error ("Two $cd in one model");
1753 cdset = true;
1754 GetToken (false);
1755 q_strlcpy (cdpartial, token, sizeof(cdpartial));
1756 q_strlcpy (cddir, ExpandPath(token), sizeof(cddir));
1757 }
1758 else if (!strcmp (token, "$sync"))
1759 {
1760 model.synctype = ST_SYNC;
1761 }
1762 else if (!strcmp (token, "$origin"))
1763 {
1764 Cmd_Origin ();
1765 }
1766 else if (!strcmp (token, "$eyeposition"))
1767 {
1768 Cmd_Eyeposition ();
1769 }
1770 else if (!strcmp (token, "$scale"))
1771 {
1772 Cmd_ScaleUp ();
1773 }
1774 else if (!strcmp (token, "$flags"))
1775 {
1776 Cmd_Flags ();
1777 }
1778 else if (!strcmp (token, "$rotatehtr"))
1779 {
1780 Cmd_RotateHTR();
1781 }
1782 else if (!strcmp (token, "$translatehtr"))
1783 {
1784 Cmd_TranslateHTR();
1785 }
1786 else if (!strcmp (token, "$frame"))
1787 {
1788 Cmd_Frame (0);
1789 }
1790 else if (!strcmp (token, "$skin"))
1791 {
1792 Cmd_Skin ();
1793 model.numskins++;
1794 }
1795 else if (!strcmp (token, "$framegroupstart"))
1796 {
1797 Cmd_FrameGroupStart ();
1798 model.numframes++;
1799 }
1800 else if (!strcmp (token, "$skingroupstart"))
1801 {
1802 Cmd_SkinGroupStart ();
1803 model.numskins++;
1804 }
1805 else
1806 {
1807 COM_Error ("bad command %s\n", token);
1808 }
1809 }
1810 }
1811
1812 //==========================================================================
1813 //
1814 // LoadPCXSkin
1815 //
1816 //==========================================================================
1817
LoadPCXSkin(const char * filename,byte ** buffer)1818 static void LoadPCXSkin(const char *filename, byte **buffer)
1819 {
1820 int i;
1821 void *buf;
1822 pcx_t *pcx;
1823 int w, h;
1824 int count;
1825 byte controlByte, repeatByte;
1826 byte *src, *dst;
1827 byte length;
1828
1829 // Load file
1830 LoadFile(filename, &buf);
1831 pcx = (pcx_t *) buf;
1832
1833 // Check for a valid PCX header
1834 w = pcx->xMax - pcx->xMin + 1;
1835 h = pcx->yMax - pcx->yMin + 1;
1836 if (pcx->tag != 10 || pcx->version != 5
1837 || pcx->encoding != 1 || pcx->pixelBits != 8
1838 || pcx->planes != 1 || pcx->lineBytes != w
1839 || w != SKINPAGE_WIDTH || h != SKINPAGE_HEIGHT)
1840 {
1841 printf("->tag = %d [10]\n", pcx->tag);
1842 printf("->version = %d [5]\n", pcx->version);
1843 printf("->encoding = %d [1]\n", pcx->encoding);
1844 printf("->pixelBits = %d [8]\n", pcx->pixelBits);
1845 printf("->planes = %d [1]\n", pcx->planes);
1846 printf("->lineBytes = %d\n", pcx->lineBytes);
1847 printf("width = %d [640]\n", w);
1848 printf("height = %d [480]\n", h);
1849 COM_Error("Bad PCX skin file.\n");
1850 }
1851
1852 // Allocate page
1853 dst = (byte *) SafeMalloc(SKINPAGE_SIZE);
1854 *buffer = dst;
1855
1856 // Decompress
1857 for (src = &pcx->data, i = 0; i < SKINPAGE_HEIGHT;
1858 //dst += SKINPAGE_WIDTH,
1859 i++)
1860 {
1861 count = 0;
1862 while (count < SKINPAGE_WIDTH)
1863 {
1864 controlByte = *src++;
1865 if ((controlByte&0xc0) == 0xc0)
1866 { // Repeat run
1867 length = controlByte&0x3f;
1868 repeatByte = *src++;
1869 memset(dst, repeatByte, length);
1870 dst += length;
1871 count += length;
1872 }
1873 else
1874 {
1875 *dst++ = controlByte;
1876 count++;
1877 }
1878 }
1879 if (count > SKINPAGE_WIDTH)
1880 {
1881 COM_Error("PCX decompression overflow.\n");
1882 }
1883 }
1884
1885 free (buf);
1886 }
1887
1888