diff options
Diffstat (limited to '')
-rw-r--r-- | src/others/mimesh/libg3d-0.0.8/plugins/import/imp_3ds/imp_3ds_callbacks.c | 992 |
1 files changed, 992 insertions, 0 deletions
diff --git a/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_3ds/imp_3ds_callbacks.c b/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_3ds/imp_3ds_callbacks.c new file mode 100644 index 0000000..fdd9823 --- /dev/null +++ b/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_3ds/imp_3ds_callbacks.c | |||
@@ -0,0 +1,992 @@ | |||
1 | /* $Id$ */ | ||
2 | |||
3 | /* | ||
4 | libg3d - 3D object loading library | ||
5 | |||
6 | Copyright (C) 2005-2009 Markus Dahms <mad@automagically.de> | ||
7 | |||
8 | This library is free software; you can redistribute it and/or | ||
9 | modify it under the terms of the GNU Lesser General Public | ||
10 | License as published by the Free Software Foundation; either | ||
11 | version 2.1 of the License, or (at your option) any later version. | ||
12 | |||
13 | This library is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | Lesser General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU Lesser General Public | ||
19 | License along with this library; if not, write to the Free Software | ||
20 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
21 | */ | ||
22 | #include <string.h> | ||
23 | #include <math.h> | ||
24 | |||
25 | #include <g3d/stream.h> | ||
26 | #include <g3d/texture.h> | ||
27 | #include <g3d/vector.h> | ||
28 | #include <g3d/matrix.h> | ||
29 | |||
30 | #include "imp_3ds_callbacks.h" | ||
31 | |||
32 | #define X3DS_FLAG_TENSION 0x01 | ||
33 | #define X3DS_FLAG_CONTINUITY 0x02 | ||
34 | #define X3DS_FLAG_BIAS 0x04 | ||
35 | #define X3DS_FLAG_EASE_TO 0x08 | ||
36 | #define X3DS_FLAG_EASE_FROM 0x10 | ||
37 | |||
38 | gboolean x3ds_cb_0x0002(x3ds_global_data *global, x3ds_parent_data *parent) | ||
39 | { | ||
40 | gint32 version; | ||
41 | |||
42 | version = g3d_stream_read_int32_le(global->stream); | ||
43 | parent->nb -= 4; | ||
44 | #if DEBUG > 0 | ||
45 | g_debug("[3DS] M3D version %d", version); | ||
46 | #endif | ||
47 | return TRUE; | ||
48 | } | ||
49 | |||
50 | /* color float */ | ||
51 | gboolean x3ds_cb_0x0010(x3ds_global_data *global, x3ds_parent_data *parent) | ||
52 | { | ||
53 | G3DMaterial *material; | ||
54 | G3DFloat r, g, b; | ||
55 | |||
56 | r = g3d_stream_read_float_le(global->stream); | ||
57 | g = g3d_stream_read_float_le(global->stream); | ||
58 | b = g3d_stream_read_float_le(global->stream); | ||
59 | parent->nb -= 12; | ||
60 | |||
61 | switch(parent->id) | ||
62 | { | ||
63 | case 0x1200: /* SOLID_BGND */ | ||
64 | g3d_context_set_bgcolor(global->context, r, g, b, 1.0); | ||
65 | break; | ||
66 | |||
67 | case 0xA010: /* ambient color */ | ||
68 | break; | ||
69 | |||
70 | case 0xA020: /* diffuse color */ | ||
71 | material = (G3DMaterial *)parent->object; | ||
72 | g_return_val_if_fail(material, FALSE); | ||
73 | |||
74 | material->r = r; | ||
75 | material->g = g; | ||
76 | material->b = b; | ||
77 | break; | ||
78 | |||
79 | case 0xA030: /* specular color */ | ||
80 | material = (G3DMaterial *)parent->object; | ||
81 | g_return_val_if_fail(material, FALSE); | ||
82 | |||
83 | material->specular[0] = r; | ||
84 | material->specular[1] = g; | ||
85 | material->specular[2] = b; | ||
86 | material->specular[3] = 0.25; | ||
87 | break; | ||
88 | |||
89 | default: | ||
90 | #if DEBUG > 0 | ||
91 | g_warning("[3DS] unhandled COLOR_F in 0x%04X", parent->id); | ||
92 | #endif | ||
93 | break; | ||
94 | } | ||
95 | |||
96 | return TRUE; | ||
97 | } | ||
98 | |||
99 | /* color 24 */ | ||
100 | gboolean x3ds_cb_0x0011(x3ds_global_data *global, x3ds_parent_data *parent) | ||
101 | { | ||
102 | G3DMaterial *material; | ||
103 | gint32 r, g, b; | ||
104 | |||
105 | material = (G3DMaterial *)parent->object; | ||
106 | g_return_val_if_fail(material, FALSE); | ||
107 | |||
108 | r = g3d_stream_read_int8(global->stream); | ||
109 | g = g3d_stream_read_int8(global->stream); | ||
110 | b = g3d_stream_read_int8(global->stream); | ||
111 | parent->nb -= 3; | ||
112 | |||
113 | switch(parent->id) | ||
114 | { | ||
115 | |||
116 | case 0xA010: /* ambient color */ | ||
117 | break; | ||
118 | |||
119 | case 0xA020: /* diffuse color */ | ||
120 | material->r = (G3DFloat)r / 255.0; | ||
121 | material->g = (G3DFloat)g / 255.0; | ||
122 | material->b = (G3DFloat)b / 255.0; | ||
123 | break; | ||
124 | |||
125 | case 0xA030: /* specular color */ | ||
126 | material->specular[0] = (GLfloat)r / 255.0; | ||
127 | material->specular[1] = (GLfloat)g / 255.0; | ||
128 | material->specular[2] = (GLfloat)b / 255.0; | ||
129 | material->specular[3] = 0.25; | ||
130 | break; | ||
131 | |||
132 | default: | ||
133 | #if DEBUG > 0 | ||
134 | g_warning("[3DS] unhandled COLOR_24 in 0x%04X", parent->id); | ||
135 | #endif | ||
136 | break; | ||
137 | } | ||
138 | |||
139 | return TRUE; | ||
140 | } | ||
141 | |||
142 | /* short percentage */ | ||
143 | gboolean x3ds_cb_0x0030(x3ds_global_data *global, x3ds_parent_data *parent) | ||
144 | { | ||
145 | G3DMaterial *material; | ||
146 | gint32 percent; | ||
147 | |||
148 | material = (G3DMaterial *)parent->object; | ||
149 | g_return_val_if_fail(material, FALSE); | ||
150 | |||
151 | percent = g3d_stream_read_int16_le(global->stream); | ||
152 | parent->nb -= 2; | ||
153 | |||
154 | switch(parent->id) | ||
155 | { | ||
156 | case 0xA040: /* shininess */ | ||
157 | material->shininess = (G3DFloat)percent / 100.0; | ||
158 | break; | ||
159 | |||
160 | case 0xA041: /* shininess (2) */ | ||
161 | /* TODO: do something here? */ | ||
162 | break; | ||
163 | |||
164 | case 0xA050: /* transparency */ | ||
165 | material->a = 1.0 - ((G3DFloat)percent / 100.0); | ||
166 | break; | ||
167 | |||
168 | case 0xA052: /* fallthrough */ | ||
169 | /* TODO: do something here? */ | ||
170 | break; | ||
171 | |||
172 | case 0xA053: /* blur */ | ||
173 | /* TODO: do something here? */ | ||
174 | break; | ||
175 | |||
176 | case 0xA084: /* self illumination */ | ||
177 | /* TODO: do something here? */ | ||
178 | break; | ||
179 | |||
180 | case 0xA200: /* texture map */ | ||
181 | /* TODO: do something here? */ | ||
182 | break; | ||
183 | |||
184 | case 0xA210: /* opacity map */ | ||
185 | /* TODO: do something here? */ | ||
186 | g_debug("[3DS] opacity percentage: %d%%\n", percent); | ||
187 | break; | ||
188 | |||
189 | case 0xA220: /* reflection map */ | ||
190 | /* TODO: do something here? */ | ||
191 | break; | ||
192 | |||
193 | case 0xA230: /* bump map */ | ||
194 | /* TODO: do something here? */ | ||
195 | break; | ||
196 | |||
197 | default: | ||
198 | #if DEBUG > 0 | ||
199 | g_warning("[3DS] unhandled INT_PERCENTAGE in 0x%04X", | ||
200 | parent->id); | ||
201 | #endif | ||
202 | break; | ||
203 | } | ||
204 | |||
205 | return TRUE; | ||
206 | } | ||
207 | |||
208 | /* float percentage */ | ||
209 | gboolean x3ds_cb_0x0031(x3ds_global_data *global, x3ds_parent_data *parent) | ||
210 | { | ||
211 | G3DMaterial *material; | ||
212 | G3DFloat percent; | ||
213 | |||
214 | material = (G3DMaterial *)parent->object; | ||
215 | g_return_val_if_fail(material, FALSE); | ||
216 | |||
217 | percent = g3d_stream_read_float_le(global->stream); | ||
218 | parent->nb -= 4; | ||
219 | |||
220 | switch(parent->id) | ||
221 | { | ||
222 | case 0xA040: /* shininess */ | ||
223 | material->shininess = percent; | ||
224 | break; | ||
225 | |||
226 | case 0xA050: /* transparency */ | ||
227 | material->a = 1.0 - percent; | ||
228 | break; | ||
229 | |||
230 | default: | ||
231 | #if DEBUG > 0 | ||
232 | g_warning("[3DS] unhandled FLOAT_PERCENTAGE in 0x%04X", | ||
233 | parent->id); | ||
234 | #endif | ||
235 | break; | ||
236 | } | ||
237 | |||
238 | return TRUE; | ||
239 | } | ||
240 | |||
241 | /* master scale */ | ||
242 | gboolean x3ds_cb_0x0100(x3ds_global_data *global, x3ds_parent_data *parent) | ||
243 | { | ||
244 | global->scale = g3d_stream_read_float_le(global->stream); | ||
245 | parent->nb -= 4; | ||
246 | |||
247 | return TRUE; | ||
248 | } | ||
249 | |||
250 | /* named object */ | ||
251 | gboolean x3ds_cb_0x4000(x3ds_global_data *global, x3ds_parent_data *parent) | ||
252 | { | ||
253 | gchar buffer[1024]; | ||
254 | |||
255 | parent->nb -= x3ds_read_cstr(global->stream, buffer); | ||
256 | parent->object = x3ds_newobject(global->model, buffer); | ||
257 | |||
258 | return TRUE; | ||
259 | } | ||
260 | |||
261 | /* point array */ | ||
262 | gboolean x3ds_cb_0x4110(x3ds_global_data *global, x3ds_parent_data *parent) | ||
263 | { | ||
264 | G3DObject *object; | ||
265 | gint32 i; | ||
266 | |||
267 | object = (G3DObject *)parent->object; | ||
268 | g_return_val_if_fail(object, FALSE); | ||
269 | |||
270 | object->vertex_count = g3d_stream_read_int16_le(global->stream); | ||
271 | parent->nb -= 2; | ||
272 | |||
273 | object->vertex_data = g_new0(G3DFloat, object->vertex_count * 3); | ||
274 | for(i = 0; i < object->vertex_count; i ++) | ||
275 | { | ||
276 | object->vertex_data[i * 3 + 0] = g3d_stream_read_float_le(global->stream); | ||
277 | object->vertex_data[i * 3 + 1] = g3d_stream_read_float_le(global->stream); | ||
278 | object->vertex_data[i * 3 + 2] = g3d_stream_read_float_le(global->stream); | ||
279 | |||
280 | parent->nb -= 12; | ||
281 | |||
282 | if((i % 1000) == 0) x3ds_update_progress(global, parent->level); | ||
283 | } | ||
284 | return TRUE; | ||
285 | } | ||
286 | |||
287 | /* face array */ | ||
288 | gboolean x3ds_cb_0x4120(x3ds_global_data *global, x3ds_parent_data *parent) | ||
289 | { | ||
290 | gint32 i, flags, nfaces; | ||
291 | #define X3DS_REORDER_FACES | ||
292 | #ifdef X3DS_REORDER_FACES | ||
293 | gint32 p1 = -1, p2 = -1, bottle; | ||
294 | #endif | ||
295 | G3DFace *face; | ||
296 | G3DObject *object; | ||
297 | |||
298 | object = (G3DObject *)parent->object; | ||
299 | g_return_val_if_fail(object, FALSE); | ||
300 | |||
301 | nfaces = g3d_stream_read_int16_le(global->stream); | ||
302 | parent->nb -= 2; | ||
303 | |||
304 | for(i = 0; i < nfaces; i ++) | ||
305 | { | ||
306 | face = g_new0(G3DFace, 1); | ||
307 | |||
308 | face->vertex_count = 3; | ||
309 | face->vertex_indices = g_malloc(3 * sizeof(guint32)); | ||
310 | |||
311 | face->vertex_indices[0] = g3d_stream_read_int16_le(global->stream); | ||
312 | face->vertex_indices[1] = g3d_stream_read_int16_le(global->stream); | ||
313 | face->vertex_indices[2] = g3d_stream_read_int16_le(global->stream); | ||
314 | flags = g3d_stream_read_int16_le(global->stream); | ||
315 | parent->nb -= 8; | ||
316 | |||
317 | #ifdef X3DS_REORDER_FACES | ||
318 | /* try to put all faces in the same direction */ | ||
319 | if((p1 == face->vertex_indices[0]) && (p2 == face->vertex_indices[1])) | ||
320 | { | ||
321 | bottle = face->vertex_indices[0]; | ||
322 | face->vertex_indices[0] = face->vertex_indices[2]; | ||
323 | face->vertex_indices[2] = bottle; | ||
324 | } | ||
325 | |||
326 | p1 = face->vertex_indices[0]; | ||
327 | p2 = face->vertex_indices[1]; | ||
328 | #endif | ||
329 | |||
330 | face->material = g_slist_nth_data(object->materials, 0); | ||
331 | |||
332 | object->faces = g_slist_append(object->faces, face); | ||
333 | |||
334 | if((i % 1000) == 0) x3ds_update_progress(global, parent->level); | ||
335 | } | ||
336 | |||
337 | return TRUE; | ||
338 | } | ||
339 | |||
340 | /* mesh mat group */ | ||
341 | gboolean x3ds_cb_0x4130(x3ds_global_data *global, x3ds_parent_data *parent) | ||
342 | { | ||
343 | G3DObject *object; | ||
344 | gint32 i, j, facenum, nfaces; | ||
345 | gchar buffer[512]; | ||
346 | G3DMaterial *material = NULL, *mat; | ||
347 | G3DFace *face; | ||
348 | GSList *mlist; | ||
349 | |||
350 | object = (G3DObject *)parent->object; | ||
351 | g_return_val_if_fail(object, FALSE); | ||
352 | |||
353 | /* name of material */ | ||
354 | parent->nb -= x3ds_read_cstr(global->stream, buffer); | ||
355 | |||
356 | /* find material in list */ | ||
357 | mlist = global->model->materials; | ||
358 | while(mlist != NULL) | ||
359 | { | ||
360 | mat = (G3DMaterial*)mlist->data; | ||
361 | if(strcmp(mat->name, buffer) == 0) | ||
362 | { | ||
363 | material = mat; | ||
364 | break; | ||
365 | } | ||
366 | mlist = mlist->next; | ||
367 | } | ||
368 | |||
369 | nfaces = g3d_stream_read_int16_le(global->stream); | ||
370 | parent->nb -= 2; | ||
371 | |||
372 | for(i = 0; i < nfaces; i ++) | ||
373 | { | ||
374 | facenum = g3d_stream_read_int16_le(global->stream); | ||
375 | parent->nb -= 2; | ||
376 | |||
377 | if(material != NULL) | ||
378 | { | ||
379 | face = (G3DFace*)g_slist_nth_data(object->faces, facenum); | ||
380 | if(face == NULL) continue; | ||
381 | |||
382 | face->material = material; | ||
383 | |||
384 | if(face->material->tex_image && object->tex_vertex_data) | ||
385 | { | ||
386 | face->flags |= G3D_FLAG_FAC_TEXMAP; | ||
387 | face->tex_image = face->material->tex_image; | ||
388 | face->tex_vertex_count = 3; | ||
389 | face->tex_vertex_data = g_new0(G3DFloat, 6); | ||
390 | for(j = 0; j < 3; j ++) | ||
391 | { | ||
392 | face->tex_vertex_data[j * 2 + 0] = object->tex_vertex_data[ | ||
393 | face->vertex_indices[j] * 2 + 0]; | ||
394 | face->tex_vertex_data[j * 2 + 1] = object->tex_vertex_data[ | ||
395 | face->vertex_indices[j] * 2 + 1]; | ||
396 | } | ||
397 | } /* textured face */ | ||
398 | } /* material != NULL */ | ||
399 | |||
400 | if((i % 1000) == 0) x3ds_update_progress(global, parent->level); | ||
401 | } /* 0..nfaces */ | ||
402 | |||
403 | return TRUE; | ||
404 | } | ||
405 | |||
406 | /* texture vertices */ | ||
407 | gboolean x3ds_cb_0x4140(x3ds_global_data *global, x3ds_parent_data *parent) | ||
408 | { | ||
409 | G3DObject *object; | ||
410 | gint32 i; | ||
411 | |||
412 | object = (G3DObject *)parent->object; | ||
413 | g_return_val_if_fail(object, FALSE); | ||
414 | |||
415 | object->tex_vertex_count = g3d_stream_read_int16_le(global->stream); | ||
416 | parent->nb -= 2; | ||
417 | |||
418 | object->tex_vertex_data = g_new0(G3DFloat, object->tex_vertex_count * 2); | ||
419 | |||
420 | for(i = 0; i < object->tex_vertex_count; i ++) | ||
421 | { | ||
422 | object->tex_vertex_data[i * 2 + 0] = g3d_stream_read_float_le(global->stream); | ||
423 | object->tex_vertex_data[i * 2 + 1] = g3d_stream_read_float_le(global->stream); | ||
424 | parent->nb -= 8; | ||
425 | |||
426 | if((i % 1000) == 0) x3ds_update_progress(global, parent->level); | ||
427 | } | ||
428 | |||
429 | return TRUE; | ||
430 | } | ||
431 | |||
432 | /* smoothing groups */ | ||
433 | gboolean x3ds_cb_0x4150(x3ds_global_data *global, x3ds_parent_data *parent) | ||
434 | { | ||
435 | G3DObject *object; | ||
436 | G3DFace *face; | ||
437 | GSList *oface; | ||
438 | gint32 i, j, k, n=0, polynum, group; | ||
439 | guint32 *smooth_list; | ||
440 | G3DFloat *pnormal_list, *vertex_normal_buf; | ||
441 | G3DFloat a[3],b[3], *p0,*p1,*p2,*r; | ||
442 | |||
443 | /* read data */ | ||
444 | object = (G3DObject *)parent->object; | ||
445 | g_return_val_if_fail(object, FALSE); | ||
446 | |||
447 | oface=object->faces; | ||
448 | polynum=0; | ||
449 | for(oface = object->faces; oface != NULL ; oface = oface->next) | ||
450 | polynum++; /* count polygons */ | ||
451 | |||
452 | /* polygon normal list */ | ||
453 | pnormal_list = g_new(float, 3 * polynum); | ||
454 | /* normals per vertice */ | ||
455 | vertex_normal_buf = g_new0(float, 3 * object->vertex_count); | ||
456 | |||
457 | smooth_list = g_new(guint32, polynum); | ||
458 | |||
459 | for(i = 0 ; i < polynum ; i ++) | ||
460 | smooth_list[i] = g3d_stream_read_int32_le(global->stream); | ||
461 | |||
462 | parent->nb -= polynum * 4; | ||
463 | /* first, we calculate the normal by the polygon vertices (just vector | ||
464 | * product) */ | ||
465 | i = 0; | ||
466 | for(oface = object->faces; oface != NULL ; oface=oface->next) | ||
467 | { | ||
468 | face = (G3DFace *)oface->data; | ||
469 | r = &(pnormal_list[i*3]); | ||
470 | p0 = &(object->vertex_data[3 * face->vertex_indices[0]]); | ||
471 | p1 = &(object->vertex_data[3 * face->vertex_indices[1]]); | ||
472 | p2 = &(object->vertex_data[3 * face->vertex_indices[2]]); | ||
473 | |||
474 | a[0]=p1[0] - p0[0]; | ||
475 | a[1]=p1[1] - p0[1]; | ||
476 | a[2]=p1[2] - p0[2]; | ||
477 | b[0]=p2[0] - p0[0]; | ||
478 | b[1]=p2[1] - p0[1]; | ||
479 | b[2]=p2[2] - p0[2]; | ||
480 | |||
481 | g3d_vector_normal(a[0], a[1], a[2], b[0], b[1], b[2], | ||
482 | &r[0], &r[1], &r[2]); | ||
483 | |||
484 | g3d_vector_unify(&r[0], &r[1], &r[2]); | ||
485 | |||
486 | face->flags |= G3D_FLAG_FAC_NORMALS; | ||
487 | i ++; | ||
488 | } | ||
489 | |||
490 | do { | ||
491 | /* find a suitable group. -1 means we've already taken care */ | ||
492 | group = -1; | ||
493 | for(i = 0; i < polynum; i ++) | ||
494 | if((group = smooth_list[i]) != -1) /* found a group */ | ||
495 | break; | ||
496 | /* handle this group */ | ||
497 | if(group != -1) | ||
498 | { | ||
499 | /* SMOOTH | ||
500 | * we add normals of the polygons's vertices so each vertex will | ||
501 | * finally have | ||
502 | * the sum of the polygons normals where the vertex is part of. | ||
503 | * | ||
504 | * run0: clear the vertex_normal_buf for this group */ | ||
505 | for(i = 0; i < object->vertex_count * 3; i ++) | ||
506 | vertex_normal_buf[i] = 0.0; | ||
507 | /* run1: add normals on themselves into the vertex_normal_buf */ | ||
508 | i = 0; | ||
509 | for(oface = object->faces; oface != NULL ; oface = oface->next) | ||
510 | { | ||
511 | face = (G3DFace *) oface->data; | ||
512 | if(smooth_list[i] == group) | ||
513 | { | ||
514 | /* for all 3 vertices of the polygon */ | ||
515 | for(j = 0; j < 3; j ++) | ||
516 | { | ||
517 | k = face->vertex_indices[j]; | ||
518 | for(n = 0; n < 3; n ++) | ||
519 | vertex_normal_buf[k * 3 + n] += | ||
520 | pnormal_list[i * 3 + n]; | ||
521 | } | ||
522 | } | ||
523 | i ++; | ||
524 | } | ||
525 | i = 0; | ||
526 | /* run2: apply to the final vertex buffer */ | ||
527 | for(oface = object->faces; oface != NULL ; oface = oface->next) | ||
528 | { | ||
529 | face = (G3DFace *)oface->data; | ||
530 | if(smooth_list[i] == group) | ||
531 | { | ||
532 | face->normals = g_new(G3DFloat, 9); | ||
533 | for(j = 0; j < 3; j ++) | ||
534 | { | ||
535 | k = face->vertex_indices[j]; | ||
536 | |||
537 | g3d_vector_unify( | ||
538 | &(vertex_normal_buf[k * 3 + 0]), | ||
539 | &(vertex_normal_buf[k * 3 + 1]), | ||
540 | &(vertex_normal_buf[k * 3 + 2])); | ||
541 | |||
542 | if(vertex_normal_buf[k * 3 + 0] != 0.0F) | ||
543 | /* finally, we save the normal in our normal | ||
544 | * buffer */ | ||
545 | memcpy(face->normals + j * 3, | ||
546 | vertex_normal_buf + k * 3, | ||
547 | sizeof(G3DFloat) * 3); | ||
548 | else | ||
549 | /* use the pbuf normal */ | ||
550 | memcpy(face->normals + j * 3, | ||
551 | pnormal_list + i * 3, | ||
552 | sizeof(G3DFloat) * 3); | ||
553 | |||
554 | } | ||
555 | smooth_list[i] = -1; /* finished this polygon */ | ||
556 | } | ||
557 | i++; | ||
558 | } | ||
559 | /* SMOOTH END */ | ||
560 | } | ||
561 | } while (group != -1); | ||
562 | |||
563 | g_free(pnormal_list); | ||
564 | g_free(vertex_normal_buf); | ||
565 | g_free(smooth_list); | ||
566 | return TRUE; | ||
567 | } | ||
568 | |||
569 | /* mesh matrix */ | ||
570 | gboolean x3ds_cb_0x4160(x3ds_global_data *global, x3ds_parent_data *parent) | ||
571 | { | ||
572 | G3DFloat matrix[16]; | ||
573 | gint32 i; | ||
574 | G3DFloat det; | ||
575 | |||
576 | g3d_matrix_identity(matrix); | ||
577 | for(i = 0; i < 12; i ++) | ||
578 | matrix[(i / 3) * 4 + (i % 3)] = g3d_stream_read_float_le(global->stream); | ||
579 | parent->nb -= 48; | ||
580 | |||
581 | det = g3d_matrix_determinant(matrix); | ||
582 | |||
583 | g3d_matrix_dump(matrix); | ||
584 | g_debug("det: %f", det); | ||
585 | |||
586 | |||
587 | if(det < 0.0) { | ||
588 | #if 0 | ||
589 | G3DFloat scale[16]; | ||
590 | g3d_matrix_identity(scale); | ||
591 | g3d_matrix_scale(-1.0, 1.0, 1.0, scale); | ||
592 | g3d_matrix_multiply(scale, matrix, matrix); | ||
593 | g3d_matrix_dump(matrix); | ||
594 | #endif | ||
595 | #define X3DS_MESH_TRANSFORM 0 | ||
596 | #if X3DS_MESH_TRANSFORM | ||
597 | object = parent->object; | ||
598 | if(object) { | ||
599 | object->transformation = g_new0(G3DTransformation, 1); | ||
600 | memcpy(object->transformation->matrix, matrix, 16 * sizeof(G3DFloat)); | ||
601 | } | ||
602 | |||
603 | #if 0 | ||
604 | if(parent->object) { | ||
605 | g3d_object_transform(parent->object, matrix); | ||
606 | } | ||
607 | #endif | ||
608 | #endif | ||
609 | } | ||
610 | return TRUE; | ||
611 | } | ||
612 | |||
613 | /* material name */ | ||
614 | gboolean x3ds_cb_0xA000(x3ds_global_data *global, x3ds_parent_data *parent) | ||
615 | { | ||
616 | G3DMaterial *material; | ||
617 | gchar buffer[1024]; | ||
618 | |||
619 | g_return_val_if_fail(parent->object, FALSE); | ||
620 | |||
621 | parent->nb -= x3ds_read_cstr(global->stream, buffer); | ||
622 | material = (G3DMaterial *)(parent->object); | ||
623 | |||
624 | material->name = g_strdup(buffer); | ||
625 | |||
626 | return TRUE; | ||
627 | } | ||
628 | |||
629 | /* two sided material */ | ||
630 | gboolean x3ds_cb_0xA081(x3ds_global_data *global, x3ds_parent_data *parent) | ||
631 | { | ||
632 | G3DMaterial *material; | ||
633 | |||
634 | material = (G3DMaterial *)parent->object; | ||
635 | g_return_val_if_fail(material, FALSE); | ||
636 | |||
637 | material->flags |= G3D_FLAG_MAT_TWOSIDE; | ||
638 | |||
639 | return TRUE; | ||
640 | } | ||
641 | |||
642 | /* texture map name */ | ||
643 | gboolean x3ds_cb_0xA300(x3ds_global_data *global, x3ds_parent_data *parent) | ||
644 | { | ||
645 | G3DMaterial *material; | ||
646 | G3DImage *image; | ||
647 | gchar buffer[512]; | ||
648 | |||
649 | material = (G3DMaterial *)parent->object; | ||
650 | g_return_val_if_fail(material, FALSE); | ||
651 | |||
652 | parent->nb -= x3ds_read_cstr(global->stream, buffer); | ||
653 | |||
654 | switch(parent->id) | ||
655 | { | ||
656 | case 0xA200: /* texture map */ | ||
657 | material->tex_image = g3d_texture_load_cached(global->context, | ||
658 | global->model, buffer); | ||
659 | if(material->tex_image) | ||
660 | { | ||
661 | g3d_texture_flip_y(material->tex_image); | ||
662 | material->tex_image->tex_id = ++ global->max_tex_id; | ||
663 | } | ||
664 | break; | ||
665 | |||
666 | case 0xA210: /* opacity map */ | ||
667 | image = g3d_texture_load(global->context, buffer); | ||
668 | if(image != NULL) | ||
669 | { | ||
670 | g3d_texture_flip_y(image); | ||
671 | material->tex_image = g3d_texture_merge_alpha( | ||
672 | material->tex_image, image); | ||
673 | g3d_texture_free(image); | ||
674 | } | ||
675 | break; | ||
676 | |||
677 | case 0xA220: /* reflection map */ | ||
678 | /* TODO: implement */ | ||
679 | break; | ||
680 | |||
681 | case 0xA230: /* bump map */ | ||
682 | /* TODO: implement */ | ||
683 | break; | ||
684 | |||
685 | default: | ||
686 | #if DEBUG > 0 | ||
687 | g_warning("[3DS] unhandled texture name in 0x%04X", parent->id); | ||
688 | #endif | ||
689 | |||
690 | break; | ||
691 | } | ||
692 | |||
693 | return TRUE; | ||
694 | } | ||
695 | |||
696 | /* texture map scale u */ | ||
697 | gboolean x3ds_cb_0xA354(x3ds_global_data *global, x3ds_parent_data *parent) | ||
698 | { | ||
699 | G3DMaterial *material; | ||
700 | G3DImage *image; | ||
701 | G3DFloat scale; | ||
702 | |||
703 | material = (G3DMaterial *)parent->object; | ||
704 | g_return_val_if_fail(material, FALSE); | ||
705 | |||
706 | image = material->tex_image; | ||
707 | g_return_val_if_fail(image, FALSE); | ||
708 | |||
709 | scale = g3d_stream_read_float_le(global->stream); | ||
710 | parent->nb -= 4; | ||
711 | |||
712 | image->tex_scale_u = scale; | ||
713 | #if DEBUG > 3 | ||
714 | g_debug("[3DS] scale_u: %f", image->tex_scale_u); | ||
715 | #endif | ||
716 | |||
717 | return TRUE; | ||
718 | } | ||
719 | |||
720 | /* texture map scale v */ | ||
721 | gboolean x3ds_cb_0xA356(x3ds_global_data *global, x3ds_parent_data *parent) | ||
722 | { | ||
723 | G3DMaterial *material; | ||
724 | G3DImage *image; | ||
725 | G3DFloat scale; | ||
726 | |||
727 | material = (G3DMaterial *)parent->object; | ||
728 | g_return_val_if_fail(material, FALSE); | ||
729 | |||
730 | image = material->tex_image; | ||
731 | g_return_val_if_fail(image, FALSE); | ||
732 | |||
733 | scale = g3d_stream_read_float_le(global->stream); | ||
734 | parent->nb -= 4; | ||
735 | |||
736 | image->tex_scale_v = scale; | ||
737 | #if DEBUG > 3 | ||
738 | g_debug("[3DS] scale_v: %f", image->tex_scale_v); | ||
739 | #endif | ||
740 | |||
741 | return TRUE; | ||
742 | } | ||
743 | |||
744 | /* material */ | ||
745 | gboolean x3ds_cb_0xAFFF(x3ds_global_data *global, x3ds_parent_data *parent) | ||
746 | { | ||
747 | G3DMaterial *material; | ||
748 | G3DObject *object; | ||
749 | |||
750 | material = g3d_material_new(); | ||
751 | |||
752 | if(parent->object) | ||
753 | { | ||
754 | object = (G3DObject *)parent->object; | ||
755 | object->materials = g_slist_append(object->materials, material); | ||
756 | } | ||
757 | else | ||
758 | { | ||
759 | global->model->materials = g_slist_append(global->model->materials, | ||
760 | material); | ||
761 | } | ||
762 | |||
763 | parent->object = material; | ||
764 | |||
765 | return TRUE; | ||
766 | } | ||
767 | |||
768 | /* keyframe data header */ | ||
769 | gboolean x3ds_cb_0xB00A(x3ds_global_data *global, x3ds_parent_data *parent) | ||
770 | { | ||
771 | gint32 rev, len; | ||
772 | gchar buffer[512]; | ||
773 | |||
774 | rev = g3d_stream_read_int16_le(global->stream); | ||
775 | parent->nb -= 2; | ||
776 | parent->nb -= x3ds_read_cstr(global->stream, buffer); | ||
777 | len = g3d_stream_read_int16_le(global->stream); | ||
778 | parent->nb -= 2; | ||
779 | |||
780 | #if DEBUG > 0 | ||
781 | g_debug("[3DS] keyframe data: r%d, %d frames, \"%s\"", | ||
782 | rev, len, buffer); | ||
783 | #endif | ||
784 | return TRUE; | ||
785 | } | ||
786 | |||
787 | /* node header */ | ||
788 | gboolean x3ds_cb_0xB010(x3ds_global_data *global, x3ds_parent_data *parent) | ||
789 | { | ||
790 | GSList *olist; | ||
791 | G3DObject *object; | ||
792 | gchar buffer[512]; | ||
793 | |||
794 | parent->nb -= x3ds_read_cstr(global->stream, buffer); | ||
795 | #if DEBUG > 3 | ||
796 | g_debug("[3DS] NODE_HDR: %s", buffer); | ||
797 | #endif | ||
798 | |||
799 | /* find object by name */ | ||
800 | olist = global->model->objects; | ||
801 | while(olist) | ||
802 | { | ||
803 | object = (G3DObject *)olist->data; | ||
804 | if(strcmp(object->name, buffer) == 0) | ||
805 | { | ||
806 | parent->level_object = object; | ||
807 | break; | ||
808 | } | ||
809 | olist = olist->next; | ||
810 | } | ||
811 | |||
812 | g3d_stream_read_int16_le(global->stream); /* flags 1 */ | ||
813 | g3d_stream_read_int16_le(global->stream); /* flags 2 */ | ||
814 | g3d_stream_read_int16_le(global->stream); /* ? */ | ||
815 | parent->nb -= 6; | ||
816 | |||
817 | return TRUE; | ||
818 | } | ||
819 | |||
820 | /* pivot */ | ||
821 | gboolean x3ds_cb_0xB013(x3ds_global_data *global, x3ds_parent_data *parent) | ||
822 | { | ||
823 | G3DObject *object; | ||
824 | #if 0 | ||
825 | gint32 i; | ||
826 | #endif | ||
827 | G3DFloat x, y, z; | ||
828 | |||
829 | object = parent->level_object; | ||
830 | if(object == NULL) return FALSE; | ||
831 | |||
832 | x = g3d_stream_read_float_le(global->stream); | ||
833 | y = g3d_stream_read_float_le(global->stream); | ||
834 | z = g3d_stream_read_float_le(global->stream); | ||
835 | parent->nb -= 12; | ||
836 | |||
837 | #if DEBUG > 3 | ||
838 | g_debug("[3DS]: PIVOT: (%.2f,%.2f,%.2f)", x, y, z); | ||
839 | #endif | ||
840 | |||
841 | return TRUE; | ||
842 | } | ||
843 | |||
844 | #define X3DS_ENABLE_POS_TRACK_TAG 0 | ||
845 | |||
846 | /* position tracking tag */ | ||
847 | gboolean x3ds_cb_0xB020(x3ds_global_data *global, x3ds_parent_data *parent) | ||
848 | { | ||
849 | G3DObject *object; | ||
850 | gint32 i, flags, fflags, nkeys, fnum; | ||
851 | #if X3DS_ENABLE_POS_TRACK_TAG | ||
852 | gint32 j; | ||
853 | #endif | ||
854 | G3DFloat x, y, z; | ||
855 | |||
856 | object = parent->level_object; | ||
857 | if(object == NULL) return FALSE; | ||
858 | |||
859 | flags = g3d_stream_read_int16_le(global->stream); | ||
860 | g3d_stream_skip(global->stream, 8); | ||
861 | nkeys = g3d_stream_read_int32_le(global->stream); | ||
862 | |||
863 | parent->nb -= 14; | ||
864 | |||
865 | for(i = 0; i < nkeys; i ++) | ||
866 | { | ||
867 | fnum = g3d_stream_read_int32_le(global->stream); | ||
868 | fflags = g3d_stream_read_int16_le(global->stream); | ||
869 | parent->nb -= 6; | ||
870 | |||
871 | if(fflags & X3DS_FLAG_TENSION) | ||
872 | { | ||
873 | g3d_stream_read_float_le(global->stream); | ||
874 | parent->nb -= 4; | ||
875 | } | ||
876 | if(fflags & X3DS_FLAG_CONTINUITY) | ||
877 | { | ||
878 | g3d_stream_read_float_le(global->stream); | ||
879 | parent->nb -= 4; | ||
880 | } | ||
881 | if(fflags & X3DS_FLAG_BIAS) | ||
882 | { | ||
883 | g3d_stream_read_float_le(global->stream); | ||
884 | parent->nb -= 4; | ||
885 | } | ||
886 | if(fflags & X3DS_FLAG_EASE_TO) | ||
887 | { | ||
888 | g3d_stream_read_float_le(global->stream); | ||
889 | parent->nb -= 4; | ||
890 | } | ||
891 | if(fflags & X3DS_FLAG_EASE_FROM) | ||
892 | { | ||
893 | g3d_stream_read_float_le(global->stream); | ||
894 | parent->nb -= 4; | ||
895 | } | ||
896 | |||
897 | x = g3d_stream_read_float_le(global->stream); | ||
898 | y = g3d_stream_read_float_le(global->stream); | ||
899 | z = g3d_stream_read_float_le(global->stream); | ||
900 | parent->nb -= 12; | ||
901 | #if DEBUG > 3 | ||
902 | g_debug("[3DS]: POS_TRACK_TAG: frame %d: (%.2f,%.2f,%.2f) (0x%X) " | ||
903 | "object: %s", | ||
904 | fnum, x, y, z, fflags, object->name); | ||
905 | #endif | ||
906 | |||
907 | #if X3DS_ENABLE_POS_TRACK_TAG | ||
908 | if(fnum == 0) | ||
909 | { | ||
910 | #if 1 | ||
911 | for(j = 0; j < object->vertex_count; j ++) | ||
912 | { | ||
913 | object->vertex_data[j * 3 + 0] -= x; | ||
914 | object->vertex_data[j * 3 + 1] -= y; | ||
915 | object->vertex_data[j * 3 + 2] -= z; | ||
916 | } | ||
917 | #endif | ||
918 | } | ||
919 | #endif | ||
920 | } | ||
921 | |||
922 | return TRUE; | ||
923 | } | ||
924 | |||
925 | /* rotation tracking tag */ | ||
926 | gboolean x3ds_cb_0xB021(x3ds_global_data *global, x3ds_parent_data *parent) | ||
927 | { | ||
928 | G3DObject *object; | ||
929 | gint32 i, j, flags, nkeys, fnum; | ||
930 | G3DFloat x, y, z, rot; | ||
931 | G3DFloat matrix[16]; | ||
932 | |||
933 | object = parent->level_object; | ||
934 | if(object == NULL) return FALSE; | ||
935 | |||
936 | flags = g3d_stream_read_int16_le(global->stream); | ||
937 | g3d_stream_skip(global->stream, 8); | ||
938 | nkeys = g3d_stream_read_int16_le(global->stream); | ||
939 | g3d_stream_read_int16_le(global->stream); | ||
940 | parent->nb -= 14; | ||
941 | |||
942 | for(i = 0; i < nkeys; i ++) | ||
943 | { | ||
944 | fnum = g3d_stream_read_int16_le(global->stream); | ||
945 | g3d_stream_read_int32_le(global->stream); | ||
946 | parent->nb -= 6; | ||
947 | |||
948 | rot = g3d_stream_read_float_le(global->stream); | ||
949 | x = g3d_stream_read_float_le(global->stream); | ||
950 | y = g3d_stream_read_float_le(global->stream); | ||
951 | z = g3d_stream_read_float_le(global->stream); | ||
952 | parent->nb -= 16; | ||
953 | #if DEBUG > 3 | ||
954 | g_debug( | ||
955 | "[3DS]: ROT_TRACK_TAG: frame %d: (%.2f,%.2f,%.2f), %.2f rad", | ||
956 | fnum, x, y, z, rot); | ||
957 | #endif | ||
958 | if(fnum == -1) | ||
959 | { | ||
960 | #if 1 | ||
961 | g3d_matrix_identity(matrix); | ||
962 | g3d_matrix_rotate(rot, x, y, z, matrix); | ||
963 | |||
964 | for(j = 0; j < object->vertex_count; j ++) | ||
965 | { | ||
966 | g3d_vector_transform( | ||
967 | &(object->vertex_data[j * 3 + 0]), | ||
968 | &(object->vertex_data[j * 3 + 1]), | ||
969 | &(object->vertex_data[j * 3 + 2]), | ||
970 | matrix); | ||
971 | } | ||
972 | #endif | ||
973 | } | ||
974 | } | ||
975 | |||
976 | return TRUE; | ||
977 | |||
978 | } | ||
979 | |||
980 | /* node id */ | ||
981 | gboolean x3ds_cb_0xB030(x3ds_global_data *global, x3ds_parent_data *parent) | ||
982 | { | ||
983 | gint32 id; | ||
984 | |||
985 | id = g3d_stream_read_int16_le(global->stream); | ||
986 | parent->nb -= 2; | ||
987 | #if DEBUG > 3 | ||
988 | g_debug("[3DS] NODE_ID: %d", id); | ||
989 | #endif | ||
990 | |||
991 | return TRUE; | ||
992 | } | ||