3
md3 *loadingmd3 = NULL;
31
int numframes, numtags, nummeshes, numskins;
32
int ofs_frames, ofs_tags, ofs_meshes, ofs_eof; // offsets
40
int numframes, numshaders, numvertices, numtriangles;
41
int ofs_triangles, ofs_shaders, ofs_uv, ofs_vertices, meshsize; // offsets
44
struct md3 : vertmodel
46
md3(const char *name) : vertmodel(name) {}
48
int type() { return MDL_MD3; }
54
if(filename) return true;
56
FILE *f = openfile(path, "rb");
59
fread(&header, sizeof(md3header), 1, f);
60
endianswap(&header.version, sizeof(int), 1);
61
endianswap(&header.flags, sizeof(int), 9);
62
if(strncmp(header.id, "IDP3", 4) != 0 || header.version != 15) // header check
65
conoutf("md3: corrupted header");
69
numframes = header.numframes;
70
numtags = header.numtags;
73
tags = new tag[numframes*numtags];
74
fseek(f, header.ofs_tags, SEEK_SET);
77
loopi(header.numframes*header.numtags)
79
fread(&tag, sizeof(md3tag), 1, f);
80
endianswap(&tag.pos, sizeof(float), 12);
81
if(tag.name[0] && i<header.numtags) tags[i].name = newstring(tag.name);
82
tags[i].pos = vec(tag.pos.y, tag.pos.x, tag.pos.z);
83
memcpy(tags[i].transform, tag.rotation, sizeof(tag.rotation));
85
loopj(3) swap(tags[i].transform[0][j], tags[i].transform[1][j]);
87
loopj(3) swap(tags[i].transform[j][0], tags[i].transform[j][1]);
89
links = new linkedpart[numtags];
92
int mesh_offset = header.ofs_meshes;
93
loopi(header.nummeshes)
95
md3meshheader mheader;
96
fseek(f, mesh_offset, SEEK_SET);
97
fread(&mheader, sizeof(md3meshheader), 1, f);
98
endianswap(&mheader.flags, sizeof(int), 10);
100
if(mheader.numtriangles <= 0)
102
mesh_offset += mheader.meshsize;
106
mesh &m = *meshes.add(new mesh);
108
m.name = newstring(mheader.name);
110
m.numtris = mheader.numtriangles;
111
m.tris = new tri[m.numtris];
112
fseek(f, mesh_offset + mheader.ofs_triangles, SEEK_SET);
113
loopj(mheader.numtriangles)
116
fread(&tri, sizeof(md3triangle), 1, f); // read the triangles
117
endianswap(&tri, sizeof(int), 3);
118
loopk(3) m.tris[j].vert[k] = (ushort)tri.vertexindices[k];
121
m.numverts = mheader.numvertices;
122
m.tcverts = new tcvert[m.numverts];
123
fseek(f, mesh_offset + mheader.ofs_uv , SEEK_SET);
124
fread(m.tcverts, 2*sizeof(float), m.numverts, f); // read the UV data
125
endianswap(m.tcverts, sizeof(float), 2*m.numverts);
127
m.verts = new vec[numframes*m.numverts + 1];
128
fseek(f, mesh_offset + mheader.ofs_vertices, SEEK_SET);
129
loopj(numframes*mheader.numvertices)
132
fread(&v, sizeof(md3vertex), 1, f); // read the vertices
133
endianswap(&v, sizeof(short), 4);
135
m.verts[j].x = v.vertex[1]/64.0f;
136
m.verts[j].y = v.vertex[0]/64.0f;
137
m.verts[j].z = v.vertex[2]/64.0f;
140
mesh_offset += mheader.meshsize;
144
filename = newstring(path);
148
void begingenshadow()
151
matrixstack[0].identity();
152
matrixstack[0].rotate_around_z(180*RAD);
156
void render(int anim, int varseed, float speed, int basetime, const vec &o, float yaw, float pitch, dynent *d, modelattach *a, float scale)
160
if(a) for(int i = 0; a[i].tag; i++)
162
vertmodel *m = (vertmodel *)a[i].m;
165
if(a[i].pos) link(NULL, a[i].tag);
168
part *p = m->parts[0];
169
if(link(p, a[i].tag, a[i].pos)) p->index = parts.length()+i;
172
if(!cullface) glDisable(GL_CULL_FACE);
173
else if(anim&ANIM_MIRROR) glCullFace(GL_BACK);
177
shadowdir = vec(0, 1/SQRT2, -1/SQRT2);
178
shadowdir.rotate_around_z((-shadowyaw-yaw-180.0f)*RAD);
179
shadowdir.rotate_around_y(-pitch*RAD);
180
(shadowpos = shadowdir).mul(shadowdist);
188
matrixstack[0].identity();
189
matrixstack[0].translate(o);
190
matrixstack[0].rotate_around_z((yaw+180)*RAD);
191
matrixstack[0].rotate_around_y(-pitch*RAD);
192
if(anim&ANIM_MIRROR || scale!=1) matrixstack[0].scale(scale, anim&ANIM_MIRROR ? -scale : scale, scale);
193
parts[0]->render(anim, varseed, speed, basetime, d);
195
if(!cullface) glEnable(GL_CULL_FACE);
196
else if(anim&ANIM_MIRROR) glCullFace(GL_FRONT);
198
if(a) for(int i = 0; a[i].tag; i++) link(NULL, a[i].tag);
200
if(d) d->lastrendered = lastmillis;
203
void rendershadow(int anim, int varseed, float speed, int basetime, const vec &o, float yaw, modelattach *a)
205
if(parts.length()>1) return;
206
parts[0]->rendershadow(anim, varseed, speed, basetime, o, yaw);
211
if(loaded) return true;
212
s_sprintf(md3dir)("packages/models/%s", loadname);
214
const char *pname = parentdir(loadname);
215
s_sprintfd(cfgname)("packages/models/%s/md3.cfg", loadname);
218
persistidents = false;
219
if(execfile(cfgname) && parts.length()) // configured md3, will call the md3* commands below
221
persistidents = true;
223
if(parts.empty()) return false;
224
loopv(parts) if(!parts[i]->filename) return false;
226
else // md3 without configuration, try default tris and skin
228
persistidents = false;
230
md3part &mdl = *new md3part;
234
s_sprintfd(name1)("packages/models/%s/tris.md3", loadname);
235
if(!mdl.load(path(name1)))
237
s_sprintf(name1)("packages/models/%s/tris.md3", pname); // try md3 in parent folder (vert sharing)
238
if(!mdl.load(path(name1))) return false;
241
loadskin(loadname, pname, skin);
242
loopv(mdl.meshes) mdl.meshes[i]->skin = skin;
243
if(skin==notexture) conoutf("could not load model skin for %s", name1);
245
loopv(parts) parts[i]->scaleverts(scale/16.0f, vec(translate.x, -translate.y, translate.z));
246
radius = calcradius();
247
if(shadowdist) calcneighbors();
249
return loaded = true;
253
void md3load(char *model)
255
if(!loadingmd3) { conoutf("not loading an md3"); return; };
256
s_sprintfd(filename)("%s/%s", md3dir, model);
257
md3::md3part &mdl = *new md3::md3part;
258
loadingmd3->parts.add(&mdl);
259
mdl.model = loadingmd3;
260
mdl.index = loadingmd3->parts.length()-1;
261
if(!mdl.load(path(filename))) conoutf("could not load %s", filename); // ignore failure
264
void md3skin(char *objname, char *skin)
266
if(!objname || !skin) return;
267
if(!loadingmd3 || loadingmd3->parts.empty()) { conoutf("not loading an md3"); return; };
268
md3::part &mdl = *loadingmd3->parts.last();
271
md3::mesh &m = *mdl.meshes[i];
272
if(!strcmp(objname, "*") || !strcmp(m.name, objname))
274
s_sprintfd(spath)("%s/%s", md3dir, skin);
275
m.skin = textureload(spath);
280
void md3anim(char *anim, char *startframe, char *range, char *speed)
282
if(!loadingmd3 || loadingmd3->parts.empty()) { conoutf("not loading an md3"); return; };
283
int num = findanim(anim);
284
if(num<0) { conoutf("could not find animation %s", anim); return; };
285
loadingmd3->parts.last()->setanim(num, atoi(startframe), atoi(range), atof(speed));
288
void md3link(char *parentno, char *childno, char *tagname)
290
if(!loadingmd3) { conoutf("not loading an md3"); return; };
291
int parent = ATOI(parentno), child = ATOI(childno);
292
if(!loadingmd3->parts.inrange(parent) || !loadingmd3->parts.inrange(child)) { conoutf("no models loaded to link"); return; }
293
if(!loadingmd3->parts[parent]->link(loadingmd3->parts[child], tagname)) conoutf("could not link model %s", loadingmd3->loadname);
296
void md3emit(char *tag, char *type, char *arg1, char *arg2)
298
if(!loadingmd3 || loadingmd3->parts.empty()) { conoutf("not loading an md3"); return; };
299
md3::part &mdl = *loadingmd3->parts.last();
300
if(!mdl.addemitter(tag, ATOI(type), ATOI(arg1), ATOI(arg2))) { conoutf("could not find tag %s", tag); return; }
303
COMMAND(md3load, ARG_1STR);
304
COMMAND(md3skin, ARG_2STR);
305
COMMAND(md3anim, ARG_4STR);
306
COMMAND(md3link, ARG_3STR);
307
COMMAND(md3emit, ARG_4STR);