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)
99 memset (&model, 0, sizeof(model));
103 VectorCopy (vec3_origin, adjust);
104 g_fixedwidth = g_fixedheight = 0;
109 void H_printf(char *fmt, ...)
114 if (!headerouthandle)
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");
122 va_start (argptr, fmt);
123 vfprintf (headerouthandle, fmt, argptr);
133 void WriteModelFile (FILE *modelouthandle)
140 byte buffer[MAX_VERTS*4+128];
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;
156 // write out the model header
158 for (i=0 ; i<sizeof(dmdl_t)/4 ; i++)
159 ((int *)&modeltemp)[i] = LittleLong (((int *)&model)[i]);
161 SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp));
164 // write out the skin names
166 SafeWrite (modelouthandle, g_skins, model.num_skins * MAX_SKINNAME);
169 // write out the texture coordinates
172 for (i=0 ; i<model.num_st ; i++)
174 base_st[i].s = LittleShort (base_st[i].s);
175 base_st[i].t = LittleShort (base_st[i].t);
178 SafeWrite (modelouthandle, base_st, model.num_st * sizeof(base_st[0]));
181 // write out the triangles
183 for (i=0 ; i<model.num_tris ; i++)
188 for (j=0 ; j<3 ; j++)
190 tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]);
191 tri.index_st[j] = LittleShort (triangles[i].index_st[j]);
194 SafeWrite (modelouthandle, &tri, sizeof(tri));
198 // write out the frames
200 for (i=0 ; i<model.num_frames ; i++)
203 out = (daliasframe_t *)buffer;
205 strcpy (out->name, in->name);
206 for (j=0 ; j<3 ; j++)
208 out->scale[j] = (in->maxs[j] - in->mins[j])/255;
209 out->translate[j] = in->mins[j];
212 for (j=0 ; j<model.num_xyz ; j++)
214 // all of these are byte values, so no need to deal with endianness
215 out->verts[j].lightnormalindex = in->v[j].lightnormalindex;
217 for (k=0 ; k<3 ; k++)
219 // scale to byte values & min/max check
220 v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] );
222 // clamp, so rounding doesn't wrap from 255.6 to 0
227 out->verts[j].v[k] = v;
231 for (j=0 ; j<3 ; j++)
233 out->scale[j] = LittleFloat (out->scale[j]);
234 out->translate[j] = LittleFloat (out->translate[j]);
237 SafeWrite (modelouthandle, out, model.framesize);
243 SafeWrite (modelouthandle, commands, numcommands*4);
252 void FinishModel (void)
254 FILE *modelouthandle;
258 if (!model.num_frames)
262 // copy to release directory tree if doing a release build
267 sprintf (name, "%s", modelname);
269 sprintf (name, "%s/tris.md2", cdpartial);
272 for (i=0 ; i<model.num_skins ; i++)
274 ReleaseFile (g_skins[i]);
276 model.num_frames = 0;
281 // write the model output file
284 sprintf (name, "%s%s", gamedir, modelname);
286 sprintf (name, "%s/tris.md2", cddir);
287 printf ("saving to %s\n", name);
289 modelouthandle = SafeOpenWrite (name);
291 WriteModelFile (modelouthandle);
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");
303 fclose (modelouthandle);
305 // finish writing header file
308 // scale_up is usefull to allow step distances to be adjusted
309 H_printf("#define MODEL_SCALE\t\t%f\n", scale_up);
311 fclose (headerouthandle);
312 headerouthandle = NULL;
317 =================================================================
319 ALIAS MODEL DISPLAY LIST GENERATION
321 =================================================================
334 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)
370 if (check->index_st[k] != st1)
372 if (check->index_xyz[ (k+1)%3 ] != m2)
374 if (check->index_st[ (k+1)%3 ] != st2)
377 // this is the next part of the fan
379 // if we can't use this triangle, this tristrip is done
386 m2 = check->index_xyz[ (k+2)%3 ];
387 st2 = check->index_st[ (k+2)%3 ];
391 m1 = check->index_xyz[ (k+2)%3 ];
392 st1 = check->index_st[ (k+2)%3 ];
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;
406 // clear the temp used flags
407 for (j=starttri+1 ; j<model.num_tris ; j++)
420 int FanLength (int starttri, int startv)
425 dtriangle_t *last, *check;
430 last = &triangles[starttri];
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];
439 strip_tris[0] = starttri;
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];
448 // look for a matching triangle
450 for (j=starttri+1, check=&triangles[starttri+1]
451 ; j<model.num_tris ; j++, check++)
453 for (k=0 ; k<3 ; k++)
455 if (check->index_xyz[k] != m1)
457 if (check->index_st[k] != st1)
459 if (check->index_xyz[ (k+1)%3 ] != m2)
461 if (check->index_st[ (k+1)%3 ] != st2)
464 // this is the next part of the fan
466 // if we can't use this triangle, this tristrip is done
471 m2 = check->index_xyz[ (k+2)%3 ];
472 st2 = check->index_st[ (k+2)%3 ];
474 strip_xyz[stripcount+2] = m2;
475 strip_st[stripcount+2] = st2;
476 strip_tris[stripcount] = j;
485 // clear the temp used flags
486 for (j=starttri+1 ; j<model.num_tris ; j++)
499 Generate a list of trifans or strips
500 for the model, which holds for all frames
503 void BuildGlCmds (void)
508 int len, bestlen, besttype;
519 memset (used, 0, sizeof(used));
520 for (i=0 ; i<model.num_tris ; i++)
522 // pick an unused triangle and start the trifan
527 for (type = 0 ; type < 2 ; type++)
530 for (startv =0 ; startv < 3 ; startv++)
533 len = StripLength (i, startv);
535 len = FanLength (i, startv);
540 for (j=0 ; j<bestlen+2 ; j++)
542 best_st[j] = strip_st[j];
543 best_xyz[j] = strip_xyz[j];
545 for (j=0 ; j<bestlen ; j++)
546 best_tris[j] = strip_tris[j];
551 // mark the tris on the best strip/fan as used
552 for (j=0 ; j<bestlen ; j++)
553 used[best_tris[j]] = 1;
556 commands[numcommands++] = (bestlen+2);
558 commands[numcommands++] = -(bestlen+2);
560 numglverts += bestlen+2;
562 for (j=0 ; j<bestlen+2 ; j++)
564 // emit a vertex into the reorder buffer
567 // emit s/t coords into the commands stream
571 s = (s + 0.5) / model.skinwidth;
572 t = (t + 0.5) / model.skinheight;
574 *(float *)&commands[numcommands++] = s;
575 *(float *)&commands[numcommands++] = t;
576 *(int *)&commands[numcommands++] = best_xyz[j];
580 commands[numcommands++] = 0; // end of list marker
585 ===============================================================
589 ===============================================================
596 Builds the triangle_st array for the base frame and
597 model.skinwidth / model.skinheight
599 FIXME: allow this to be loaded from a file for
603 void BuildST (triangle_t *ptri, int numtri)
606 int width, height, iwidth, iheight, swidth;
608 float s_scale, t_scale;
612 vec3_t vtemp1, vtemp2, normal;
615 // find bounds of all the verts on the base frame
617 ClearBounds (mins, maxs);
619 for (i=0 ; i<numtri ; i++)
620 for (j=0 ; j<3 ; j++)
621 AddPointToBounds (ptri[i].verts[j], mins, maxs);
623 for (i=0 ; i<3 ; i++)
625 mins[i] = floor(mins[i]);
626 maxs[i] = ceil(maxs[i]);
629 width = maxs[0] - mins[0];
630 height = maxs[2] - mins[2];
635 if (width*scale >= 150)
636 scale = 150.0 / width;
637 if (height*scale >= 190)
638 scale = 190.0 / height;
640 s_scale = t_scale = scale;
642 iwidth = ceil(width*s_scale);
643 iheight = ceil(height*t_scale);
650 iwidth = g_fixedwidth / 2;
651 iheight = g_fixedheight;
653 s_scale = (float)(iwidth-4) / width;
654 t_scale = (float)(iheight-4) / height;
658 // determine which side of each triangle to map the texture to
660 for (i=0 ; i<numtri ; i++)
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);
676 for (j=0 ; j<3 ; j++)
678 pbasevert = ptri[i].verts[j];
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);
685 // make the width a multiple of 4; some hardware requires this, and it ensures
686 // dword alignment for each scan
688 model.skinwidth = (swidth + 3) & ~3;
689 model.skinheight = iheight;
707 if (g_skipmodel || g_release || g_archive)
710 printf ("---------------------\n");
711 sprintf (file1, "%s/%s.%s", cdarchive, token, trifileext);
712 printf ("%s\n", file1);
714 ExpandPathAndArchive (file1);
716 sprintf (file1, "%s/%s.%s", cddir, token, trifileext);
718 time1 = FileTime (file1);
720 Error ("%s doesn't exist", file1);
723 // load the base triangles
726 Load3DSTriangleList (file1, &ptri, &model.num_tris);
728 LoadTriangleList (file1, &ptri, &model.num_tris);
733 BuildST (ptri, model.num_tris);
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
740 for (i=0 ; i<model.num_tris ; i++)
742 for (j=0 ; j<3 ; j++)
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
749 if (k == model.num_xyz)
751 VectorCopy (ptri[i].verts[j], base_xyz[model.num_xyz]);
755 triangles[i].index_xyz[j] = k;
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
763 if (k == model.num_st)
765 base_st[model.num_st].s = triangle_st[i][j][0];
766 base_st[model.num_st].t = triangle_st[i][j][1];
770 triangles[i].index_st[j] = k;
774 // build triangle strips / fans
778 //===============================================================
780 char *FindFrameFile (char *frame)
784 static char retname[1024];
789 if (strstr (frame, "."))
790 return frame; // allready in dot format
792 // split 'run1' into 'run' and '1'
793 s = frame + strlen(frame)-1;
795 while (s != frame && *s >= '0' && *s <= '9')
798 strcpy (suffix, s+1);
799 strcpy (base, frame);
802 // check for 'run1.tri'
803 sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, trifileext);
804 time1 = FileTime (file1);
807 sprintf (retname, "%s%s.%s", base, suffix, trifileext);
812 sprintf (file1, "%s/%s.%s",cddir, base, suffix);
813 time1 = FileTime (file1);
816 sprintf (retname, "%s.%s", base, suffix);
820 Error ("frame %s could not be found",frame);
829 void GrabFrame (char *frame)
837 vertexnormals_t vnorms[MAX_VERTS];
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);
846 sprintf (file1, "%s/%s", cdarchive, framefile);
847 ExpandPathAndArchive (file1);
849 sprintf (file1, "%s/%s",cddir, framefile);
851 printf ("grabbing %s\n", file1);
853 if (model.num_frames >= MAX_FRAMES)
854 Error ("model.num_frames >= MAX_FRAMES");
855 fr = &g_frames[model.num_frames];
858 strcpy (fr->name, frame);
864 Load3DSTriangleList (file1, &ptri, &num_tris);
866 LoadTriangleList (file1, &ptri, &num_tris);
868 if (num_tris != model.num_tris)
869 Error ("%s: number of triangles doesn't match base frame\n", file1);
872 // allocate storage for the frame's vertices
876 for (i=0 ; i<model.num_xyz ; i++)
878 vnorms[i].numnormals = 0;
879 VectorClear (vnorms[i].normalsum);
881 ClearBounds (fr->mins, fr->maxs);
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
888 for (i=0 ; i<num_tris ; i++)
890 vec3_t vtemp1, vtemp2, normal;
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);
897 VectorNormalize (normal, normal);
899 // rotate the normal so the model faces down the positive x axis
901 normal[0] = -normal[1];
904 for (j=0 ; j<3 ; j++)
906 index_xyz = triangles[i].index_xyz[j];
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) +
912 ptrivert[index_xyz].v[1] = (ptri[i].verts[j][0] * scale_up) +
914 ptrivert[index_xyz].v[2] = (ptri[i].verts[j][2] * scale_up) +
917 AddPointToBounds (ptrivert[index_xyz].v, fr->mins, fr->maxs);
919 VectorAdd (vnorms[index_xyz].normalsum, normal, vnorms[index_xyz].normalsum);
920 vnorms[index_xyz].numnormals++;
925 // calculate the vertex normals, match them to the template list, and store the
926 // index of the best match
928 for (i=0 ; i<model.num_xyz ; i++)
936 c = vnorms[i].numnormals;
938 Error ("Vertex with no triangles attached");
940 VectorScale (vnorms[i].normalsum, 1.0/c, v);
941 VectorNormalize (v, v);
946 for (j=0 ; j<NUMVERTEXNORMALS ; j++)
950 dot = DotProduct (v, avertexnormals[j]);
958 ptrivert[i].lightnormalindex = maxdotindex;
969 void Cmd_Frame (void)
971 while (TokenAvailable())
976 if (g_release || g_archive)
978 model.num_frames = 1; // don't skip the writeout
982 H_printf("#define FRAME_%-16s\t%i\n", token, model.num_frames);
993 Skins aren't actually stored in the file, only a reference
994 is saved out to the header file.
1004 char name[1024], savename[1024];
1008 if (model.num_skins == MAX_MD2SKINS)
1009 Error ("model.num_skins == MAX_MD2SKINS");
1014 sprintf (name, "%s/%s.lbm", cdarchive, token);
1015 strcpy (name, ExpandPathAndArchive( name ) );
1016 // sprintf (name, "%s/%s.lbm", cddir, token);
1018 if (TokenAvailable())
1021 sprintf (g_skins[model.num_skins], "%s.pcx", token);
1022 sprintf (savename, "%s%s.pcx", gamedir, g_skins[model.num_skins]);
1026 sprintf (savename, "%s/%s.pcx", cddir, token);
1027 sprintf (g_skins[model.num_skins], "%s/%s.pcx", cdpartial, token);
1032 if (g_skipmodel || g_release || g_archive)
1036 printf ("loading %s\n", name);
1037 Load256Image (name, &pixels, &palette, &width, &height);
1038 RemapZero (pixels, palette, width, height);
1040 // crop it to the proper size
1041 cropped = malloc (model.skinwidth*model.skinheight);
1042 for (y=0 ; y<model.skinheight ; y++)
1044 memcpy (cropped+y*model.skinwidth,
1045 pixels+y*width, model.skinwidth);
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);
1065 void Cmd_Origin (void)
1067 // rotate points into frame of reference so model points down the
1070 adjust[1] = -atof (token);
1073 adjust[0] = atof (token);
1076 adjust[2] = -atof (token);
1085 void Cmd_ScaleUp (void)
1088 scale_up = atof (token);
1089 if (g_skipmodel || g_release || g_archive)
1092 printf ("Scale up: %f\n", scale_up);
1100 Set a skin size other than the default
1103 void Cmd_Skinsize (void)
1106 g_fixedwidth = atoi(token);
1108 g_fixedheight = atoi(token);
1115 Gives a different name/location for the file, instead of the cddir
1118 void Cmd_Modelname (void)
1121 strcpy (modelname, token);
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);
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)
1146 if (strncmp(token, g_only, strlen(g_only)))
1149 printf ("skipping %s\n", cdpartial);