Inexor
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
md5.hpp
Go to the documentation of this file.
1 #pragma once
3 
4 struct md5joint
5 {
8 };
9 
10 struct md5weight
11 {
12  int joint;
13  float bias;
15 };
16 
17 struct md5vert
18 {
21 };
22 
24 {
25  string name;
27 };
28 
29 struct md5 : skelmodel, skelloader<md5>
30 {
31  md5(const char *name) : skelmodel(name) {}
32 
33  static const char *formatname() { return "md5"; }
34  int type() const override { return MDL_MD5; }
35 
36  struct md5mesh : skelmesh
37  {
41 
42  md5mesh() : weightinfo(nullptr), numweights(0), vertinfo(nullptr)
43  {
44  }
45 
46  ~md5mesh() override
47  {
48  cleanup();
49  }
50 
51  void cleanup()
52  {
55  }
56 
58  {
60  {
61  md5vert &v = vertinfo[i];
62  vec pos(0, 0, 0);
63  loopk(v.count)
64  {
65  md5weight &w = weightinfo[v.start+k];
66  md5joint &j = joints[w.joint];
67  vec wpos = j.orient.rotate(w.pos);
68  wpos.add(j.pos);
69  wpos.mul(w.bias);
70  pos.add(wpos);
71  }
72  vert &vv = verts[i];
73  vv.pos = pos;
74  vv.tc = v.tc;
75 
76  blendcombo c;
77  int sorted = 0;
78  loopj(v.count)
79  {
80  md5weight &w = weightinfo[v.start+j];
81  sorted = c.addweight(sorted, w.bias, w.joint);
82  }
83  c.finalize(sorted);
84  vv.blend = addblendcombo(c);
85  }
86  }
87 
88  void load(stream *f, char *buf, size_t bufsize)
89  {
90  md5weight w;
91  md5vert v;
92  tri t;
93  int index;
94 
95  while(f->getline(buf, bufsize) && buf[0]!='}')
96  {
97  if(strstr(buf, "// meshes:"))
98  {
99  char *start = strchr(buf, ':')+1;
100  if(*start==' ') start++;
101  char *end = start + strlen(start)-1;
102  while(end >= start && isspace(*end)) end--;
103  name = newstring(start, end+1-start);
104  }
105  else if(strstr(buf, "shader"))
106  {
107  char *start = strchr(buf, '"'), *end = start ? strchr(start+1, '"') : nullptr;
108  if(start && end)
109  {
110  char *texname = newstring(start+1, end-(start+1));
111  part *p = loading->parts.last();
112  p->initskins(notexture, notexture, group->meshes.length());
113  skin &s = p->skins.last();
114  s.tex = textureload(makerelpath(dir, texname), 0, true, false);
115  delete[] texname;
116  }
117  }
118  else if(sscanf(buf, " numverts %d", &numverts)==1)
119  {
120  numverts = max(numverts, 0);
121  if(numverts)
122  {
123  vertinfo = new md5vert[numverts];
124  verts = new vert[numverts];
125  }
126  }
127  else if(sscanf(buf, " numtris %d", &numtris)==1)
128  {
129  numtris = max(numtris, 0);
130  if(numtris) tris = new tri[numtris];
131  }
132  else if(sscanf(buf, " numweights %d", &numweights)==1)
133  {
134  numweights = max(numweights, 0);
136  }
137  else if(sscanf(buf, " vert %d ( %f %f ) %hu %hu", &index, &v.tc.x, &v.tc.y, &v.start, &v.count)==5)
138  {
139  if(index>=0 && index<numverts) vertinfo[index] = v;
140  }
141  else if(sscanf(buf, " tri %d %hu %hu %hu", &index, &t.vert[0], &t.vert[1], &t.vert[2])==4)
142  {
143  if(index>=0 && index<numtris) tris[index] = t;
144  }
145  else if(sscanf(buf, " weight %d %d %f ( %f %f %f ) ", &index, &w.joint, &w.bias, &w.pos.x, &w.pos.y, &w.pos.z)==6)
146  {
147  w.pos.y = -w.pos.y;
148  if(index>=0 && index<numweights) weightinfo[index] = w;
149  }
150  }
151  }
152  };
153 
154  struct md5meshgroup : skelmeshgroup
155  {
157  {
158  }
159 
160  bool loadmesh(const char *filename, float smooth)
161  {
162  stream *f = openfile(filename, "r");
163  if(!f) return false;
164 
165  char buf[512];
166  vector<md5joint> basejoints;
167  while(f->getline(buf, sizeof(buf)))
168  {
169  int tmp;
170  if(sscanf(buf, " MD5Version %d", &tmp)==1)
171  {
172  if(tmp!=10) { delete f; return false; }
173  }
174  else if(sscanf(buf, " numJoints %d", &tmp)==1)
175  {
176  if(tmp<1) { delete f; return false; }
177  if(skel->numbones>0) continue;
178  skel->numbones = tmp;
179  skel->bones = new boneinfo[skel->numbones];
180  }
181  else if(sscanf(buf, " numMeshes %d", &tmp)==1)
182  {
183  if(tmp<1) { delete f; return false; }
184  }
185  else if(strstr(buf, "joints {"))
186  {
187  string name;
188  int parent;
189  md5joint j;
190  while(f->getline(buf, sizeof(buf)) && buf[0]!='}')
191  {
192  char *curbuf = buf, *curname = name;
193  bool allowspace = false;
194  while(*curbuf && isspace(*curbuf)) curbuf++;
195  if(*curbuf == '"') { curbuf++; allowspace = true; }
196  while(*curbuf && curname < &name[sizeof(name)-1])
197  {
198  char c = *curbuf++;
199  if(c == '"') break;
200  if(isspace(c) && !allowspace) break;
201  *curname++ = c;
202  }
203  *curname = '\0';
204  if(sscanf(curbuf, " %d ( %f %f %f ) ( %f %f %f )",
205  &parent, &j.pos.x, &j.pos.y, &j.pos.z,
206  &j.orient.x, &j.orient.y, &j.orient.z)==7)
207  {
208  j.pos.y = -j.pos.y;
209  j.orient.x = -j.orient.x;
210  j.orient.z = -j.orient.z;
211  if(basejoints.length()<skel->numbones)
212  {
213  if(!skel->bones[basejoints.length()].name)
214  skel->bones[basejoints.length()].name = newstring(name);
215  skel->bones[basejoints.length()].parent = parent;
216  }
217  j.orient.restorew();
218  basejoints.add(j);
219  }
220  }
221  if(basejoints.length()!=skel->numbones) { delete f; return false; }
222  }
223  else if(strstr(buf, "mesh {"))
224  {
225  md5mesh *m = new md5mesh;
226  m->group = this;
227  meshes.add(m);
228  m->load(f, buf, sizeof(buf));
229  if(!m->numtris || !m->numverts)
230  {
231  Log.std->info("empty mesh in {}", filename);
232  meshes.removeobj(m);
233  delete m;
234  }
235  }
236  }
237 
238  if(skel->shared <= 1)
239  {
240  skel->linkchildren();
241  loopv(basejoints)
242  {
243  boneinfo &b = skel->bones[i];
244  b.base = dualquat(basejoints[i].orient, basejoints[i].pos);
245  (b.invbase = b.base).invert();
246  }
247  }
248 
249  loopv(meshes)
250  {
251  md5mesh &m = *(md5mesh *)meshes[i];
252  m.buildverts(basejoints);
253  if(smooth <= 1) m.smoothnorms(smooth);
254  else m.buildnorms();
255  m.cleanup();
256  }
257 
258  sortblendcombos();
259 
260  delete f;
261  return true;
262  }
263 
264  skelanimspec *loadanim(const char *filename) override
265  {
266  skelanimspec *sa = skel->findskelanim(filename);
267  if(sa) return sa;
268 
269  stream *f = openfile(filename, "r");
270  if(!f) return nullptr;
271 
272  vector<md5hierarchy> hierarchy;
273  vector<md5joint> basejoints;
274  int animdatalen = 0, animframes = 0;
275  float *animdata = nullptr;
276  dualquat *animbones = nullptr;
277  char buf[512];
278  while(f->getline(buf, sizeof(buf)))
279  {
280  int tmp;
281  if(sscanf(buf, " MD5Version %d", &tmp)==1)
282  {
283  if(tmp!=10) { delete f; return nullptr; }
284  }
285  else if(sscanf(buf, " numJoints %d", &tmp)==1)
286  {
287  if(tmp!=skel->numbones) { delete f; return nullptr; }
288  }
289  else if(sscanf(buf, " numFrames %d", &animframes)==1)
290  {
291  if(animframes<1) { delete f; return nullptr; }
292  }
293  else if(sscanf(buf, " frameRate %d", &tmp)==1);
294  else if(sscanf(buf, " numAnimatedComponents %d", &animdatalen)==1)
295  {
296  if(animdatalen>0) animdata = new float[animdatalen];
297  }
298  else if(strstr(buf, "bounds {"))
299  {
300  while(f->getline(buf, sizeof(buf)) && buf[0]!='}');
301  }
302  else if(strstr(buf, "hierarchy {"))
303  {
304  while(f->getline(buf, sizeof(buf)) && buf[0]!='}')
305  {
306  md5hierarchy h;
307  if(sscanf(buf, " %100s %d %d %d", h.name, &h.parent, &h.flags, &h.start)==4)
308  hierarchy.add(h);
309  }
310  }
311  else if(strstr(buf, "baseframe {"))
312  {
313  while(f->getline(buf, sizeof(buf)) && buf[0]!='}')
314  {
315  md5joint j;
316  if(sscanf(buf, " ( %f %f %f ) ( %f %f %f )", &j.pos.x, &j.pos.y, &j.pos.z, &j.orient.x, &j.orient.y, &j.orient.z)==6)
317  {
318  j.pos.y = -j.pos.y;
319  j.orient.x = -j.orient.x;
320  j.orient.z = -j.orient.z;
321  j.orient.restorew();
322  basejoints.add(j);
323  }
324  }
325  if(basejoints.length()!=skel->numbones) { delete f; if(animdata) delete[] animdata; return nullptr; }
326  animbones = new dualquat[(skel->numframes+animframes)*skel->numbones];
327  if(skel->framebones)
328  {
329  memcpy(animbones, skel->framebones, skel->numframes*skel->numbones*sizeof(dualquat));
330  delete[] skel->framebones;
331  }
332  skel->framebones = animbones;
333  animbones += skel->numframes*skel->numbones;
334 
335  sa = &skel->addskelanim(filename);
336  sa->frame = skel->numframes;
337  sa->range = animframes;
338 
339  skel->numframes += animframes;
340  }
341  else if(sscanf(buf, " frame %d", &tmp)==1)
342  {
343  for(int numdata = 0; f->getline(buf, sizeof(buf)) && buf[0]!='}';)
344  {
345  for(char *src = buf, *next = src; numdata < animdatalen; numdata++, src = next)
346  {
347  animdata[numdata] = strtod(src, &next);
348  if(next <= src) break;
349  }
350  }
351  dualquat *frame = &animbones[tmp*skel->numbones];
352  loopv(basejoints)
353  {
354  md5hierarchy &h = hierarchy[i];
355  md5joint j = basejoints[i];
356  if(h.start < animdatalen && h.flags)
357  {
358  float *jdata = &animdata[h.start];
359  if(h.flags&1) j.pos.x = *jdata++;
360  if(h.flags&2) j.pos.y = -*jdata++;
361  if(h.flags&4) j.pos.z = *jdata++;
362  if(h.flags&8) j.orient.x = -*jdata++;
363  if(h.flags&16) j.orient.y = *jdata++;
364  if(h.flags&32) j.orient.z = -*jdata++;
365  j.orient.restorew();
366  }
367  frame[i] = dualquat(j.orient, j.pos);
368  if(adjustments.inrange(i)) adjustments[i].adjust(frame[i]);
369  frame[i].mul(skel->bones[i].invbase);
370  if(h.parent >= 0) frame[i].mul(skel->bones[h.parent].base, dualquat(frame[i]));
371  frame[i].fixantipodal(skel->framebones[i]);
372  }
373  }
374  }
375 
376  if(animdata) delete[] animdata;
377  delete f;
378 
379  return sa;
380  }
381 
382  bool load(const char *meshfile, float smooth)
383  {
384  name = newstring(meshfile);
385 
386  if(!loadmesh(meshfile, smooth)) return false;
387 
388  return true;
389  }
390  };
391 
392  meshgroup *loadmeshes(const char *name, va_list args) override
393  {
394  md5meshgroup *group = new md5meshgroup;
395  group->shareskeleton(va_arg(args, char *));
396  if(!group->load(name, va_arg(args, double))) { delete group; return nullptr; }
397  return group;
398  }
399 
400  bool loaddefaultparts() override
401  {
402  skelpart &mdl = addpart();
403  mdl.pitchscale = mdl.pitchoffset = mdl.pitchmin = mdl.pitchmax = 0;
404  adjustments.setsize(0);
405  const char *fname = name + strlen(name);
406  do --fname; while(fname >= name && *fname!='/' && *fname!='\\');
407  fname++;
408  defformatstring(meshname, "%s/%s/%s.md5mesh", *modeldir, name, fname);
409  mdl.meshes = sharemeshes(path(meshname), NULL, 2.0);
410  if(!mdl.meshes) return false;
411  mdl.initanimparts();
412  mdl.initskins();
413  defformatstring(animname, "%s/%s/%s.md5anim", *modeldir, name, fname);
414  ((md5meshgroup *)mdl.meshes)->loadanim(path(animname));
415  return true;
416  }
417 
418  bool load() override
419  {
420  formatstring(dir, "%s/%s", *modeldir, name);
421  defformatstring(cfgname, "%s/%s/md5.cfg", *modeldir, name);
422 
423  loading = this;
425  if(execfile(cfgname, false) && parts.length()) // configured md5, will call the md5* commands below
426  {
428  loading = nullptr;
429  loopv(parts) if(!parts[i]->meshes) return false;
430  }
431  else // md5 without configuration, try default tris and skin
432  {
434  if(!loaddefaultparts())
435  {
436  loading = nullptr;
437  return false;
438  }
439  loading = nullptr;
440  }
441  loaded();
442  return true;
443  }
444 };
445 
447 
Definition: skelmodel.hpp:21
void smoothnorms(float limit=0, bool areaweight=true)
Definition: skelmodel.hpp:197
ushort vert[3]
Definition: skelmodel.hpp:21
Vector template.
Definition: cube_vector.hpp:22
md5(const char *name)
Definition: md5.hpp:31
virtual void loaded()
Definition: animmodel.hpp:1298
const T & max(const inexor::rpc::SharedVar< T > &a, const T &b)
Definition: SharedVar.hpp:224
char * name
Definition: model.hpp:42
string cfgname
Definition: worldio.cpp:227
skelcommands< md5 > md5commands
Definition: md5.hpp:446
int addblendcombo(const blendcombo &c)
Definition: skelmodel.hpp:191
int identflags
Definition: command.cpp:41
void load(stream *f, char *buf, size_t bufsize)
Definition: md5.hpp:88
vec pos
Definition: md5.hpp:14
int start
Definition: md5.hpp:26
int numweights
Definition: md5.hpp:39
void initskins(Texture *tex=notexture, Texture *masks=notexture, int limit=0)
Definition: animmodel.hpp:691
Definition: animmodel.hpp:465
bool execfile(const char *cfgfile, bool msg)
Definition: command.cpp:2262
skelanimspec * loadanim(const char *filename) override
Definition: md5.hpp:264
static Logger std
Logger for everything not fitting elsewhere.
Definition: Logging.hpp:89
meshgroup * sharemeshes(const char *name,...)
Definition: animmodel.hpp:583
void smooth()
Definition: octaedit.cpp:1942
Definition: md5.hpp:17
float pitchmin
Definition: animmodel.hpp:618
vec & mul(const vec &o)
scalar multiplication
Definition: geom.hpp:168
meshgroup * meshes
Definition: animmodel.hpp:613
Definition: animmodel.hpp:104
Definition: skelmodel.hpp:23
vector< skin > skins
Definition: animmodel.hpp:615
int addweight(int sorted, float weight, int bone)
Definition: skelmodel.hpp:61
2-dimensional float vectors
Definition: geom.hpp:38
ushort count
Definition: md5.hpp:20
vec2 tc
Definition: skelmodel.hpp:13
md5vert * vertinfo
Definition: md5.hpp:40
float bias
Definition: md5.hpp:13
SharedVar< char * > modeldir
static md5 * loading
Definition: animmodel.hpp:1396
Definition: skelmodel.hpp:411
bool loadmesh(const char *filename, float smooth)
Definition: md5.hpp:160
int blend
Definition: skelmodel.hpp:13
meshgroup * loadmeshes(const char *name, va_list args) override
Definition: md5.hpp:392
Definition: skelmodel.hpp:1518
Texture * textureload(const char *name, int clamp, bool mipit, bool msg, bool threadsafe)
Definition: texture.cpp:501
tri * tris
Definition: skelmodel.hpp:174
Definition: geom.hpp:536
ICOMMAND * f(float *a, float *b), floatret(*a **b)
bool inrange(size_t i) const
safety check: tests if index i exists in this vector
Definition: cube_vector.hpp:123
unsigned short ushort
Definition: cube_types.hpp:8
void finalize(int sorted)
Definition: skelmodel.hpp:81
void setsize(int i)
shrink vector memory size
Definition: cube_vector.hpp:163
else loopi(numargs)
Definition: command.cpp:3019
skelpart & addpart()
Definition: skelmodel.hpp:1602
#define NULL
Definition: cube_types.hpp:35
Definition: md5.hpp:23
GLuint index
Definition: glexts.hpp:412
void buildverts(vector< md5joint > &joints)
Definition: md5.hpp:57
int flags
Definition: md5.hpp:26
void start(const char *filename, int videofps, int videow, int videoh, bool sound)
Definition: movie.cpp:975
float pitchoffset
Definition: animmodel.hpp:618
T & add(const T &x)
Add new index to vector.
Definition: cube_vector.hpp:73
int numtris
Definition: skelmodel.hpp:175
vector with 3 floats and some useful methods.
Definition: geom.hpp:110
#define DELETEA(p)
Delete Array, Wrapper around delete[], sets pointer to NULL afterwards(!).
Definition: cube_tools.hpp:31
md5weight * weightinfo
Definition: md5.hpp:38
Definition: skelmodel.hpp:1626
char void formatstring(char(&d)[N], const char *fmt,...) PRINTFARGS(2
Definition: skelmodel.hpp:170
inexor::util::log_manager Log
Definition: Logging.cpp:241
char * path(char *s)
Modifies the input string to only contain slashes in the direction the platform allows.
Definition: stream.cpp:63
Definition: md5.hpp:10
dualquat invbase
Definition: skelmodel.hpp:428
Definition: skelmodel.hpp:423
Definition: md5.hpp:29
dualquat base
Definition: skelmodel.hpp:428
bool load(const char *meshfile, float smooth)
Definition: md5.hpp:382
Definition: skelmodel.hpp:1633
quaternions are number systems that extend complex numbers complex numbers extend the number system o...
Definition: geom.hpp:435
float pitchscale
Definition: animmodel.hpp:618
int length() const
return size of used memory
Definition: cube_vector.hpp:146
int orient
Definition: octaedit.cpp:164
int range
Definition: skelmodel.hpp:414
vec pos
Definition: md5.hpp:6
md5meshgroup()
Definition: md5.hpp:156
void t(T x, const char *cmp)
Definition: utilTest.cpp:52
Legacy file system streams.
Definition: stream.hpp:22
#define loopk(m)
Definition: cube_loops.hpp:10
Definition: command.hpp:72
vector< part * > parts
Definition: animmodel.hpp:1118
string name
Definition: md5.hpp:25
bool loaddefaultparts() override
Definition: md5.hpp:400
Definition: model.hpp:11
int end()
Definition: glemu.cpp:256
char * makerelpath(const char *dir, const char *file, const char *prefix, const char *cmd)
Append a string together but add the prefix in the field.
Definition: stream.cpp:35
~md5mesh() override
Definition: md5.hpp:46
vert * verts
Definition: skelmodel.hpp:172
virtual bool getline(char *str, size_t len)
Definition: stream.cpp:318
void cleanup()
Definition: md5.hpp:51
bool load() override
Definition: md5.hpp:418
vec & add(const vec &o)
scalar sum
Definition: geom.hpp:174
void restorew()
Definition: geom.hpp:458
static vector< skeladjustment > adjustments
Definition: skelmodel.hpp:1628
vec pos
Definition: skelmodel.hpp:13
Definition: animmodel.hpp:609
#define loopj(m)
Definition: cube_loops.hpp:9
int parent
Definition: md5.hpp:26
int joint
Definition: md5.hpp:12
Texture * notexture
Global used to specify this texture has not be found.
Definition: texture.cpp:266
void initanimparts()
Definition: skelmodel.hpp:1556
ushort start
Definition: md5.hpp:20
Texture * tex
Definition: animmodel.hpp:107
Definition: skelmodel.hpp:11
quat orient
Definition: md5.hpp:7
static const char * formatname()
Definition: md5.hpp:33
int numverts
Definition: skelmodel.hpp:175
#define defformatstring(d,...)
Definition: cube_formatting.hpp:62
dualquat & mul(float k)
Definition: geom.hpp:552
stream * openfile(const char *filename, const char *mode)
Definition: stream.cpp:907
int type() const override
Definition: md5.hpp:34
Definition: md5.hpp:4
int frame
Definition: skelmodel.hpp:414
void fixantipodal(const dualquat &d)
Definition: geom.hpp:621
Definition: md5.hpp:154
md5mesh()
Definition: md5.hpp:42
#define loopv(v)
Definition: cube_loops.hpp:21
float pitchmax
Definition: animmodel.hpp:618
char * newstring(size_t l)
Definition: cube_tools.hpp:71
static string dir
Definition: animmodel.hpp:1397
vec rotate(const vec &v) const
Definition: geom.hpp:487
vec2 tc
Definition: md5.hpp:19
Definition: md5.hpp:36
Definition: skelmodel.hpp:13
void buildnorms(bool areaweight=true)
Definition: skelmodel.hpp:202
Definition: octree.hpp:50