Inexor
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
smd.hpp
Go to the documentation of this file.
1 #pragma once
3 
4 struct smdbone
5 {
6  string name;
7  int parent;
8  smdbone() : parent(-1) { name[0] = '\0'; }
9 };
10 
11 struct smd : skelmodel, skelloader<smd>
12 {
13  smd(const char *name) : skelmodel(name) {}
14 
15  static const char *formatname() { return "smd"; }
16  int type() const override { return MDL_SMD; }
17 
18  struct smdmesh : skelmesh
19  {
20  };
21 
23  {
25  {
26  }
27 
28  bool skipcomment(char *&curbuf)
29  {
30  while(*curbuf && isspace(*curbuf)) curbuf++;
31  switch(*curbuf)
32  {
33  case '#':
34  case ';':
35  case '\r':
36  case '\n':
37  case '\0':
38  return true;
39  case '/':
40  if(curbuf[1] == '/') return true;
41  break;
42  }
43  return false;
44  }
45 
46  void skipsection(stream *f, char *buf, size_t bufsize)
47  {
48  while(f->getline(buf, bufsize))
49  {
50  char *curbuf = buf;
51  if(skipcomment(curbuf)) continue;
52  if(!strncmp(curbuf, "end", 3)) break;
53  }
54  }
55 
56  void readname(char *&curbuf, char *name, size_t namesize)
57  {
58  char *curname = name;
59  while(*curbuf && isspace(*curbuf)) curbuf++;
60  bool allowspace = false;
61  if(*curbuf == '"') { curbuf++; allowspace = true; }
62  while(*curbuf)
63  {
64  char c = *curbuf++;
65  if(c == '"') break;
66  if(isspace(c) && !allowspace) break;
67  if(curname < &name[namesize-1]) *curname++ = c;
68  }
69  *curname = '\0';
70  }
71 
72  void readnodes(stream *f, char *buf, size_t bufsize, vector<smdbone> &bones)
73  {
74  while(f->getline(buf, bufsize))
75  {
76  char *curbuf = buf;
77  if(skipcomment(curbuf)) continue;
78  if(!strncmp(curbuf, "end", 3)) break;
79  int id = strtol(curbuf, &curbuf, 10);
80  string name;
81  readname(curbuf, name, sizeof(name));
82  int parent = strtol(curbuf, &curbuf, 10);
83  if(id < 0 || id > 255 || parent > 255 || !name[0]) continue;
84  while(!bones.inrange(id)) bones.add();
85  smdbone &bone = bones[id];
86  copystring(bone.name, name);
87  bone.parent = parent;
88  }
89  }
90 
91  void readmaterial(char *&curbuf, char *name, size_t namesize)
92  {
93  char *curname = name;
94  while(*curbuf && isspace(*curbuf)) curbuf++;
95  while(*curbuf)
96  {
97  char c = *curbuf++;
98  if(isspace(c)) break;
99  if(c == '.')
100  {
101  while(*curbuf && !isspace(*curbuf)) curbuf++;
102  break;
103  }
104  if(curname < &name[namesize-1]) *curname++ = c;
105  }
106  *curname = '\0';
107  }
108 
109  struct smdmeshdata
110  {
114 
115  void finalize()
116  {
117  if(verts.empty() || tris.empty()) return;
118  vert *mverts = new vert[mesh->numverts + verts.length()];
119  if(mesh->numverts)
120  {
121  memcpy(mverts, mesh->verts, mesh->numverts*sizeof(vert));
122  delete[] mesh->verts;
123  }
124  memcpy(&mverts[mesh->numverts], verts.getbuf(), verts.length()*sizeof(vert));
125  mesh->numverts += verts.length();
126  mesh->verts = mverts;
127  tri *mtris = new tri[mesh->numtris + tris.length()];
128  if(mesh->numtris)
129  {
130  memcpy(mtris, mesh->tris, mesh->numtris*sizeof(tri));
131  delete[] mesh->tris;
132  }
133  memcpy(&mtris[mesh->numtris], tris.getbuf(), tris.length()*sizeof(tri));
134  mesh->numtris += tris.length();
135  mesh->tris = mtris;
136  }
137  };
138 
139  struct smdvertkey : vert
140  {
142 
143  smdvertkey(smdmeshdata *mesh) : mesh(mesh) {}
144  };
145 
146  void readtriangles(stream *f, char *buf, size_t bufsize)
147  {
148  smdmeshdata *curmesh = nullptr;
150  hashset<int> verts(1<<12);
151  while(f->getline(buf, bufsize))
152  {
153  char *curbuf = buf;
154  if(skipcomment(curbuf)) continue;
155  if(!strncmp(curbuf, "end", 3)) break;
156  string material;
157  readmaterial(curbuf, material, sizeof(material));
158  if(!curmesh || strcmp(curmesh->mesh->name, material))
159  {
160  curmesh = materials.access(material);
161  if(!curmesh)
162  {
163  smdmesh *m = new smdmesh;
164  m->group = this;
165  m->name = newstring(material);
166  meshes.add(m);
167  curmesh = &materials[m->name];
168  curmesh->mesh = m;
169  }
170  }
171  tri curtri;
172  loopi(3)
173  {
174  char *curbuf;
175  do
176  {
177  if(!f->getline(buf, bufsize)) goto endsection;
178  curbuf = buf;
179  } while(skipcomment(curbuf));
180  smdvertkey key(curmesh);
181  int parent = -1, numlinks = 0, len = 0;
182  if(sscanf(curbuf, " %d %f %f %f %f %f %f %f %f %d%n", &parent, &key.pos.x, &key.pos.y, &key.pos.z, &key.norm.x, &key.norm.y, &key.norm.z, &key.tc.x, &key.tc.y, &numlinks, &len) < 9) goto endsection;
183  curbuf += len;
184  key.pos.y = -key.pos.y;
185  key.norm.y = -key.norm.y;
186  key.tc.y = 1 - key.tc.y;
187  blendcombo c;
188  int sorted = 0;
189  float pweight = 0, tweight = 0;
190  for(; numlinks > 0; numlinks--)
191  {
192  int bone = -1, len = 0;
193  float weight = 0;
194  if(sscanf(curbuf, " %d %f%n", &bone, &weight, &len) < 2) break;
195  curbuf += len;
196  tweight += weight;
197  if(bone == parent) pweight += weight;
198  else sorted = c.addweight(sorted, weight, bone);
199  }
200  if(tweight < 1) pweight += 1 - tweight;
201  if(pweight > 0) sorted = c.addweight(sorted, pweight, parent);
202  c.finalize(sorted);
203  key.blend = curmesh->mesh->addblendcombo(c);
204  int index = verts.access(key, curmesh->verts.length());
205  if(index == curmesh->verts.length()) curmesh->verts.add(key);
206  curtri.vert[2-i] = index;
207  }
208  curmesh->tris.add(curtri);
209  }
210  endsection:
211  enumerate(materials, smdmeshdata, data, data.finalize());
212  }
213 
214  void readskeleton(stream *f, char *buf, size_t bufsize)
215  {
216  int frame = -1;
217  while(f->getline(buf, bufsize))
218  {
219  char *curbuf = buf;
220  if(skipcomment(curbuf)) continue;
221  if(sscanf(curbuf, " time %d", &frame) == 1) continue;
222  else if(!strncmp(curbuf, "end", 3)) break;
223  else if(frame != 0) continue;
224  int bone;
225  vec pos, rot;
226  if(sscanf(curbuf, " %d %f %f %f %f %f %f", &bone, &pos.x, &pos.y, &pos.z, &rot.x, &rot.y, &rot.z) != 7)
227  continue;
228  if(bone < 0 || bone >= skel->numbones)
229  continue;
230  rot.x = -rot.x;
231  rot.z = -rot.z;
232  float cx = cosf(rot.x/2), sx = sinf(rot.x/2),
233  cy = cosf(rot.y/2), sy = sinf(rot.y/2),
234  cz = cosf(rot.z/2), sz = sinf(rot.z/2);
235  pos.y = -pos.y;
236  dualquat dq(quat(sx*cy*cz - cx*sy*sz,
237  cx*sy*cz + sx*cy*sz,
238  cx*cy*sz - sx*sy*cz,
239  cx*cy*cz + sx*sy*sz),
240  pos);
241  boneinfo &b = skel->bones[bone];
242  if(b.parent < 0) b.base = dq;
243  else b.base.mul(skel->bones[b.parent].base, dq);
244  (b.invbase = b.base).invert();
245  }
246  }
247 
248  bool loadmesh(const char *filename)
249  {
250  stream *f = openfile(filename, "r");
251  if(!f) return false;
252 
253  char buf[512];
254  int version = -1;
255  while(f->getline(buf, sizeof(buf)))
256  {
257  char *curbuf = buf;
258  if(skipcomment(curbuf)) continue;
259  if(sscanf(curbuf, " version %d", &version) == 1)
260  {
261  if(version != 1) { delete f; return false; }
262  }
263  else if(!strncmp(curbuf, "nodes", 5))
264  {
265  if(skel->numbones > 0) { skipsection(f, buf, sizeof(buf)); continue; }
266  vector<smdbone> bones;
267  readnodes(f, buf, sizeof(buf), bones);
268  if(bones.empty()) continue;
269  skel->numbones = bones.length();
270  skel->bones = new boneinfo[skel->numbones];
271  loopv(bones)
272  {
273  boneinfo &dst = skel->bones[i];
274  smdbone &src = bones[i];
275  dst.name = newstring(src.name);
276  dst.parent = src.parent;
277  }
278  skel->linkchildren();
279  }
280  else if(!strncmp(curbuf, "triangles", 9))
281  readtriangles(f, buf, sizeof(buf));
282  else if(!strncmp(curbuf, "skeleton", 8))
283  {
284  if(skel->shared > 1) skipsection(f, buf, sizeof(buf));
285  else readskeleton(f, buf, sizeof(buf));
286  }
287  else if(!strncmp(curbuf, "vertexanimation", 15))
288  skipsection(f, buf, sizeof(buf));
289  }
290 
291  sortblendcombos();
292 
293  delete f;
294  return true;
295  }
296 
297  int readframes(stream *f, char *buf, size_t bufsize, vector<dualquat> &animbones)
298  {
299  int frame = -1, numframes = 0, lastbone = skel->numbones;
300  while(f->getline(buf, bufsize))
301  {
302  char *curbuf = buf;
303  if(skipcomment(curbuf)) continue;
304  int nextframe = -1;
305  if(sscanf(curbuf, " time %d", &nextframe) == 1)
306  {
307  for(; lastbone < skel->numbones; lastbone++) animbones[frame*skel->numbones + lastbone] = animbones[lastbone];
308  if(nextframe >= numframes)
309  {
310  databuf<dualquat> framebones = animbones.reserve(skel->numbones * (nextframe + 1 - numframes));
311  loopi(nextframe - numframes) framebones.put(animbones.getbuf(), skel->numbones);
312  animbones.addbuf(framebones);
313  animbones.advance(skel->numbones);
314  numframes = nextframe + 1;
315  }
316  frame = nextframe;
317  lastbone = 0;
318  continue;
319  }
320  else if(!strncmp(curbuf, "end", 3)) break;
321  int bone;
322  vec pos, rot;
323  if(sscanf(curbuf, " %d %f %f %f %f %f %f", &bone, &pos.x, &pos.y, &pos.z, &rot.x, &rot.y, &rot.z) != 7)
324  continue;
325  if(bone < 0 || bone >= skel->numbones)
326  continue;
327  for(; lastbone < bone; lastbone++) animbones[frame*skel->numbones + lastbone] = animbones[lastbone];
328  lastbone++;
329  float cx = cosf(rot.x/2), sx = sinf(rot.x/2),
330  cy = cosf(rot.y/2), sy = sinf(rot.y/2),
331  cz = cosf(rot.z/2), sz = sinf(rot.z/2);
332  pos.y = -pos.y;
333  dualquat dq(quat(-(sx*cy*cz - cx*sy*sz),
334  cx*sy*cz + sx*cy*sz,
335  -(cx*cy*sz - sx*sy*cz),
336  cx*cy*cz + sx*sy*sz),
337  pos);
338  if(adjustments.inrange(bone)) adjustments[bone].adjust(dq);
339  dq.mul(skel->bones[bone].invbase);
340  dualquat &dst = animbones[frame*skel->numbones + bone];
341  if(skel->bones[bone].parent < 0) dst = dq;
342  else dst.mul(skel->bones[skel->bones[bone].parent].base, dq);
343  dst.fixantipodal(skel->numframes > 0 ? skel->framebones[bone] : animbones[bone]);
344  }
345  for(; lastbone < skel->numbones; lastbone++) animbones[frame*skel->numbones + lastbone] = animbones[lastbone];
346  return numframes;
347  }
348 
349  skelanimspec *loadanim(const char *filename) override
350  {
351  skelanimspec *sa = skel->findskelanim(filename);
352  if(sa || skel->numbones <= 0) return sa;
353 
354  stream *f = openfile(filename, "r");
355  if(!f) return nullptr;
356 
357  char buf[512];
358  int version = -1;
359  vector<dualquat> animbones;
360  while(f->getline(buf, sizeof(buf)))
361  {
362  char *curbuf = buf;
363  if(skipcomment(curbuf)) continue;
364  if(sscanf(curbuf, " version %d", &version) == 1)
365  {
366  if(version != 1) { delete f; return nullptr; }
367  }
368  else if(!strncmp(curbuf, "nodes", 5))
369  {
370  vector<smdbone> bones;
371  readnodes(f, buf, sizeof(buf), bones);
372  if(bones.length() != skel->numbones) { delete f; return nullptr; }
373  }
374  else if(!strncmp(curbuf, "triangles", 9))
375  skipsection(f, buf, sizeof(buf));
376  else if(!strncmp(curbuf, "skeleton", 8))
377  readframes(f, buf, sizeof(buf), animbones);
378  else if(!strncmp(curbuf, "vertexanimation", 15))
379  skipsection(f, buf, sizeof(buf));
380  }
381  int numframes = animbones.length() / skel->numbones;
382  dualquat *framebones = new dualquat[(skel->numframes+numframes)*skel->numbones];
383  if(skel->framebones)
384  {
385  memcpy(framebones, skel->framebones, skel->numframes*skel->numbones*sizeof(dualquat));
386  delete[] skel->framebones;
387  }
388  memcpy(&framebones[skel->numframes*skel->numbones], animbones.getbuf(), numframes*skel->numbones*sizeof(dualquat));
389  skel->framebones = framebones;
390  sa = &skel->addskelanim(filename);
391  sa->frame = skel->numframes;
392  sa->range = numframes;
393  skel->numframes += numframes;
394 
395  delete f;
396 
397  return sa;
398  }
399 
400  bool load(const char *meshfile)
401  {
402  name = newstring(meshfile);
403 
404  if(!loadmesh(meshfile)) return false;
405 
406  return true;
407  }
408  };
409 
410  meshgroup *loadmeshes(const char *name, va_list args) override
411  {
412  smdmeshgroup *group = new smdmeshgroup;
413  group->shareskeleton(va_arg(args, char *));
414  if(!group->load(name)) { delete group; return nullptr; }
415  return group;
416  }
417 
418  bool loaddefaultparts() override
419  {
420  skelpart &mdl = addpart();
421  mdl.pitchscale = mdl.pitchoffset = mdl.pitchmin = mdl.pitchmax = 0;
422  adjustments.setsize(0);
423  const char *fname = name + strlen(name);
424  do --fname; while(fname >= name && *fname!='/' && *fname!='\\');
425  fname++;
426  defformatstring(meshname, "%s/%s/%s.smd", *modeldir, name, fname);
427  mdl.meshes = sharemeshes(path(meshname), NULL);
428  if(!mdl.meshes) return false;
429  mdl.initanimparts();
430  mdl.initskins();
431  return true;
432  }
433 
434  bool load() override
435  {
436  formatstring(dir, "%s/%s", *modeldir, name);
437  defformatstring(cfgname, "%s/%s/smd.cfg", *modeldir, name);
438 
439  loading = this;
441  if(execfile(cfgname, false) && parts.length()) // configured smd, will call the smd* commands below
442  {
444  loading = nullptr;
445  loopv(parts) if(!parts[i]->meshes) return false;
446  }
447  else // smd without configuration, try default tris and skin
448  {
450  if(!loaddefaultparts())
451  {
452  loading = nullptr;
453  return false;
454  }
455  loading = nullptr;
456  }
457  loaded();
458  return true;
459  }
460 };
461 
463 {
464  return hthash(k.pos);
465 }
466 
467 static inline bool htcmp(const smd::smdmeshgroup::smdvertkey &k, int index)
468 {
469  if(!k.mesh->verts.inrange(index)) return false;
470  const smd::vert &v = k.mesh->verts[index];
471  return k.pos == v.pos && k.norm == v.norm && k.tc == v.tc && k.blend == v.blend;
472 }
473 
475 
Definition: skelmodel.hpp:21
int type() const override
Definition: smd.hpp:16
bool empty() const
is this vector empty?
Definition: cube_vector.hpp:141
ushort vert[3]
Definition: skelmodel.hpp:21
Vector template.
Definition: cube_vector.hpp:22
virtual void loaded()
Definition: animmodel.hpp:1298
void put(const T &val)
put one element at the end of the buffer.
Definition: buffer_types.hpp:73
char * name
Definition: model.hpp:42
string cfgname
Definition: worldio.cpp:227
smd(const char *name)
Definition: smd.hpp:13
int addblendcombo(const blendcombo &c)
Definition: skelmodel.hpp:191
smdbone()
Definition: smd.hpp:8
template implementation of buffers (networking e.g.).
Definition: buffer_types.hpp:14
int numframes
Definition: skelmodel.hpp:471
int identflags
Definition: command.cpp:41
Definition: smd.hpp:11
unsigned int uint
Definition: cube_types.hpp:9
void initskins(Texture *tex=notexture, Texture *masks=notexture, int limit=0)
Definition: animmodel.hpp:691
Definition: animmodel.hpp:465
Definition: material.cpp:178
skelanimspec * findskelanim(const char *name, char sep= '\0')
Definition: skelmodel.hpp:501
void advance(int sz)
increase value of used bytes manually (?)
Definition: cube_vector.hpp:215
const struct material materials[]
bool execfile(const char *cfgfile, bool msg)
Definition: command.cpp:2262
void readmaterial(char *&curbuf, char *name, size_t namesize)
Definition: smd.hpp:91
bool loadmesh(const char *filename)
Definition: smd.hpp:248
vector< tri > tris
Definition: smd.hpp:113
meshgroup * sharemeshes(const char *name,...)
Definition: animmodel.hpp:583
void sortblendcombos()
Definition: skelmodel.hpp:1325
float pitchmin
Definition: animmodel.hpp:618
boneinfo * bones
Definition: skelmodel.hpp:470
Definition: smd.hpp:109
meshgroup * meshes
Definition: animmodel.hpp:613
dualquat * framebones
Definition: skelmodel.hpp:472
Definition: skelmodel.hpp:23
smdmeshgroup()
Definition: smd.hpp:24
int addweight(int sorted, float weight, int bone)
Definition: skelmodel.hpp:61
T * getbuf()
get the whole vector
Definition: cube_vector.hpp:169
static uint hthash(const smd::smdmeshgroup::smdvertkey &k)
Definition: smd.hpp:462
vec2 tc
Definition: skelmodel.hpp:13
int numbones
Definition: skelmodel.hpp:471
SharedVar< char * > modeldir
char * name
Definition: animmodel.hpp:469
static smd * loading
Definition: animmodel.hpp:1396
Definition: skelmodel.hpp:411
int parent
Definition: skelmodel.hpp:426
int blend
Definition: skelmodel.hpp:13
Definition: skelmodel.hpp:1518
Definition: cube_hash.hpp:207
void readname(char *&curbuf, char *name, size_t namesize)
Definition: smd.hpp:56
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
static bool htcmp(const smd::smdmeshgroup::smdvertkey &k, int index)
Definition: smd.hpp:467
skelanimspec & addskelanim(const char *name)
Definition: skelmodel.hpp:519
void finalize(int sorted)
Definition: skelmodel.hpp:81
void setsize(int i)
shrink vector memory size
Definition: cube_vector.hpp:163
skeleton * skel
Definition: skelmodel.hpp:1101
else loopi(numargs)
Definition: command.cpp:3019
skelpart & addpart()
Definition: skelmodel.hpp:1602
#define NULL
Definition: cube_types.hpp:35
GLuint index
Definition: glexts.hpp:412
skelcommands< smd > smdcommands
Definition: smd.hpp:474
void skipsection(stream *f, char *buf, size_t bufsize)
Definition: smd.hpp:46
void addbuf(const databuf< T > &p)
increase value of used bytes by size of a vector
Definition: cube_vector.hpp:221
void finalize()
Definition: smd.hpp:115
float pitchoffset
Definition: animmodel.hpp:618
T & add(const T &x)
Add new index to vector.
Definition: cube_vector.hpp:73
vector< vert > verts
Definition: smd.hpp:112
vector with 3 floats and some useful methods.
Definition: geom.hpp:110
Definition: skelmodel.hpp:1626
char void formatstring(char(&d)[N], const char *fmt,...) PRINTFARGS(2
databuf< T > reserve(int sz)
reserved memory and returns vector of the reserved memory
Definition: cube_vector.hpp:208
smdmeshdata * mesh
Definition: smd.hpp:141
char * path(char *s)
Modifies the input string to only contain slashes in the direction the platform allows.
Definition: stream.cpp:63
void readtriangles(stream *f, char *buf, size_t bufsize)
Definition: smd.hpp:146
dualquat invbase
Definition: skelmodel.hpp:428
Definition: skelmodel.hpp:423
dualquat base
Definition: skelmodel.hpp:428
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
Definition: smd.hpp:4
int range
Definition: skelmodel.hpp:414
void linkchildren()
Definition: skelmodel.hpp:792
meshgroup * loadmeshes(const char *name, va_list args) override
Definition: smd.hpp:410
Legacy file system streams.
Definition: stream.hpp:22
void shareskeleton(char *name)
Definition: skelmodel.hpp:1142
smdvertkey(smdmeshdata *mesh)
Definition: smd.hpp:143
Definition: command.hpp:72
vector< part * > parts
Definition: animmodel.hpp:1118
vec norm
Definition: skelmodel.hpp:13
bool skipcomment(char *&curbuf)
Definition: smd.hpp:28
int parent
Definition: smd.hpp:7
#define enumerate(ht, t, e, b)
Definition: cube_hash.hpp:261
vector< mesh * > meshes
Definition: animmodel.hpp:470
Definition: model.hpp:11
struct sphere::vert * verts
char * copystring(char *d, const char *s, size_t len)
Definition: cube_tools.hpp:56
skelanimspec * loadanim(const char *filename) override
Definition: smd.hpp:349
virtual bool getline(char *str, size_t len)
Definition: stream.cpp:318
void readnodes(stream *f, char *buf, size_t bufsize, vector< smdbone > &bones)
Definition: smd.hpp:72
int readframes(stream *f, char *buf, size_t bufsize, vector< dualquat > &animbones)
Definition: smd.hpp:297
static vector< skeladjustment > adjustments
Definition: skelmodel.hpp:1628
vec pos
Definition: skelmodel.hpp:13
bool loaddefaultparts() override
Definition: smd.hpp:418
void readskeleton(stream *f, char *buf, size_t bufsize)
Definition: smd.hpp:214
static const char * formatname()
Definition: smd.hpp:15
Definition: smd.hpp:18
Definition: skelmodel.hpp:1099
Definition: smd.hpp:139
T * access(const U &key)
Definition: cube_hash.hpp:135
smdmesh * mesh
Definition: smd.hpp:111
void initanimparts()
Definition: skelmodel.hpp:1556
const char * name
Definition: skelmodel.hpp:425
Definition: smd.hpp:22
Definition: skelmodel.hpp:11
#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 frame
Definition: skelmodel.hpp:414
string name
Definition: smd.hpp:6
void fixantipodal(const dualquat &d)
Definition: geom.hpp:621
Definition: cube_hash.hpp:248
#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
int shared
Definition: skelmodel.hpp:468
Definition: animmodel.hpp:277
bool load() override
Definition: smd.hpp:434
Definition: skelmodel.hpp:13
bool load(const char *meshfile)
Definition: smd.hpp:400