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