diff options
Diffstat (limited to 'src/others/mimesh/libg3d-0.0.8/plugins/import/imp_ac3d/imp_ac3d.c')
-rw-r--r-- | src/others/mimesh/libg3d-0.0.8/plugins/import/imp_ac3d/imp_ac3d.c | 534 |
1 files changed, 534 insertions, 0 deletions
diff --git a/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_ac3d/imp_ac3d.c b/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_ac3d/imp_ac3d.c new file mode 100644 index 0000000..61199ae --- /dev/null +++ b/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_ac3d/imp_ac3d.c | |||
@@ -0,0 +1,534 @@ | |||
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 <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <string.h> | ||
26 | #include <locale.h> | ||
27 | |||
28 | #include <glib.h> | ||
29 | |||
30 | #include <g3d/types.h> | ||
31 | #include <g3d/context.h> | ||
32 | #include <g3d/stream.h> | ||
33 | #include <g3d/material.h> | ||
34 | #include <g3d/texture.h> | ||
35 | #include <g3d/debug.h> | ||
36 | |||
37 | #define AC3D_FLAG_ACC 0x01 | ||
38 | |||
39 | struct ac3d_transform { | ||
40 | G3DFloat offx, offy, offz; | ||
41 | }; | ||
42 | |||
43 | static gint32 ac3d_read_object(G3DStream *stream, G3DContext *context, | ||
44 | G3DModel *model, gchar *line, struct ac3d_transform *transform, | ||
45 | guint32 flags, GSList **objectlist, gint32 *rowcnt, guint32 level); | ||
46 | |||
47 | EAPI | ||
48 | gboolean plugin_load_model_from_stream(G3DContext *context, G3DStream *stream, | ||
49 | G3DModel *model, gpointer user_data) | ||
50 | { | ||
51 | struct ac3d_transform *transform; | ||
52 | gchar buffer[2049], namebuf[257], *filename; | ||
53 | guint32 version, ti1, flags = 0; | ||
54 | G3DMaterial *material; | ||
55 | G3DFloat tf1, tf2, tf3, tf4, tf5, tf6, trans; | ||
56 | gint32 rowcnt = 0; | ||
57 | |||
58 | setlocale(LC_NUMERIC, "C"); | ||
59 | |||
60 | rowcnt ++; | ||
61 | g3d_stream_read_line(stream, buffer, 2048); | ||
62 | |||
63 | if(strncmp(buffer, "AC3D", 4) != 0) | ||
64 | { | ||
65 | g_warning("file is not a AC3D model"); | ||
66 | return FALSE; | ||
67 | } | ||
68 | |||
69 | filename = g3d_stream_get_uri(stream); | ||
70 | if(g_ascii_strcasecmp(filename + strlen(filename) - 4, ".acc") == 0) | ||
71 | { | ||
72 | #if DEBUG > 0 | ||
73 | g_debug("AC3D: .acc file"); | ||
74 | #endif | ||
75 | flags |= AC3D_FLAG_ACC; | ||
76 | } | ||
77 | |||
78 | version = strtoul(buffer + 4, NULL, 16); | ||
79 | |||
80 | #if DEBUG > 0 | ||
81 | g_debug("AC3D: version %d", version); | ||
82 | #endif | ||
83 | |||
84 | while(g3d_stream_read_line(stream, buffer, 2048)) | ||
85 | { | ||
86 | rowcnt ++; | ||
87 | if(strncmp(buffer, "MATERIAL", 8) == 0) | ||
88 | { | ||
89 | material = g3d_material_new(); | ||
90 | if(sscanf(buffer, | ||
91 | "MATERIAL %s " | ||
92 | "rgb " G3D_SCANF_FLOAT " " G3D_SCANF_FLOAT " " G3D_SCANF_FLOAT " " | ||
93 | "amb " G3D_SCANF_FLOAT " " G3D_SCANF_FLOAT " " G3D_SCANF_FLOAT " " | ||
94 | "emis " G3D_SCANF_FLOAT " " G3D_SCANF_FLOAT " " G3D_SCANF_FLOAT " " | ||
95 | "spec %f %f %f " | ||
96 | "shi %u " | ||
97 | "trans " G3D_SCANF_FLOAT, | ||
98 | namebuf, | ||
99 | &(material->r), &(material->g), &(material->b), | ||
100 | &tf1, &tf2, &tf3, | ||
101 | &tf4, &tf5, &tf6, | ||
102 | &(material->specular[0]), | ||
103 | &(material->specular[1]), | ||
104 | &(material->specular[2]), | ||
105 | &ti1, | ||
106 | &trans) != 15) | ||
107 | { | ||
108 | g_warning("AC3D: error reading material line (%s)", buffer); | ||
109 | } | ||
110 | |||
111 | material->name = g_strdup(namebuf); | ||
112 | material->a = 1.0 - trans; | ||
113 | |||
114 | model->materials = g_slist_append(model->materials, material); | ||
115 | g_debug("\\(0) Material (line %d)", rowcnt); | ||
116 | } | ||
117 | else if(strncmp(buffer, "OBJECT", 6) == 0) | ||
118 | { | ||
119 | transform = g_new0(struct ac3d_transform, 1); | ||
120 | g_debug("\\(0) Object (line %d)", rowcnt); | ||
121 | ac3d_read_object(stream, context, model, buffer, transform, flags, | ||
122 | &(model->objects), &rowcnt, 1); | ||
123 | } | ||
124 | else | ||
125 | { | ||
126 | #if DEBUG > 0 | ||
127 | g_warning("AC3D: unhandled line: %s", buffer); | ||
128 | #endif | ||
129 | } | ||
130 | } | ||
131 | |||
132 | return TRUE; | ||
133 | } | ||
134 | |||
135 | EAPI | ||
136 | gchar *plugin_description(G3DContext *context) | ||
137 | { | ||
138 | return g_strdup("AC3D models."); | ||
139 | } | ||
140 | |||
141 | EAPI | ||
142 | gchar **plugin_extensions(G3DContext *context) | ||
143 | { | ||
144 | return g_strsplit("ac:acc", ":", 0); | ||
145 | } | ||
146 | |||
147 | /* | ||
148 | * AC3D specific | ||
149 | */ | ||
150 | |||
151 | static gchar *ac3d_remove_quotes(gchar *text) | ||
152 | { | ||
153 | if(text[0] == '"') | ||
154 | return g_strndup(text + 1, strlen(text) - 2); | ||
155 | else | ||
156 | return g_strdup(text); | ||
157 | } | ||
158 | |||
159 | /** | ||
160 | * ac3d_read_object: | ||
161 | * returns: number of objects (including sub-objects) read, 0 in case of | ||
162 | * error. | ||
163 | */ | ||
164 | |||
165 | static gint32 ac3d_read_object(G3DStream *stream, G3DContext *context, | ||
166 | G3DModel *model, gchar *line, struct ac3d_transform *parent_transform, | ||
167 | guint32 flags, GSList **objectlist, gint32 *rowcnt, guint32 level) | ||
168 | { | ||
169 | struct ac3d_transform *transform; | ||
170 | G3DObject *object; | ||
171 | G3DMaterial *material = NULL; | ||
172 | G3DFace *face; | ||
173 | gchar buffer[2049], namebuf[257]; | ||
174 | guint32 nkids, ti1, i, surf_flags, surf_done; | ||
175 | guint32 i1, i2, i3; | ||
176 | G3DFloat u1, u2, u3, v1, v2, v3; | ||
177 | G3DFloat locx = 0.0, locy = 0.0, locz = 0.0; | ||
178 | G3DFloat texrepu = 1.0, texrepv = 1.0, texoffu = 0.0, texoffv = 0.0; | ||
179 | G3DFloat texscaleu = 1.0, texscalev = 1.0; | ||
180 | G3DFloat crease = 0.0; | ||
181 | guint32 len, facecnt = 0; | ||
182 | gchar *filename; | ||
183 | gint32 kidsread, objectcount = 0; | ||
184 | G3DFloat pcnt, prev_pcnt = 0.0; | ||
185 | |||
186 | if(sscanf(line, "OBJECT %s", namebuf) != 1) | ||
187 | { | ||
188 | g_warning("AC3D: error reading object line (%s)", line); | ||
189 | } | ||
190 | |||
191 | transform = g_new0(struct ac3d_transform, 1); | ||
192 | memcpy(transform, parent_transform, sizeof(struct ac3d_transform)); | ||
193 | |||
194 | object = g_new0(G3DObject, 1); | ||
195 | objectcount ++; | ||
196 | *(objectlist) = g_slist_append(*(objectlist), object); | ||
197 | |||
198 | while(g3d_stream_read_line(stream, buffer, 2048)) | ||
199 | { | ||
200 | *rowcnt += 1; | ||
201 | if(strncmp(buffer, "kids", 4) == 0) | ||
202 | { | ||
203 | /* final line of object */ | ||
204 | if(sscanf(buffer, "kids %u", &nkids) != 1) | ||
205 | { | ||
206 | g_warning("AC3D: error reading kids line (%s)", buffer); | ||
207 | return 0; | ||
208 | } | ||
209 | for(i = 0; i < nkids; i ++) | ||
210 | { | ||
211 | /* read kids */ | ||
212 | *rowcnt += 1; | ||
213 | g3d_stream_read_line(stream, buffer, 2048); | ||
214 | #if DEBUG > 0 | ||
215 | g_debug("\\%s(%d) Object (line %d)", debug_pad(level), | ||
216 | level, *rowcnt); | ||
217 | #endif | ||
218 | kidsread = ac3d_read_object(stream, context, model, buffer, | ||
219 | transform, flags, &(object->objects), rowcnt, level + 1); | ||
220 | objectcount += kidsread; | ||
221 | } | ||
222 | |||
223 | #if DEBUG > 0 | ||
224 | g_debug("AC3D: \"%s\": %d sub-objects read", | ||
225 | object->name ? object->name : "unnamed", | ||
226 | objectcount - 1); | ||
227 | #endif | ||
228 | |||
229 | if(crease > 0.0) | ||
230 | { | ||
231 | /* doesn't really work */ | ||
232 | #if 0 | ||
233 | g3d_object_smooth(object, crease); | ||
234 | #endif | ||
235 | } | ||
236 | return objectcount; | ||
237 | } | ||
238 | else if(strncmp(buffer, "name", 4) == 0) | ||
239 | { | ||
240 | if(sscanf(buffer, "name %s", namebuf) != 1) | ||
241 | { | ||
242 | g_warning("AC3D: error reading name line (%s)", buffer); | ||
243 | } | ||
244 | else | ||
245 | { | ||
246 | object->name = g_strdup(namebuf); | ||
247 | } | ||
248 | } | ||
249 | else if(strncmp(buffer, "loc", 3) == 0) | ||
250 | { | ||
251 | if(sscanf(buffer, "loc " G3D_SCANF_FLOAT " " G3D_SCANF_FLOAT " " G3D_SCANF_FLOAT, &locx, &locy, &locz) != 3) | ||
252 | { | ||
253 | g_warning("AC3D: error reading loc line (%s)", buffer); | ||
254 | locx = locy = locz = 0.0; | ||
255 | } | ||
256 | |||
257 | transform->offx += locx; | ||
258 | transform->offy += locy; | ||
259 | transform->offz += locz; | ||
260 | } | ||
261 | else if(strncmp(buffer, "numvert", 7) == 0) | ||
262 | { | ||
263 | if(sscanf(buffer, "numvert %u", &(object->vertex_count)) != 1) | ||
264 | { | ||
265 | g_warning("AC3D: error reading numvert line (%s)", buffer); | ||
266 | object->vertex_count = 0; | ||
267 | } | ||
268 | else | ||
269 | { | ||
270 | object->vertex_data = | ||
271 | g_new0(G3DFloat, object->vertex_count * 3); | ||
272 | for(i = 0; i < object->vertex_count; i ++) | ||
273 | { | ||
274 | if(g3d_stream_read_line(stream, buffer, 2048)) | ||
275 | { | ||
276 | *rowcnt += 1; | ||
277 | if(sscanf(buffer, G3D_SCANF_FLOAT " " G3D_SCANF_FLOAT " " G3D_SCANF_FLOAT, | ||
278 | &(object->vertex_data[i * 3 + 0]), | ||
279 | &(object->vertex_data[i * 3 + 1]), | ||
280 | &(object->vertex_data[i * 3 + 2])) != 3) | ||
281 | { | ||
282 | g_warning("AC3D: error reading vertex (%s)", | ||
283 | buffer); | ||
284 | } | ||
285 | |||
286 | object->vertex_data[i * 3 + 0] += transform->offx; | ||
287 | object->vertex_data[i * 3 + 1] += transform->offy; | ||
288 | object->vertex_data[i * 3 + 2] += transform->offz; | ||
289 | } | ||
290 | } | ||
291 | } | ||
292 | /* END numvert */ | ||
293 | } | ||
294 | else if(strncmp(buffer, "numsurf", 7) == 0) | ||
295 | { | ||
296 | /* ignore for now */ | ||
297 | } | ||
298 | else if(strncmp(buffer, "SURF", 4) == 0) | ||
299 | { | ||
300 | surf_done = 0; | ||
301 | |||
302 | if(sscanf(buffer, "SURF %x", &surf_flags) != 1) | ||
303 | { | ||
304 | g_warning("AC3D: error reading surf (%s)", buffer); | ||
305 | } | ||
306 | |||
307 | while(!surf_done) | ||
308 | { | ||
309 | if(!g3d_stream_read_line(stream, buffer, 2048)) | ||
310 | return 0; | ||
311 | *rowcnt += 1; | ||
312 | |||
313 | if(sscanf(buffer, "refs %u", &ti1) == 1) | ||
314 | { | ||
315 | if(!(flags & AC3D_FLAG_ACC)) | ||
316 | { | ||
317 | face = g_new0(G3DFace, 1); | ||
318 | face->vertex_count = ti1; | ||
319 | face->vertex_indices = | ||
320 | g_new0(guint32, face->vertex_count); | ||
321 | face->material = material; | ||
322 | |||
323 | face->tex_image = object->tex_image; | ||
324 | if(face->tex_image) | ||
325 | { | ||
326 | face->flags |= G3D_FLAG_FAC_TEXMAP; | ||
327 | } | ||
328 | |||
329 | face->tex_vertex_count = ti1; | ||
330 | face->tex_vertex_data = | ||
331 | g_new0(G3DFloat, 2 * face->tex_vertex_count); | ||
332 | |||
333 | /* normal face */ | ||
334 | for(i = 0; i < face->vertex_count; i ++) | ||
335 | { | ||
336 | if(!g3d_stream_read_line(stream, buffer, 2048)) | ||
337 | return 0; | ||
338 | *rowcnt += 1; | ||
339 | |||
340 | if(sscanf(buffer, "%u " G3D_SCANF_FLOAT " " G3D_SCANF_FLOAT, | ||
341 | &(face->vertex_indices[i]), | ||
342 | &(face->tex_vertex_data[i * 2 + 0]), | ||
343 | &(face->tex_vertex_data[i * 2 + 1])) != 3) | ||
344 | { | ||
345 | g_warning( | ||
346 | "AC3D: error reading vertex index (%s)", | ||
347 | buffer); | ||
348 | } | ||
349 | face->tex_vertex_data[i * 2 + 0] *= | ||
350 | (texrepu * texscaleu); | ||
351 | face->tex_vertex_data[i * 2 + 1] *= | ||
352 | (texrepv * texscalev); | ||
353 | |||
354 | face->tex_vertex_data[i * 2 + 0] += texoffu; | ||
355 | face->tex_vertex_data[i * 2 + 1] += texoffv; | ||
356 | |||
357 | #if 0 | ||
358 | face->tex_coords[i * 2 + 0] *= texscaleu; | ||
359 | face->tex_coords[i * 2 + 1] *= texscalev; | ||
360 | #endif | ||
361 | } | ||
362 | |||
363 | if(face->material && (face->vertex_count >= 3)) | ||
364 | object->faces = | ||
365 | g_slist_prepend(object->faces, face); | ||
366 | |||
367 | } /* not .acc */ | ||
368 | else | ||
369 | { | ||
370 | /* triangle stripes */ | ||
371 | i = 0; | ||
372 | while(i < ti1) | ||
373 | { | ||
374 | face = g_new0(G3DFace, 1); | ||
375 | face->vertex_count = 3; | ||
376 | face->vertex_indices = g_new0(guint32, 3); | ||
377 | |||
378 | face->material = material; | ||
379 | |||
380 | face->tex_image = object->tex_image; | ||
381 | if(face->tex_image) | ||
382 | { | ||
383 | face->flags |= G3D_FLAG_FAC_TEXMAP; | ||
384 | } | ||
385 | |||
386 | face->tex_vertex_count = 3; | ||
387 | face->tex_vertex_data = | ||
388 | g_new0(G3DFloat, 2 * face->tex_vertex_count); | ||
389 | |||
390 | if(i == 0) | ||
391 | { | ||
392 | /* TODO: error handling */ | ||
393 | g3d_stream_read_line(stream, buffer, 2048); | ||
394 | sscanf(buffer, "%u " G3D_SCANF_FLOAT " " G3D_SCANF_FLOAT, &i1, &u1, &v1); | ||
395 | g3d_stream_read_line(stream, buffer, 2048); | ||
396 | sscanf(buffer, "%u " G3D_SCANF_FLOAT " " G3D_SCANF_FLOAT, &i2, &u2, &v2); | ||
397 | g3d_stream_read_line(stream, buffer, 2048); | ||
398 | sscanf(buffer, "%u " G3D_SCANF_FLOAT " " G3D_SCANF_FLOAT, &i3, &u3, &v3); | ||
399 | |||
400 | *rowcnt += 3; | ||
401 | i += 3; | ||
402 | } | ||
403 | else | ||
404 | { | ||
405 | /* TODO: error handling */ | ||
406 | i1 = i2; | ||
407 | u1 = u2; | ||
408 | v1 = v2; | ||
409 | i2 = i3; | ||
410 | u2 = u3; | ||
411 | v2 = v3; | ||
412 | |||
413 | g3d_stream_read_line(stream, buffer, 2048); | ||
414 | *rowcnt += 1; | ||
415 | sscanf(buffer, "%u " G3D_SCANF_FLOAT " " G3D_SCANF_FLOAT, &i3, &u3, &v3); | ||
416 | |||
417 | i ++; | ||
418 | } | ||
419 | |||
420 | face->vertex_indices[0] = i1; | ||
421 | face->tex_vertex_data[0] = u1; | ||
422 | face->tex_vertex_data[1] = v1; | ||
423 | if(facecnt % 2) { | ||
424 | face->vertex_indices[1] = i3; | ||
425 | face->vertex_indices[2] = i2; | ||
426 | face->tex_vertex_data[2] = u3; | ||
427 | face->tex_vertex_data[3] = v3; | ||
428 | face->tex_vertex_data[4] = u2; | ||
429 | face->tex_vertex_data[5] = v2; | ||
430 | } else { | ||
431 | face->vertex_indices[1] = i2; | ||
432 | face->vertex_indices[2] = i3; | ||
433 | face->tex_vertex_data[2] = u2; | ||
434 | face->tex_vertex_data[3] = v2; | ||
435 | face->tex_vertex_data[4] = u3; | ||
436 | face->tex_vertex_data[5] = v3; | ||
437 | } | ||
438 | |||
439 | object->faces = | ||
440 | g_slist_prepend(object->faces, face); | ||
441 | facecnt ++; | ||
442 | } | ||
443 | } /* .acc */ | ||
444 | |||
445 | surf_done = 1; | ||
446 | } | ||
447 | else if(sscanf(buffer, "mat %u", &ti1) == 1) | ||
448 | { | ||
449 | material = g_slist_nth_data(model->materials, ti1); | ||
450 | } | ||
451 | } | ||
452 | |||
453 | material = NULL; | ||
454 | /* END SURF */ | ||
455 | } | ||
456 | else if(strncmp(buffer, "texture", 7) == 0) | ||
457 | { | ||
458 | if(sscanf(buffer, "texture %s", namebuf) == 1) | ||
459 | { | ||
460 | filename = ac3d_remove_quotes(namebuf); | ||
461 | object->tex_image = g3d_texture_load_cached(context, model, | ||
462 | filename); | ||
463 | if(object->tex_image) | ||
464 | { | ||
465 | g3d_texture_prepare(object->tex_image); | ||
466 | |||
467 | texscaleu = object->tex_image->tex_scale_u; | ||
468 | texscalev = object->tex_image->tex_scale_v; | ||
469 | } | ||
470 | } | ||
471 | else | ||
472 | { | ||
473 | g_warning("error reading texture line (%s)", buffer); | ||
474 | } | ||
475 | } | ||
476 | else if(strncmp(buffer, "texrep", 6) == 0) | ||
477 | { | ||
478 | if(sscanf(buffer, "texrep " G3D_SCANF_FLOAT " " G3D_SCANF_FLOAT, &texrepu, &texrepv) != 2) | ||
479 | { | ||
480 | g_warning("error reading texrep line (%s)", buffer); | ||
481 | texrepu = 1.0; | ||
482 | texrepv = 1.0; | ||
483 | } | ||
484 | |||
485 | if(texrepu == 0.0) texrepu = 1.0; | ||
486 | if(texrepv == 0.0) texrepv = 1.0; | ||
487 | } | ||
488 | else if(strncmp(buffer, "texoff", 6) == 0) | ||
489 | { | ||
490 | if(sscanf(buffer, "texoff " G3D_SCANF_FLOAT " " G3D_SCANF_FLOAT, &texoffu, &texoffv) != 2) | ||
491 | { | ||
492 | g_warning("error reading texoff line (%s)", buffer); | ||
493 | } | ||
494 | } | ||
495 | else if(strncmp(buffer, "crease", 6) == 0) | ||
496 | { | ||
497 | if(sscanf(buffer, "crease " G3D_SCANF_FLOAT, &crease) != 1) | ||
498 | { | ||
499 | g_warning("AC3D: error reading crease line (%i): %s", | ||
500 | *rowcnt, buffer); | ||
501 | } | ||
502 | } | ||
503 | else if(strncmp(buffer, "data ", 5) == 0) | ||
504 | { | ||
505 | /* object data */ | ||
506 | if(sscanf(buffer, "data %u", &len) != 1) | ||
507 | { | ||
508 | g_warning("AC3D: error in data line (%i): %s", | ||
509 | *rowcnt, buffer); | ||
510 | } | ||
511 | /* object data on next line */ | ||
512 | g3d_stream_read_line(stream, buffer, 2048); | ||
513 | *rowcnt += 1; | ||
514 | } | ||
515 | else | ||
516 | { | ||
517 | #if DEBUG > 0 | ||
518 | g_warning("AC3D: unhandled line %d: %s", *rowcnt, buffer); | ||
519 | #endif | ||
520 | } | ||
521 | |||
522 | pcnt = (G3DFloat)g3d_stream_tell(stream) / | ||
523 | (G3DFloat)g3d_stream_size(stream); | ||
524 | if((pcnt - prev_pcnt) > 0.005) { | ||
525 | prev_pcnt = pcnt; | ||
526 | g3d_context_update_progress_bar(context, pcnt, TRUE); | ||
527 | } | ||
528 | } | ||
529 | |||
530 | /* cleanup */ | ||
531 | g_free(transform); | ||
532 | |||
533 | return 0; | ||
534 | } | ||