goat3d

view src/goat3d.cc @ 40:a5c5cec3cb88

- added mesh attribute and face append functions - added Int4 constructor - continued the blender exporter - fixed a bug in clean_filename which made it produce unterminated strings - renamed clean_filename to goat3d_clean_filename and made it extern - added call to goat3d_clean_filename in the mesh XML export code to cleanup ctm filenames
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 13 Oct 2013 10:14:19 +0300
parents d24f63e8031e
children da3f335e0069
line source
1 #include <string.h>
2 #include <errno.h>
3 #include <ctype.h>
4 #include <string>
5 #include "goat3d.h"
6 #include "goat3d_impl.h"
7 #include "log.h"
9 #ifndef _MSC_VER
10 #include <alloca.h>
11 #else
12 #include <malloc.h>
13 #endif
15 struct goat3d {
16 Scene *scn;
17 unsigned int flags;
18 char *search_path;
19 };
21 struct goat3d_material : public Material {};
22 struct goat3d_mesh : public Mesh {};
23 struct goat3d_light : public Light {};
24 struct goat3d_camera : public Camera {};
25 struct goat3d_node : public Node {};
28 static long read_file(void *buf, size_t bytes, void *uptr);
29 static long write_file(const void *buf, size_t bytes, void *uptr);
30 static long seek_file(long offs, int whence, void *uptr);
32 extern "C" {
34 struct goat3d *goat3d_create(void)
35 {
36 goat3d *goat = new goat3d;
37 goat->flags = 0;
38 goat->search_path = 0;
39 goat->scn = new Scene;
41 goat3d_setopt(goat, GOAT3D_OPT_SAVEXML, 1);
42 return goat;
43 }
45 void goat3d_free(struct goat3d *g)
46 {
47 delete g->search_path;
48 delete g->scn;
49 delete g;
50 }
52 void goat3d_setopt(struct goat3d *g, enum goat3d_option opt, int val)
53 {
54 if(val) {
55 g->flags |= (1 << (int)opt);
56 } else {
57 g->flags &= ~(1 << (int)opt);
58 }
59 }
61 int goat3d_getopt(const struct goat3d *g, enum goat3d_option opt)
62 {
63 return (g->flags >> (int)opt) & 1;
64 }
66 int goat3d_load(struct goat3d *g, const char *fname)
67 {
68 FILE *fp = fopen(fname, "rb");
69 if(!fp) {
70 logmsg(LOG_ERROR, "failed to open file \"%s\" for reading: %s\n", fname, strerror(errno));
71 return -1;
72 }
74 /* if the filename contained any directory components, keep the prefix
75 * to use it as a search path for external mesh file loading
76 */
77 g->search_path = new char[strlen(fname) + 1];
78 strcpy(g->search_path, fname);
80 char *slash = strrchr(g->search_path, '/');
81 if(slash) {
82 *slash = 0;
83 } else {
84 if((slash = strrchr(g->search_path, '\\'))) {
85 *slash = 0;
86 } else {
87 delete [] g->search_path;
88 g->search_path = 0;
89 }
90 }
92 int res = goat3d_load_file(g, fp);
93 fclose(fp);
94 return res;
95 }
97 int goat3d_save(const struct goat3d *g, const char *fname)
98 {
99 FILE *fp = fopen(fname, "wb");
100 if(!fp) {
101 logmsg(LOG_ERROR, "failed to open file \"%s\" for writing: %s\n", fname, strerror(errno));
102 return -1;
103 }
105 int res = goat3d_save_file(g, fp);
106 fclose(fp);
107 return res;
108 }
110 int goat3d_load_file(struct goat3d *g, FILE *fp)
111 {
112 goat3d_io io;
113 io.cls = fp;
114 io.read = read_file;
115 io.write = write_file;
116 io.seek = seek_file;
118 return goat3d_load_io(g, &io);
119 }
121 int goat3d_save_file(const struct goat3d *g, FILE *fp)
122 {
123 goat3d_io io;
124 io.cls = fp;
125 io.read = read_file;
126 io.write = write_file;
127 io.seek = seek_file;
129 return goat3d_save_io(g, &io);
130 }
132 int goat3d_load_io(struct goat3d *g, struct goat3d_io *io)
133 {
134 if(!g->scn->load(io)) {
135 if(g->scn->loadxml(io)) {
136 return -1;
137 }
138 }
139 return 0;
140 }
142 int goat3d_save_io(const struct goat3d *g, struct goat3d_io *io)
143 {
144 if(goat3d_getopt(g, GOAT3D_OPT_SAVEXML)) {
145 return g->scn->savexml(io) ? 0 : -1;
146 }
147 return g->scn->save(io) ? 0 : -1;
148 }
150 int goat3d_set_name(struct goat3d *g, const char *name)
151 {
152 g->scn->set_name(name);
153 return 0;
154 }
156 const char *goat3d_get_name(const struct goat3d *g)
157 {
158 return g->scn->get_name();
159 }
161 void goat3d_set_ambient(struct goat3d *g, const float *amb)
162 {
163 g->scn->set_ambient(Vector3(amb[0], amb[1], amb[2]));
164 }
166 void goat3d_set_ambient3f(struct goat3d *g, float ar, float ag, float ab)
167 {
168 g->scn->set_ambient(Vector3(ar, ag, ab));
169 }
171 const float *goat3d_get_ambient(const struct goat3d *g)
172 {
173 return &g->scn->get_ambient().x;
174 }
176 // ---- materials ----
177 void goat3d_add_mtl(struct goat3d *g, struct goat3d_material *mtl)
178 {
179 g->scn->add_material(mtl);
180 }
182 struct goat3d_material *goat3d_create_mtl(void)
183 {
184 return new goat3d_material;
185 }
187 void goat3d_destroy_mtl(struct goat3d_material *mtl)
188 {
189 delete mtl;
190 }
192 void goat3d_set_mtl_name(struct goat3d_material *mtl, const char *name)
193 {
194 mtl->name = std::string(name);
195 }
197 const char *goat3d_get_mtl_name(const struct goat3d_material *mtl)
198 {
199 return mtl->name.c_str();
200 }
202 void goat3d_set_mtl_attrib(struct goat3d_material *mtl, const char *attrib, const float *val)
203 {
204 (*mtl)[attrib].value = Vector4(val[0], val[1], val[2], val[3]);
205 }
207 void goat3d_set_mtl_attrib1f(struct goat3d_material *mtl, const char *attrib, float val)
208 {
209 goat3d_set_mtl_attrib4f(mtl, attrib, val, 0, 0, 1);
210 }
212 void goat3d_set_mtl_attrib3f(struct goat3d_material *mtl, const char *attrib, float r, float g, float b)
213 {
214 goat3d_set_mtl_attrib4f(mtl, attrib, r, g, b, 1);
215 }
217 void goat3d_set_mtl_attrib4f(struct goat3d_material *mtl, const char *attrib, float r, float g, float b, float a)
218 {
219 (*mtl)[attrib].value = Vector4(r, g, b, a);
220 }
222 const float *goat3d_get_mtl_attrib(struct goat3d_material *mtl, const char *attrib)
223 {
224 return &(*mtl)[attrib].value.x;
225 }
227 void goat3d_set_mtl_attrib_map(struct goat3d_material *mtl, const char *attrib, const char *mapname)
228 {
229 (*mtl)[attrib].map = goat3d_clean_filename(mapname);
230 }
232 const char *goat3d_get_mtl_attrib_map(struct goat3d_material *mtl, const char *attrib)
233 {
234 return (*mtl)[attrib].map.c_str();
235 }
237 // ---- meshes ----
238 void goat3d_add_mesh(struct goat3d *g, struct goat3d_mesh *mesh)
239 {
240 g->scn->add_mesh(mesh);
241 }
243 int goat3d_get_mesh_count(struct goat3d *g)
244 {
245 return g->scn->get_mesh_count();
246 }
248 struct goat3d_mesh *goat3d_get_mesh(struct goat3d *g, int idx)
249 {
250 return (goat3d_mesh*)g->scn->get_mesh(idx);
251 }
253 struct goat3d_mesh *goat3d_get_mesh_by_name(struct goat3d *g, const char *name)
254 {
255 return (goat3d_mesh*)g->scn->get_mesh(name);
256 }
258 struct goat3d_mesh *goat3d_create_mesh(void)
259 {
260 return new goat3d_mesh;
261 }
263 void goat3d_destroy_mesh(struct goat3d_mesh *mesh)
264 {
265 delete mesh;
266 }
268 void goat3d_set_mesh_name(struct goat3d_mesh *mesh, const char *name)
269 {
270 mesh->name = std::string(name);
271 }
273 const char *goat3d_get_mesh_name(const struct goat3d_mesh *mesh)
274 {
275 return mesh->name.c_str();
276 }
278 void goat3d_set_mesh_mtl(struct goat3d_mesh *mesh, struct goat3d_material *mtl)
279 {
280 mesh->material = mtl;
281 }
283 struct goat3d_material *goat3d_get_mesh_mtl(struct goat3d_mesh *mesh)
284 {
285 return (goat3d_material*)mesh->material;
286 }
288 int goat3d_get_mesh_attrib_count(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib)
289 {
290 return (int)mesh->vertices.size();
291 }
293 int goat3d_get_mesh_face_count(struct goat3d_mesh *mesh)
294 {
295 return (int)mesh->faces.size();
296 }
298 // VECDATA is in goat3d_impl.h
299 void goat3d_set_mesh_attribs(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib, const void *data, int vnum)
300 {
301 if(attrib == GOAT3D_MESH_ATTR_VERTEX) {
302 mesh->vertices = VECDATA(Vector3, data, vnum);
303 return;
304 }
306 if(vnum != (int)mesh->vertices.size()) {
307 logmsg(LOG_ERROR, "trying to set mesh attrib data with number of elements different than the vertex array\n");
308 return;
309 }
311 switch(attrib) {
312 case GOAT3D_MESH_ATTR_NORMAL:
313 mesh->normals = VECDATA(Vector3, data, vnum);
314 break;
315 case GOAT3D_MESH_ATTR_TANGENT:
316 mesh->tangents = VECDATA(Vector3, data, vnum);
317 break;
318 case GOAT3D_MESH_ATTR_TEXCOORD:
319 mesh->texcoords = VECDATA(Vector2, data, vnum);
320 break;
321 case GOAT3D_MESH_ATTR_SKIN_WEIGHT:
322 mesh->skin_weights = VECDATA(Vector4, data, vnum);
323 break;
324 case GOAT3D_MESH_ATTR_SKIN_MATRIX:
325 mesh->skin_matrices = VECDATA(Int4, data, vnum);
326 break;
327 case GOAT3D_MESH_ATTR_COLOR:
328 mesh->colors = VECDATA(Vector4, data, vnum);
329 default:
330 break;
331 }
332 }
334 void goat3d_add_mesh_attrib1f(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib,
335 float val)
336 {
337 goat3d_add_mesh_attrib4f(mesh, attrib, val, 0, 0, 1);
338 }
340 void goat3d_add_mesh_attrib3f(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib,
341 float x, float y, float z)
342 {
343 goat3d_add_mesh_attrib4f(mesh, attrib, x, y, z, 1);
344 }
346 void goat3d_add_mesh_attrib4f(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib,
347 float x, float y, float z, float w)
348 {
349 switch(attrib) {
350 case GOAT3D_MESH_ATTR_VERTEX:
351 mesh->vertices.push_back(Vector3(x, y, z));
352 break;
353 case GOAT3D_MESH_ATTR_NORMAL:
354 mesh->normals.push_back(Vector3(x, y, z));
355 break;
356 case GOAT3D_MESH_ATTR_TANGENT:
357 mesh->tangents.push_back(Vector3(x, y, z));
358 break;
359 case GOAT3D_MESH_ATTR_TEXCOORD:
360 mesh->texcoords.push_back(Vector2(x, y));
361 break;
362 case GOAT3D_MESH_ATTR_SKIN_WEIGHT:
363 mesh->skin_weights.push_back(Vector4(x, y, z, w));
364 break;
365 case GOAT3D_MESH_ATTR_SKIN_MATRIX:
366 mesh->skin_matrices.push_back(Int4(x, y, z, w));
367 break;
368 case GOAT3D_MESH_ATTR_COLOR:
369 mesh->colors.push_back(Vector4(x, y, z, w));
370 default:
371 break;
372 }
373 }
375 void *goat3d_get_mesh_attribs(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib)
376 {
377 return goat3d_get_mesh_attrib(mesh, attrib, 0);
378 }
380 void *goat3d_get_mesh_attrib(struct goat3d_mesh *mesh, enum goat3d_mesh_attrib attrib, int idx)
381 {
382 switch(attrib) {
383 case GOAT3D_MESH_ATTR_VERTEX:
384 return mesh->vertices.empty() ? 0 : (void*)&mesh->vertices[idx];
385 case GOAT3D_MESH_ATTR_NORMAL:
386 return mesh->normals.empty() ? 0 : (void*)&mesh->normals[idx];
387 case GOAT3D_MESH_ATTR_TANGENT:
388 return mesh->tangents.empty() ? 0 : (void*)&mesh->tangents[idx];
389 case GOAT3D_MESH_ATTR_TEXCOORD:
390 return mesh->texcoords.empty() ? 0 : (void*)&mesh->texcoords[idx];
391 case GOAT3D_MESH_ATTR_SKIN_WEIGHT:
392 return mesh->skin_weights.empty() ? 0 : (void*)&mesh->skin_weights[idx];
393 case GOAT3D_MESH_ATTR_SKIN_MATRIX:
394 return mesh->skin_matrices.empty() ? 0 : (void*)&mesh->skin_matrices[idx];
395 case GOAT3D_MESH_ATTR_COLOR:
396 return mesh->colors.empty() ? 0 : (void*)&mesh->colors[idx];
397 default:
398 break;
399 }
400 return 0;
401 }
404 void goat3d_set_mesh_faces(struct goat3d_mesh *mesh, const int *data, int num)
405 {
406 mesh->faces = VECDATA(Face, data, num);
407 }
409 void goat3d_add_mesh_face(struct goat3d_mesh *mesh, int a, int b, int c)
410 {
411 Face face;
412 face.v[0] = a;
413 face.v[1] = b;
414 face.v[2] = c;
415 mesh->faces.push_back(face);
416 }
418 int *goat3d_get_mesh_faces(struct goat3d_mesh *mesh)
419 {
420 return goat3d_get_mesh_face(mesh, 0);
421 }
423 int *goat3d_get_mesh_face(struct goat3d_mesh *mesh, int idx)
424 {
425 return mesh->faces.empty() ? 0 : mesh->faces[idx].v;
426 }
428 // immedate mode state
429 static enum goat3d_im_primitive im_prim;
430 static struct goat3d_mesh *im_mesh;
431 static Vector3 im_norm, im_tang;
432 static Vector2 im_texcoord;
433 static Vector4 im_skinw, im_color = Vector4(1, 1, 1, 1);
434 static Int4 im_skinmat;
435 static bool im_use[NUM_GOAT3D_MESH_ATTRIBS];
438 void goat3d_begin(struct goat3d_mesh *mesh, enum goat3d_im_primitive prim)
439 {
440 mesh->vertices.clear();
441 mesh->normals.clear();
442 mesh->tangents.clear();
443 mesh->texcoords.clear();
444 mesh->skin_weights.clear();
445 mesh->skin_matrices.clear();
446 mesh->colors.clear();
447 mesh->faces.clear();
449 im_mesh = mesh;
450 memset(im_use, 0, sizeof im_use);
452 im_prim = prim;
453 }
455 void goat3d_end(void)
456 {
457 switch(im_prim) {
458 case GOAT3D_TRIANGLES:
459 {
460 int num_faces = (int)im_mesh->vertices.size() / 3;
461 im_mesh->faces.resize(num_faces);
463 int vidx = 0;
464 for(int i=0; i<num_faces; i++) {
465 im_mesh->faces[i].v[0] = vidx++;
466 im_mesh->faces[i].v[1] = vidx++;
467 im_mesh->faces[i].v[2] = vidx++;
468 }
469 }
470 break;
472 case GOAT3D_QUADS:
473 {
474 int num_quads = (int)im_mesh->vertices.size() / 4;
475 im_mesh->faces.resize(num_quads * 2);
477 int vidx = 0;
478 for(int i=0; i<num_quads; i++) {
479 im_mesh->faces[i * 2].v[0] = vidx;
480 im_mesh->faces[i * 2].v[1] = vidx + 1;
481 im_mesh->faces[i * 2].v[2] = vidx + 2;
483 im_mesh->faces[i * 2 + 1].v[0] = vidx;
484 im_mesh->faces[i * 2 + 1].v[1] = vidx + 2;
485 im_mesh->faces[i * 2 + 1].v[2] = vidx + 3;
487 vidx += 4;
488 }
489 }
490 break;
492 default:
493 return;
494 };
495 }
497 void goat3d_vertex3f(float x, float y, float z)
498 {
499 im_mesh->vertices.push_back(Vector3(x, y, z));
500 if(im_use[GOAT3D_MESH_ATTR_NORMAL]) {
501 im_mesh->normals.push_back(im_norm);
502 }
503 if(im_use[GOAT3D_MESH_ATTR_TANGENT]) {
504 im_mesh->tangents.push_back(im_tang);
505 }
506 if(im_use[GOAT3D_MESH_ATTR_TEXCOORD]) {
507 im_mesh->texcoords.push_back(im_texcoord);
508 }
509 if(im_use[GOAT3D_MESH_ATTR_SKIN_WEIGHT]) {
510 im_mesh->skin_weights.push_back(im_skinw);
511 }
512 if(im_use[GOAT3D_MESH_ATTR_SKIN_MATRIX]) {
513 im_mesh->skin_matrices.push_back(im_skinmat);
514 }
515 if(im_use[GOAT3D_MESH_ATTR_COLOR]) {
516 im_mesh->colors.push_back(im_color);
517 }
518 }
520 void goat3d_normal3f(float x, float y, float z)
521 {
522 im_norm = Vector3(x, y, z);
523 im_use[GOAT3D_MESH_ATTR_NORMAL] = true;
524 }
526 void goat3d_tangent3f(float x, float y, float z)
527 {
528 im_tang = Vector3(x, y, z);
529 im_use[GOAT3D_MESH_ATTR_TANGENT] = true;
530 }
532 void goat3d_texcoord2f(float x, float y)
533 {
534 im_texcoord = Vector2(x, y);
535 im_use[GOAT3D_MESH_ATTR_TEXCOORD] = true;
536 }
538 void goat3d_skin_weight4f(float x, float y, float z, float w)
539 {
540 im_skinw = Vector4(x, y, z, w);
541 im_use[GOAT3D_MESH_ATTR_SKIN_WEIGHT] = true;
542 }
544 void goat3d_skin_matrix4i(int x, int y, int z, int w)
545 {
546 im_skinmat.x = x;
547 im_skinmat.y = y;
548 im_skinmat.z = z;
549 im_skinmat.w = w;
550 im_use[GOAT3D_MESH_ATTR_SKIN_MATRIX] = true;
551 }
553 void goat3d_color3f(float x, float y, float z)
554 {
555 goat3d_color4f(x, y, z, 1.0f);
556 }
558 void goat3d_color4f(float x, float y, float z, float w)
559 {
560 im_color = Vector4(x, y, z, w);
561 im_use[GOAT3D_MESH_ATTR_COLOR] = true;
562 }
564 /* lights */
565 void goat3d_add_light(struct goat3d *g, struct goat3d_light *lt)
566 {
567 g->scn->add_light(lt);
568 }
570 int goat3d_get_light_count(struct goat3d *g)
571 {
572 return g->scn->get_light_count();
573 }
575 struct goat3d_light *goat3d_get_light(struct goat3d *g, int idx)
576 {
577 return (goat3d_light*)g->scn->get_light(idx);
578 }
580 struct goat3d_light *goat3d_get_light_by_name(struct goat3d *g, const char *name)
581 {
582 return (goat3d_light*)g->scn->get_light(name);
583 }
586 struct goat3d_light *goat3d_create_light(void)
587 {
588 return new goat3d_light;
589 }
591 void goat3d_destroy_light(struct goat3d_light *lt)
592 {
593 delete lt;
594 }
597 /* cameras */
598 void goat3d_add_camera(struct goat3d *g, struct goat3d_camera *cam)
599 {
600 g->scn->add_camera(cam);
601 }
603 int goat3d_get_camera_count(struct goat3d *g)
604 {
605 return g->scn->get_camera_count();
606 }
608 struct goat3d_camera *goat3d_get_camera(struct goat3d *g, int idx)
609 {
610 return (goat3d_camera*)g->scn->get_camera(idx);
611 }
613 struct goat3d_camera *goat3d_get_camera_by_name(struct goat3d *g, const char *name)
614 {
615 return (goat3d_camera*)g->scn->get_camera(name);
616 }
618 struct goat3d_camera *goat3d_create_camera(void)
619 {
620 return new goat3d_camera;
621 }
623 void goat3d_destroy_camera(struct goat3d_camera *cam)
624 {
625 delete cam;
626 }
630 // node
631 void goat3d_add_node(struct goat3d *g, struct goat3d_node *node)
632 {
633 g->scn->add_node(node);
634 }
636 int goat3d_get_node_count(struct goat3d *g)
637 {
638 return g->scn->get_node_count();
639 }
641 struct goat3d_node *goat3d_get_node(struct goat3d *g, int idx)
642 {
643 return (goat3d_node*)g->scn->get_node(idx);
644 }
646 struct goat3d_node *goat3d_get_node_by_name(struct goat3d *g, const char *name)
647 {
648 return (goat3d_node*)g->scn->get_node(name);
649 }
651 struct goat3d_node *goat3d_create_node(void)
652 {
653 return new goat3d_node;
654 }
656 void goat3d_set_node_name(struct goat3d_node *node, const char *name)
657 {
658 node->set_name(name);
659 }
661 const char *goat3d_get_node_name(const struct goat3d_node *node)
662 {
663 return node->get_name();
664 }
666 void goat3d_set_node_object(struct goat3d_node *node, enum goat3d_node_type type, void *obj)
667 {
668 node->set_object((Object*)obj);
669 }
671 void *goat3d_get_node_object(const struct goat3d_node *node)
672 {
673 return (void*)node->get_object();
674 }
676 enum goat3d_node_type goat3d_get_node_type(const struct goat3d_node *node)
677 {
678 const Object *obj = node->get_object();
679 if(dynamic_cast<const Mesh*>(obj)) {
680 return GOAT3D_NODE_MESH;
681 }
682 if(dynamic_cast<const Light*>(obj)) {
683 return GOAT3D_NODE_LIGHT;
684 }
685 if(dynamic_cast<const Camera*>(obj)) {
686 return GOAT3D_NODE_CAMERA;
687 }
689 return GOAT3D_NODE_NULL;
690 }
692 void goat3d_add_node_child(struct goat3d_node *node, struct goat3d_node *child)
693 {
694 node->add_child(node);
695 }
697 int goat3d_get_node_child_count(const struct goat3d_node *node)
698 {
699 return node->get_children_count();
700 }
702 struct goat3d_node *goat3d_get_node_child(const struct goat3d_node *node, int idx)
703 {
704 return (goat3d_node*)node->get_child(idx);
705 }
707 void goat3d_set_node_position(struct goat3d_node *node, float x, float y, float z, long tmsec)
708 {
709 node->set_position(Vector3(x, y, z), tmsec);
710 }
712 void goat3d_set_node_rotation(struct goat3d_node *node, float qx, float qy, float qz, float qw, long tmsec)
713 {
714 node->set_rotation(Quaternion(qw, qx, qy, qz), tmsec);
715 }
717 void goat3d_set_node_scaling(struct goat3d_node *node, float sx, float sy, float sz, long tmsec)
718 {
719 node->set_scaling(Vector3(sx, sy, sz), tmsec);
720 }
722 void goat3d_set_node_pivot(struct goat3d_node *node, float px, float py, float pz)
723 {
724 node->set_pivot(Vector3(px, py, pz));
725 }
728 void goat3d_get_node_position(const struct goat3d_node *node, float *xptr, float *yptr, float *zptr, long tmsec)
729 {
730 Vector3 pos = node->get_position(tmsec);
731 *xptr = pos.x;
732 *yptr = pos.y;
733 *zptr = pos.z;
734 }
736 void goat3d_get_node_rotation(const struct goat3d_node *node, float *xptr, float *yptr, float *zptr, float *wptr, long tmsec)
737 {
738 Quaternion q = node->get_rotation(tmsec);
739 *xptr = q.v.x;
740 *yptr = q.v.y;
741 *zptr = q.v.z;
742 *wptr = q.s;
743 }
745 void goat3d_get_node_scaling(const struct goat3d_node *node, float *xptr, float *yptr, float *zptr, long tmsec)
746 {
747 Vector3 scale = node->get_scaling(tmsec);
748 *xptr = scale.x;
749 *yptr = scale.y;
750 *zptr = scale.z;
751 }
753 void goat3d_get_node_pivot(const struct goat3d_node *node, float *xptr, float *yptr, float *zptr)
754 {
755 Vector3 pivot = node->get_pivot();
756 *xptr = pivot.x;
757 *yptr = pivot.y;
758 *zptr = pivot.z;
759 }
762 void goat3d_get_node_matrix(const struct goat3d_node *node, float *matrix, long tmsec)
763 {
764 node->get_xform(tmsec, (Matrix4x4*)matrix);
765 }
768 } // extern "C"
771 static long read_file(void *buf, size_t bytes, void *uptr)
772 {
773 return (long)fread(buf, 1, bytes, (FILE*)uptr);
774 }
776 static long write_file(const void *buf, size_t bytes, void *uptr)
777 {
778 return (long)fwrite(buf, 1, bytes, (FILE*)uptr);
779 }
781 static long seek_file(long offs, int whence, void *uptr)
782 {
783 if(fseek((FILE*)uptr, offs, whence) == -1) {
784 return -1;
785 }
786 return ftell((FILE*)uptr);
787 }
789 std::string goat3d_clean_filename(const char *str)
790 {
791 const char *last_slash = strrchr(str, '/');
792 if(!last_slash) {
793 last_slash = strrchr(str, '\\');
794 }
796 if(last_slash) {
797 str = last_slash + 1;
798 }
800 char *buf = (char*)alloca(strlen(str) + 1);
801 char *dest = buf;
802 while(*str) {
803 char c = *str++;
804 *dest++ = tolower(c);
805 }
806 *dest = 0;
807 return buf;
808 }