11
int skinwidth, skinheight;
13
int numskins, numvertices, numtexcoords;
14
int numtriangles, numglcommands, numframes;
15
int offsetskins, offsettexcoords, offsettriangles;
16
int offsetframes, offsetglcommands, offsetend;
21
uchar vertex[3], normalindex;
31
md2(const char *name) : vertmodel(name) {}
33
int type() { return MDL_MD2; }
37
void gentcverts(int *glcommands, vector<tcvert> &tcverts, vector<ushort> &vindexes, vector<tri> &tris)
39
hashtable<ivec, int> tchash;
41
for(int *command = glcommands; (*command)!=0;)
43
int numvertex = *command++;
44
bool isfan = numvertex<0;
45
if(isfan) numvertex = -numvertex;
46
idxs.setsizenodelete(0);
49
union { int i; float f; } u, v;
52
int vindex = *command++;
53
ivec tckey(u.i, v.i, vindex);
54
int *idx = tchash.access(tckey);
58
*idx = tcverts.length();
59
tcvert &tc = tcverts.add();
62
vindexes.add((ushort)vindex);
72
t.vert[1] = idxs[i+1];
73
t.vert[2] = idxs[i+2];
75
else loopk(3) t.vert[k] = idxs[i&1 && k ? i+(1-(k-1))+1 : i+k];
82
if(filename) return true;
84
FILE *file = openfile(path, "rb");
85
if(!file) return false;
88
fread(&header, sizeof(md2_header), 1, file);
89
endianswap(&header, sizeof(int), sizeof(md2_header)/sizeof(int));
91
if(header.magic!=844121161 || header.version!=8)
97
numframes = header.numframes;
103
int *glcommands = new int[header.numglcommands];
104
fseek(file, header.offsetglcommands, SEEK_SET);
105
int numglcommands = (int)fread(glcommands, sizeof(int), header.numglcommands, file);
106
endianswap(glcommands, sizeof(int), numglcommands);
107
if(numglcommands < header.numglcommands) memset(&glcommands[numglcommands], 0, (header.numglcommands-numglcommands)*sizeof(int));
109
vector<tcvert> tcgen;
112
gentcverts(glcommands, tcgen, vgen, trigen);
115
m.numverts = tcgen.length();
116
m.tcverts = new tcvert[m.numverts];
117
memcpy(m.tcverts, tcgen.getbuf(), m.numverts*sizeof(tcvert));
118
m.numtris = trigen.length();
119
m.tris = new tri[m.numtris];
120
memcpy(m.tris, trigen.getbuf(), m.numtris*sizeof(tri));
122
m.verts = new vec[m.numverts*numframes+1];
124
md2_vertex *tmpverts = new md2_vertex[header.numvertices];
125
int frame_offset = header.offsetframes;
126
vec *curvert = m.verts;
127
loopi(header.numframes)
130
fseek(file, frame_offset, SEEK_SET);
131
fread(&frame, sizeof(md2_frame), 1, file);
132
endianswap(&frame, sizeof(float), 6);
134
fread(tmpverts, sizeof(md2_vertex), header.numvertices, file);
137
const md2_vertex &v = tmpverts[vgen[j]];
138
*curvert++ = vec(v.vertex[0]*frame.scale[0]+frame.translate[0],
139
-(v.vertex[1]*frame.scale[1]+frame.translate[1]),
140
v.vertex[2]*frame.scale[2]+frame.translate[2]);
142
frame_offset += header.framesize;
148
filename = newstring(path);
152
void getdefaultanim(animstate &as, int anim, int varseed)
154
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 21 23 24
155
// I R A P P P J L F S T W P CI CW CA CP CD D D D LD LD LD F
156
static int frame[] = { 0, 40, 46, 54, 58, 62, 66, 69, 72, 84, 95, 112,123,135,154,160,169,173,178,184,190,183,189,197, 0 };
157
static int range[] = { 40, 6, 8, 4, 4, 4, 3, 3, 12, 11, 17, 11, 12, 19, 6, 9, 4, 5, 6, 6, 8, 1, 1, 1, 7 };
158
static int animfr[] = { 0, 1, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 24 };
160
if((size_t)anim >= sizeof(animfr)/sizeof(animfr[0]))
166
int n = animfr[anim];
167
if(anim==ANIM_PAIN || anim==ANIM_DEATH || anim==ANIM_LYING_DEAD) n += uint(varseed)%3;
172
void begingenshadow()
175
matrixstack[0].identity();
176
matrixstack[0].rotate_around_z(180*RAD);
180
void render(int anim, int varseed, float speed, int basetime, const vec &o, float yaw, float pitch, dynent *d, modelattach *a, float scale)
184
if(a) for(int i = 0; a[i].tag; i++)
186
if(a[i].pos) link(NULL, a[i].tag, a[i].pos);
189
if(!cullface) glDisable(GL_CULL_FACE);
190
else if(anim&ANIM_MIRROR) glCullFace(GL_BACK);
192
if(stenciling && !parts[0]->index)
194
shadowdir = vec(0, 1/SQRT2, -1/SQRT2);
195
shadowdir.rotate_around_z((-shadowyaw-yaw-180.0f)*RAD);
196
shadowdir.rotate_around_y(-pitch*RAD);
197
(shadowpos = shadowdir).mul(shadowdist);
205
matrixstack[0].identity();
206
matrixstack[0].translate(o);
207
matrixstack[0].rotate_around_z((yaw+180)*RAD);
208
matrixstack[0].rotate_around_y(-pitch*RAD);
209
if(anim&ANIM_MIRROR || scale!=1) matrixstack[0].scale(scale, anim&ANIM_MIRROR ? -scale : scale, scale);
210
parts[0]->render(anim, varseed, speed, basetime, d);
212
if(!cullface) glEnable(GL_CULL_FACE);
213
else if(anim&ANIM_MIRROR) glCullFace(GL_FRONT);
215
if(a) for(int i = 0; a[i].tag; i++)
217
if(a[i].pos) link(NULL, a[i].tag, NULL);
219
vertmodel *m = (vertmodel *)a[i].m;
221
m->parts[0]->index = parts.length()+i;
223
m->render(anim, varseed, speed, basetime, o, yaw, pitch, d, NULL, scale);
226
if(d) d->lastrendered = lastmillis;
229
void rendershadow(int anim, int varseed, float speed, int basetime, const vec &o, float yaw, modelattach *a)
231
parts[0]->rendershadow(anim, varseed, speed, basetime, o, yaw);
232
if(a) for(int i = 0; a[i].tag; i++)
234
vertmodel *m = (vertmodel *)a[i].m;
236
part *p = m->parts[0];
237
p->rendershadow(anim, varseed, speed, basetime, o, yaw);
243
if(loaded) return true;
244
md2part &mdl = *new md2part;
248
const char *pname = parentdir(loadname);
249
s_sprintfd(name1)("packages/models/%s/tris.md2", loadname);
250
if(!mdl.load(path(name1)))
252
s_sprintf(name1)("packages/models/%s/tris.md2", pname); // try md2 in parent folder (vert sharing)
253
if(!mdl.load(path(name1))) return false;
256
loadskin(loadname, pname, skin);
257
loopv(mdl.meshes) mdl.meshes[i]->skin = skin;
258
if(skin==notexture) conoutf("could not load model skin for %s", name1);
260
s_sprintfd(name2)("packages/models/%s/md2.cfg", loadname);
261
persistidents = false;
264
s_sprintf(name2)("packages/models/%s/md2.cfg", pname);
267
persistidents = true;
269
loopv(parts) parts[i]->scaleverts(scale/16.0f, vec(translate.x, -translate.y, translate.z));
270
radius = calcradius();
271
if(shadowdist) calcneighbors();
273
return loaded = true;
277
void md2anim(char *anim, char *frame, char *range, char *speed)
279
if(!loadingmd2 || loadingmd2->parts.empty()) { conoutf("not loading an md2"); return; }
280
int num = findanim(anim);
281
if(num<0) { conoutf("could not find animation %s", anim); return; }
282
loadingmd2->parts.last()->setanim(num, atoi(frame), atoi(range), atof(speed));
285
void md2tag(char *name, char *vert1, char *vert2, char *vert3, char *vert4)
287
if(!loadingmd2 || loadingmd2->parts.empty()) { conoutf("not loading an md2"); return; }
288
md2::part &mdl = *loadingmd2->parts.last();
289
int indexes[4] = { -1, -1, -1, -1 }, numverts = 0;
295
case 0: vert = vert1; break;
296
case 1: vert = vert2; break;
297
case 2: vert = vert3; break;
298
case 3: vert = vert4; break;
301
if(isdigit(vert[0])) indexes[i] = ATOI(vert);
304
int axis = 0, dir = 1;
305
for(char *s = vert; *s; s++) switch(*s)
307
case '+': dir = 1; break;
308
case '-': dir = -1; break;
310
case 'X': axis = 0; break;
312
case 'Y': axis = 1; break;
314
case 'Z': axis = 2; break;
316
if(!mdl.meshes.empty()) indexes[i] = mdl.meshes[0]->findvert(axis, dir);
318
if(indexes[i] < 0) { conoutf("could not find vertex %s", vert); return; }
321
if(!mdl.gentag(name, indexes, numverts)) { conoutf("could not generate tag %s", name); return; }
324
void md2emit(char *tag, char *type, char *arg1, char *arg2)
326
if(!loadingmd2 || loadingmd2->parts.empty()) { conoutf("not loading an md2"); return; };
327
md2::part &mdl = *loadingmd2->parts.last();
328
if(!mdl.addemitter(tag, ATOI(type), ATOI(arg1), ATOI(arg2))) { conoutf("could not find tag %s", tag); return; }
331
COMMAND(md2anim, ARG_4STR);
332
COMMAND(md2tag, ARG_5STR);
333
COMMAND(md2emit, ARG_4STR);