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