1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153 |
- /*
- ===========================================================================
- Copyright (C) 1997-2006 Id Software, Inc.
- This file is part of Quake 2 Tools source code.
- Quake 2 Tools source code is free software; you can redistribute it
- and/or modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
- Quake 2 Tools source code is distributed in the hope that it will be
- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Quake 2 Tools source code; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- ===========================================================================
- */
- #include "qdata.h"
- //=================================================================
- typedef struct
- {
- int numnormals;
- vec3_t normalsum;
- } vertexnormals_t;
- typedef struct
- {
- vec3_t v;
- int lightnormalindex;
- } trivert_t;
- typedef struct
- {
- vec3_t mins, maxs;
- char name[16];
- trivert_t v[MAX_VERTS];
- } frame_t;
- //================================================================
- frame_t g_frames[MAX_FRAMES];
- dmdl_t model;
- float scale_up; // set by $scale
- vec3_t adjust; // set by $origin
- int g_fixedwidth, g_fixedheight; // set by $skinsize
- //
- // base frame info
- //
- vec3_t base_xyz[MAX_VERTS];
- dstvert_t base_st[MAX_VERTS];
- dtriangle_t triangles[MAX_TRIANGLES];
- int triangle_st[MAX_TRIANGLES][3][2];
- // the command list holds counts, s/t values, and xyz indexes
- // that are valid for every frame
- int commands[16384];
- int numcommands;
- int numglverts;
- int used[MAX_TRIANGLES];
- char g_skins[MAX_MD2SKINS][64];
- char cdarchive[1024];
- char cdpartial[1024];
- char cddir[1024];
- char modelname[64]; // empty unless $modelname issued (players)
- #define NUMVERTEXNORMALS 162
- float avertexnormals[NUMVERTEXNORMALS][3] = {
- #include "anorms.h"
- };
- FILE *headerouthandle = NULL;
- //==============================================================
- /*
- ===============
- ClearModel
- ===============
- */
- void ClearModel (void)
- {
- memset (&model, 0, sizeof(model));
- modelname[0] = 0;
- scale_up = 1.0;
- VectorCopy (vec3_origin, adjust);
- g_fixedwidth = g_fixedheight = 0;
- g_skipmodel = false;
- }
- void H_printf(char *fmt, ...)
- {
- va_list argptr;
- char name[1024];
- if (!headerouthandle)
- {
- sprintf (name, "%s/tris.h", cddir);
- headerouthandle = SafeOpenWrite (name);
- fprintf(headerouthandle, "// %s\n\n", cddir);
- fprintf(headerouthandle, "// This file generated by qdata - Do NOT Modify\n\n");
- }
- va_start (argptr, fmt);
- vfprintf (headerouthandle, fmt, argptr);
- va_end (argptr);
- }
- /*
- ============
- WriteModelFile
- ============
- */
- void WriteModelFile (FILE *modelouthandle)
- {
- int i;
- dmdl_t modeltemp;
- int j, k;
- frame_t *in;
- daliasframe_t *out;
- byte buffer[MAX_VERTS*4+128];
- float v;
- int c_on, c_off;
- model.ident = IDALIASHEADER;
- model.version = ALIAS_VERSION;
- model.framesize = (int)&((daliasframe_t *)0)->verts[model.num_xyz];
- model.num_glcmds = numcommands;
- model.ofs_skins = sizeof(dmdl_t);
- model.ofs_st = model.ofs_skins + model.num_skins * MAX_SKINNAME;
- model.ofs_tris = model.ofs_st + model.num_st*sizeof(dstvert_t);
- model.ofs_frames = model.ofs_tris + model.num_tris*sizeof(dtriangle_t);
- model.ofs_glcmds = model.ofs_frames + model.num_frames*model.framesize;
- model.ofs_end = model.ofs_glcmds + model.num_glcmds*4;
- //
- // write out the model header
- //
- for (i=0 ; i<sizeof(dmdl_t)/4 ; i++)
- ((int *)&modeltemp)[i] = LittleLong (((int *)&model)[i]);
- SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp));
- //
- // write out the skin names
- //
- SafeWrite (modelouthandle, g_skins, model.num_skins * MAX_SKINNAME);
- //
- // write out the texture coordinates
- //
- c_on = c_off = 0;
- for (i=0 ; i<model.num_st ; i++)
- {
- base_st[i].s = LittleShort (base_st[i].s);
- base_st[i].t = LittleShort (base_st[i].t);
- }
- SafeWrite (modelouthandle, base_st, model.num_st * sizeof(base_st[0]));
- //
- // write out the triangles
- //
- for (i=0 ; i<model.num_tris ; i++)
- {
- int j;
- dtriangle_t tri;
- for (j=0 ; j<3 ; j++)
- {
- tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]);
- tri.index_st[j] = LittleShort (triangles[i].index_st[j]);
- }
- SafeWrite (modelouthandle, &tri, sizeof(tri));
- }
- //
- // write out the frames
- //
- for (i=0 ; i<model.num_frames ; i++)
- {
- in = &g_frames[i];
- out = (daliasframe_t *)buffer;
- strcpy (out->name, in->name);
- for (j=0 ; j<3 ; j++)
- {
- out->scale[j] = (in->maxs[j] - in->mins[j])/255;
- out->translate[j] = in->mins[j];
- }
- for (j=0 ; j<model.num_xyz ; j++)
- {
- // all of these are byte values, so no need to deal with endianness
- out->verts[j].lightnormalindex = in->v[j].lightnormalindex;
- for (k=0 ; k<3 ; k++)
- {
- // scale to byte values & min/max check
- v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] );
- // clamp, so rounding doesn't wrap from 255.6 to 0
- if (v > 255.0)
- v = 255.0;
- if (v < 0)
- v = 0;
- out->verts[j].v[k] = v;
- }
- }
- for (j=0 ; j<3 ; j++)
- {
- out->scale[j] = LittleFloat (out->scale[j]);
- out->translate[j] = LittleFloat (out->translate[j]);
- }
- SafeWrite (modelouthandle, out, model.framesize);
- }
- //
- // write out glcmds
- //
- SafeWrite (modelouthandle, commands, numcommands*4);
- }
- /*
- ===============
- FinishModel
- ===============
- */
- void FinishModel (void)
- {
- FILE *modelouthandle;
- int i;
- char name[1024];
- if (!model.num_frames)
- return;
- //
- // copy to release directory tree if doing a release build
- //
- if (g_release)
- {
- if (modelname[0])
- sprintf (name, "%s", modelname);
- else
- sprintf (name, "%s/tris.md2", cdpartial);
- ReleaseFile (name);
- for (i=0 ; i<model.num_skins ; i++)
- {
- ReleaseFile (g_skins[i]);
- }
- model.num_frames = 0;
- return;
- }
- //
- // write the model output file
- //
- if (modelname[0])
- sprintf (name, "%s%s", gamedir, modelname);
- else
- sprintf (name, "%s/tris.md2", cddir);
- printf ("saving to %s\n", name);
- CreatePath (name);
- modelouthandle = SafeOpenWrite (name);
- WriteModelFile (modelouthandle);
- printf ("%3dx%3d skin\n", model.skinwidth, model.skinheight);
- printf ("%4d vertexes\n", model.num_xyz);
- printf ("%4d triangles\n", model.num_tris);
- printf ("%4d frame\n", model.num_frames);
- printf ("%4d glverts\n", numglverts);
- printf ("%4d glcmd\n", model.num_glcmds);
- printf ("%4d skins\n", model.num_skins);
- printf ("file size: %d\n", (int)ftell (modelouthandle) );
- printf ("---------------------\n");
- fclose (modelouthandle);
- // finish writing header file
- H_printf("\n");
- // scale_up is usefull to allow step distances to be adjusted
- H_printf("#define MODEL_SCALE\t\t%f\n", scale_up);
- fclose (headerouthandle);
- headerouthandle = NULL;
- }
- /*
- =================================================================
- ALIAS MODEL DISPLAY LIST GENERATION
- =================================================================
- */
- int strip_xyz[128];
- int strip_st[128];
- int strip_tris[128];
- int stripcount;
- /*
- ================
- StripLength
- ================
- */
- int StripLength (int starttri, int startv)
- {
- int m1, m2;
- int st1, st2;
- int j;
- dtriangle_t *last, *check;
- int k;
- used[starttri] = 2;
- last = &triangles[starttri];
- strip_xyz[0] = last->index_xyz[(startv)%3];
- strip_xyz[1] = last->index_xyz[(startv+1)%3];
- strip_xyz[2] = last->index_xyz[(startv+2)%3];
- strip_st[0] = last->index_st[(startv)%3];
- strip_st[1] = last->index_st[(startv+1)%3];
- strip_st[2] = last->index_st[(startv+2)%3];
- strip_tris[0] = starttri;
- stripcount = 1;
- m1 = last->index_xyz[(startv+2)%3];
- st1 = last->index_st[(startv+2)%3];
- m2 = last->index_xyz[(startv+1)%3];
- st2 = last->index_st[(startv+1)%3];
- // look for a matching triangle
- nexttri:
- for (j=starttri+1, check=&triangles[starttri+1]
- ; j<model.num_tris ; j++, check++)
- {
- for (k=0 ; k<3 ; k++)
- {
- if (check->index_xyz[k] != m1)
- continue;
- if (check->index_st[k] != st1)
- continue;
- if (check->index_xyz[ (k+1)%3 ] != m2)
- continue;
- if (check->index_st[ (k+1)%3 ] != st2)
- continue;
- // this is the next part of the fan
- // if we can't use this triangle, this tristrip is done
- if (used[j])
- goto done;
- // the new edge
- if (stripcount & 1)
- {
- m2 = check->index_xyz[ (k+2)%3 ];
- st2 = check->index_st[ (k+2)%3 ];
- }
- else
- {
- m1 = check->index_xyz[ (k+2)%3 ];
- st1 = check->index_st[ (k+2)%3 ];
- }
- strip_xyz[stripcount+2] = check->index_xyz[ (k+2)%3 ];
- strip_st[stripcount+2] = check->index_st[ (k+2)%3 ];
- strip_tris[stripcount] = j;
- stripcount++;
- used[j] = 2;
- goto nexttri;
- }
- }
- done:
- // clear the temp used flags
- for (j=starttri+1 ; j<model.num_tris ; j++)
- if (used[j] == 2)
- used[j] = 0;
- return stripcount;
- }
- /*
- ===========
- FanLength
- ===========
- */
- int FanLength (int starttri, int startv)
- {
- int m1, m2;
- int st1, st2;
- int j;
- dtriangle_t *last, *check;
- int k;
- used[starttri] = 2;
- last = &triangles[starttri];
- strip_xyz[0] = last->index_xyz[(startv)%3];
- strip_xyz[1] = last->index_xyz[(startv+1)%3];
- strip_xyz[2] = last->index_xyz[(startv+2)%3];
- strip_st[0] = last->index_st[(startv)%3];
- strip_st[1] = last->index_st[(startv+1)%3];
- strip_st[2] = last->index_st[(startv+2)%3];
- strip_tris[0] = starttri;
- stripcount = 1;
- m1 = last->index_xyz[(startv+0)%3];
- st1 = last->index_st[(startv+0)%3];
- m2 = last->index_xyz[(startv+2)%3];
- st2 = last->index_st[(startv+2)%3];
- // look for a matching triangle
- nexttri:
- for (j=starttri+1, check=&triangles[starttri+1]
- ; j<model.num_tris ; j++, check++)
- {
- for (k=0 ; k<3 ; k++)
- {
- if (check->index_xyz[k] != m1)
- continue;
- if (check->index_st[k] != st1)
- continue;
- if (check->index_xyz[ (k+1)%3 ] != m2)
- continue;
- if (check->index_st[ (k+1)%3 ] != st2)
- continue;
- // this is the next part of the fan
- // if we can't use this triangle, this tristrip is done
- if (used[j])
- goto done;
- // the new edge
- m2 = check->index_xyz[ (k+2)%3 ];
- st2 = check->index_st[ (k+2)%3 ];
- strip_xyz[stripcount+2] = m2;
- strip_st[stripcount+2] = st2;
- strip_tris[stripcount] = j;
- stripcount++;
- used[j] = 2;
- goto nexttri;
- }
- }
- done:
- // clear the temp used flags
- for (j=starttri+1 ; j<model.num_tris ; j++)
- if (used[j] == 2)
- used[j] = 0;
- return stripcount;
- }
- /*
- ================
- BuildGlCmds
- Generate a list of trifans or strips
- for the model, which holds for all frames
- ================
- */
- void BuildGlCmds (void)
- {
- int i, j, k;
- int startv;
- float s, t;
- int len, bestlen, besttype;
- int best_xyz[1024];
- int best_st[1024];
- int best_tris[1024];
- int type;
- //
- // build tristrips
- //
- numcommands = 0;
- numglverts = 0;
- memset (used, 0, sizeof(used));
- for (i=0 ; i<model.num_tris ; i++)
- {
- // pick an unused triangle and start the trifan
- if (used[i])
- continue;
- bestlen = 0;
- for (type = 0 ; type < 2 ; type++)
- // type = 1;
- {
- for (startv =0 ; startv < 3 ; startv++)
- {
- if (type == 1)
- len = StripLength (i, startv);
- else
- len = FanLength (i, startv);
- if (len > bestlen)
- {
- besttype = type;
- bestlen = len;
- for (j=0 ; j<bestlen+2 ; j++)
- {
- best_st[j] = strip_st[j];
- best_xyz[j] = strip_xyz[j];
- }
- for (j=0 ; j<bestlen ; j++)
- best_tris[j] = strip_tris[j];
- }
- }
- }
- // mark the tris on the best strip/fan as used
- for (j=0 ; j<bestlen ; j++)
- used[best_tris[j]] = 1;
- if (besttype == 1)
- commands[numcommands++] = (bestlen+2);
- else
- commands[numcommands++] = -(bestlen+2);
- numglverts += bestlen+2;
- for (j=0 ; j<bestlen+2 ; j++)
- {
- // emit a vertex into the reorder buffer
- k = best_st[j];
- // emit s/t coords into the commands stream
- s = base_st[k].s;
- t = base_st[k].t;
- s = (s + 0.5) / model.skinwidth;
- t = (t + 0.5) / model.skinheight;
- *(float *)&commands[numcommands++] = s;
- *(float *)&commands[numcommands++] = t;
- *(int *)&commands[numcommands++] = best_xyz[j];
- }
- }
- commands[numcommands++] = 0; // end of list marker
- }
- /*
- ===============================================================
- BASE FRAME SETUP
- ===============================================================
- */
- /*
- ============
- BuildST
- Builds the triangle_st array for the base frame and
- model.skinwidth / model.skinheight
- FIXME: allow this to be loaded from a file for
- arbitrary mappings
- ============
- */
- void BuildST (triangle_t *ptri, int numtri)
- {
- int i, j;
- int width, height, iwidth, iheight, swidth;
- float basex, basey;
- float s_scale, t_scale;
- float scale;
- vec3_t mins, maxs;
- float *pbasevert;
- vec3_t vtemp1, vtemp2, normal;
- //
- // find bounds of all the verts on the base frame
- //
- ClearBounds (mins, maxs);
- for (i=0 ; i<numtri ; i++)
- for (j=0 ; j<3 ; j++)
- AddPointToBounds (ptri[i].verts[j], mins, maxs);
- for (i=0 ; i<3 ; i++)
- {
- mins[i] = floor(mins[i]);
- maxs[i] = ceil(maxs[i]);
- }
- width = maxs[0] - mins[0];
- height = maxs[2] - mins[2];
- if (!g_fixedwidth)
- { // old style
- scale = 8;
- if (width*scale >= 150)
- scale = 150.0 / width;
- if (height*scale >= 190)
- scale = 190.0 / height;
- s_scale = t_scale = scale;
- iwidth = ceil(width*s_scale);
- iheight = ceil(height*t_scale);
- iwidth += 4;
- iheight += 4;
- }
- else
- { // new style
- iwidth = g_fixedwidth / 2;
- iheight = g_fixedheight;
- s_scale = (float)(iwidth-4) / width;
- t_scale = (float)(iheight-4) / height;
- }
- //
- // determine which side of each triangle to map the texture to
- //
- for (i=0 ; i<numtri ; i++)
- {
- VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);
- VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);
- CrossProduct (vtemp1, vtemp2, normal);
- if (normal[1] > 0)
- {
- basex = iwidth + 2;
- }
- else
- {
- basex = 2;
- }
- basey = 2;
- for (j=0 ; j<3 ; j++)
- {
- pbasevert = ptri[i].verts[j];
- triangle_st[i][j][0] = Q_rint((pbasevert[0] - mins[0]) * s_scale + basex);
- triangle_st[i][j][1] = Q_rint((maxs[2] - pbasevert[2]) * t_scale + basey);
- }
- }
- // make the width a multiple of 4; some hardware requires this, and it ensures
- // dword alignment for each scan
- swidth = iwidth*2;
- model.skinwidth = (swidth + 3) & ~3;
- model.skinheight = iheight;
- }
- /*
- =================
- Cmd_Base
- =================
- */
- void Cmd_Base (void)
- {
- triangle_t *ptri;
- int i, j, k;
- int time1;
- char file1[1024];
- GetToken (false);
- if (g_skipmodel || g_release || g_archive)
- return;
- printf ("---------------------\n");
- sprintf (file1, "%s/%s.%s", cdarchive, token, trifileext);
- printf ("%s\n", file1);
- ExpandPathAndArchive (file1);
- sprintf (file1, "%s/%s.%s", cddir, token, trifileext);
- time1 = FileTime (file1);
- if (time1 == -1)
- Error ("%s doesn't exist", file1);
- //
- // load the base triangles
- //
- if (do3ds)
- Load3DSTriangleList (file1, &ptri, &model.num_tris);
- else
- LoadTriangleList (file1, &ptri, &model.num_tris);
- //
- // get the ST values
- //
- BuildST (ptri, model.num_tris);
- //
- // run through all the base triangles, storing each unique vertex in the
- // base vertex list and setting the indirect triangles to point to the base
- // vertices
- //
- for (i=0 ; i<model.num_tris ; i++)
- {
- for (j=0 ; j<3 ; j++)
- {
- // get the xyz index
- for (k=0 ; k<model.num_xyz ; k++)
- if (VectorCompare (ptri[i].verts[j], base_xyz[k]))
- break; // this vertex is already in the base vertex list
- if (k == model.num_xyz)
- { // new index
- VectorCopy (ptri[i].verts[j], base_xyz[model.num_xyz]);
- model.num_xyz++;
- }
- triangles[i].index_xyz[j] = k;
- // get the st index
- for (k=0 ; k<model.num_st ; k++)
- if (triangle_st[i][j][0] == base_st[k].s
- && triangle_st[i][j][1] == base_st[k].t)
- break; // this vertex is already in the base vertex list
- if (k == model.num_st)
- { // new index
- base_st[model.num_st].s = triangle_st[i][j][0];
- base_st[model.num_st].t = triangle_st[i][j][1];
- model.num_st++;
- }
- triangles[i].index_st[j] = k;
- }
- }
- // build triangle strips / fans
- BuildGlCmds ();
- }
- //===============================================================
- char *FindFrameFile (char *frame)
- {
- int time1;
- char file1[1024];
- static char retname[1024];
- char base[32];
- char suffix[32];
- char *s;
- if (strstr (frame, "."))
- return frame; // allready in dot format
- // split 'run1' into 'run' and '1'
- s = frame + strlen(frame)-1;
- while (s != frame && *s >= '0' && *s <= '9')
- s--;
- strcpy (suffix, s+1);
- strcpy (base, frame);
- base[s-frame+1] = 0;
- // check for 'run1.tri'
- sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, trifileext);
- time1 = FileTime (file1);
- if (time1 != -1)
- {
- sprintf (retname, "%s%s.%s", base, suffix, trifileext);
- return retname;
- }
- // check for 'run.1'
- sprintf (file1, "%s/%s.%s",cddir, base, suffix);
- time1 = FileTime (file1);
- if (time1 != -1)
- {
- sprintf (retname, "%s.%s", base, suffix);
- return retname;
- }
- Error ("frame %s could not be found",frame);
- return NULL;
- }
- /*
- ===============
- GrabFrame
- ===============
- */
- void GrabFrame (char *frame)
- {
- triangle_t *ptri;
- int i, j;
- trivert_t *ptrivert;
- int num_tris;
- char file1[1024];
- frame_t *fr;
- vertexnormals_t vnorms[MAX_VERTS];
- int index_xyz;
- char *framefile;
- // the frame 'run1' will be looked for as either
- // run.1 or run1.tri, so the new alias sequence save
- // feature an be used
- framefile = FindFrameFile (frame);
- sprintf (file1, "%s/%s", cdarchive, framefile);
- ExpandPathAndArchive (file1);
- sprintf (file1, "%s/%s",cddir, framefile);
- printf ("grabbing %s\n", file1);
- if (model.num_frames >= MAX_FRAMES)
- Error ("model.num_frames >= MAX_FRAMES");
- fr = &g_frames[model.num_frames];
- model.num_frames++;
- strcpy (fr->name, frame);
- //
- // load the frame
- //
- if (do3ds)
- Load3DSTriangleList (file1, &ptri, &num_tris);
- else
- LoadTriangleList (file1, &ptri, &num_tris);
- if (num_tris != model.num_tris)
- Error ("%s: number of triangles doesn't match base frame\n", file1);
- //
- // allocate storage for the frame's vertices
- //
- ptrivert = fr->v;
- for (i=0 ; i<model.num_xyz ; i++)
- {
- vnorms[i].numnormals = 0;
- VectorClear (vnorms[i].normalsum);
- }
- ClearBounds (fr->mins, fr->maxs);
- //
- // store the frame's vertices in the same order as the base. This assumes the
- // triangles and vertices in this frame are in exactly the same order as in the
- // base
- //
- for (i=0 ; i<num_tris ; i++)
- {
- vec3_t vtemp1, vtemp2, normal;
- float ftemp;
- VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1);
- VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2);
- CrossProduct (vtemp1, vtemp2, normal);
- VectorNormalize (normal, normal);
- // rotate the normal so the model faces down the positive x axis
- ftemp = normal[0];
- normal[0] = -normal[1];
- normal[1] = ftemp;
- for (j=0 ; j<3 ; j++)
- {
- index_xyz = triangles[i].index_xyz[j];
- // rotate the vertices so the model faces down the positive x axis
- // also adjust the vertices to the desired origin
- ptrivert[index_xyz].v[0] = ((-ptri[i].verts[j][1]) * scale_up) +
- adjust[0];
- ptrivert[index_xyz].v[1] = (ptri[i].verts[j][0] * scale_up) +
- adjust[1];
- ptrivert[index_xyz].v[2] = (ptri[i].verts[j][2] * scale_up) +
- adjust[2];
- AddPointToBounds (ptrivert[index_xyz].v, fr->mins, fr->maxs);
- VectorAdd (vnorms[index_xyz].normalsum, normal, vnorms[index_xyz].normalsum);
- vnorms[index_xyz].numnormals++;
- }
- }
- //
- // calculate the vertex normals, match them to the template list, and store the
- // index of the best match
- //
- for (i=0 ; i<model.num_xyz ; i++)
- {
- int j;
- vec3_t v;
- float maxdot;
- int maxdotindex;
- int c;
- c = vnorms[i].numnormals;
- if (!c)
- Error ("Vertex with no triangles attached");
- VectorScale (vnorms[i].normalsum, 1.0/c, v);
- VectorNormalize (v, v);
- maxdot = -999999.0;
- maxdotindex = -1;
- for (j=0 ; j<NUMVERTEXNORMALS ; j++)
- {
- float dot;
- dot = DotProduct (v, avertexnormals[j]);
- if (dot > maxdot)
- {
- maxdot = dot;
- maxdotindex = j;
- }
- }
- ptrivert[i].lightnormalindex = maxdotindex;
- }
- free (ptri);
- }
- /*
- ===============
- Cmd_Frame
- ===============
- */
- void Cmd_Frame (void)
- {
- while (TokenAvailable())
- {
- GetToken (false);
- if (g_skipmodel)
- continue;
- if (g_release || g_archive)
- {
- model.num_frames = 1; // don't skip the writeout
- continue;
- }
- H_printf("#define FRAME_%-16s\t%i\n", token, model.num_frames);
- GrabFrame (token);
- }
- }
- /*
- ===============
- Cmd_Skin
- Skins aren't actually stored in the file, only a reference
- is saved out to the header file.
- ===============
- */
- void Cmd_Skin (void)
- {
- byte *palette;
- byte *pixels;
- int width, height;
- byte *cropped;
- int y;
- char name[1024], savename[1024];
- GetToken (false);
- if (model.num_skins == MAX_MD2SKINS)
- Error ("model.num_skins == MAX_MD2SKINS");
- if (g_skipmodel)
- return;
- sprintf (name, "%s/%s.lbm", cdarchive, token);
- strcpy (name, ExpandPathAndArchive( name ) );
- // sprintf (name, "%s/%s.lbm", cddir, token);
- if (TokenAvailable())
- {
- GetToken (false);
- sprintf (g_skins[model.num_skins], "%s.pcx", token);
- sprintf (savename, "%s%s.pcx", gamedir, g_skins[model.num_skins]);
- }
- else
- {
- sprintf (savename, "%s/%s.pcx", cddir, token);
- sprintf (g_skins[model.num_skins], "%s/%s.pcx", cdpartial, token);
- }
- model.num_skins++;
- if (g_skipmodel || g_release || g_archive)
- return;
- // load the image
- printf ("loading %s\n", name);
- Load256Image (name, &pixels, &palette, &width, &height);
- RemapZero (pixels, palette, width, height);
- // crop it to the proper size
- cropped = malloc (model.skinwidth*model.skinheight);
- for (y=0 ; y<model.skinheight ; y++)
- {
- memcpy (cropped+y*model.skinwidth,
- pixels+y*width, model.skinwidth);
- }
- // save off the new image
- printf ("saving %s\n", savename);
- CreatePath (savename);
- WritePCXfile (savename, cropped, model.skinwidth,
- model.skinheight, palette);
- free (pixels);
- free (palette);
- free (cropped);
- }
- /*
- =================
- Cmd_Origin
- =================
- */
- void Cmd_Origin (void)
- {
- // rotate points into frame of reference so model points down the
- // positive x axis
- GetToken (false);
- adjust[1] = -atof (token);
- GetToken (false);
- adjust[0] = atof (token);
- GetToken (false);
- adjust[2] = -atof (token);
- }
- /*
- =================
- Cmd_ScaleUp
- =================
- */
- void Cmd_ScaleUp (void)
- {
- GetToken (false);
- scale_up = atof (token);
- if (g_skipmodel || g_release || g_archive)
- return;
- printf ("Scale up: %f\n", scale_up);
- }
- /*
- =================
- Cmd_Skinsize
- Set a skin size other than the default
- =================
- */
- void Cmd_Skinsize (void)
- {
- GetToken (false);
- g_fixedwidth = atoi(token);
- GetToken (false);
- g_fixedheight = atoi(token);
- }
- /*
- =================
- Cmd_Modelname
- Gives a different name/location for the file, instead of the cddir
- =================
- */
- void Cmd_Modelname (void)
- {
- GetToken (false);
- strcpy (modelname, token);
- }
- /*
- ===============
- Cmd_Cd
- ===============
- */
- void Cmd_Cd (void)
- {
- FinishModel ();
- ClearModel ();
- GetToken (false);
- // this is a silly mess...
- sprintf (cdpartial, "models/%s", token);
- sprintf (cdarchive, "%smodels/%s", gamedir+strlen(qdir), token);
- sprintf (cddir, "%s%s", gamedir, cdpartial);
- // if -only was specified and this cd doesn't match,
- // skip the model (you only need to match leading chars,
- // so you could regrab all monsters with -only monsters)
- if (!g_only[0])
- return;
- if (strncmp(token, g_only, strlen(g_only)))
- {
- g_skipmodel = true;
- printf ("skipping %s\n", cdpartial);
- }
- }
|