rev |
line source |
nuclear@29
|
1 #include <stdio.h>
|
nuclear@29
|
2 #include <stdlib.h>
|
nuclear@29
|
3 #include "goat3d.h"
|
nuclear@29
|
4 #include "assimp/cimport.h"
|
nuclear@29
|
5 #include "assimp/postprocess.h"
|
nuclear@29
|
6 #include "assimp/scene.h"
|
nuclear@29
|
7
|
nuclear@55
|
8 enum {
|
nuclear@55
|
9 CONV_SCENE,
|
nuclear@55
|
10 CONV_ANIM
|
nuclear@55
|
11 };
|
nuclear@55
|
12
|
nuclear@55
|
13 int convert(const char *infname);
|
nuclear@55
|
14 int convert_anim(const char *infname);
|
nuclear@29
|
15 void process_material(struct goat3d_material *mtl, struct aiMaterial *aimtl);
|
nuclear@57
|
16 void process_mesh(struct goat3d *goat, struct goat3d_mesh *mesh, struct aiMesh *aimesh);
|
nuclear@29
|
17 void process_node(struct goat3d *goat, struct goat3d_node *parent, struct aiNode *ainode);
|
nuclear@55
|
18 int process_anim(struct goat3d *goat, struct aiAnimation *aianim);
|
nuclear@55
|
19 static int output_filename(char *buf, int bufsz, const char *fname, const char *suffix);
|
nuclear@55
|
20 static long assimp_time(const struct aiAnimation *anim, double aitime);
|
nuclear@29
|
21
|
nuclear@29
|
22 int main(int argc, char **argv)
|
nuclear@29
|
23 {
|
nuclear@29
|
24 int i, num_done = 0;
|
nuclear@55
|
25 int conv_targ = CONV_SCENE;
|
nuclear@29
|
26
|
nuclear@29
|
27 for(i=1; i<argc; i++) {
|
nuclear@29
|
28 if(argv[i][0] == '-') {
|
nuclear@55
|
29 if(argv[i][2] != 0) {
|
nuclear@55
|
30 fprintf(stderr, "invalid option: %s\n", argv[i]);
|
nuclear@55
|
31 return 1;
|
nuclear@55
|
32 }
|
nuclear@55
|
33
|
nuclear@55
|
34 switch(argv[i][1]) {
|
nuclear@55
|
35 case 'a':
|
nuclear@55
|
36 conv_targ = CONV_ANIM;
|
nuclear@55
|
37 break;
|
nuclear@55
|
38
|
nuclear@55
|
39 case 's':
|
nuclear@55
|
40 conv_targ = CONV_SCENE;
|
nuclear@55
|
41 break;
|
nuclear@55
|
42
|
nuclear@55
|
43 default:
|
nuclear@55
|
44 fprintf(stderr, "invalid option: %s\n", argv[i]);
|
nuclear@55
|
45 return 1;
|
nuclear@55
|
46 }
|
nuclear@55
|
47
|
nuclear@29
|
48 } else {
|
nuclear@55
|
49 if(conv_targ == CONV_SCENE) {
|
nuclear@55
|
50 convert(argv[i]);
|
nuclear@55
|
51 } else {
|
nuclear@55
|
52 convert_anim(argv[i]);
|
nuclear@29
|
53 }
|
nuclear@29
|
54 num_done++;
|
nuclear@29
|
55 }
|
nuclear@29
|
56 }
|
nuclear@29
|
57
|
nuclear@29
|
58 if(!num_done) {
|
nuclear@29
|
59 fprintf(stderr, "you must specify a 3D scene file to convert\n");
|
nuclear@29
|
60 return 1;
|
nuclear@29
|
61 }
|
nuclear@29
|
62
|
nuclear@29
|
63 return 0;
|
nuclear@29
|
64 }
|
nuclear@29
|
65
|
nuclear@55
|
66 #define SCE_PPFLAGS \
|
nuclear@29
|
67 (aiProcess_Triangulate | \
|
nuclear@29
|
68 aiProcess_GenNormals | \
|
nuclear@29
|
69 aiProcess_JoinIdenticalVertices | \
|
nuclear@29
|
70 aiProcess_CalcTangentSpace | \
|
nuclear@29
|
71 aiProcess_LimitBoneWeights | \
|
nuclear@29
|
72 aiProcess_GenUVCoords)
|
nuclear@29
|
73
|
nuclear@55
|
74 #define ANM_PPFLAGS \
|
nuclear@55
|
75 (aiProcess_LimitBoneWeights)
|
nuclear@55
|
76
|
nuclear@55
|
77 int convert(const char *infname)
|
nuclear@29
|
78 {
|
nuclear@55
|
79 int i, bufsz;
|
nuclear@29
|
80 const struct aiScene *aiscn;
|
nuclear@29
|
81 struct goat3d *goat;
|
nuclear@55
|
82 char *outfname;
|
nuclear@29
|
83
|
nuclear@55
|
84 bufsz = output_filename(0, 0, infname, "goat3d");
|
nuclear@55
|
85 outfname = alloca(bufsz);
|
nuclear@55
|
86 output_filename(outfname, bufsz, infname, "goat3d");
|
nuclear@55
|
87 printf("converting %s -> %s\n", infname, outfname);
|
nuclear@55
|
88
|
nuclear@55
|
89
|
nuclear@55
|
90 if(!(aiscn = aiImportFile(infname, SCE_PPFLAGS))) {
|
nuclear@29
|
91 fprintf(stderr, "failed to import %s\n", infname);
|
nuclear@29
|
92 return -1;
|
nuclear@29
|
93 }
|
nuclear@29
|
94
|
nuclear@29
|
95 goat = goat3d_create();
|
nuclear@29
|
96
|
nuclear@29
|
97 for(i=0; i<(int)aiscn->mNumMaterials; i++) {
|
nuclear@29
|
98 struct aiMaterial *aimat = aiscn->mMaterials[i];
|
nuclear@29
|
99 struct goat3d_material *mat = goat3d_create_mtl();
|
nuclear@29
|
100
|
nuclear@29
|
101 process_material(mat, aimat);
|
nuclear@29
|
102 goat3d_add_mtl(goat, mat);
|
nuclear@29
|
103 }
|
nuclear@29
|
104
|
nuclear@57
|
105 for(i=0; i<(int)aiscn->mNumMeshes; i++) {
|
nuclear@57
|
106 struct aiMesh *aimesh = aiscn->mMeshes[i];
|
nuclear@57
|
107 struct goat3d_mesh *mesh = goat3d_create_mesh();
|
nuclear@57
|
108
|
nuclear@57
|
109 process_mesh(goat, mesh, aimesh);
|
nuclear@57
|
110 goat3d_add_mesh(goat, mesh);
|
nuclear@57
|
111 }
|
nuclear@57
|
112
|
nuclear@29
|
113 for(i=0; i<(int)aiscn->mRootNode->mNumChildren; i++) {
|
nuclear@29
|
114 process_node(goat, 0, aiscn->mRootNode->mChildren[i]);
|
nuclear@29
|
115 }
|
nuclear@29
|
116
|
nuclear@29
|
117 goat3d_save(goat, outfname);
|
nuclear@29
|
118 goat3d_free(goat);
|
nuclear@29
|
119 aiReleaseImport(aiscn);
|
nuclear@29
|
120 return 0;
|
nuclear@29
|
121 }
|
nuclear@29
|
122
|
nuclear@55
|
123 int convert_anim(const char *infname)
|
nuclear@55
|
124 {
|
nuclear@55
|
125 int i, bufsz;
|
nuclear@55
|
126 const struct aiScene *aiscn;
|
nuclear@55
|
127 struct goat3d *goat;
|
nuclear@55
|
128 char *outfname;
|
nuclear@55
|
129
|
nuclear@55
|
130 bufsz = output_filename(0, 0, infname, "goatanim");
|
nuclear@55
|
131 outfname = alloca(bufsz);
|
nuclear@55
|
132 output_filename(outfname, bufsz, infname, "goatanim");
|
nuclear@55
|
133 printf("converting %s -> %s\n", infname, outfname);
|
nuclear@55
|
134
|
nuclear@55
|
135
|
nuclear@55
|
136 if(!(aiscn = aiImportFile(infname, ANM_PPFLAGS))) {
|
nuclear@55
|
137 fprintf(stderr, "failed to import %s\n", infname);
|
nuclear@55
|
138 return -1;
|
nuclear@55
|
139 }
|
nuclear@55
|
140
|
nuclear@55
|
141 goat = goat3d_create();
|
nuclear@55
|
142
|
nuclear@55
|
143 for(i=0; i<(int)aiscn->mRootNode->mNumChildren; i++) {
|
nuclear@55
|
144 process_node(goat, 0, aiscn->mRootNode->mChildren[i]);
|
nuclear@55
|
145 }
|
nuclear@55
|
146
|
nuclear@55
|
147 for(i=0; i<aiscn->mNumAnimations; i++) {
|
nuclear@55
|
148 if(process_anim(goat, aiscn->mAnimations[i]) == -1) {
|
nuclear@55
|
149 return -1;
|
nuclear@55
|
150 }
|
nuclear@55
|
151 }
|
nuclear@55
|
152
|
nuclear@55
|
153 goat3d_save_anim(goat, outfname);
|
nuclear@55
|
154 goat3d_free(goat);
|
nuclear@55
|
155 aiReleaseImport(aiscn);
|
nuclear@55
|
156 return 0;
|
nuclear@55
|
157 }
|
nuclear@55
|
158
|
nuclear@29
|
159 void process_material(struct goat3d_material *mtl, struct aiMaterial *aimtl)
|
nuclear@29
|
160 {
|
nuclear@29
|
161 struct aiString aistr;
|
nuclear@29
|
162 struct aiColor4D color;
|
nuclear@29
|
163 float val;
|
nuclear@29
|
164
|
nuclear@29
|
165 if(aiGetMaterialString(aimtl, AI_MATKEY_NAME, &aistr) == aiReturn_SUCCESS) {
|
nuclear@29
|
166 goat3d_set_mtl_name(mtl, aistr.data);
|
nuclear@29
|
167 }
|
nuclear@29
|
168
|
nuclear@29
|
169 if(aiGetMaterialColor(aimtl, AI_MATKEY_COLOR_DIFFUSE, &color) == aiReturn_SUCCESS) {
|
nuclear@29
|
170 goat3d_set_mtl_attrib3f(mtl, GOAT3D_MAT_ATTR_DIFFUSE, color.r, color.g, color.b);
|
nuclear@29
|
171 }
|
nuclear@29
|
172
|
nuclear@29
|
173 if(aiGetMaterialColor(aimtl, AI_MATKEY_COLOR_SPECULAR, &color) == aiReturn_SUCCESS) {
|
nuclear@29
|
174 float sstr = 1.0;
|
nuclear@29
|
175 aiGetMaterialFloatArray(aimtl, AI_MATKEY_SHININESS_STRENGTH, &sstr, 0);
|
nuclear@29
|
176 goat3d_set_mtl_attrib3f(mtl, GOAT3D_MAT_ATTR_SPECULAR, color.r * sstr, color.g * sstr, color.b * sstr);
|
nuclear@29
|
177 }
|
nuclear@29
|
178
|
nuclear@29
|
179 if(aiGetMaterialFloatArray(aimtl, AI_MATKEY_BUMPSCALING, &val, 0) == aiReturn_SUCCESS) {
|
nuclear@29
|
180 goat3d_set_mtl_attrib3f(mtl, GOAT3D_MAT_ATTR_BUMP, val, val, val);
|
nuclear@29
|
181 }
|
nuclear@29
|
182
|
nuclear@29
|
183 if(aiGetMaterialFloatArray(aimtl, AI_MATKEY_REFLECTIVITY, &val, 0) == aiReturn_SUCCESS) {
|
nuclear@29
|
184 goat3d_set_mtl_attrib1f(mtl, GOAT3D_MAT_ATTR_REFLECTION, val);
|
nuclear@29
|
185 }
|
nuclear@29
|
186
|
nuclear@29
|
187 if(aiGetMaterialFloatArray(aimtl, AI_MATKEY_OPACITY, &val, 0) == aiReturn_SUCCESS) {
|
nuclear@29
|
188 goat3d_set_mtl_attrib1f(mtl, GOAT3D_MAT_ATTR_TRANSMISSION, 1.0 - val);
|
nuclear@29
|
189 }
|
nuclear@29
|
190
|
nuclear@29
|
191 if(aiGetMaterialString(aimtl, AI_MATKEY_TEXTURE_DIFFUSE(0), &aistr) == aiReturn_SUCCESS) {
|
nuclear@29
|
192 goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_DIFFUSE, aistr.data);
|
nuclear@29
|
193 }
|
nuclear@29
|
194 if(aiGetMaterialString(aimtl, AI_MATKEY_TEXTURE_SPECULAR(0), &aistr) == aiReturn_SUCCESS) {
|
nuclear@29
|
195 goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_SPECULAR, aistr.data);
|
nuclear@29
|
196 }
|
nuclear@29
|
197 if(aiGetMaterialString(aimtl, AI_MATKEY_TEXTURE_SHININESS(0), &aistr) == aiReturn_SUCCESS) {
|
nuclear@29
|
198 goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_SHININESS, aistr.data);
|
nuclear@29
|
199 }
|
nuclear@29
|
200 if(aiGetMaterialString(aimtl, AI_MATKEY_TEXTURE_NORMALS(0), &aistr) == aiReturn_SUCCESS) {
|
nuclear@29
|
201 goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_NORMAL, aistr.data);
|
nuclear@29
|
202 }
|
nuclear@29
|
203 if(aiGetMaterialString(aimtl, AI_MATKEY_TEXTURE_REFLECTION(0), &aistr) == aiReturn_SUCCESS) {
|
nuclear@29
|
204 goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_REFLECTION, aistr.data);
|
nuclear@29
|
205 }
|
nuclear@29
|
206 if(aiGetMaterialString(aimtl, AI_MATKEY_TEXTURE_OPACITY(0), &aistr) == aiReturn_SUCCESS) {
|
nuclear@57
|
207 /* TODO this is semantically inverted... maybe add an alpha attribute? */
|
nuclear@29
|
208 goat3d_set_mtl_attrib_map(mtl, GOAT3D_MAT_ATTR_TRANSMISSION, aistr.data);
|
nuclear@29
|
209 }
|
nuclear@29
|
210 }
|
nuclear@29
|
211
|
nuclear@57
|
212 void process_mesh(struct goat3d *goat, struct goat3d_mesh *mesh, struct aiMesh *aimesh)
|
nuclear@57
|
213 {
|
nuclear@57
|
214 int i, num_verts, num_faces;
|
nuclear@57
|
215 struct goat3d_material *mtl;
|
nuclear@57
|
216
|
nuclear@57
|
217 if(aimesh->mName.length > 0) {
|
nuclear@57
|
218 goat3d_set_mesh_name(mesh, aimesh->mName.data);
|
nuclear@57
|
219 }
|
nuclear@57
|
220
|
nuclear@57
|
221 if((mtl = goat3d_get_mtl(goat, aimesh->mMaterialIndex))) {
|
nuclear@57
|
222 goat3d_set_mesh_mtl(mesh, mtl);
|
nuclear@57
|
223 }
|
nuclear@57
|
224
|
nuclear@57
|
225 num_verts = aimesh->mNumVertices;
|
nuclear@57
|
226 num_faces = aimesh->mNumFaces;
|
nuclear@57
|
227
|
nuclear@57
|
228 for(i=0; i<num_verts; i++) {
|
nuclear@57
|
229 struct aiVector3D *v;
|
nuclear@57
|
230 struct aiColor4D *col;
|
nuclear@57
|
231
|
nuclear@57
|
232 v = aimesh->mVertices + i;
|
nuclear@57
|
233 goat3d_add_mesh_attrib3f(mesh, GOAT3D_MESH_ATTR_VERTEX, v->x, v->y, v->z);
|
nuclear@57
|
234
|
nuclear@57
|
235 if(aimesh->mNormals) {
|
nuclear@57
|
236 v = aimesh->mNormals + i;
|
nuclear@57
|
237 goat3d_add_mesh_attrib3f(mesh, GOAT3D_MESH_ATTR_NORMAL, v->x, v->y, v->z);
|
nuclear@57
|
238 }
|
nuclear@57
|
239 if(aimesh->mTangents) {
|
nuclear@57
|
240 v = aimesh->mTangents + i;
|
nuclear@57
|
241 goat3d_add_mesh_attrib3f(mesh, GOAT3D_MESH_ATTR_TANGENT, v->x, v->y, v->z);
|
nuclear@57
|
242 }
|
nuclear@57
|
243 if(aimesh->mTextureCoords[0]) {
|
nuclear@57
|
244 v = aimesh->mTextureCoords[0] + i;
|
nuclear@57
|
245 goat3d_add_mesh_attrib2f(mesh, GOAT3D_MESH_ATTR_TEXCOORD, v->x, v->y);
|
nuclear@57
|
246 }
|
nuclear@57
|
247 if(aimesh->mColors[0]) {
|
nuclear@57
|
248 col = aimesh->mColors[0] + i;
|
nuclear@57
|
249 goat3d_add_mesh_attrib4f(mesh, GOAT3D_MESH_ATTR_COLOR, col->r, col->g, col->b, col->a);
|
nuclear@57
|
250 }
|
nuclear@57
|
251 /* TODO: add bones */
|
nuclear@57
|
252 }
|
nuclear@57
|
253
|
nuclear@57
|
254 for(i=0; i<num_faces; i++) {
|
nuclear@57
|
255 struct aiFace *face = aimesh->mFaces + i;
|
nuclear@57
|
256
|
nuclear@57
|
257 goat3d_add_mesh_face(mesh, face->mIndices[0], face->mIndices[1], face->mIndices[2]);
|
nuclear@57
|
258 }
|
nuclear@57
|
259 }
|
nuclear@57
|
260
|
nuclear@29
|
261 void process_node(struct goat3d *goat, struct goat3d_node *parent, struct aiNode *ainode)
|
nuclear@29
|
262 {
|
nuclear@29
|
263 int i;
|
nuclear@29
|
264 struct goat3d_node *node;
|
nuclear@29
|
265
|
nuclear@29
|
266 node = goat3d_create_node();
|
nuclear@29
|
267 goat3d_set_node_name(node, ainode->mName.data);
|
nuclear@29
|
268
|
nuclear@29
|
269 for(i=0; i<ainode->mNumChildren; i++) {
|
nuclear@29
|
270 process_node(goat, node, ainode->mChildren[i]);
|
nuclear@29
|
271 }
|
nuclear@29
|
272
|
nuclear@29
|
273 goat3d_add_node(goat, node);
|
nuclear@29
|
274 }
|
nuclear@55
|
275
|
nuclear@55
|
276 int process_anim(struct goat3d *goat, struct aiAnimation *aianim)
|
nuclear@55
|
277 {
|
nuclear@55
|
278 int i, j, num_nodes, rnodes_count;
|
nuclear@55
|
279 const char *anim_name;
|
nuclear@55
|
280
|
nuclear@55
|
281 if(aianim->mName.length <= 0) {
|
nuclear@55
|
282 anim_name = "unnamed";
|
nuclear@55
|
283 } else {
|
nuclear@55
|
284 anim_name = aianim->mName.data;
|
nuclear@55
|
285 }
|
nuclear@55
|
286
|
nuclear@55
|
287 num_nodes = goat3d_get_node_count(goat);
|
nuclear@55
|
288
|
nuclear@55
|
289 rnodes_count = 0;
|
nuclear@55
|
290 for(i=0; i<num_nodes; i++) {
|
nuclear@55
|
291 int anim_idx;
|
nuclear@55
|
292 struct goat3d_node *n = goat3d_get_node(goat, i);
|
nuclear@55
|
293 /* skip non-root nodes */
|
nuclear@55
|
294 if(goat3d_get_node_parent(n)) {
|
nuclear@55
|
295 break;
|
nuclear@55
|
296 }
|
nuclear@55
|
297
|
nuclear@55
|
298 /* then add another animation to those root nodes */
|
nuclear@55
|
299 anim_idx = goat3d_get_anim_count(n);
|
nuclear@55
|
300 goat3d_add_anim(n);
|
nuclear@55
|
301 goat3d_use_anim(n, anim_idx);
|
nuclear@55
|
302
|
nuclear@55
|
303 goat3d_set_anim_name(n, anim_name);
|
nuclear@55
|
304 }
|
nuclear@55
|
305
|
nuclear@55
|
306 /* for each animation "channel" ... */
|
nuclear@55
|
307 for(i=0; i<(int)aianim->mNumChannels; i++) {
|
nuclear@55
|
308 struct goat3d_node *node;
|
nuclear@55
|
309 struct aiNodeAnim *ainodeanim = aianim->mChannels[i];
|
nuclear@55
|
310
|
nuclear@55
|
311 /* find the node it refers to */
|
nuclear@55
|
312 const char *nodename = ainodeanim->mNodeName.data;
|
nuclear@55
|
313 if(!(node = goat3d_get_node_by_name(goat, nodename))) {
|
nuclear@55
|
314 fprintf(stderr, "failed to process animation for unknown node: %s\n", nodename);
|
nuclear@55
|
315 return -1;
|
nuclear@55
|
316 }
|
nuclear@55
|
317
|
nuclear@55
|
318 /* add all the keys ... */
|
nuclear@55
|
319 for(j=0; j<(int)ainodeanim->mNumPositionKeys; j++) {
|
nuclear@55
|
320 struct aiVectorKey *key = ainodeanim->mPositionKeys + j;
|
nuclear@55
|
321 long tm = assimp_time(aianim, key->mTime);
|
nuclear@55
|
322 goat3d_set_node_position(node, key->mValue.x, key->mValue.y, key->mValue.z, tm);
|
nuclear@55
|
323 }
|
nuclear@55
|
324
|
nuclear@55
|
325 for(j=0; j<(int)ainodeanim->mNumRotationKeys; j++) {
|
nuclear@55
|
326 struct aiQuatKey *key = ainodeanim->mRotationKeys + j;
|
nuclear@55
|
327 long tm = assimp_time(aianim, key->mTime);
|
nuclear@55
|
328 goat3d_set_node_rotation(node, key->mValue.x, key->mValue.y, key->mValue.z, key->mValue.w, tm);
|
nuclear@55
|
329 }
|
nuclear@55
|
330
|
nuclear@55
|
331 for(j=0; j<(int)ainodeanim->mNumScalingKeys; j++) {
|
nuclear@55
|
332 struct aiVectorKey *key = ainodeanim->mScalingKeys + j;
|
nuclear@55
|
333 long tm = assimp_time(aianim, key->mTime);
|
nuclear@55
|
334 goat3d_set_node_scaling(node, key->mValue.x, key->mValue.y, key->mValue.z, tm);
|
nuclear@55
|
335 }
|
nuclear@55
|
336 }
|
nuclear@55
|
337
|
nuclear@55
|
338 return 0;
|
nuclear@55
|
339 }
|
nuclear@55
|
340
|
nuclear@55
|
341 static int output_filename(char *buf, int bufsz, const char *fname, const char *suffix)
|
nuclear@55
|
342 {
|
nuclear@55
|
343 int reqsz, namesz;
|
nuclear@55
|
344 char *tmpfname;
|
nuclear@55
|
345 const char *fname_end, *lastdot;
|
nuclear@55
|
346
|
nuclear@55
|
347 lastdot = strrchr(fname, '.');
|
nuclear@55
|
348
|
nuclear@56
|
349 fname_end = lastdot ? lastdot : fname + strlen(fname);
|
nuclear@55
|
350 namesz = fname_end - fname;
|
nuclear@55
|
351 reqsz = namesz + strlen(suffix) + 2; /* plus 1 for the dot */
|
nuclear@55
|
352
|
nuclear@55
|
353 if(buf && bufsz) {
|
nuclear@55
|
354 tmpfname = alloca(namesz + 1);
|
nuclear@55
|
355 memcpy(tmpfname, fname, namesz);
|
nuclear@55
|
356 tmpfname[namesz] = 0;
|
nuclear@55
|
357
|
nuclear@55
|
358 if(suffix) {
|
nuclear@55
|
359 snprintf(buf, bufsz, "%s.%s", tmpfname, suffix);
|
nuclear@55
|
360 } else {
|
nuclear@55
|
361 strncpy(buf, tmpfname, bufsz);
|
nuclear@55
|
362 }
|
nuclear@55
|
363 buf[bufsz - 1] = 0;
|
nuclear@55
|
364 }
|
nuclear@55
|
365
|
nuclear@55
|
366 return reqsz;
|
nuclear@55
|
367 }
|
nuclear@55
|
368
|
nuclear@55
|
369 static long assimp_time(const struct aiAnimation *anim, double aitime)
|
nuclear@55
|
370 {
|
nuclear@55
|
371 double sec;
|
nuclear@55
|
372 if(anim->mTicksPerSecond < 1e-6) {
|
nuclear@55
|
373 /* assume time in frames? */
|
nuclear@55
|
374 sec = aitime / 30.0;
|
nuclear@55
|
375 } else {
|
nuclear@55
|
376 sec = aitime / anim->mTicksPerSecond;
|
nuclear@55
|
377 }
|
nuclear@55
|
378 return (long)(sec * 1000.0);
|
nuclear@55
|
379 }
|