aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_3dmf/imp_3dmf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/mimesh/libg3d-0.0.8/plugins/import/imp_3dmf/imp_3dmf.c')
-rw-r--r--src/others/mimesh/libg3d-0.0.8/plugins/import/imp_3dmf/imp_3dmf.c646
1 files changed, 646 insertions, 0 deletions
diff --git a/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_3dmf/imp_3dmf.c b/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_3dmf/imp_3dmf.c
new file mode 100644
index 0000000..82a46d3
--- /dev/null
+++ b/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_3dmf/imp_3dmf.c
@@ -0,0 +1,646 @@
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
23#include <string.h>
24
25#include <g3d/types.h>
26#include <g3d/context.h>
27#include <g3d/stream.h>
28#include <g3d/object.h>
29#include <g3d/vector.h>
30#include <g3d/matrix.h>
31#include <g3d/material.h>
32#include <g3d/iff.h>
33#include <g3d/debug.h>
34
35#include "imp_3dmf_chunks.h"
36
37#define X3DMF_CHUNK_CHAR(id, shift) \
38 ((((id) >> (shift)) & 0xFF) == 0) ? \
39 ' ' : ((id) >> (shift)) & 0xFF
40
41typedef struct {
42 guint32 id;
43 guint32 offset;
44 guint32 type;
45}
46X3dmfTocEntry;
47
48typedef struct {
49 guint32 num_entries;
50 X3dmfTocEntry *entries;
51}
52X3dmfToc;
53
54
55static gboolean x3dmf_read_container(G3DStream *stream, guint32 length,
56 G3DModel *model, G3DObject *object, guint32 level, X3dmfToc *toc,
57 G3DContext *context);
58static X3dmfToc *x3dmf_read_toc(G3DStream *stream, X3dmfToc *prev_toc,
59 G3DContext *context);
60
61EAPI
62gboolean plugin_load_model_from_stream(G3DContext *context, G3DStream *stream,
63 G3DModel *model, gpointer user_data)
64{
65 guint32 id, flags, tocloc, pos;
66 gsize len;
67 guint16 ver_min, ver_maj;
68 gchar txthead[10];
69 X3dmfToc *toc = NULL;
70
71 g3d_iff_read_chunk(stream, &id, &len, 0);
72 if((id != G3D_IFF_MKID('3', 'D', 'M', 'F')) || (len != 16)) {
73 g3d_stream_seek(stream, 0, G_SEEK_SET);
74 g3d_stream_read(stream, txthead, 10);
75 if(strncmp(txthead, "3DMetafile", 10) == 0) {
76 g_warning("file %s is an ASCII 3D Metafile (unhandled)\n",
77 stream->uri);
78 } else {
79 g_warning("file %s is not a 3D Metafile\n", stream->uri);
80 }
81 return FALSE;
82 }
83
84 ver_maj = g3d_stream_read_int16_be(stream);
85 ver_min = g3d_stream_read_int16_be(stream);
86
87 flags = g3d_stream_read_int32_be(stream);
88
89 g3d_stream_skip(stream, 4); /* FIXME: 64bit file offsets */
90 tocloc = g3d_stream_read_int32_be(stream);
91
92 /* read TOC if available */
93 if(tocloc > 0) {
94 pos = g3d_stream_tell(stream);
95 g3d_stream_seek(stream, tocloc, G_SEEK_SET);
96 toc = x3dmf_read_toc(stream, NULL, context);
97 g3d_stream_seek(stream, pos, G_SEEK_SET);
98 }
99
100#if DEBUG > 0
101 g_debug("3DMF: version %d.%d (0x%08x) TOC @ 0x%08x",
102 ver_maj, ver_min, flags, tocloc);
103#endif
104
105 x3dmf_read_container(stream, (guint32) -1, model, NULL, 0, toc, context);
106
107 return TRUE;
108}
109
110EAPI
111gchar *plugin_description(void)
112{
113 return g_strdup("3D Metafiles.");
114}
115
116EAPI
117gchar **plugin_extensions(void)
118{
119 return g_strsplit("b3d:3mf:3dmf", ":", 0);
120}
121
122/******************************************************************************
123 * 3DMF specific
124 */
125
126static X3dmfChunkDesc *x3dmf_get_chunk_info(guint32 id)
127{
128 gint32 i;
129
130 for(i = 0; x3dmf_chunks[i].id != 0; i ++)
131 if(x3dmf_chunks[i].id == id)
132 return &(x3dmf_chunks[i]);
133 return NULL;
134}
135
136static X3dmfToc *x3dmf_read_toc(G3DStream *stream, X3dmfToc *prev_toc,
137 G3DContext *context)
138{
139 X3dmfToc *toc;
140 guint32 off_next_toc, typeseed, refseed, entrytype, entrysize, nentries;
141 guint32 noff, i;
142
143 if(prev_toc)
144 toc = prev_toc;
145 else
146 toc = g_new0(X3dmfToc, 1);
147
148 /* skip tag and size (FIXME) */
149 g3d_stream_skip(stream, 8);
150
151 g3d_stream_skip(stream, 4); /* FIXME: 64bit file offsets */
152 off_next_toc = g3d_stream_read_int32_be(stream);
153 typeseed = g3d_stream_read_int32_be(stream);
154 refseed = g3d_stream_read_int32_be(stream);
155 entrytype = g3d_stream_read_int32_be(stream);
156 entrysize = g3d_stream_read_int32_be(stream);
157 nentries = g3d_stream_read_int32_be(stream);
158
159 /* resize entry array */
160 noff = toc->num_entries;
161 toc->num_entries += nentries;
162 toc->entries = (X3dmfTocEntry *)g_realloc(toc->entries,
163 toc->num_entries * sizeof(X3dmfTocEntry));
164
165 /* read TOC entries */
166 for(i = 0; i < nentries; i ++) {
167 toc->entries[noff + i].id = g3d_stream_read_int32_be(stream);
168 g3d_stream_skip(stream, 4); /* FIXME: 64bit file offsets */
169 toc->entries[noff + i].offset = g3d_stream_read_int32_be(stream);
170
171 if((entrytype == 1) && (entrysize == 16)) {
172 toc->entries[noff + i].type = g3d_stream_read_int32_be(stream);
173 }
174#if DEBUG > 0
175 g_debug("3DMF: TOC: %06d @ 0x%08x",
176 toc->entries[noff + i].id,
177 toc->entries[noff + i].offset);
178#endif
179 }
180
181 /* read next toc */
182 if(off_next_toc > 0) {
183 g3d_stream_seek(stream, off_next_toc, SEEK_SET);
184 toc = x3dmf_read_toc(stream, toc, context);
185 }
186
187 return toc;
188}
189
190static guint32 x3dmf_read_mesh(G3DStream *stream, G3DObject *object,
191 G3DContext *context)
192{
193 guint32 i, j, nconts, nfaces, nbytes = 0, ncverts, offv;
194 G3DFace *face;
195
196 g_return_val_if_fail(object != NULL, FALSE);
197
198 offv = object->vertex_count;
199 object->vertex_count += g3d_stream_read_int32_be(stream);
200 object->vertex_data = g_realloc(object->vertex_data,
201 object->vertex_count * 3 * sizeof(G3DFloat));
202 nbytes += 4;
203
204 for(i = offv; i < object->vertex_count; i ++) {
205 for(j = 0; j < 3; j ++)
206 object->vertex_data[i * 3 + j] = g3d_stream_read_float_be(stream);
207 nbytes += 12;
208
209 g3d_context_update_interface(context);
210 }
211
212 nfaces = g3d_stream_read_int32_be(stream);
213 nconts = g3d_stream_read_int32_be(stream);
214 nbytes += 8;
215
216#if DEBUG > 0
217 g_debug("|%u verts, %u faces, %u conts", object->vertex_count,
218 nfaces, nconts);
219#endif
220
221 for(i = 0; i < nfaces; i ++) {
222 face = g_new0(G3DFace, 1);
223
224 face->vertex_count = g3d_stream_read_int32_be(stream);
225 nbytes += 4;
226 face->vertex_indices = g_new0(guint32, face->vertex_count);
227
228 for(j = 0; j < face->vertex_count; j ++) {
229 face->vertex_indices[j] = offv + g3d_stream_read_int32_be(stream);
230 nbytes += 4;
231 if(face->vertex_indices[j] >= object->vertex_count) {
232 g_warning("face index wrong: %u >= %u",
233 face->vertex_indices[j], object->vertex_count);
234 face->vertex_indices[j] = 0;
235 }
236 }
237
238#if DEBUG > 3
239 g_debug("|face %u: %u %u %u", i, face->vertex_indices[0],
240 face->vertex_indices[1], face->vertex_indices[2]);
241#endif
242
243 face->material = g_slist_nth_data(object->materials, 0);
244 object->faces = g_slist_prepend(object->faces, face);
245
246 g3d_context_update_interface(context);
247 }
248
249 /* contours */
250 for(i = 0; i < nconts; i ++) {
251 ncverts = g3d_stream_read_int32_be(stream);
252 nbytes += 4;
253 for(j = 0; j < ncverts; j ++) {
254 g3d_stream_read_int32_be(stream);
255 nbytes += 4;
256 }
257 }
258
259 return nbytes;
260}
261
262static G3DObject *x3dmf_object_new(G3DStream *stream, G3DModel *model)
263{
264 G3DObject *object;
265 G3DMaterial *material;
266
267 object = g_new0(G3DObject, 1);
268 material = g3d_material_new();
269
270 object->name = g_strdup_printf("container @ 0x%08x",
271 (guint32)g3d_stream_tell(stream) - 8);
272 model->objects = g_slist_append(model->objects, object);
273 object->materials = g_slist_append(object->materials, material);
274
275 return object;
276}
277
278static guint32 x3dmf_read_packed(G3DStream *stream, guint32 maxx,
279 guint32 *nread)
280{
281 if(maxx > 0xFFFE) {
282 if(nread)
283 (*nread) += 4;
284 return g3d_stream_read_int32_be(stream);
285 } else if(maxx > 0xFE) {
286 if(nread)
287 (*nread) += 2;
288 return g3d_stream_read_int16_be(stream);
289 } else {
290 if(nread)
291 (*nread) += 1;
292 return g3d_stream_read_int8(stream);
293 }
294}
295
296/*
297 [tmsh] - TriMesh
298 http://developer.apple.com/documentation/QuickTime/QD3D/qd3dmetafile.33.htm
299
300 Uns32 numTriangles
301 Uns32 numTriangleAttributeTypes
302 Uns32 numEdges
303 Uns32 numEdgeAttributeTypes
304 Uns32 numPoints
305 Uns32 numVertexAttributeTypes
306 TriMeshTriangleData triangles[numTriangles]
307 TriMeshEdgeData edges[numEdges]
308 Point3D points[numPoints]
309 BoundingBox bBox
310*/
311
312static guint32 x3dmf_read_tmsh(G3DStream *stream, G3DObject *object,
313 G3DContext *context)
314{
315 G3DFace *face;
316 guint32 nread = 0, nfaces, nverts, nedges;
317 gint32 i, j;
318
319 nfaces = g3d_stream_read_int32_be(stream); /* numTriangles */
320 nread += 4;
321
322 g3d_stream_read_int32_be(stream); /* numTriangleAttributeTypes */
323 nread += 4;
324
325 nedges = g3d_stream_read_int32_be(stream); /* numEdges */
326 nread += 4;
327
328 g3d_stream_read_int32_be(stream); /* numEdgeAttributeTypes */
329 nread += 4;
330
331 nverts = g3d_stream_read_int32_be(stream); /* numPoints */
332 nread += 4;
333
334 g3d_stream_read_int32_be(stream); /* numVertexAttributeTypes */
335 nread += 4;
336
337#if DEBUG > 3
338 g_debug("3DMF: [tmsh] %d faces, %d edges, %d vertices",
339 nfaces, nedges, nverts);
340#endif
341
342 /* triangles */
343 for(i = 0; i < nfaces; i ++) {
344 face = g_new0(G3DFace, 1);
345
346 face->vertex_count = 3;
347 face->vertex_indices = g_new0(guint32, 3);
348 for(j = 0; j < 3; j ++) {
349 face->vertex_indices[j] =
350 x3dmf_read_packed(stream, nfaces, &nread);
351 if(face->vertex_indices[j] >= nverts) {
352 g_warning("face index error: %u >= %u",
353 face->vertex_indices[j], nverts);
354 face->vertex_indices[j] = 0;
355 }
356 }
357
358#if DEBUG > 3
359 g_debug("face %u (packed): %u %u %u", i, face->vertex_indices[0],
360 face->vertex_indices[1], face->vertex_indices[2]);
361#endif
362
363 face->material = g_slist_nth_data(object->materials, 0);
364 object->faces = g_slist_prepend(object->faces, face);
365 }
366
367 /* edges */
368 for(i = 0; i < nedges; i ++) {
369 /* pointIndices */
370 x3dmf_read_packed(stream, nedges, &nread);
371 x3dmf_read_packed(stream, nedges, &nread);
372 /* triangleIndices */
373 x3dmf_read_packed(stream, nedges, &nread);
374 x3dmf_read_packed(stream, nedges, &nread);
375 }
376
377 /* points */
378 object->vertex_count = nverts;
379 object->vertex_data = g_new0(G3DFloat, 3 * nverts);
380 for(i = 0; i < nverts; i ++) {
381 object->vertex_data[i * 3 + 0] = g3d_stream_read_float_be(stream);
382 object->vertex_data[i * 3 + 1] = g3d_stream_read_float_be(stream);
383 object->vertex_data[i * 3 + 2] = g3d_stream_read_float_be(stream);
384 nread += 12;
385 }
386
387 /* bBox */
388 /* Point3D min */
389 g3d_stream_read_float_be(stream);
390 g3d_stream_read_float_be(stream);
391 g3d_stream_read_float_be(stream);
392 nread += 12;
393 /* Point3D max */
394 g3d_stream_read_float_be(stream);
395 g3d_stream_read_float_be(stream);
396 g3d_stream_read_float_be(stream);
397 nread += 12;
398 /* boolean isEmpty */
399 g3d_stream_read_int32_be(stream);
400 nread += 4;
401
402 return nread;
403}
404
405static gboolean x3dmf_read_rfrn(G3DStream *stream, G3DModel *model,
406 X3dmfToc *toc, G3DContext *context)
407{
408 G3DObject *object;
409 guint32 id, i, refid, savedoffset;
410 gsize len;
411 X3dmfTocEntry *tocentry = NULL;
412
413 refid = g3d_stream_read_int32_be(stream);
414 if(refid == 0) {
415 /* FIXME */
416 return FALSE;
417 }
418
419 if(toc == NULL) {
420 return FALSE;
421 }
422
423 /* find reference object */
424 for(i = 0; i < toc->num_entries; i ++)
425 if(toc->entries[i].id == refid)
426 tocentry = &(toc->entries[i]);
427
428 g_return_val_if_fail(tocentry != NULL, FALSE);
429
430 savedoffset = g3d_stream_tell(stream);
431 g3d_stream_seek(stream, tocentry->offset, G_SEEK_SET);
432
433 object = x3dmf_object_new(stream, model);
434
435 g3d_iff_read_chunk(stream, &id, &len, 0);
436 switch(id) {
437 case G3D_IFF_MKID('c', 't', 'n', 'r'):
438 x3dmf_read_container(stream, len, model, NULL, 0xFF, toc, context);
439 break;
440
441 default:
442 break;
443 }
444
445 g3d_stream_seek(stream, savedoffset, G_SEEK_SET);
446
447 return TRUE;
448}
449
450static gboolean x3dmf_read_container(G3DStream *stream, guint32 length,
451 G3DModel *model, G3DObject *object, guint32 level, X3dmfToc *toc,
452 G3DContext *context)
453{
454 G3DMaterial *material = NULL;
455 X3dmfChunkDesc *chunkdesc;
456 guint32 id, chk, i;
457 gsize len;
458 G3DFloat matrix[16];
459
460 g3d_matrix_identity(matrix);
461
462 while(length > 0) {
463 if(g3d_stream_eof(stream))
464 break;
465
466 g3d_iff_read_chunk(stream, &id, &len, 0);
467 length -= 8;
468
469 if(id == 0)
470 return FALSE;
471
472 chunkdesc = x3dmf_get_chunk_info(id);
473
474#if DEBUG > 0
475 g_debug("\\%s[%c%c%c%c]: %s (%d bytes)", debug_pad(level),
476 X3DMF_CHUNK_CHAR(id, 24), X3DMF_CHUNK_CHAR(id, 16),
477 X3DMF_CHUNK_CHAR(id, 8), X3DMF_CHUNK_CHAR(id, 0),
478 chunkdesc ? chunkdesc->description : "unknown chunk",
479 len);
480#endif
481 length -= len;
482
483 switch(id) {
484 case G3D_IFF_MKID('c', 'n', 't', 'r'):
485 /* container */
486#if DEBUG > 0
487 g_debug("|%snew container @ 0x%x (%d bytes)",
488 debug_pad(level - 1),
489 (guint32)g3d_stream_tell(stream) - 8, len);
490#endif
491 x3dmf_read_container(stream, len, model, object, level + 1,
492 toc, context);
493 break;
494
495 case G3D_IFF_MKID('k', 'd', 'i', 'f'):
496 /* diffuse color */
497 if(object) {
498#if DEBUG > 2
499 g_debug("3DMF: kdif: got object");
500#endif
501 material = g_slist_nth_data(object->materials, 0);
502 material->r = g3d_stream_read_float_be(stream);
503 material->g = g3d_stream_read_float_be(stream);
504 material->b = g3d_stream_read_float_be(stream);
505 } else {
506 g3d_stream_skip(stream, len);
507 }
508 break;
509
510 case G3D_IFF_MKID('k', 's', 'p', 'c'):
511 /* specular color */
512 if(object) {
513#if DEBUG > 2
514 g_debug("3DMF: kspc: got object");
515#endif
516 material = g_slist_nth_data(object->materials, 0);
517 material->specular[0] = g3d_stream_read_float_be(stream);
518 material->specular[1] = g3d_stream_read_float_be(stream);
519 material->specular[2] = g3d_stream_read_float_be(stream);
520 } else {
521 g3d_stream_skip(stream, len);
522 }
523 break;
524
525 case G3D_IFF_MKID('k', 'x', 'p', 'r'):
526 /* transparency color */
527 if(object) {
528 /* use average as alpha */
529 material = g_slist_nth_data(object->materials, 0);
530 material->a = 1.0 -
531 (g3d_stream_read_float_be(stream) +
532 g3d_stream_read_float_be(stream) +
533 g3d_stream_read_float_be(stream)) / 3.0;
534
535 if(material->a < 0.1)
536 material->a = 0.1;
537 } else {
538 g3d_stream_skip(stream, len);
539 }
540 break;
541
542 case G3D_IFF_MKID('m', 'e', 's', 'h'):
543 /* mesh */
544 if(object == NULL)
545 object = x3dmf_object_new(stream, model);
546 material = g_slist_nth_data(object->materials, 0);
547
548 chk = x3dmf_read_mesh(stream, object, context);
549 g3d_object_transform(object, matrix);
550 if(chk != len) {
551 g_warning("3DMF: mesh: wrong length (%u != %u)\n",
552 chk, (unsigned int) len);
553 return FALSE;
554 }
555 break;
556
557 case G3D_IFF_MKID('m', 't', 'r', 'x'):
558 /* matrix */
559 for(i = 0; i < 16; i ++)
560 matrix[i] = g3d_stream_read_float_be(stream);
561 if(object) {
562#if DEBUG > 2
563 g_debug("3DMF: mtrx: object is set");
564#endif
565 g3d_object_transform(object, matrix);
566 }
567#if DEBUG > 3
568 for(i = 0; i < 4; i ++)
569 g_debug("3DMF: mtrx: %+1.2f %+1.2f %+1.2f %+1.2f",
570 matrix[i * 4 + 0], matrix[i * 4 + 1],
571 matrix[i * 4 + 2], matrix[i * 4 + 3]);
572#endif
573 break;
574
575 case G3D_IFF_MKID('r', 'f', 'r', 'n'):
576 /* reference */
577 x3dmf_read_rfrn(stream, model, toc, context);
578 break;
579
580 case G3D_IFF_MKID('s', 'e', 't', ' '):
581 /* ??: skip this cntr chunk */
582 g3d_stream_skip(stream, length);
583 length = 0;
584 break;
585
586 case G3D_IFF_MKID('t', 'm', 's', 'h'):
587 /* triangle mesh */
588 if(object == NULL)
589 object = x3dmf_object_new(stream, model);
590 material = g_slist_nth_data(object->materials, 0);
591
592 chk = x3dmf_read_tmsh(stream, object, context);
593 g3d_object_transform(object, matrix);
594 if(chk != len) {
595#if DEBUG > 0
596 g_debug("3DMF: tmsh: offset %d bytes", len - chk);
597#endif
598 g3d_stream_skip(stream, len - chk);
599 }
600 break;
601
602 case G3D_IFF_MKID('t', 'r', 'n', 's'):
603 /* translate */
604 if(object) {
605 G3DFloat x,y,z;
606 G3DFloat matrix[16];
607
608 x = g3d_stream_read_float_be(stream);
609 y = g3d_stream_read_float_be(stream);
610 z = g3d_stream_read_float_be(stream);
611
612 g3d_matrix_identity(matrix);
613 g3d_matrix_translate(x, y, z, matrix);
614
615 g3d_object_transform(object, matrix);
616 } else {
617#if DEBUG > 0
618 g_warning("3DMF: [trns] no object");
619#endif
620 g3d_stream_skip(stream, 12);
621 }
622 break;
623
624 default:
625 if(chunkdesc) {
626 g3d_stream_skip(stream, len);
627 } else {
628#if DEBUG > 0
629 g_warning("3DMF: Container: unknown chunk '%c%c%c%c'/"
630 "0x%02X%02X%02X%02X @ 0x%08x "
631 "(%d bytes)",
632 X3DMF_CHUNK_CHAR(id, 24), X3DMF_CHUNK_CHAR(id, 16),
633 X3DMF_CHUNK_CHAR(id, 8), X3DMF_CHUNK_CHAR(id, 0),
634 X3DMF_CHUNK_CHAR(id, 24), X3DMF_CHUNK_CHAR(id, 16),
635 X3DMF_CHUNK_CHAR(id, 8), X3DMF_CHUNK_CHAR(id, 0),
636 (guint32)g3d_stream_tell(stream) - 8, len);
637#endif
638 g3d_stream_skip(stream, len);
639 }
640 break;
641 }
642 }
643
644 return TRUE;
645}
646