1 /*
2     Copyright (C) 1996-2008 by Jan Eric Kyprianidis <www.kyprianidis.com>
3     All rights reserved.
4 
5     This program is free  software: you can redistribute it and/or modify
6     it under the terms of the GNU Lesser General Public License as published
7     by the Free Software Foundation, either version 2.1 of the License, or
8     (at your option) any later version.
9 
10     Thisprogram  is  distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13     GNU Lesser General Public License for more details.
14 
15     You should  have received a copy of the GNU Lesser General Public License
16     along with  this program; If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "lib3ds_impl.h"
19 
20 
21 /*!
22  * Create and return a new node object.
23  *
24  * The node is returned with an identity matrix. All other fields
25  * are zero.
26  *
27  * \return Lib3dsNode
28  */
29 Lib3dsNode*
lib3ds_node_new(Lib3dsNodeType type)30 lib3ds_node_new(Lib3dsNodeType type) {
31     Lib3dsNode *node;
32     switch (type) {
33         case LIB3DS_NODE_AMBIENT_COLOR: {
34             Lib3dsAmbientColorNode *n = (Lib3dsAmbientColorNode*)calloc(sizeof(Lib3dsAmbientColorNode), 1);
35             node = (Lib3dsNode*)n;
36             strcpy(node->name, "$AMBIENT$");
37             n->color_track.type = LIB3DS_TRACK_VECTOR;
38             break;
39         }
40 
41         case LIB3DS_NODE_MESH_INSTANCE: {
42             Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)calloc(sizeof(Lib3dsMeshInstanceNode), 1);
43             node = (Lib3dsNode*)n;
44             strcpy(node->name, "$$$DUMMY");
45             n->pos_track.type = LIB3DS_TRACK_VECTOR;
46             n->scl_track.type = LIB3DS_TRACK_VECTOR;
47             n->rot_track.type = LIB3DS_TRACK_QUAT;
48             n->hide_track.type = LIB3DS_TRACK_BOOL;
49             break;
50         }
51 
52         case LIB3DS_NODE_CAMERA: {
53             Lib3dsCameraNode *n = (Lib3dsCameraNode*)calloc(sizeof(Lib3dsCameraNode), 1);
54             node = (Lib3dsNode*)n;
55             n->pos_track.type = LIB3DS_TRACK_VECTOR;
56             n->fov_track.type = LIB3DS_TRACK_FLOAT;
57             n->roll_track.type = LIB3DS_TRACK_FLOAT;
58             break;
59         }
60 
61         case LIB3DS_NODE_CAMERA_TARGET: {
62             Lib3dsTargetNode *n = (Lib3dsTargetNode*)calloc(sizeof(Lib3dsTargetNode), 1);
63             node = (Lib3dsNode*)n;
64             n->pos_track.type = LIB3DS_TRACK_VECTOR;
65             break;
66         }
67 
68         case LIB3DS_NODE_OMNILIGHT: {
69             Lib3dsOmnilightNode *n = (Lib3dsOmnilightNode*)calloc(sizeof(Lib3dsOmnilightNode), 1);
70             node = (Lib3dsNode*)n;
71             n->pos_track.type = LIB3DS_TRACK_VECTOR;
72             n->color_track.type = LIB3DS_TRACK_VECTOR;
73             break;
74         }
75 
76         case LIB3DS_NODE_SPOTLIGHT: {
77             Lib3dsSpotlightNode *n = (Lib3dsSpotlightNode*)calloc(sizeof(Lib3dsSpotlightNode), 1);
78             node = (Lib3dsNode*)n;
79             n->pos_track.type = LIB3DS_TRACK_VECTOR;
80             n->color_track.type = LIB3DS_TRACK_VECTOR;
81             n->hotspot_track.type = LIB3DS_TRACK_FLOAT;
82             n->falloff_track.type = LIB3DS_TRACK_FLOAT;
83             n->roll_track.type = LIB3DS_TRACK_FLOAT;
84             break;
85         }
86 
87         case LIB3DS_NODE_SPOTLIGHT_TARGET: {
88             Lib3dsTargetNode *n = (Lib3dsTargetNode*)calloc(sizeof(Lib3dsTargetNode), 1);
89             node = (Lib3dsNode*)n;
90             n->pos_track.type = LIB3DS_TRACK_VECTOR;
91             break;
92         }
93 
94         default:
95             assert(0);
96             return NULL;
97     }
98 
99     node->type = type;
100     node->node_id = 65535;
101     node->user_id = 65535;
102     lib3ds_matrix_identity(node->matrix);
103     return node;
104 }
105 
106 
107 Lib3dsAmbientColorNode*
lib3ds_node_new_ambient_color(float color0[3])108 lib3ds_node_new_ambient_color(float color0[3]) {
109     Lib3dsNode *node;
110     Lib3dsAmbientColorNode *n;
111 
112     node = lib3ds_node_new(LIB3DS_NODE_AMBIENT_COLOR);
113 
114     n = (Lib3dsAmbientColorNode*)node;
115     lib3ds_track_resize(&n->color_track, 1);
116     if (color0) {
117         lib3ds_vector_copy(n->color_track.keys[0].value, color0);
118     } else {
119         lib3ds_vector_zero(n->color_track.keys[0].value);
120     }
121 
122     return n;
123 }
124 
125 
126 Lib3dsMeshInstanceNode*
lib3ds_node_new_mesh_instance(Lib3dsMesh * mesh,const char * instance_name,float pos0[3],float scl0[3],float rot0[4])127 lib3ds_node_new_mesh_instance(Lib3dsMesh *mesh, const char *instance_name, float pos0[3], float scl0[3], float rot0[4]) {
128     Lib3dsNode *node;
129     Lib3dsMeshInstanceNode *n;
130     int i;
131 
132     node = lib3ds_node_new(LIB3DS_NODE_MESH_INSTANCE);
133     if (mesh) {
134         strcpy(node->name, mesh->name);
135     } else {
136         strcpy(node->name, "$$$DUMMY");
137     }
138 
139     n = (Lib3dsMeshInstanceNode*)node;
140     if (instance_name) {
141         strcpy(n->instance_name, instance_name);
142     }
143 
144     lib3ds_track_resize(&n->pos_track, 1);
145     if (pos0) {
146         lib3ds_vector_copy(n->pos_track.keys[0].value, pos0);
147     }
148 
149     lib3ds_track_resize(&n->scl_track, 1);
150     if (scl0) {
151         lib3ds_vector_copy(n->scl_track.keys[0].value, scl0);
152     } else {
153         lib3ds_vector_make(n->scl_track.keys[0].value, 1, 1, 1);
154     }
155 
156     lib3ds_track_resize(&n->rot_track, 1);
157     if (rot0) {
158         for (i = 0; i < 4; ++i) n->rot_track.keys[0].value[i] = rot0[i];
159     } else {
160         for (i = 0; i < 4; ++i) n->rot_track.keys[0].value[i] = 0;
161     }
162 
163     return n;
164 }
165 
166 
167 Lib3dsCameraNode*
lib3ds_node_new_camera(Lib3dsCamera * camera)168 lib3ds_node_new_camera(Lib3dsCamera *camera) {
169     Lib3dsNode *node;
170     Lib3dsCameraNode *n;
171 
172     assert(camera);
173     node = lib3ds_node_new(LIB3DS_NODE_CAMERA);
174     strcpy(node->name, camera->name);
175 
176     n = (Lib3dsCameraNode*)node;
177     lib3ds_track_resize(&n->pos_track, 1);
178     lib3ds_vector_copy(n->pos_track.keys[0].value, camera->position);
179 
180     lib3ds_track_resize(&n->fov_track, 1);
181     n->fov_track.keys[0].value[0] = camera->fov;
182 
183     lib3ds_track_resize(&n->roll_track, 1);
184     n->roll_track.keys[0].value[0] = camera->roll;
185 
186     return n;
187 }
188 
189 
190 Lib3dsTargetNode*
lib3ds_node_new_camera_target(Lib3dsCamera * camera)191 lib3ds_node_new_camera_target(Lib3dsCamera *camera) {
192     Lib3dsNode *node;
193     Lib3dsTargetNode *n;
194 
195     assert(camera);
196     node = lib3ds_node_new(LIB3DS_NODE_CAMERA_TARGET);
197     strcpy(node->name, camera->name);
198 
199     n = (Lib3dsTargetNode*)node;
200     lib3ds_track_resize(&n->pos_track, 1);
201     lib3ds_vector_copy(n->pos_track.keys[0].value, camera->target);
202 
203     return n;
204 }
205 
206 
207 Lib3dsOmnilightNode*
lib3ds_node_new_omnilight(Lib3dsLight * light)208 lib3ds_node_new_omnilight(Lib3dsLight *light) {
209     Lib3dsNode *node;
210     Lib3dsOmnilightNode *n;
211 
212     assert(light);
213     node = lib3ds_node_new(LIB3DS_NODE_OMNILIGHT);
214     strcpy(node->name, light->name);
215 
216     n = (Lib3dsOmnilightNode*)node;
217     lib3ds_track_resize(&n->pos_track, 1);
218     lib3ds_vector_copy(n->pos_track.keys[0].value, light->position);
219 
220     lib3ds_track_resize(&n->color_track, 1);
221     lib3ds_vector_copy(n->color_track.keys[0].value, light->color);
222 
223     return n;
224 }
225 
226 
227 Lib3dsSpotlightNode*
lib3ds_node_new_spotlight(Lib3dsLight * light)228 lib3ds_node_new_spotlight(Lib3dsLight *light) {
229     Lib3dsNode *node;
230     Lib3dsSpotlightNode *n;
231 
232     assert(light);
233     node = lib3ds_node_new(LIB3DS_NODE_SPOTLIGHT);
234     strcpy(node->name, light->name);
235 
236     n = (Lib3dsSpotlightNode*)node;
237     lib3ds_track_resize(&n->pos_track, 1);
238     lib3ds_vector_copy(n->pos_track.keys[0].value, light->position);
239 
240     lib3ds_track_resize(&n->color_track, 1);
241     lib3ds_vector_copy(n->color_track.keys[0].value, light->color);
242 
243     lib3ds_track_resize(&n->hotspot_track, 1);
244     n->hotspot_track.keys[0].value[0] = light->hotspot;
245 
246     lib3ds_track_resize(&n->falloff_track, 1);
247     n->falloff_track.keys[0].value[0] = light->falloff;
248 
249     lib3ds_track_resize(&n->roll_track, 1);
250     n->roll_track.keys[0].value[0] = light->roll;
251 
252     return n;
253 }
254 
255 
256 Lib3dsTargetNode*
lib3ds_node_new_spotligf_target(Lib3dsLight * light)257 lib3ds_node_new_spotligf_target(Lib3dsLight *light) {
258     Lib3dsNode *node;
259     Lib3dsTargetNode *n;
260 
261     assert(light);
262     node = lib3ds_node_new(LIB3DS_NODE_SPOTLIGHT_TARGET);
263     strcpy(node->name, light->name);
264 
265     n = (Lib3dsTargetNode*)node;
266     lib3ds_track_resize(&n->pos_track, 1);
267     lib3ds_vector_copy(n->pos_track.keys[0].value, light->target);
268 
269     return n;
270 }
271 
272 
273 static void
free_node_and_childs(Lib3dsNode * node)274 free_node_and_childs(Lib3dsNode *node) {
275     assert(node);
276     switch (node->type) {
277         case LIB3DS_NODE_AMBIENT_COLOR: {
278             Lib3dsAmbientColorNode *n = (Lib3dsAmbientColorNode*)node;
279             lib3ds_track_resize(&n->color_track, 0);
280             break;
281         }
282 
283         case LIB3DS_NODE_MESH_INSTANCE: {
284             Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node;
285             lib3ds_track_resize(&n->pos_track, 0);
286             lib3ds_track_resize(&n->rot_track, 0);
287             lib3ds_track_resize(&n->scl_track, 0);
288             lib3ds_track_resize(&n->hide_track, 0);
289             break;
290         }
291 
292         case LIB3DS_NODE_CAMERA: {
293             Lib3dsCameraNode *n = (Lib3dsCameraNode*)node;
294             lib3ds_track_resize(&n->pos_track, 0);
295             lib3ds_track_resize(&n->fov_track, 0);
296             lib3ds_track_resize(&n->roll_track, 0);
297             break;
298         }
299 
300         case LIB3DS_NODE_CAMERA_TARGET: {
301             Lib3dsTargetNode *n = (Lib3dsTargetNode*)node;
302             lib3ds_track_resize(&n->pos_track, 0);
303             break;
304         }
305 
306         case LIB3DS_NODE_OMNILIGHT: {
307             Lib3dsOmnilightNode *n = (Lib3dsOmnilightNode*)node;
308             lib3ds_track_resize(&n->pos_track, 0);
309             lib3ds_track_resize(&n->color_track, 0);
310             break;
311         }
312 
313         case LIB3DS_NODE_SPOTLIGHT: {
314             Lib3dsSpotlightNode *n = (Lib3dsSpotlightNode*)node;
315             lib3ds_track_resize(&n->pos_track, 0);
316             lib3ds_track_resize(&n->color_track, 0);
317             lib3ds_track_resize(&n->hotspot_track, 0);
318             lib3ds_track_resize(&n->falloff_track, 0);
319             lib3ds_track_resize(&n->roll_track, 0);
320             break;
321         }
322 
323         case LIB3DS_NODE_SPOTLIGHT_TARGET: {
324             Lib3dsTargetNode *n = (Lib3dsTargetNode*)node;
325             lib3ds_track_resize(&n->pos_track, 0);
326             break;
327         }
328     }
329     {
330         Lib3dsNode *p, *q;
331         for (p = node->childs; p; p = q) {
332             q = p->next;
333             free_node_and_childs(p);
334         }
335     }
336     free(node);
337 }
338 
339 
340 /*!
341  * Free a node and all of its resources.
342  *
343  * \param node Lib3dsNode object to be freed.
344  */
345 void
lib3ds_node_free(Lib3dsNode * node)346 lib3ds_node_free(Lib3dsNode *node) {
347     assert(node);
348     free_node_and_childs(node);
349 }
350 
351 
352 /*!
353  * Evaluate an animation node.
354  *
355  * Recursively sets node and its children to their appropriate values
356  * for this point in the animation.
357  *
358  * \param node Node to be evaluated.
359  * \param t time value, between 0. and file->frames
360  */
361 void
lib3ds_node_eval(Lib3dsNode * node,float t)362 lib3ds_node_eval(Lib3dsNode *node, float t) {
363     assert(node);
364     switch (node->type) {
365         case LIB3DS_NODE_AMBIENT_COLOR: {
366             Lib3dsAmbientColorNode *n = (Lib3dsAmbientColorNode*)node;
367             if (node->parent) {
368                 lib3ds_matrix_copy(node->matrix, node->parent->matrix);
369             } else {
370                 lib3ds_matrix_identity(node->matrix);
371             }
372             lib3ds_track_eval_vector(&n->color_track, n->color, t);
373             break;
374         }
375 
376         case LIB3DS_NODE_MESH_INSTANCE: {
377             float M[4][4];
378             Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node;
379 
380             lib3ds_track_eval_vector(&n->pos_track, n->pos, t);
381             lib3ds_track_eval_quat(&n->rot_track, n->rot, t);
382             if (n->scl_track.nkeys) {
383                 lib3ds_track_eval_vector(&n->scl_track, n->scl, t);
384             } else {
385                 n->scl[0] = n->scl[1] = n->scl[2] = 1.0f;
386             }
387             lib3ds_track_eval_bool(&n->hide_track, &n->hide, t);
388 
389             lib3ds_matrix_identity(M);
390             lib3ds_matrix_translate(M, n->pos[0], n->pos[1], n->pos[2]);
391             lib3ds_matrix_rotate_quat(M, n->rot);
392             lib3ds_matrix_scale(M, n->scl[0], n->scl[1], n->scl[2]);
393 
394             if (node->parent) {
395                 lib3ds_matrix_mult(node->matrix, node->parent->matrix, M);
396             } else {
397                 lib3ds_matrix_copy(node->matrix, M);
398             }
399             break;
400         }
401 
402         case LIB3DS_NODE_CAMERA: {
403             Lib3dsCameraNode *n = (Lib3dsCameraNode*)node;
404             lib3ds_track_eval_vector(&n->pos_track, n->pos, t);
405             lib3ds_track_eval_float(&n->fov_track, &n->fov, t);
406             lib3ds_track_eval_float(&n->roll_track, &n->roll, t);
407             if (node->parent) {
408                 lib3ds_matrix_copy(node->matrix, node->parent->matrix);
409             } else {
410                 lib3ds_matrix_identity(node->matrix);
411             }
412             lib3ds_matrix_translate(node->matrix, n->pos[0], n->pos[1], n->pos[2]);
413             break;
414         }
415 
416         case LIB3DS_NODE_CAMERA_TARGET: {
417             Lib3dsTargetNode *n = (Lib3dsTargetNode*)node;
418             lib3ds_track_eval_vector(&n->pos_track, n->pos, t);
419             if (node->parent) {
420                 lib3ds_matrix_copy(node->matrix, node->parent->matrix);
421             } else {
422                 lib3ds_matrix_identity(node->matrix);
423             }
424             lib3ds_matrix_translate(node->matrix, n->pos[0], n->pos[1], n->pos[2]);
425             break;
426         }
427 
428         case LIB3DS_NODE_OMNILIGHT: {
429             Lib3dsOmnilightNode *n = (Lib3dsOmnilightNode*)node;
430             lib3ds_track_eval_vector(&n->pos_track, n->pos, t);
431             lib3ds_track_eval_vector(&n->color_track, n->color, t);
432             if (node->parent) {
433                 lib3ds_matrix_copy(node->matrix, node->parent->matrix);
434             } else {
435                 lib3ds_matrix_identity(node->matrix);
436             }
437             lib3ds_matrix_translate(node->matrix, n->pos[0], n->pos[1], n->pos[2]);
438             break;
439         }
440 
441         case LIB3DS_NODE_SPOTLIGHT: {
442             Lib3dsSpotlightNode *n = (Lib3dsSpotlightNode*)node;
443             lib3ds_track_eval_vector(&n->pos_track, n->pos, t);
444             lib3ds_track_eval_vector(&n->color_track, n->color, t);
445             lib3ds_track_eval_float(&n->hotspot_track, &n->hotspot, t);
446             lib3ds_track_eval_float(&n->falloff_track, &n->falloff, t);
447             lib3ds_track_eval_float(&n->roll_track, &n->roll, t);
448             if (node->parent) {
449                 lib3ds_matrix_copy(node->matrix, node->parent->matrix);
450             } else {
451                 lib3ds_matrix_identity(node->matrix);
452             }
453             lib3ds_matrix_translate(node->matrix, n->pos[0], n->pos[1], n->pos[2]);
454             break;
455         }
456 
457         case LIB3DS_NODE_SPOTLIGHT_TARGET: {
458             Lib3dsTargetNode *n = (Lib3dsTargetNode*)node;
459             lib3ds_track_eval_vector(&n->pos_track, n->pos, t);
460             if (node->parent) {
461                 lib3ds_matrix_copy(node->matrix, node->parent->matrix);
462             } else {
463                 lib3ds_matrix_identity(node->matrix);
464             }
465             lib3ds_matrix_translate(node->matrix, n->pos[0], n->pos[1], n->pos[2]);
466             break;
467         }
468     }
469     {
470         Lib3dsNode *p;
471         for (p = node->childs; p != 0; p = p->next) {
472             lib3ds_node_eval(p, t);
473         }
474     }
475 }
476 
477 
478 /*!
479  * Return a node object by name and type.
480  *
481  * This function performs a recursive search for the specified node.
482  * Both name and type must match.
483  *
484  * \param node The parent node for the search
485  * \param name The target node name.
486  * \param type The target node type
487  *
488  * \return A pointer to the first matching node, or NULL if not found.
489  */
490 Lib3dsNode*
lib3ds_node_by_name(Lib3dsNode * node,const char * name,Lib3dsNodeType type)491 lib3ds_node_by_name(Lib3dsNode *node, const char* name, Lib3dsNodeType type) {
492     Lib3dsNode *p, *q;
493 
494     for (p = node->childs; p != 0; p = p->next) {
495         if ((p->type == type) && (strcmp(p->name, name) == 0)) {
496             return(p);
497         }
498         q = lib3ds_node_by_name(p, name, type);
499         if (q) {
500             return(q);
501         }
502     }
503     return(0);
504 }
505 
506 
507 /*!
508  * Return a node object by id.
509  *
510  * This function performs a recursive search for the specified node.
511  *
512  * \param node The parent node for the search
513  * \param node_id The target node id.
514  *
515  * \return A pointer to the first matching node, or NULL if not found.
516  */
517 Lib3dsNode*
lib3ds_node_by_id(Lib3dsNode * node,uint16_t node_id)518 lib3ds_node_by_id(Lib3dsNode *node, uint16_t node_id) {
519     Lib3dsNode *p, *q;
520 
521     for (p = node->childs; p != 0; p = p->next) {
522         if (p->node_id == node_id) {
523             return(p);
524         }
525         q = lib3ds_node_by_id(p, node_id);
526         if (q) {
527             return(q);
528         }
529     }
530     return(0);
531 }
532 
533 
534 void
lib3ds_node_read(Lib3dsNode * node,Lib3dsIo * io)535 lib3ds_node_read(Lib3dsNode *node, Lib3dsIo *io) {
536     Lib3dsChunk c;
537     uint16_t chunk;
538 
539     assert(node);
540     lib3ds_chunk_read_start(&c, 0, io);
541 
542     switch (c.chunk) {
543         case CHK_AMBIENT_NODE_TAG:
544         case CHK_OBJECT_NODE_TAG:
545         case CHK_CAMERA_NODE_TAG:
546         case CHK_TARGET_NODE_TAG:
547         case CHK_LIGHT_NODE_TAG:
548         case CHK_SPOTLIGHT_NODE_TAG:
549         case CHK_L_TARGET_NODE_TAG:
550             break;
551         default:
552             return;
553     }
554 
555     while ((chunk = lib3ds_chunk_read_next(&c, io)) != 0)  {
556         switch (chunk) {
557             case CHK_NODE_ID: {
558                 node->node_id = lib3ds_io_read_word(io);
559                 lib3ds_io_log_indent(io, 1);
560                 lib3ds_io_log(io, LIB3DS_LOG_INFO, "ID=%d", (short)node->node_id);
561                 lib3ds_io_log_indent(io, -1);
562                 break;
563             }
564 
565             case CHK_NODE_HDR: {
566                 lib3ds_io_read_string(io, node->name, 64);
567                 node->flags = lib3ds_io_read_word(io);
568                 node->flags |= ((uint32_t)lib3ds_io_read_word(io)) << 16;
569                 node->user_id = lib3ds_io_read_word(io);
570 
571                 lib3ds_io_log_indent(io, 1);
572                 lib3ds_io_log(io, LIB3DS_LOG_INFO, "NAME=%s", node->name);
573                 lib3ds_io_log(io, LIB3DS_LOG_INFO, "PARENT=%d", (short)node->user_id);
574                 lib3ds_io_log_indent(io, -1);
575                 break;
576             }
577 
578             case CHK_PIVOT: {
579                 if (node->type == LIB3DS_NODE_MESH_INSTANCE) {
580                     Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node;
581                     lib3ds_io_read_vector(io, n->pivot);
582                 } else {
583                     lib3ds_chunk_unknown(chunk, io);
584                 }
585                 break;
586             }
587 
588             case CHK_INSTANCE_NAME: {
589                 if (node->type == LIB3DS_NODE_MESH_INSTANCE) {
590                     Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node;
591                     lib3ds_io_read_string(io, n->instance_name, 64);
592                 } else {
593                     lib3ds_chunk_unknown(chunk, io);
594                 }
595                 break;
596             }
597 
598             case CHK_BOUNDBOX: {
599                 if (node->type == LIB3DS_NODE_MESH_INSTANCE) {
600                     Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node;
601                     lib3ds_io_read_vector(io, n->bbox_min);
602                     lib3ds_io_read_vector(io, n->bbox_max);
603                 } else {
604                     lib3ds_chunk_unknown(chunk, io);
605                 }
606                 break;
607             }
608 
609             case CHK_COL_TRACK_TAG: {
610                 Lib3dsTrack *track = 0;
611                 switch (node->type) {
612                     case LIB3DS_NODE_AMBIENT_COLOR: {
613                         Lib3dsAmbientColorNode *n = (Lib3dsAmbientColorNode*)node;
614                         track = &n->color_track;
615                         break;
616                     }
617                     case LIB3DS_NODE_OMNILIGHT: {
618                         Lib3dsOmnilightNode *n = (Lib3dsOmnilightNode*)node;
619                         track = &n->color_track;
620                         break;
621                     }
622                     case LIB3DS_NODE_SPOTLIGHT: {
623                         Lib3dsSpotlightNode *n = (Lib3dsSpotlightNode*)node;
624                         track = &n->color_track;
625                         break;
626                     }
627                     default:
628                         lib3ds_chunk_unknown(chunk, io);
629                 }
630                 if (track) {
631                     lib3ds_track_read(track, io);
632                 }
633                 break;
634             }
635 
636             case CHK_POS_TRACK_TAG: {
637                 Lib3dsTrack *track = 0;
638                 switch (node->type) {
639                     case LIB3DS_NODE_MESH_INSTANCE: {
640                         Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node;
641                         track = &n->pos_track;
642                         break;
643                     }
644                     case LIB3DS_NODE_CAMERA: {
645                         Lib3dsCameraNode *n = (Lib3dsCameraNode*)node;
646                         track = &n->pos_track;
647                         break;
648                     }
649                     case LIB3DS_NODE_CAMERA_TARGET: {
650                         Lib3dsTargetNode *n = (Lib3dsTargetNode*)node;
651                         track = &n->pos_track;
652                         break;
653                     }
654                     case LIB3DS_NODE_OMNILIGHT: {
655                         Lib3dsOmnilightNode *n = (Lib3dsOmnilightNode*)node;
656                         track = &n->pos_track;
657                         break;
658                     }
659                     case LIB3DS_NODE_SPOTLIGHT: {
660                         Lib3dsSpotlightNode *n = (Lib3dsSpotlightNode*)node;
661                         track = &n->pos_track;
662                         break;
663                     }
664                     case LIB3DS_NODE_SPOTLIGHT_TARGET: {
665                         Lib3dsTargetNode *n = (Lib3dsTargetNode*)node;
666                         track = &n->pos_track;
667                         break;
668                     }
669                     default:
670                         lib3ds_chunk_unknown(chunk, io);
671                 }
672                 if (track) {
673                     lib3ds_track_read(track, io);
674                 }
675                 break;
676             }
677 
678             case CHK_ROT_TRACK_TAG: {
679                 if (node->type == LIB3DS_NODE_MESH_INSTANCE) {
680                     Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node;
681                     n->rot_track.type = LIB3DS_TRACK_QUAT;
682                     lib3ds_track_read(&n->rot_track, io);
683                 } else {
684                     lib3ds_chunk_unknown(chunk, io);
685                 }
686                 break;
687             }
688 
689             case CHK_SCL_TRACK_TAG: {
690                 if (node->type == LIB3DS_NODE_MESH_INSTANCE) {
691                     Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node;
692                     n->scl_track.type = LIB3DS_TRACK_VECTOR;
693                     lib3ds_track_read(&n->scl_track, io);
694                 } else {
695                     lib3ds_chunk_unknown(chunk, io);
696                 }
697                 break;
698             }
699 
700             case CHK_FOV_TRACK_TAG: {
701                 if (node->type == LIB3DS_NODE_CAMERA) {
702                     Lib3dsCameraNode *n = (Lib3dsCameraNode*)node;
703                     n->fov_track.type = LIB3DS_TRACK_FLOAT;
704                     lib3ds_track_read(&n->fov_track, io);
705                 } else {
706                     lib3ds_chunk_unknown(chunk, io);
707                 }
708                 break;
709             }
710 
711             case CHK_HOT_TRACK_TAG: {
712                 if (node->type == LIB3DS_NODE_SPOTLIGHT) {
713                     Lib3dsSpotlightNode *n = (Lib3dsSpotlightNode*)node;
714                     n->hotspot_track.type = LIB3DS_TRACK_FLOAT;
715                     lib3ds_track_read(&n->hotspot_track, io);
716                 } else {
717                     lib3ds_chunk_unknown(chunk, io);
718                 }
719                 break;
720             }
721 
722             case CHK_FALL_TRACK_TAG: {
723                 if (node->type == LIB3DS_NODE_SPOTLIGHT) {
724                     Lib3dsSpotlightNode *n = (Lib3dsSpotlightNode*)node;
725                     n->falloff_track.type= LIB3DS_TRACK_FLOAT;
726                     lib3ds_track_read(&n->falloff_track, io);
727                 } else {
728                     lib3ds_chunk_unknown(chunk, io);
729                 }
730                 break;
731             }
732 
733             case CHK_ROLL_TRACK_TAG: {
734                 switch (node->type) {
735                     case LIB3DS_NODE_CAMERA: {
736                         Lib3dsCameraNode *n = (Lib3dsCameraNode*)node;
737                         n->roll_track.type = LIB3DS_TRACK_FLOAT;
738                         lib3ds_track_read(&n->roll_track, io);
739                         break;
740                     }
741                     case LIB3DS_NODE_SPOTLIGHT: {
742                         Lib3dsSpotlightNode *n = (Lib3dsSpotlightNode*)node;
743                         n->roll_track.type = LIB3DS_TRACK_FLOAT;
744                         lib3ds_track_read(&n->roll_track, io);
745                         break;
746                     }
747                     default:
748                         lib3ds_chunk_unknown(chunk, io);
749                 }
750                 break;
751             }
752 
753             case CHK_HIDE_TRACK_TAG: {
754                 if (node->type == LIB3DS_NODE_MESH_INSTANCE) {
755                     Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node;
756                     n->hide_track.type = LIB3DS_TRACK_BOOL;
757                     lib3ds_track_read(&n->hide_track, io);
758                 } else {
759                     lib3ds_chunk_unknown(chunk, io);
760                 }
761                 break;
762             }
763 
764             case CHK_MORPH_SMOOTH: {
765                 if (node->type == LIB3DS_NODE_MESH_INSTANCE) {
766                     Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node;
767                     n->morph_smooth = lib3ds_io_read_float(io);
768                 } else {
769                     lib3ds_chunk_unknown(chunk, io);
770                 }
771             }
772             break;
773 
774             /*
775             case LIB3DS_MORPH_TRACK_TAG: {
776                 if (node->type == LIB3DS_NODE_MESH_INSTANCE) {
777                     Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node;
778                     n->morph_track = lib3ds_track_new(node, LIB3DS_TRACK_MORPH, 0);
779                     lib3ds_track_read(n->morph_track, io);
780                 } else {
781                     lib3ds_chunk_unknown(chunk, io);
782                 }
783             }
784             break;
785             */
786 
787             default:
788                 lib3ds_chunk_unknown(chunk, io);
789         }
790     }
791 
792     lib3ds_chunk_read_end(&c, io);
793 }
794 
795 
796 void
lib3ds_node_write(Lib3dsNode * node,uint16_t node_id,uint16_t parent_id,Lib3dsIo * io)797 lib3ds_node_write(Lib3dsNode *node, uint16_t node_id, uint16_t parent_id, Lib3dsIo *io) {
798     Lib3dsChunk c;
799 
800     switch (node->type) {
801         case LIB3DS_NODE_AMBIENT_COLOR:
802             c.chunk = CHK_AMBIENT_NODE_TAG;
803             break;
804 
805         case LIB3DS_NODE_MESH_INSTANCE:
806             c.chunk = CHK_OBJECT_NODE_TAG;
807             break;
808 
809         case LIB3DS_NODE_CAMERA:
810             c.chunk = CHK_CAMERA_NODE_TAG;
811             break;
812 
813         case LIB3DS_NODE_CAMERA_TARGET:
814             c.chunk = CHK_TARGET_NODE_TAG;
815             break;
816 
817         case LIB3DS_NODE_OMNILIGHT:
818             c.chunk = CHK_LIGHT_NODE_TAG;
819             break;
820 
821         case LIB3DS_NODE_SPOTLIGHT:
822             c.chunk = CHK_SPOTLIGHT_NODE_TAG;
823             break;
824 
825         case LIB3DS_NODE_SPOTLIGHT_TARGET:
826             c.chunk = CHK_L_TARGET_NODE_TAG;
827             break;
828 
829         default:
830             assert(0);
831             return;
832     }
833 
834     lib3ds_chunk_write_start(&c, io);
835 
836     { /*---- CHK_NODE_ID ----*/
837         Lib3dsChunk c;
838         c.chunk = CHK_NODE_ID;
839         c.size = 8;
840         lib3ds_chunk_write(&c, io);
841         lib3ds_io_write_intw(io, node_id);
842     }
843 
844     { /*---- CHK_NODE_HDR ----*/
845         Lib3dsChunk c;
846         c.chunk = CHK_NODE_HDR;
847         c.size = 6 + 1 + (uint32_t)strlen(node->name) + 2 + 2 + 2;
848         lib3ds_chunk_write(&c, io);
849         lib3ds_io_write_string(io, node->name);
850         lib3ds_io_write_word(io, node->flags & 0xffff);
851         lib3ds_io_write_word(io, (node->flags >> 16) & 0xffff);
852         lib3ds_io_write_word(io, parent_id);
853     }
854 
855     switch (c.chunk) {
856         case CHK_AMBIENT_NODE_TAG: {
857             Lib3dsAmbientColorNode *n = (Lib3dsAmbientColorNode*)node;
858             if (n->color_track.nkeys) { /*---- CHK_COL_TRACK_TAG ----*/
859                 Lib3dsChunk c;
860                 c.chunk = CHK_COL_TRACK_TAG;
861                 lib3ds_chunk_write_start(&c, io);
862                 lib3ds_track_write(&n->color_track, io);
863                 lib3ds_chunk_write_end(&c, io);
864             }
865             break;
866         }
867 
868         case CHK_OBJECT_NODE_TAG: {
869             Lib3dsMeshInstanceNode *n = (Lib3dsMeshInstanceNode*)node;
870             { /*---- CHK_PIVOT ----*/
871                 Lib3dsChunk c;
872                 c.chunk = CHK_PIVOT;
873                 c.size = 18;
874                 lib3ds_chunk_write(&c, io);
875                 lib3ds_io_write_vector(io, n->pivot);
876             }
877 
878             { /*---- CHK_INSTANCE_NAME ----*/
879                 Lib3dsChunk c;
880                 const char *name;
881                 if (strlen(n->instance_name)) {
882                     name = n->instance_name;
883 
884                     c.chunk = CHK_INSTANCE_NAME;
885                     c.size = 6 + 1 + (uint32_t)strlen(name);
886                     lib3ds_chunk_write(&c, io);
887                     lib3ds_io_write_string(io, name);
888                 }
889             }
890             {
891                 int i;
892                 for (i = 0; i < 3; ++i) {
893                     if ((fabs(n->bbox_min[i]) > LIB3DS_EPSILON) ||
894                         (fabs(n->bbox_max[i]) > LIB3DS_EPSILON)) {
895                         break;
896                     }
897                 }
898 
899                 if (i < 3) { /*---- CHK_BOUNDBOX ----*/
900                     Lib3dsChunk c;
901                     c.chunk = CHK_BOUNDBOX;
902                     c.size = 30;
903                     lib3ds_chunk_write(&c, io);
904                     lib3ds_io_write_vector(io, n->bbox_min);
905                     lib3ds_io_write_vector(io, n->bbox_max);
906                 }
907             }
908 
909             if (n->pos_track.nkeys) { /*---- CHK_POS_TRACK_TAG ----*/
910                 Lib3dsChunk c;
911                 c.chunk = CHK_POS_TRACK_TAG;
912                 lib3ds_chunk_write_start(&c, io);
913                 lib3ds_track_write(&n->pos_track, io);
914                 lib3ds_chunk_write_end(&c, io);
915             }
916             if (n->rot_track.nkeys) { /*---- CHK_ROT_TRACK_TAG ----*/
917                 Lib3dsChunk c;
918                 c.chunk = CHK_ROT_TRACK_TAG;
919                 lib3ds_chunk_write_start(&c, io);
920                 lib3ds_track_write(&n->rot_track, io);
921                 lib3ds_chunk_write_end(&c, io);
922             }
923             if (n->scl_track.nkeys) { /*---- LIB3DS_SCL_TRACK_TAG ----*/
924                 Lib3dsChunk c;
925                 c.chunk = CHK_SCL_TRACK_TAG;
926                 lib3ds_chunk_write_start(&c, io);
927                 lib3ds_track_write(&n->scl_track, io);
928                 lib3ds_chunk_write_end(&c, io);
929             }
930             if (n->hide_track.nkeys) { /*---- CHK_HIDE_TRACK_TAG ----*/
931                 Lib3dsChunk c;
932                 c.chunk = CHK_HIDE_TRACK_TAG;
933                 lib3ds_chunk_write_start(&c, io);
934                 lib3ds_track_write(&n->hide_track, io);
935                 lib3ds_chunk_write_end(&c, io);
936             }
937             if (fabs(n->morph_smooth) > LIB3DS_EPSILON) { /*---- CHK_MORPH_SMOOTH ----*/
938                 Lib3dsChunk c;
939                 c.chunk = CHK_MORPH_SMOOTH;
940                 c.size = 10;
941                 lib3ds_chunk_write(&c, io);
942                 lib3ds_io_write_float(io, n->morph_smooth);
943             }
944             break;
945         }
946 
947         case CHK_CAMERA_NODE_TAG: {
948             Lib3dsCameraNode *n = (Lib3dsCameraNode*)node;
949             if (n->pos_track.nkeys) { /*---- CHK_POS_TRACK_TAG ----*/
950                 Lib3dsChunk c;
951                 c.chunk = CHK_POS_TRACK_TAG;
952                 lib3ds_chunk_write_start(&c, io);
953                 lib3ds_track_write(&n->pos_track, io);
954                 lib3ds_chunk_write_end(&c, io);
955             }
956             if (n->fov_track.nkeys) { /*---- CHK_FOV_TRACK_TAG ----*/
957                 Lib3dsChunk c;
958                 c.chunk = CHK_FOV_TRACK_TAG;
959                 lib3ds_chunk_write_start(&c, io);
960                 lib3ds_track_write(&n->fov_track, io);
961                 lib3ds_chunk_write_end(&c, io);
962             }
963             if (n->roll_track.nkeys) { /*---- CHK_ROLL_TRACK_TAG ----*/
964                 Lib3dsChunk c;
965                 c.chunk = CHK_ROLL_TRACK_TAG;
966                 lib3ds_chunk_write_start(&c, io);
967                 lib3ds_track_write(&n->roll_track, io);
968                 lib3ds_chunk_write_end(&c, io);
969             }
970             break;
971         }
972 
973         case CHK_TARGET_NODE_TAG: {
974             Lib3dsTargetNode *n = (Lib3dsTargetNode*)node;
975             if (n->pos_track.nkeys) { /*---- CHK_POS_TRACK_TAG ----*/
976                 Lib3dsChunk c;
977                 c.chunk = CHK_POS_TRACK_TAG;
978                 lib3ds_chunk_write_start(&c, io);
979                 lib3ds_track_write(&n->pos_track, io);
980                 lib3ds_chunk_write_end(&c, io);
981             }
982             break;
983         }
984 
985         case CHK_LIGHT_NODE_TAG: {
986             Lib3dsOmnilightNode *n = (Lib3dsOmnilightNode*)node;
987             if (n->pos_track.nkeys) { /*---- CHK_POS_TRACK_TAG ----*/
988                 Lib3dsChunk c;
989                 c.chunk = CHK_POS_TRACK_TAG;
990                 lib3ds_chunk_write_start(&c, io);
991                 lib3ds_track_write(&n->pos_track, io);
992                 lib3ds_chunk_write_end(&c, io);
993             }
994             if (n->color_track.nkeys) { /*---- CHK_COL_TRACK_TAG ----*/
995                 Lib3dsChunk c;
996                 c.chunk = CHK_COL_TRACK_TAG;
997                 lib3ds_chunk_write_start(&c, io);
998                 lib3ds_track_write(&n->color_track, io);
999                 lib3ds_chunk_write_end(&c, io);
1000             }
1001             break;
1002         }
1003 
1004         case CHK_SPOTLIGHT_NODE_TAG: {
1005             Lib3dsSpotlightNode *n = (Lib3dsSpotlightNode*)node;
1006             if (n->pos_track.nkeys) { /*---- CHK_POS_TRACK_TAG ----*/
1007                 Lib3dsChunk c;
1008                 c.chunk = CHK_POS_TRACK_TAG;
1009                 lib3ds_chunk_write_start(&c, io);
1010                 lib3ds_track_write(&n->pos_track, io);
1011                 lib3ds_chunk_write_end(&c, io);
1012             }
1013             if (n->color_track.nkeys) { /*---- CHK_COL_TRACK_TAG ----*/
1014                 Lib3dsChunk c;
1015                 c.chunk = CHK_COL_TRACK_TAG;
1016                 lib3ds_chunk_write_start(&c, io);
1017                 lib3ds_track_write(&n->color_track, io);
1018                 lib3ds_chunk_write_end(&c, io);
1019             }
1020             if (n->hotspot_track.nkeys) { /*---- CHK_HOT_TRACK_TAG ----*/
1021                 Lib3dsChunk c;
1022                 c.chunk = CHK_HOT_TRACK_TAG;
1023                 lib3ds_chunk_write_start(&c, io);
1024                 lib3ds_track_write(&n->hotspot_track, io);
1025                 lib3ds_chunk_write_end(&c, io);
1026             }
1027             if (n->falloff_track.nkeys) { /*---- CHK_FALL_TRACK_TAG ----*/
1028                 Lib3dsChunk c;
1029                 c.chunk = CHK_FALL_TRACK_TAG;
1030                 lib3ds_chunk_write_start(&c, io);
1031                 lib3ds_track_write(&n->falloff_track, io);
1032                 lib3ds_chunk_write_end(&c, io);
1033             }
1034             if (n->roll_track.nkeys) { /*---- CHK_ROLL_TRACK_TAG ----*/
1035                 Lib3dsChunk c;
1036                 c.chunk = CHK_ROLL_TRACK_TAG;
1037                 lib3ds_chunk_write_start(&c, io);
1038                 lib3ds_track_write(&n->roll_track, io);
1039                 lib3ds_chunk_write_end(&c, io);
1040             }
1041             break;
1042         }
1043 
1044         case CHK_L_TARGET_NODE_TAG: {
1045             Lib3dsTargetNode *n = (Lib3dsTargetNode*)node;
1046             if (n->pos_track.nkeys) { /*---- CHK_POS_TRACK_TAG ----*/
1047                 Lib3dsChunk c;
1048                 c.chunk = CHK_POS_TRACK_TAG;
1049                 lib3ds_chunk_write_start(&c, io);
1050                 lib3ds_track_write(&n->pos_track, io);
1051                 lib3ds_chunk_write_end(&c, io);
1052             }
1053             break;
1054         }
1055 
1056         default:
1057             break;
1058     }
1059 
1060     lib3ds_chunk_write_end(&c, io);
1061 }
1062 
1063