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