5 //=================================================================
23 trivert_t v[MAX_VERTS];
26 //================================================================
28 frame_t g_frames[MAX_FRAMES];
33 float scale_up; // set by $scale
34 vec3_t adjust; // set by $origin
35 int g_fixedwidth, g_fixedheight; // set by $skinsize
41 vec3_t base_xyz[MAX_VERTS];
42 dstvert_t base_st[MAX_VERTS];
43 dtriangle_t triangles[MAX_TRIANGLES];
45 int triangle_st[MAX_TRIANGLES][3][2];
47 // the command list holds counts, s/t values, and xyz indexes
48 // that are valid for every frame
52 int used[MAX_TRIANGLES];
54 char g_skins[MAX_MD2SKINS][64];
60 char modelname[64]; // empty unless $modelname issued (players)
62 #define NUMVERTEXNORMALS 162
64 float avertexnormals[NUMVERTEXNORMALS][3] = {
68 FILE *headerouthandle = NULL;
70 //==============================================================
77 void ClearModel (void)
79 memset (&model, 0, sizeof(model));
83 VectorCopy (vec3_origin, adjust);
84 g_fixedwidth = g_fixedheight = 0;
89 void H_printf(char *fmt, ...)
96 sprintf (name, "%s/tris.h", cddir);
97 headerouthandle = SafeOpenWrite (name);
98 fprintf(headerouthandle, "// %s\n\n", cddir);
99 fprintf(headerouthandle, "// This file generated by qdata - Do NOT Modify\n\n");
102 va_start (argptr, fmt);
103 vfprintf (headerouthandle, fmt, argptr);
113 void WriteModelFile (FILE *modelouthandle)
120 byte buffer[MAX_VERTS*4+128];
124 model.ident = IDALIASHEADER;
125 model.version = ALIAS_VERSION;
126 model.framesize = (int)&((daliasframe_t *)0)->verts[model.num_xyz];
127 model.num_glcmds = numcommands;
128 model.ofs_skins = sizeof(dmdl_t);
129 model.ofs_st = model.ofs_skins + model.num_skins * MAX_SKINNAME;
130 model.ofs_tris = model.ofs_st + model.num_st*sizeof(dstvert_t);
131 model.ofs_frames = model.ofs_tris + model.num_tris*sizeof(dtriangle_t);
132 model.ofs_glcmds = model.ofs_frames + model.num_frames*model.framesize;
133 model.ofs_end = model.ofs_glcmds + model.num_glcmds*4;
136 // write out the model header
138 for (i=0 ; i<sizeof(dmdl_t)/4 ; i++)
139 ((int *)&modeltemp)[i] = LittleLong (((int *)&model)[i]);
141 SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp));
144 // write out the skin names
146 SafeWrite (modelouthandle, g_skins, model.num_skins * MAX_SKINNAME);
149 // write out the texture coordinates
152 for (i=0 ; i<model.num_st ; i++)
154 base_st[i].s = LittleShort (base_st[i].s);
155 base_st[i].t = LittleShort (base_st[i].t);
158 SafeWrite (modelouthandle, base_st, model.num_st * sizeof(base_st[0]));
161 // write out the triangles
163 for (i=0 ; i<model.num_tris ; i++)
168 for (j=0 ; j<3 ; j++)
170 tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]);
171 tri.index_st[j] = LittleShort (triangles[i].index_st[j]);
174 SafeWrite (modelouthandle, &tri, sizeof(tri));
178 // write out the frames
180 for (i=0 ; i<model.num_frames ; i++)
183 out = (daliasframe_t *)buffer;
185 strcpy (out->name, in->name);
186 for (j=0 ; j<3 ; j++)
188 out->scale[j] = (in->maxs[j] - in->mins[j])/255;
189 out->translate[j] = in->mins[j];
192 for (j=0 ; j<model.num_xyz ; j++)
194 // all of these are byte values, so no need to deal with endianness
195 out->verts[j].lightnormalindex = in->v[j].lightnormalindex;
197 for (k=0 ; k<3 ; k++)
199 // scale to byte values & min/max check
200 v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] );
202 // clamp, so rounding doesn't wrap from 255.6 to 0
207 out->verts[j].v[k] = v;
211 for (j=0 ; j<3 ; j++)
213 out->scale[j] = LittleFloat (out->scale[j]);
214 out->translate[j] = LittleFloat (out->translate[j]);
217 SafeWrite (modelouthandle, out, model.framesize);
223 SafeWrite (modelouthandle, commands, numcommands*4);
232 void FinishModel (void)
234 FILE *modelouthandle;
238 if (!model.num_frames)
242 // copy to release directory tree if doing a release build
247 sprintf (name, "%s", modelname);
249 sprintf (name, "%s/tris.md2", cdpartial);
252 for (i=0 ; i<model.num_skins ; i++)
254 ReleaseFile (g_skins[i]);
256 model.num_frames = 0;
261 // write the model output file
264 sprintf (name, "%s%s", gamedir, modelname);
266 sprintf (name, "%s/tris.md2", cddir);
267 printf ("saving to %s\n", name);
269 modelouthandle = SafeOpenWrite (name);
271 WriteModelFile (modelouthandle);
273 printf ("%3dx%3d skin\n", model.skinwidth, model.skinheight);
274 printf ("%4d vertexes\n", model.num_xyz);
275 printf ("%4d triangles\n", model.num_tris);
276 printf ("%4d frame\n", model.num_frames);
277 printf ("%4d glverts\n", numglverts);
278 printf ("%4d glcmd\n", model.num_glcmds);
279 printf ("%4d skins\n", model.num_skins);
280 printf ("file size: %d\n", (int)ftell (modelouthandle) );
281 printf ("---------------------\n");
283 fclose (modelouthandle);
285 // finish writing header file
288 // scale_up is usefull to allow step distances to be adjusted
289 H_printf("#define MODEL_SCALE\t\t%f\n", scale_up);
291 fclose (headerouthandle);
292 headerouthandle = NULL;
297 =================================================================
299 ALIAS MODEL DISPLAY LIST GENERATION
301 =================================================================
314 int StripLength (int starttri, int startv)
319 dtriangle_t *last, *check;
324 last = &triangles[starttri];
326 strip_xyz[0] = last->index_xyz[(startv)%3];
327 strip_xyz[1] = last->index_xyz[(startv+1)%3];
328 strip_xyz[2] = last->index_xyz[(startv+2)%3];
329 strip_st[0] = last->index_st[(startv)%3];
330 strip_st[1] = last->index_st[(startv+1)%3];
331 strip_st[2] = last->index_st[(startv+2)%3];
333 strip_tris[0] = starttri;
336 m1 = last->index_xyz[(startv+2)%3];
337 st1 = last->index_st[(startv+2)%3];
338 m2 = last->index_xyz[(startv+1)%3];
339 st2 = last->index_st[(startv+1)%3];
341 // look for a matching triangle
343 for (j=starttri+1, check=&triangles[starttri+1]
344 ; j<model.num_tris ; j++, check++)
346 for (k=0 ; k<3 ; k++)
348 if (check->index_xyz[k] != m1)
350 if (check->index_st[k] != st1)
352 if (check->index_xyz[ (k+1)%3 ] != m2)
354 if (check->index_st[ (k+1)%3 ] != st2)
357 // this is the next part of the fan
359 // if we can't use this triangle, this tristrip is done
366 m2 = check->index_xyz[ (k+2)%3 ];
367 st2 = check->index_st[ (k+2)%3 ];
371 m1 = check->index_xyz[ (k+2)%3 ];
372 st1 = check->index_st[ (k+2)%3 ];
375 strip_xyz[stripcount+2] = check->index_xyz[ (k+2)%3 ];
376 strip_st[stripcount+2] = check->index_st[ (k+2)%3 ];
377 strip_tris[stripcount] = j;
386 // clear the temp used flags
387 for (j=starttri+1 ; j<model.num_tris ; j++)
400 int FanLength (int starttri, int startv)
405 dtriangle_t *last, *check;
410 last = &triangles[starttri];
412 strip_xyz[0] = last->index_xyz[(startv)%3];
413 strip_xyz[1] = last->index_xyz[(startv+1)%3];
414 strip_xyz[2] = last->index_xyz[(startv+2)%3];
415 strip_st[0] = last->index_st[(startv)%3];
416 strip_st[1] = last->index_st[(startv+1)%3];
417 strip_st[2] = last->index_st[(startv+2)%3];
419 strip_tris[0] = starttri;
422 m1 = last->index_xyz[(startv+0)%3];
423 st1 = last->index_st[(startv+0)%3];
424 m2 = last->index_xyz[(startv+2)%3];
425 st2 = last->index_st[(startv+2)%3];
428 // look for a matching triangle
430 for (j=starttri+1, check=&triangles[starttri+1]
431 ; j<model.num_tris ; j++, check++)
433 for (k=0 ; k<3 ; k++)
435 if (check->index_xyz[k] != m1)
437 if (check->index_st[k] != st1)
439 if (check->index_xyz[ (k+1)%3 ] != m2)
441 if (check->index_st[ (k+1)%3 ] != st2)
444 // this is the next part of the fan
446 // if we can't use this triangle, this tristrip is done
451 m2 = check->index_xyz[ (k+2)%3 ];
452 st2 = check->index_st[ (k+2)%3 ];
454 strip_xyz[stripcount+2] = m2;
455 strip_st[stripcount+2] = st2;
456 strip_tris[stripcount] = j;
465 // clear the temp used flags
466 for (j=starttri+1 ; j<model.num_tris ; j++)
479 Generate a list of trifans or strips
480 for the model, which holds for all frames
483 void BuildGlCmds (void)
488 int len, bestlen, besttype;
499 memset (used, 0, sizeof(used));
500 for (i=0 ; i<model.num_tris ; i++)
502 // pick an unused triangle and start the trifan
507 for (type = 0 ; type < 2 ; type++)
510 for (startv =0 ; startv < 3 ; startv++)
513 len = StripLength (i, startv);
515 len = FanLength (i, startv);
520 for (j=0 ; j<bestlen+2 ; j++)
522 best_st[j] = strip_st[j];
523 best_xyz[j] = strip_xyz[j];
525 for (j=0 ; j<bestlen ; j++)
526 best_tris[j] = strip_tris[j];
531 // mark the tris on the best strip/fan as used
532 for (j=0 ; j<bestlen ; j++)
533 used[best_tris[j]] = 1;
536 commands[numcommands++] = (bestlen+2);
538 commands[numcommands++] = -(bestlen+2);
540 numglverts += bestlen+2;
542 for (j=0 ; j<bestlen+2 ; j++)
544 // emit a vertex into the reorder buffer
547 // emit s/t coords into the commands stream
551 s = (s + 0.5) / model.skinwidth;
552 t = (t + 0.5) / model.skinheight;
554 *(float *)&commands[numcommands++] = s;
555 *(float *)&commands[numcommands++] = t;
556 *(int *)&commands[numcommands++] = best_xyz[j];
560 commands[numcommands++] = 0; // end of list marker
565 ===============================================================
569 ===============================================================
576 Builds the triangle_st array for the base frame and
577 model.skinwidth / model.skinheight
579 FIXME: allow this to be loaded from a file for
583 void BuildST (triangle_t *ptri, int numtri)
586 int width, height, iwidth, iheight, swidth;
588 float s_scale, t_scale;
592 vec3_t vtemp1, vtemp2, normal;
595 // find bounds of all the verts on the base frame
597 ClearBounds (mins, maxs);
599 for (i=0 ; i<numtri ; i++)
600 for (j=0 ; j<3 ; j++)
601 AddPointToBounds (ptri[i].verts[j], mins, maxs);
603 for (i=0 ; i<3 ; i++)
605 mins[i] = floor(mins[i]);
606 maxs[i] = ceil(maxs[i]);
609 width = maxs[0] - mins[0];
610 height = maxs[2] - mins[2];
615 if (width*scale >= 150)
616 scale = 150.0 / width;
617 if (height*scale >= 190)
618 scale = 190.0 / height;
620 s_scale = t_scale = scale;
622 iwidth = ceil(width*s_scale);
623 iheight = ceil(height*t_scale);
630 iwidth = g_fixedwidth / 2;
631 iheight = g_fixedheight;
633 s_scale = (float)(iwidth-4) / width;
634 t_scale = (float)(iheight-4) / height;
638 // determine which side of each triangle to map the texture to
640 for (i=0 ; i<numtri ; i++)
642 VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);
643 VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);
644 CrossProduct (vtemp1, vtemp2, normal);
656 for (j=0 ; j<3 ; j++)
658 pbasevert = ptri[i].verts[j];
660 triangle_st[i][j][0] = Q_rint((pbasevert[0] - mins[0]) * s_scale + basex);
661 triangle_st[i][j][1] = Q_rint((maxs[2] - pbasevert[2]) * t_scale + basey);
665 // make the width a multiple of 4; some hardware requires this, and it ensures
666 // dword alignment for each scan
668 model.skinwidth = (swidth + 3) & ~3;
669 model.skinheight = iheight;
687 if (g_skipmodel || g_release || g_archive)
690 printf ("---------------------\n");
691 sprintf (file1, "%s/%s.%s", cdarchive, token, trifileext);
692 printf ("%s\n", file1);
694 ExpandPathAndArchive (file1);
696 sprintf (file1, "%s/%s.%s", cddir, token, trifileext);
698 time1 = FileTime (file1);
700 Error ("%s doesn't exist", file1);
703 // load the base triangles
706 Load3DSTriangleList (file1, &ptri, &model.num_tris);
708 LoadTriangleList (file1, &ptri, &model.num_tris);
713 BuildST (ptri, model.num_tris);
716 // run through all the base triangles, storing each unique vertex in the
717 // base vertex list and setting the indirect triangles to point to the base
720 for (i=0 ; i<model.num_tris ; i++)
722 for (j=0 ; j<3 ; j++)
725 for (k=0 ; k<model.num_xyz ; k++)
726 if (VectorCompare (ptri[i].verts[j], base_xyz[k]))
727 break; // this vertex is already in the base vertex list
729 if (k == model.num_xyz)
731 VectorCopy (ptri[i].verts[j], base_xyz[model.num_xyz]);
735 triangles[i].index_xyz[j] = k;
738 for (k=0 ; k<model.num_st ; k++)
739 if (triangle_st[i][j][0] == base_st[k].s
740 && triangle_st[i][j][1] == base_st[k].t)
741 break; // this vertex is already in the base vertex list
743 if (k == model.num_st)
745 base_st[model.num_st].s = triangle_st[i][j][0];
746 base_st[model.num_st].t = triangle_st[i][j][1];
750 triangles[i].index_st[j] = k;
754 // build triangle strips / fans
758 //===============================================================
760 char *FindFrameFile (char *frame)
764 static char retname[1024];
769 if (strstr (frame, "."))
770 return frame; // allready in dot format
772 // split 'run1' into 'run' and '1'
773 s = frame + strlen(frame)-1;
775 while (s != frame && *s >= '0' && *s <= '9')
778 strcpy (suffix, s+1);
779 strcpy (base, frame);
782 // check for 'run1.tri'
783 sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, trifileext);
784 time1 = FileTime (file1);
787 sprintf (retname, "%s%s.%s", base, suffix, trifileext);
792 sprintf (file1, "%s/%s.%s",cddir, base, suffix);
793 time1 = FileTime (file1);
796 sprintf (retname, "%s.%s", base, suffix);
800 Error ("frame %s could not be found",frame);
809 void GrabFrame (char *frame)
817 vertexnormals_t vnorms[MAX_VERTS];
821 // the frame 'run1' will be looked for as either
822 // run.1 or run1.tri, so the new alias sequence save
823 // feature an be used
824 framefile = FindFrameFile (frame);
826 sprintf (file1, "%s/%s", cdarchive, framefile);
827 ExpandPathAndArchive (file1);
829 sprintf (file1, "%s/%s",cddir, framefile);
831 printf ("grabbing %s\n", file1);
833 if (model.num_frames >= MAX_FRAMES)
834 Error ("model.num_frames >= MAX_FRAMES");
835 fr = &g_frames[model.num_frames];
838 strcpy (fr->name, frame);
844 Load3DSTriangleList (file1, &ptri, &num_tris);
846 LoadTriangleList (file1, &ptri, &num_tris);
848 if (num_tris != model.num_tris)
849 Error ("%s: number of triangles doesn't match base frame\n", file1);
852 // allocate storage for the frame's vertices
856 for (i=0 ; i<model.num_xyz ; i++)
858 vnorms[i].numnormals = 0;
859 VectorClear (vnorms[i].normalsum);
861 ClearBounds (fr->mins, fr->maxs);
864 // store the frame's vertices in the same order as the base. This assumes the
865 // triangles and vertices in this frame are in exactly the same order as in the
868 for (i=0 ; i<num_tris ; i++)
870 vec3_t vtemp1, vtemp2, normal;
873 VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);
874 VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);
875 CrossProduct (vtemp1, vtemp2, normal);
877 VectorNormalize (normal, normal);
879 // rotate the normal so the model faces down the positive x axis
881 normal[0] = -normal[1];
884 for (j=0 ; j<3 ; j++)
886 index_xyz = triangles[i].index_xyz[j];
888 // rotate the vertices so the model faces down the positive x axis
889 // also adjust the vertices to the desired origin
890 ptrivert[index_xyz].v[0] = ((-ptri[i].verts[j][1]) * scale_up) +
892 ptrivert[index_xyz].v[1] = (ptri[i].verts[j][0] * scale_up) +
894 ptrivert[index_xyz].v[2] = (ptri[i].verts[j][2] * scale_up) +
897 AddPointToBounds (ptrivert[index_xyz].v, fr->mins, fr->maxs);
899 VectorAdd (vnorms[index_xyz].normalsum, normal, vnorms[index_xyz].normalsum);
900 vnorms[index_xyz].numnormals++;
905 // calculate the vertex normals, match them to the template list, and store the
906 // index of the best match
908 for (i=0 ; i<model.num_xyz ; i++)
916 c = vnorms[i].numnormals;
918 Error ("Vertex with no triangles attached");
920 VectorScale (vnorms[i].normalsum, 1.0/c, v);
921 VectorNormalize (v, v);
926 for (j=0 ; j<NUMVERTEXNORMALS ; j++)
930 dot = DotProduct (v, avertexnormals[j]);
938 ptrivert[i].lightnormalindex = maxdotindex;
949 void Cmd_Frame (void)
951 while (TokenAvailable())
956 if (g_release || g_archive)
958 model.num_frames = 1; // don't skip the writeout
962 H_printf("#define FRAME_%-16s\t%i\n", token, model.num_frames);
973 Skins aren't actually stored in the file, only a reference
974 is saved out to the header file.
984 char name[1024], savename[1024];
988 if (model.num_skins == MAX_MD2SKINS)
989 Error ("model.num_skins == MAX_MD2SKINS");
994 sprintf (name, "%s/%s.lbm", cdarchive, token);
995 strcpy (name, ExpandPathAndArchive( name ) );
996 // sprintf (name, "%s/%s.lbm", cddir, token);
998 if (TokenAvailable())
1001 sprintf (g_skins[model.num_skins], "%s.pcx", token);
1002 sprintf (savename, "%s%s.pcx", gamedir, g_skins[model.num_skins]);
1006 sprintf (savename, "%s/%s.pcx", cddir, token);
1007 sprintf (g_skins[model.num_skins], "%s/%s.pcx", cdpartial, token);
1012 if (g_skipmodel || g_release || g_archive)
1016 printf ("loading %s\n", name);
1017 Load256Image (name, &pixels, &palette, &width, &height);
1018 RemapZero (pixels, palette, width, height);
1020 // crop it to the proper size
1021 cropped = malloc (model.skinwidth*model.skinheight);
1022 for (y=0 ; y<model.skinheight ; y++)
1024 memcpy (cropped+y*model.skinwidth,
1025 pixels+y*width, model.skinwidth);
1028 // save off the new image
1029 printf ("saving %s\n", savename);
1030 CreatePath (savename);
1031 WritePCXfile (savename, cropped, model.skinwidth,
1032 model.skinheight, palette);
1045 void Cmd_Origin (void)
1047 // rotate points into frame of reference so model points down the
1050 adjust[1] = -atof (token);
1053 adjust[0] = atof (token);
1056 adjust[2] = -atof (token);
1065 void Cmd_ScaleUp (void)
1068 scale_up = atof (token);
1069 if (g_skipmodel || g_release || g_archive)
1072 printf ("Scale up: %f\n", scale_up);
1080 Set a skin size other than the default
1083 void Cmd_Skinsize (void)
1086 g_fixedwidth = atoi(token);
1088 g_fixedheight = atoi(token);
1095 Gives a different name/location for the file, instead of the cddir
1098 void Cmd_Modelname (void)
1101 strcpy (modelname, token);
1116 // this is a silly mess...
1117 sprintf (cdpartial, "models/%s", token);
1118 sprintf (cdarchive, "%smodels/%s", gamedir+strlen(qdir), token);
1119 sprintf (cddir, "%s%s", gamedir, cdpartial);
1121 // if -only was specified and this cd doesn't match,
1122 // skip the model (you only need to match leading chars,
1123 // so you could regrab all monsters with -only monsters)
1126 if (strncmp(token, g_only, strlen(g_only)))
1129 printf ("skipping %s\n", cdpartial);