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