2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
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.
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.
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
25 //=================================================================
43 trivert_t v[MAX_VERTS];
46 //================================================================
48 frame_t g_frames[MAX_FRAMES];
53 float scale_up; // set by $scale
54 vec3_t adjust; // set by $origin
55 int g_fixedwidth, g_fixedheight; // set by $skinsize
61 vec3_t base_xyz[MAX_VERTS];
62 dstvert_t base_st[MAX_VERTS];
63 dtriangle_t triangles[MAX_TRIANGLES];
65 int triangle_st[MAX_TRIANGLES][3][2];
67 // the command list holds counts, s/t values, and xyz indexes
68 // that are valid for every frame
72 int used[MAX_TRIANGLES];
74 char g_skins[MAX_MD2SKINS][64];
80 char modelname[64]; // empty unless $modelname issued (players)
82 #define NUMVERTEXNORMALS 162
84 float avertexnormals[NUMVERTEXNORMALS][3] = {
88 FILE *headerouthandle = NULL;
90 //==============================================================
97 void ClearModel( void ){
98 memset( &model, 0, sizeof( model ) );
102 VectorCopy( vec3_origin, adjust );
103 g_fixedwidth = g_fixedheight = 0;
108 void H_printf( char *fmt, ... ){
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" );
119 va_start( argptr, fmt );
120 vfprintf( headerouthandle, fmt, argptr );
130 void WriteModelFile( FILE *modelouthandle ){
136 byte buffer[MAX_VERTS * 4 + 128];
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;
152 // write out the model header
154 for ( i = 0 ; i < sizeof( dmdl_t ) / 4 ; i++ )
155 ( (int *)&modeltemp )[i] = LittleLong( ( (int *)&model )[i] );
157 SafeWrite( modelouthandle, &modeltemp, sizeof( modeltemp ) );
160 // write out the skin names
162 SafeWrite( modelouthandle, g_skins, model.num_skins * MAX_SKINNAME );
165 // write out the texture coordinates
168 for ( i = 0 ; i < model.num_st ; i++ )
170 base_st[i].s = LittleShort( base_st[i].s );
171 base_st[i].t = LittleShort( base_st[i].t );
174 SafeWrite( modelouthandle, base_st, model.num_st * sizeof( base_st[0] ) );
177 // write out the triangles
179 for ( i = 0 ; i < model.num_tris ; i++ )
184 for ( j = 0 ; j < 3 ; j++ )
186 tri.index_xyz[j] = LittleShort( triangles[i].index_xyz[j] );
187 tri.index_st[j] = LittleShort( triangles[i].index_st[j] );
190 SafeWrite( modelouthandle, &tri, sizeof( tri ) );
194 // write out the frames
196 for ( i = 0 ; i < model.num_frames ; i++ )
199 out = (daliasframe_t *)buffer;
201 strcpy( out->name, in->name );
202 for ( j = 0 ; j < 3 ; j++ )
204 out->scale[j] = ( in->maxs[j] - in->mins[j] ) / 255;
205 out->translate[j] = in->mins[j];
208 for ( j = 0 ; j < model.num_xyz ; j++ )
210 // all of these are byte values, so no need to deal with endianness
211 out->verts[j].lightnormalindex = in->v[j].lightnormalindex;
213 for ( k = 0 ; k < 3 ; k++ )
215 // scale to byte values & min/max check
216 v = Q_rint( ( in->v[j].v[k] - out->translate[k] ) / out->scale[k] );
218 // clamp, so rounding doesn't wrap from 255.6 to 0
225 out->verts[j].v[k] = v;
229 for ( j = 0 ; j < 3 ; j++ )
231 out->scale[j] = LittleFloat( out->scale[j] );
232 out->translate[j] = LittleFloat( out->translate[j] );
235 SafeWrite( modelouthandle, out, model.framesize );
241 SafeWrite( modelouthandle, commands, numcommands * 4 );
250 void FinishModel( void ){
251 FILE *modelouthandle;
255 if ( !model.num_frames ) {
260 // copy to release directory tree if doing a release build
263 if ( modelname[0] ) {
264 sprintf( name, "%s", modelname );
267 sprintf( name, "%s/tris.md2", cdpartial );
271 for ( i = 0 ; i < model.num_skins ; i++ )
273 ReleaseFile( g_skins[i] );
275 model.num_frames = 0;
280 // write the model output file
282 if ( modelname[0] ) {
283 sprintf( name, "%s%s", gamedir, modelname );
286 sprintf( name, "%s/tris.md2", cddir );
288 printf( "saving to %s\n", name );
290 modelouthandle = SafeOpenWrite( name );
292 WriteModelFile( modelouthandle );
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" );
304 fclose( modelouthandle );
306 // finish writing header file
309 // scale_up is usefull to allow step distances to be adjusted
310 H_printf( "#define MODEL_SCALE\t\t%f\n", scale_up );
312 fclose( headerouthandle );
313 headerouthandle = NULL;
318 =================================================================
320 ALIAS MODEL DISPLAY LIST GENERATION
322 =================================================================
335 int StripLength( int starttri, int startv ){
339 dtriangle_t *last, *check;
344 last = &triangles[starttri];
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];
353 strip_tris[0] = starttri;
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];
361 // look for a matching triangle
363 for ( j = starttri + 1, check = &triangles[starttri + 1]
364 ; j < model.num_tris ; j++, check++ )
366 for ( k = 0 ; k < 3 ; k++ )
368 if ( check->index_xyz[k] != m1 ) {
371 if ( check->index_st[k] != st1 ) {
374 if ( check->index_xyz[ ( k + 1 ) % 3 ] != m2 ) {
377 if ( check->index_st[ ( k + 1 ) % 3 ] != st2 ) {
381 // this is the next part of the fan
383 // if we can't use this triangle, this tristrip is done
389 if ( stripcount & 1 ) {
390 m2 = check->index_xyz[ ( k + 2 ) % 3 ];
391 st2 = check->index_st[ ( k + 2 ) % 3 ];
395 m1 = check->index_xyz[ ( k + 2 ) % 3 ];
396 st1 = check->index_st[ ( k + 2 ) % 3 ];
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;
410 // clear the temp used flags
411 for ( j = starttri + 1 ; j < model.num_tris ; j++ )
412 if ( used[j] == 2 ) {
425 int FanLength( int starttri, int startv ){
429 dtriangle_t *last, *check;
434 last = &triangles[starttri];
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];
443 strip_tris[0] = starttri;
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];
452 // look for a matching triangle
454 for ( j = starttri + 1, check = &triangles[starttri + 1]
455 ; j < model.num_tris ; j++, check++ )
457 for ( k = 0 ; k < 3 ; k++ )
459 if ( check->index_xyz[k] != m1 ) {
462 if ( check->index_st[k] != st1 ) {
465 if ( check->index_xyz[ ( k + 1 ) % 3 ] != m2 ) {
468 if ( check->index_st[ ( k + 1 ) % 3 ] != st2 ) {
472 // this is the next part of the fan
474 // if we can't use this triangle, this tristrip is done
480 m2 = check->index_xyz[ ( k + 2 ) % 3 ];
481 st2 = check->index_st[ ( k + 2 ) % 3 ];
483 strip_xyz[stripcount + 2] = m2;
484 strip_st[stripcount + 2] = st2;
485 strip_tris[stripcount] = j;
494 // clear the temp used flags
495 for ( j = starttri + 1 ; j < model.num_tris ; j++ )
496 if ( used[j] == 2 ) {
509 Generate a list of trifans or strips
510 for the model, which holds for all frames
513 void BuildGlCmds( void ){
517 int len, bestlen, besttype;
528 memset( used, 0, sizeof( used ) );
529 for ( i = 0 ; i < model.num_tris ; i++ )
531 // pick an unused triangle and start the trifan
537 for ( type = 0 ; type < 2 ; type++ )
540 for ( startv = 0 ; startv < 3 ; startv++ )
543 len = StripLength( i, startv );
546 len = FanLength( i, startv );
548 if ( len > bestlen ) {
551 for ( j = 0 ; j < bestlen + 2 ; j++ )
553 best_st[j] = strip_st[j];
554 best_xyz[j] = strip_xyz[j];
556 for ( j = 0 ; j < bestlen ; j++ )
557 best_tris[j] = strip_tris[j];
562 // mark the tris on the best strip/fan as used
563 for ( j = 0 ; j < bestlen ; j++ )
564 used[best_tris[j]] = 1;
566 if ( besttype == 1 ) {
567 commands[numcommands++] = ( bestlen + 2 );
570 commands[numcommands++] = -( bestlen + 2 );
573 numglverts += bestlen + 2;
575 for ( j = 0 ; j < bestlen + 2 ; j++ )
577 // emit a vertex into the reorder buffer
580 // emit s/t coords into the commands stream
584 s = ( s + 0.5 ) / model.skinwidth;
585 t = ( t + 0.5 ) / model.skinheight;
587 *(float *)&commands[numcommands++] = s;
588 *(float *)&commands[numcommands++] = t;
589 *(int *)&commands[numcommands++] = best_xyz[j];
593 commands[numcommands++] = 0; // end of list marker
598 ===============================================================
602 ===============================================================
609 Builds the triangle_st array for the base frame and
610 model.skinwidth / model.skinheight
612 FIXME: allow this to be loaded from a file for
616 void BuildST( triangle_t *ptri, int numtri ){
618 int width, height, iwidth, iheight, swidth;
620 float s_scale, t_scale;
624 vec3_t vtemp1, vtemp2, normal;
627 // find bounds of all the verts on the base frame
629 ClearBounds( mins, maxs );
631 for ( i = 0 ; i < numtri ; i++ )
632 for ( j = 0 ; j < 3 ; j++ )
633 AddPointToBounds( ptri[i].verts[j], mins, maxs );
635 for ( i = 0 ; i < 3 ; i++ )
637 mins[i] = floor( mins[i] );
638 maxs[i] = ceil( maxs[i] );
641 width = maxs[0] - mins[0];
642 height = maxs[2] - mins[2];
644 if ( !g_fixedwidth ) { // old style
646 if ( width * scale >= 150 ) {
647 scale = 150.0 / width;
649 if ( height * scale >= 190 ) {
650 scale = 190.0 / height;
653 s_scale = t_scale = scale;
655 iwidth = ceil( width * s_scale );
656 iheight = ceil( height * t_scale );
663 iwidth = g_fixedwidth / 2;
664 iheight = g_fixedheight;
666 s_scale = (float)( iwidth - 4 ) / width;
667 t_scale = (float)( iheight - 4 ) / height;
671 // determine which side of each triangle to map the texture to
673 for ( i = 0 ; i < numtri ; i++ )
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 );
679 if ( normal[1] > 0 ) {
688 for ( j = 0 ; j < 3 ; j++ )
690 pbasevert = ptri[i].verts[j];
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 );
697 // make the width a multiple of 4; some hardware requires this, and it ensures
698 // dword alignment for each scan
700 model.skinwidth = ( swidth + 3 ) & ~3;
701 model.skinheight = iheight;
710 void Cmd_Base( void ){
718 if ( g_skipmodel || g_release || g_archive ) {
722 printf( "---------------------\n" );
723 sprintf( file1, "%s/%s.%s", cdarchive, token, trifileext );
724 printf( "%s\n", file1 );
726 ExpandPathAndArchive( file1 );
728 sprintf( file1, "%s/%s.%s", cddir, token, trifileext );
730 time1 = FileTime( file1 );
732 Error( "%s doesn't exist", file1 );
736 // load the base triangles
739 Load3DSTriangleList( file1, &ptri, &model.num_tris );
742 LoadTriangleList( file1, &ptri, &model.num_tris );
748 BuildST( ptri, model.num_tris );
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
755 for ( i = 0 ; i < model.num_tris ; i++ )
757 for ( j = 0 ; j < 3 ; j++ )
760 for ( k = 0 ; k < model.num_xyz ; k++ )
761 if ( VectorCompare( ptri[i].verts[j], base_xyz[k] ) ) {
763 } // this vertex is already in the base vertex list
765 if ( k == model.num_xyz ) { // new index
766 VectorCopy( ptri[i].verts[j], base_xyz[model.num_xyz] );
770 triangles[i].index_xyz[j] = k;
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 ) {
777 } // this vertex is already in the base vertex list
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];
785 triangles[i].index_st[j] = k;
789 // build triangle strips / fans
793 //===============================================================
795 char *FindFrameFile( char *frame ){
798 static char retname[1024];
803 if ( strstr( frame, "." ) ) {
804 return frame; // allready in dot format
807 // split 'run1' into 'run' and '1'
808 s = frame + strlen( frame ) - 1;
810 while ( s != frame && *s >= '0' && *s <= '9' )
813 strcpy( suffix, s + 1 );
814 strcpy( base, frame );
815 base[s - frame + 1] = 0;
817 // check for 'run1.tri'
818 sprintf( file1, "%s/%s%s.%s",cddir, base, suffix, trifileext );
819 time1 = FileTime( file1 );
821 sprintf( retname, "%s%s.%s", base, suffix, trifileext );
826 sprintf( file1, "%s/%s.%s",cddir, base, suffix );
827 time1 = FileTime( file1 );
829 sprintf( retname, "%s.%s", base, suffix );
833 Error( "frame %s could not be found",frame );
842 void GrabFrame( char *frame ){
849 vertexnormals_t vnorms[MAX_VERTS];
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 );
858 sprintf( file1, "%s/%s", cdarchive, framefile );
859 ExpandPathAndArchive( file1 );
861 sprintf( file1, "%s/%s",cddir, framefile );
863 printf( "grabbing %s\n", file1 );
865 if ( model.num_frames >= MAX_FRAMES ) {
866 Error( "model.num_frames >= MAX_FRAMES" );
868 fr = &g_frames[model.num_frames];
871 strcpy( fr->name, frame );
877 Load3DSTriangleList( file1, &ptri, &num_tris );
880 LoadTriangleList( file1, &ptri, &num_tris );
883 if ( num_tris != model.num_tris ) {
884 Error( "%s: number of triangles doesn't match base frame\n", file1 );
888 // allocate storage for the frame's vertices
892 for ( i = 0 ; i < model.num_xyz ; i++ )
894 vnorms[i].numnormals = 0;
895 VectorClear( vnorms[i].normalsum );
897 ClearBounds( fr->mins, fr->maxs );
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
904 for ( i = 0 ; i < num_tris ; i++ )
906 vec3_t vtemp1, vtemp2, normal;
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 );
913 VectorNormalize( normal, normal );
915 // rotate the normal so the model faces down the positive x axis
917 normal[0] = -normal[1];
920 for ( j = 0 ; j < 3 ; j++ )
922 index_xyz = triangles[i].index_xyz[j];
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 ) +
928 ptrivert[index_xyz].v[1] = ( ptri[i].verts[j][0] * scale_up ) +
930 ptrivert[index_xyz].v[2] = ( ptri[i].verts[j][2] * scale_up ) +
933 AddPointToBounds( ptrivert[index_xyz].v, fr->mins, fr->maxs );
935 VectorAdd( vnorms[index_xyz].normalsum, normal, vnorms[index_xyz].normalsum );
936 vnorms[index_xyz].numnormals++;
941 // calculate the vertex normals, match them to the template list, and store the
942 // index of the best match
944 for ( i = 0 ; i < model.num_xyz ; i++ )
952 c = vnorms[i].numnormals;
954 Error( "Vertex with no triangles attached" );
957 VectorScale( vnorms[i].normalsum, 1.0 / c, v );
958 VectorNormalize( v, v );
963 for ( j = 0 ; j < NUMVERTEXNORMALS ; j++ )
967 dot = DotProduct( v, avertexnormals[j] );
968 if ( dot > maxdot ) {
974 ptrivert[i].lightnormalindex = maxdotindex;
985 void Cmd_Frame( void ){
986 while ( TokenAvailable() )
992 if ( g_release || g_archive ) {
993 model.num_frames = 1; // don't skip the writeout
997 H_printf( "#define FRAME_%-16s\t%i\n", token, model.num_frames );
1008 Skins aren't actually stored in the file, only a reference
1009 is saved out to the header file.
1012 void Cmd_Skin( void ){
1018 char name[1024], savename[1024];
1022 if ( model.num_skins == MAX_MD2SKINS ) {
1023 Error( "model.num_skins == MAX_MD2SKINS" );
1026 if ( g_skipmodel ) {
1030 sprintf( name, "%s/%s.lbm", cdarchive, token );
1031 strcpy( name, ExpandPathAndArchive( name ) );
1032 // sprintf (name, "%s/%s.lbm", cddir, token);
1034 if ( TokenAvailable() ) {
1036 sprintf( g_skins[model.num_skins], "%s.pcx", token );
1037 sprintf( savename, "%s%s.pcx", gamedir, g_skins[model.num_skins] );
1041 sprintf( savename, "%s/%s.pcx", cddir, token );
1042 sprintf( g_skins[model.num_skins], "%s/%s.pcx", cdpartial, token );
1047 if ( g_skipmodel || g_release || g_archive ) {
1052 printf( "loading %s\n", name );
1053 Load256Image( name, &pixels, &palette, &width, &height );
1054 RemapZero( pixels, palette, width, height );
1056 // crop it to the proper size
1057 cropped = malloc( model.skinwidth * model.skinheight );
1058 for ( y = 0 ; y < model.skinheight ; y++ )
1060 memcpy( cropped + y * model.skinwidth,
1061 pixels + y * width, model.skinwidth );
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 );
1081 void Cmd_Origin( void ){
1082 // rotate points into frame of reference so model points down the
1085 adjust[1] = -atof( token );
1088 adjust[0] = atof( token );
1091 adjust[2] = -atof( token );
1100 void Cmd_ScaleUp( void ){
1102 scale_up = atof( token );
1103 if ( g_skipmodel || g_release || g_archive ) {
1107 printf( "Scale up: %f\n", scale_up );
1115 Set a skin size other than the default
1118 void Cmd_Skinsize( void ){
1120 g_fixedwidth = atoi( token );
1122 g_fixedheight = atoi( token );
1129 Gives a different name/location for the file, instead of the cddir
1132 void Cmd_Modelname( void ){
1134 strcpy( modelname, token );
1142 void Cmd_Cd( void ){
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 );
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)
1159 if ( strncmp( token, g_only, strlen( g_only ) ) ) {
1161 printf( "skipping %s\n", cdpartial );