diff options
Diffstat (limited to '')
-rw-r--r-- | src/others/mimesh/libg3d-0.0.8/plugins/import/imp_max/imp_max.c | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_max/imp_max.c b/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_max/imp_max.c new file mode 100644 index 0000000..0dba25c --- /dev/null +++ b/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_max/imp_max.c | |||
@@ -0,0 +1,358 @@ | |||
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 <g3d/config.h> | ||
24 | |||
25 | #include <string.h> | ||
26 | |||
27 | #include <g3d/types.h> | ||
28 | #include <g3d/context.h> | ||
29 | #include <g3d/object.h> | ||
30 | #include <g3d/material.h> | ||
31 | #include <g3d/stream.h> | ||
32 | #include <g3d/debug.h> | ||
33 | |||
34 | #include "imp_max_chunks.h" | ||
35 | |||
36 | |||
37 | |||
38 | static gboolean max_read_subfile(G3DContext *context, G3DModel *model, | ||
39 | G3DStream *stream, const gchar *subfile); | ||
40 | static gboolean max_read_chunk(MaxGlobalData *global, gint32 *nb, | ||
41 | guint32 level, gint32 parentid, gpointer object, guint32 *l2cnt, | ||
42 | GNode *tree); | ||
43 | static MaxChunk *max_get_chunk_desc(guint16 id, gint32 parentid, | ||
44 | gboolean container); | ||
45 | |||
46 | static const gchar *max_subfiles[] = { | ||
47 | #if 0 | ||
48 | "Config", | ||
49 | "VideoPostQueue", | ||
50 | "ScriptedCustAttribDefs", | ||
51 | "DllDirectory", | ||
52 | "ClassDirectory", | ||
53 | "ClassDirectory2", | ||
54 | "ClassDirectory3", | ||
55 | "ClassData", | ||
56 | #endif | ||
57 | "Scene", | ||
58 | NULL | ||
59 | }; | ||
60 | |||
61 | typedef enum { | ||
62 | MAX_ROOT_NODE, | ||
63 | MAX_L2_NODE, | ||
64 | MAX_CNT_NODE, | ||
65 | MAX_DATA_NODE | ||
66 | } MaxNodeType; | ||
67 | |||
68 | typedef struct { | ||
69 | MaxNodeType type; | ||
70 | gchar *name; | ||
71 | guint32 cnt2034; | ||
72 | guint32 val2034; | ||
73 | gint32 data2034; | ||
74 | GSList *children; | ||
75 | } MaxNode; | ||
76 | |||
77 | typedef struct { | ||
78 | guint32 l2id; | ||
79 | guint32 id; | ||
80 | gchar *text; | ||
81 | G3DObject *object; | ||
82 | } MaxTreeItem; | ||
83 | |||
84 | EAPI | ||
85 | gboolean plugin_load_model_from_stream(G3DContext *context, G3DStream *stream, | ||
86 | G3DModel *model) | ||
87 | { | ||
88 | gboolean retval = FALSE; | ||
89 | G3DMaterial *material; | ||
90 | const gchar **subfile = max_subfiles; | ||
91 | |||
92 | /* create default material */ | ||
93 | material = g3d_material_new(); | ||
94 | material->name = g_strdup("default material"); | ||
95 | model->materials = g_slist_append(model->materials, material); | ||
96 | |||
97 | /* debugging material */ | ||
98 | material = g3d_material_new(); | ||
99 | material->r = 1.0; | ||
100 | material->g = 0.2; | ||
101 | material->b = 0.1; | ||
102 | material->name = g_strdup("debugging material"); | ||
103 | model->materials = g_slist_append(model->materials, material); | ||
104 | |||
105 | while(*subfile) { | ||
106 | retval = max_read_subfile(context, model, stream, *subfile); | ||
107 | subfile ++; | ||
108 | } | ||
109 | |||
110 | g3d_context_update_progress_bar(context, 0.0, FALSE); | ||
111 | |||
112 | return retval; | ||
113 | } | ||
114 | |||
115 | EAPI | ||
116 | gchar *plugin_description(void) | ||
117 | { | ||
118 | return g_strdup("3D Studio MAX models (EXPERIMENTAL)."); | ||
119 | } | ||
120 | |||
121 | EAPI | ||
122 | gchar **plugin_extensions(void) | ||
123 | { | ||
124 | return g_strsplit("max:gmax", ":", 0); | ||
125 | } | ||
126 | |||
127 | /***************************************************************************** | ||
128 | * max specific | ||
129 | *****************************************************************************/ | ||
130 | |||
131 | static void max_walk_tree(GNode *tree, guint32 level) | ||
132 | { | ||
133 | GNode *node; | ||
134 | MaxTreeItem *mtitem; | ||
135 | |||
136 | mtitem = (MaxTreeItem *)tree->data; | ||
137 | |||
138 | #if DEBUG > 0 | ||
139 | g_debug("\\%s(%u)[0x%04X][0x%04X] %s", debug_pad(level), level, | ||
140 | mtitem->l2id, mtitem->id, mtitem->text); | ||
141 | #endif | ||
142 | |||
143 | for(node = tree->children; node != NULL; node = node->next) { | ||
144 | max_walk_tree(node, level + 1); | ||
145 | } | ||
146 | } | ||
147 | |||
148 | static gboolean max_read_subfile(G3DContext *context, G3DModel *model, | ||
149 | G3DStream *stream, const gchar *subfile) | ||
150 | { | ||
151 | G3DStream *ssf; | ||
152 | MaxGlobalData *global; | ||
153 | gint32 fsize; | ||
154 | guint32 l2cnt = 0; | ||
155 | MaxTreeItem *rootitem; | ||
156 | GNode *tree; | ||
157 | |||
158 | rootitem = g_new0(MaxTreeItem, 1); | ||
159 | rootitem->text = g_strdup("ROOT"); | ||
160 | tree = g_node_new(rootitem); | ||
161 | |||
162 | ssf = g3d_stream_open_structured_file_from_stream(stream, subfile); | ||
163 | if(ssf == NULL) { | ||
164 | g_warning("MAX: failed to open '%s' in structured file '%s'", | ||
165 | subfile, stream->uri); | ||
166 | return FALSE; | ||
167 | } | ||
168 | |||
169 | fsize = g3d_stream_size(ssf); | ||
170 | |||
171 | g_debug("\\%s (%d bytes)", subfile, fsize); | ||
172 | |||
173 | global = g_new0(MaxGlobalData, 1); | ||
174 | global->context = context; | ||
175 | global->model = model; | ||
176 | global->stream = ssf; | ||
177 | global->subfile = subfile; | ||
178 | |||
179 | while(max_read_chunk(global, &fsize, 1 /* level */, IDNONE, NULL, &l2cnt, | ||
180 | tree)); | ||
181 | |||
182 | g_debug("MAX tree:"); | ||
183 | max_walk_tree(tree, 0); | ||
184 | |||
185 | g_free(global); | ||
186 | g3d_stream_close(ssf); | ||
187 | |||
188 | return TRUE; | ||
189 | } | ||
190 | |||
191 | static GNode *max_find_node(GNode *tree, guint32 id) | ||
192 | { | ||
193 | GNode *node, *found; | ||
194 | MaxTreeItem *mtitem; | ||
195 | |||
196 | mtitem = (MaxTreeItem *)tree->data; | ||
197 | if(mtitem->l2id == id) | ||
198 | return tree; | ||
199 | |||
200 | for(node = tree->children; node != NULL; node = node->next) { | ||
201 | found = max_find_node(node, id); | ||
202 | if(found != NULL) | ||
203 | return found; | ||
204 | } | ||
205 | |||
206 | return NULL; | ||
207 | } | ||
208 | |||
209 | static gboolean max_create_l2_tree_object(MaxGlobalData *global, | ||
210 | MaxLocalData *local, G3DObject *parent) | ||
211 | { | ||
212 | G3DObject *object; | ||
213 | |||
214 | object = g_new0(G3DObject, 1); | ||
215 | object->name = g_strdup_printf("0x%04X object @ 0x%08x", | ||
216 | local->id, (guint32)g3d_stream_tell(global->stream)); | ||
217 | local->object = object; | ||
218 | if(parent) | ||
219 | parent->objects = g_slist_append(parent->objects, object); | ||
220 | else | ||
221 | global->model->objects = g_slist_append(global->model->objects, | ||
222 | object); | ||
223 | |||
224 | global->object = object; | ||
225 | global->vertex_offset = 0; | ||
226 | |||
227 | return TRUE; | ||
228 | } | ||
229 | |||
230 | static gboolean max_read_chunk(MaxGlobalData *global, gint32 *nb, | ||
231 | guint32 level, gint32 parentid, gpointer object, guint32 *l2cnt, | ||
232 | GNode *tree) | ||
233 | { | ||
234 | guint16 id; | ||
235 | guint32 length; | ||
236 | gboolean container; | ||
237 | MaxChunk *chunk; | ||
238 | MaxLocalData *local; | ||
239 | MaxTreeItem *mtitem; | ||
240 | GNode *pnode = NULL, *node; | ||
241 | |||
242 | if(nb && (*nb < 6)) | ||
243 | return FALSE; | ||
244 | |||
245 | id = g3d_stream_read_int16_le(global->stream); | ||
246 | length = g3d_stream_read_int32_le(global->stream); | ||
247 | container = (length & 0x80000000); | ||
248 | length &= 0x7FFFFFFF; | ||
249 | |||
250 | if(nb && (length > *nb)) | ||
251 | return FALSE; | ||
252 | if(nb) | ||
253 | *nb -= length; | ||
254 | |||
255 | if((level == 2) && l2cnt) | ||
256 | (*l2cnt) ++; | ||
257 | |||
258 | chunk = max_get_chunk_desc(id, parentid, container); | ||
259 | |||
260 | #if DEBUG > 0 | ||
261 | g_debug("\\%s(%d)[0x%04X][%c%c] %s -- %d (%d) bytes @ 0x%08x", | ||
262 | debug_pad(level), level, | ||
263 | id, (container ? 'c' : ' '), | ||
264 | (chunk && chunk->callback) ? 'f' : ' ', | ||
265 | chunk ? chunk->desc : (level == 2) ? "level 2 container" : "unknown", | ||
266 | length - 6, length, | ||
267 | (guint32)g3d_stream_tell(global->stream) - 6); | ||
268 | #endif | ||
269 | |||
270 | node = tree; | ||
271 | if(level == 2) { | ||
272 | pnode = max_find_node(tree, id); | ||
273 | if(pnode != NULL) { | ||
274 | mtitem = g_new0(MaxTreeItem, 1); | ||
275 | mtitem->l2id = *l2cnt; | ||
276 | mtitem->id = id; | ||
277 | mtitem->text = g_strdup("L2ITEM"); | ||
278 | node = g_node_append_data(pnode, mtitem); | ||
279 | } else { | ||
280 | mtitem = g_new0(MaxTreeItem, 1); | ||
281 | mtitem->l2id = 0xFFFF; | ||
282 | mtitem->id = id; | ||
283 | mtitem->text = g_strdup_printf("OUTOFTREE: 0x%04X", id); | ||
284 | node = g_node_append_data(tree, mtitem); | ||
285 | } | ||
286 | } else if(level > 2) { | ||
287 | mtitem = g_new0(MaxTreeItem, 1); | ||
288 | mtitem->l2id = 0xFFFF; | ||
289 | mtitem->id = id; | ||
290 | mtitem->text = g_strdup_printf("REGITEM: 0x%04X: %s", | ||
291 | id, chunk ? chunk->desc : "unknown"); | ||
292 | node = g_node_append_data(tree, mtitem); | ||
293 | } | ||
294 | |||
295 | local = g_new0(MaxLocalData, 1); | ||
296 | local->id = (level > 2) ? id : 0x0000; | ||
297 | local->parentid = parentid; | ||
298 | local->nb = length - 6; | ||
299 | local->level = level + 1; | ||
300 | local->object = object; | ||
301 | |||
302 | if((level > 2) && chunk && chunk->callback) | ||
303 | chunk->callback(global, local); | ||
304 | if(level == 2) { | ||
305 | mtitem = pnode ? pnode->data : NULL; | ||
306 | max_create_l2_tree_object(global, local, | ||
307 | mtitem ? mtitem->object : NULL); | ||
308 | mtitem = node->data; | ||
309 | mtitem->object = local->object; | ||
310 | } | ||
311 | |||
312 | if(container) | ||
313 | while(local->nb > 0) | ||
314 | if(!max_read_chunk(global, &(local->nb), level + 1, id, | ||
315 | local->object, l2cnt, node)) | ||
316 | return FALSE; | ||
317 | |||
318 | if(local->nb > 0) | ||
319 | g3d_stream_skip(global->stream, local->nb); | ||
320 | |||
321 | g_free(local); | ||
322 | |||
323 | g3d_context_update_interface(global->context); | ||
324 | |||
325 | if(level < 3) | ||
326 | g3d_context_update_progress_bar(global->context, | ||
327 | (G3DFloat)g3d_stream_tell(global->stream) / | ||
328 | (G3DFloat)g3d_stream_size(global->stream), | ||
329 | TRUE); | ||
330 | |||
331 | return TRUE; | ||
332 | } | ||
333 | |||
334 | static MaxChunk *max_get_chunk_desc(guint16 id, gint32 parentid, | ||
335 | gboolean container) | ||
336 | { | ||
337 | MaxChunk *chunk, *chunks; | ||
338 | gint32 i; | ||
339 | |||
340 | if(container) | ||
341 | chunks = max_cnt_chunks; | ||
342 | else | ||
343 | chunks = max_chunks; | ||
344 | |||
345 | for(i = 0, chunk = &(chunks[i]); chunk->id != IDNONE; | ||
346 | i ++, chunk = &(chunks[i])) { | ||
347 | if((chunk->parentid == IDSOME) || (parentid == chunk->parentid) || | ||
348 | (parentid == IDSOME) || | ||
349 | ((chunk->parentid == IDROOT) && ID_IS_ROOT(parentid)) || | ||
350 | ((chunk->parentid == IDGEOM) && ID_IS_GEOM(parentid)) || | ||
351 | ((chunk->parentid == IDMATG) && ID_IS_MATG(parentid)) || | ||
352 | ((chunk->parentid == IDFILE) && ID_IS_FILE(parentid))) { | ||
353 | if(chunk->id == id) | ||
354 | return chunk; | ||
355 | } /* parentid */ | ||
356 | } | ||
357 | return NULL; | ||
358 | } | ||