diff options
Diffstat (limited to 'src/others/mimesh/libg3d-0.0.8/plugins/import/imp_md3/imp_md3.c')
-rw-r--r-- | src/others/mimesh/libg3d-0.0.8/plugins/import/imp_md3/imp_md3.c | 396 |
1 files changed, 396 insertions, 0 deletions
diff --git a/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_md3/imp_md3.c b/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_md3/imp_md3.c new file mode 100644 index 0000000..360a568 --- /dev/null +++ b/src/others/mimesh/libg3d-0.0.8/plugins/import/imp_md3/imp_md3.c | |||
@@ -0,0 +1,396 @@ | |||
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 | #include <math.h> | ||
25 | |||
26 | #ifndef M_PI | ||
27 | # define M_PI 3.14159265358979323846 | ||
28 | #endif | ||
29 | |||
30 | #include <g3d/types.h> | ||
31 | #include <g3d/object.h> | ||
32 | #include <g3d/stream.h> | ||
33 | #include <g3d/iff.h> | ||
34 | #include <g3d/material.h> | ||
35 | #include <g3d/texture.h> | ||
36 | #include <g3d/vector.h> | ||
37 | |||
38 | #define MD3_TYPE_MD3 0x01 | ||
39 | #define MD3_TYPE_MDC 0x02 | ||
40 | |||
41 | gboolean md3_load_skin(G3DContext *context, G3DModel *model, | ||
42 | const gchar *filename); | ||
43 | gboolean md3_read_tag(G3DStream *stream, G3DContext *context, G3DModel *model); | ||
44 | gboolean md3_read_mesh(G3DStream *stream, G3DContext *context, G3DModel *model); | ||
45 | |||
46 | |||
47 | EAPI | ||
48 | gboolean plugin_load_model_from_stream(G3DContext *context, G3DStream *stream, | ||
49 | G3DModel *model, gpointer user_data) | ||
50 | { | ||
51 | guint32 magic, version, nboneframes, ntags, nmeshes, nskins; | ||
52 | guint32 off_bfs, off_tags, off_meshes, filesize, i, flags; | ||
53 | |||
54 | magic = g3d_stream_read_int32_be(stream); | ||
55 | if((magic != G3D_IFF_MKID('I', 'D', 'P', '3')) && | ||
56 | (magic != G3D_IFF_MKID('I', 'D', 'P', 'C'))) { | ||
57 | g_warning("MD3: %s is not a valid md3 file", stream->uri); | ||
58 | return FALSE; | ||
59 | } | ||
60 | |||
61 | version = g3d_stream_read_int32_le(stream); | ||
62 | g3d_stream_skip(stream, 64); | ||
63 | |||
64 | flags = g3d_stream_read_int32_le(stream); | ||
65 | nboneframes = g3d_stream_read_int32_le(stream); | ||
66 | ntags = g3d_stream_read_int32_le(stream); | ||
67 | nmeshes = g3d_stream_read_int32_le(stream); | ||
68 | nskins = g3d_stream_read_int32_le(stream); | ||
69 | off_bfs = g3d_stream_read_int32_le(stream); | ||
70 | off_tags = g3d_stream_read_int32_le(stream); | ||
71 | off_meshes = g3d_stream_read_int32_le(stream); | ||
72 | filesize = g3d_stream_read_int32_le(stream); | ||
73 | |||
74 | /* try to load skin */ | ||
75 | md3_load_skin(context, model, stream->uri); | ||
76 | |||
77 | g_debug("MD3: version: %u, file size: %u bytes", version, filesize); | ||
78 | g_debug("MD3: tags @ 0x%08x, meshes @ 0x%08x", off_tags, off_meshes); | ||
79 | |||
80 | g3d_stream_seek(stream, off_tags, G_SEEK_SET); | ||
81 | if(magic == G3D_IFF_MKID('I', 'D', 'P', '3')) | ||
82 | for(i = 0; i < nboneframes * ntags; i ++) | ||
83 | md3_read_tag(stream, context, model); | ||
84 | |||
85 | /* read meshes */ | ||
86 | g3d_stream_seek(stream, off_meshes, G_SEEK_SET); | ||
87 | for(i = 0; i < nmeshes; i ++) | ||
88 | md3_read_mesh(stream, context, model); | ||
89 | |||
90 | return TRUE; | ||
91 | } | ||
92 | |||
93 | EAPI | ||
94 | gchar *plugin_description(G3DContext *context) | ||
95 | { | ||
96 | return g_strdup("Quake 3 models."); | ||
97 | } | ||
98 | |||
99 | EAPI | ||
100 | gchar **plugin_extensions(G3DContext *context) | ||
101 | { | ||
102 | return g_strsplit("md3:mdc", ":", 0); | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * MD3 specific | ||
107 | */ | ||
108 | |||
109 | gboolean md3_load_skin(G3DContext *context, G3DModel *model, | ||
110 | const gchar *filename) | ||
111 | { | ||
112 | gchar *basename, *skinname, **parts; | ||
113 | gchar line[256]; | ||
114 | G3DStream *stream; | ||
115 | G3DMaterial *material; | ||
116 | |||
117 | basename = g_path_get_basename(filename); | ||
118 | skinname = g_strdup_printf("%.*s_default.skin", | ||
119 | ((int) strlen(basename)) - 4, basename); | ||
120 | |||
121 | g_debug("MD3: trying to open skin file %s", skinname); | ||
122 | |||
123 | stream = g3d_stream_open_file(skinname, "r"); | ||
124 | |||
125 | g_free(basename); | ||
126 | g_free(skinname); | ||
127 | |||
128 | /* no skin */ | ||
129 | if(stream == NULL) | ||
130 | return FALSE; | ||
131 | |||
132 | while(g3d_stream_read_line(stream, line, 255) != NULL) { | ||
133 | parts = g_strsplit(line, ",", 2); | ||
134 | if(parts[0] && parts[1]) { | ||
135 | g_strchomp(parts[1]); | ||
136 | if(strlen(parts[1]) > 0) | ||
137 | { | ||
138 | g_debug("MD3: skin texture for %s: %s", | ||
139 | parts[0], parts[1]); | ||
140 | |||
141 | material = g3d_material_new(); | ||
142 | material->name = g_strdup(parts[0]); | ||
143 | material->tex_image = g3d_texture_load_cached(context, model, | ||
144 | parts[1]); | ||
145 | |||
146 | model->materials = g_slist_append(model->materials, | ||
147 | material); | ||
148 | } | ||
149 | } | ||
150 | g_strfreev(parts); | ||
151 | } | ||
152 | |||
153 | g3d_stream_close(stream); | ||
154 | |||
155 | return TRUE; | ||
156 | } | ||
157 | |||
158 | gboolean md3_read_tag(G3DStream *stream, G3DContext *context, G3DModel *model) | ||
159 | { | ||
160 | gchar name[65]; | ||
161 | |||
162 | g3d_stream_read(stream, name, 64); | ||
163 | name[64] = '\0'; | ||
164 | |||
165 | g_debug("MD3: tag: %s", name); | ||
166 | |||
167 | /* position */ | ||
168 | g3d_stream_read_float_le(stream); | ||
169 | g3d_stream_read_float_le(stream); | ||
170 | g3d_stream_read_float_le(stream); | ||
171 | |||
172 | /* rotation */ | ||
173 | g3d_stream_read_float_le(stream); | ||
174 | g3d_stream_read_float_le(stream); | ||
175 | g3d_stream_read_float_le(stream); | ||
176 | |||
177 | g3d_stream_read_float_le(stream); | ||
178 | g3d_stream_read_float_le(stream); | ||
179 | g3d_stream_read_float_le(stream); | ||
180 | |||
181 | g3d_stream_read_float_le(stream); | ||
182 | g3d_stream_read_float_le(stream); | ||
183 | g3d_stream_read_float_le(stream); | ||
184 | |||
185 | return TRUE; | ||
186 | } | ||
187 | |||
188 | gboolean md3_read_mesh(G3DStream *stream, G3DContext *context, G3DModel *model) | ||
189 | { | ||
190 | G3DObject *object; | ||
191 | G3DImage *image = NULL; | ||
192 | G3DMaterial *material, *mat; | ||
193 | G3DFace *face; | ||
194 | GSList *mitem; | ||
195 | guint32 magic, i, j; | ||
196 | guint8 type = 0, r, s; | ||
197 | G3DFloat rho, sigma, *normals; | ||
198 | gchar name[64], *strp; | ||
199 | guint32 nmeshframe, nskin, nvertex, ntris, mlength, flags; | ||
200 | goffset off_tris, off_texvec, off_vertex, off_start, off_skins; | ||
201 | |||
202 | off_start = g3d_stream_tell(stream); | ||
203 | |||
204 | magic = g3d_stream_read_int32_be(stream); | ||
205 | |||
206 | if(magic == G3D_IFF_MKID('I', 'D', 'P', '3')) | ||
207 | type = MD3_TYPE_MD3; | ||
208 | else /* if(magic == 0x07000000)*/ | ||
209 | type = MD3_TYPE_MDC; | ||
210 | #if 0 | ||
211 | else | ||
212 | { | ||
213 | g_warning("MD3: mesh magic unknown (%02x%02x%02x%02x)\n", | ||
214 | (magic >> 24) & 0xFF, | ||
215 | (magic >> 16) & 0xFF, | ||
216 | (magic >> 8) & 0xFF, | ||
217 | magic & 0xFF); | ||
218 | return FALSE; | ||
219 | } | ||
220 | #endif | ||
221 | |||
222 | object = g_new0(G3DObject, 1); | ||
223 | |||
224 | /* read name */ | ||
225 | g3d_stream_read(stream, name, 64); | ||
226 | object->name = g_strndup(name, 64); | ||
227 | |||
228 | flags = g3d_stream_read_int32_le(stream); | ||
229 | |||
230 | if(type == MD3_TYPE_MD3) { | ||
231 | nmeshframe = g3d_stream_read_int32_le(stream); | ||
232 | nskin = g3d_stream_read_int32_le(stream); | ||
233 | } else if(type == MD3_TYPE_MDC) { | ||
234 | g3d_stream_read_int32_le(stream); /* ncompframes */ | ||
235 | g3d_stream_read_int32_le(stream); /* nbaseframes */ | ||
236 | g3d_stream_read_int32_le(stream); /* nshaders */ | ||
237 | } | ||
238 | |||
239 | nvertex = g3d_stream_read_int32_le(stream); | ||
240 | ntris = g3d_stream_read_int32_le(stream); | ||
241 | |||
242 | off_tris = g3d_stream_read_int32_le(stream); | ||
243 | off_skins = g3d_stream_read_int32_le(stream); | ||
244 | |||
245 | off_texvec = g3d_stream_read_int32_le(stream); | ||
246 | off_vertex = g3d_stream_read_int32_le(stream); | ||
247 | |||
248 | if(type == MD3_TYPE_MDC) { | ||
249 | g3d_stream_read_int32_le(stream); /* off_compvert */ | ||
250 | g3d_stream_read_int32_le(stream); /* off_fbasef */ | ||
251 | g3d_stream_read_int32_le(stream); /* off_fcompf */ | ||
252 | } | ||
253 | |||
254 | mlength = g3d_stream_read_int32_le(stream); | ||
255 | |||
256 | if((nvertex == 0) || (ntris == 0)) { | ||
257 | g_warning("MD3: %u vertices, %u triangles", nvertex, ntris); | ||
258 | g3d_stream_seek(stream, off_start + mlength, G_SEEK_SET); | ||
259 | return FALSE; | ||
260 | } | ||
261 | |||
262 | /* default material */ | ||
263 | material = g3d_material_new(); | ||
264 | material->name = g_strdup("default material"); | ||
265 | object->materials = g_slist_append(object->materials, material); | ||
266 | |||
267 | /* skins */ | ||
268 | g3d_stream_seek(stream, off_start + off_skins, G_SEEK_SET); | ||
269 | g3d_stream_read(stream, name, 64); | ||
270 | g_debug("MD3: skin name: %s", name); | ||
271 | |||
272 | /* read texture image */ | ||
273 | if(strlen(name) > 0) { | ||
274 | image = g3d_texture_load_cached(context, model, name); | ||
275 | if(image == NULL) { | ||
276 | /* try jpeg */ | ||
277 | strp = strrchr(name, '.'); | ||
278 | if(strp) { | ||
279 | strcpy(strp, ".jpg"); | ||
280 | image = g3d_texture_load_cached(context, model, name); | ||
281 | } | ||
282 | } | ||
283 | } | ||
284 | |||
285 | if(image == NULL) { | ||
286 | mitem = model->materials; | ||
287 | while(mitem) { | ||
288 | mat = (G3DMaterial *)mitem->data; | ||
289 | if(strcmp(mat->name, object->name) == 0) { | ||
290 | image = mat->tex_image; | ||
291 | break; | ||
292 | } | ||
293 | mitem = mitem->next; | ||
294 | } | ||
295 | } | ||
296 | |||
297 | /* read vertex data */ | ||
298 | g3d_stream_seek(stream, off_start + off_vertex, G_SEEK_SET); | ||
299 | object->vertex_count = nvertex; | ||
300 | object->vertex_data = g_new0(G3DFloat, nvertex * 3); | ||
301 | normals = g_new0(G3DFloat, nvertex * 3); | ||
302 | for(i = 0; i < nvertex; i ++) { | ||
303 | gint16 d; | ||
304 | |||
305 | d = g3d_stream_read_int16_le(stream); | ||
306 | object->vertex_data[i * 3 + 0] = d; | ||
307 | d = g3d_stream_read_int16_le(stream); | ||
308 | object->vertex_data[i * 3 + 1] = d; | ||
309 | d = g3d_stream_read_int16_le(stream); | ||
310 | object->vertex_data[i * 3 + 2] = d; | ||
311 | |||
312 | /* compressed normal */ | ||
313 | /* FIXME: the normals don't look right... */ | ||
314 | r = g3d_stream_read_int8(stream); /* rho */ | ||
315 | s = g3d_stream_read_int8(stream); /* sigma */ | ||
316 | rho = r * 2 * M_PI / 256.0; | ||
317 | sigma = s * 2 * M_PI / 256.0; | ||
318 | |||
319 | normals[i * 3 + 0] = - cos(sigma) * sin(rho); | ||
320 | normals[i * 3 + 1] = - cos(sigma) * sin(rho); | ||
321 | normals[i * 3 + 2] = - cos(rho); | ||
322 | |||
323 | g3d_vector_unify( | ||
324 | &(normals[i * 3 + 0]), | ||
325 | &(normals[i * 3 + 1]), | ||
326 | &(normals[i * 3 + 2])); | ||
327 | } | ||
328 | |||
329 | /* read texture vertex data */ | ||
330 | g3d_stream_seek(stream, off_start + off_texvec, G_SEEK_SET); | ||
331 | object->tex_vertex_data = g_new0(G3DFloat, nvertex * 2); | ||
332 | for(i = 0; i < nvertex; i ++) { | ||
333 | object->tex_vertex_data[i * 2 + 0] = g3d_stream_read_float_le(stream); | ||
334 | object->tex_vertex_data[i * 2 + 1] = g3d_stream_read_float_le(stream); | ||
335 | } | ||
336 | |||
337 | /* read triangles */ | ||
338 | g3d_stream_seek(stream, off_start + off_tris, G_SEEK_SET); | ||
339 | for(i = 0; i < ntris; i ++) | ||
340 | { | ||
341 | face = g_new0(G3DFace, 1); | ||
342 | face->vertex_count = 3; | ||
343 | face->vertex_indices = g_new0(guint32, 3); | ||
344 | face->material = material; | ||
345 | |||
346 | face->flags |= G3D_FLAG_FAC_NORMALS; | ||
347 | face->normals = g_new0(G3DFloat, 3 * 3); | ||
348 | |||
349 | face->tex_image = image; | ||
350 | if(face->tex_image) | ||
351 | { | ||
352 | face->tex_vertex_data = g_new0(G3DFloat, 3 * 2); | ||
353 | face->flags |= G3D_FLAG_FAC_TEXMAP; | ||
354 | } | ||
355 | |||
356 | for(j = 0; j < 3; j ++) | ||
357 | { | ||
358 | face->vertex_indices[j] = g3d_stream_read_int32_le(stream); | ||
359 | |||
360 | /* copy normals */ | ||
361 | face->normals[j * 3 + 0] = | ||
362 | normals[face->vertex_indices[j] * 3 + 0]; | ||
363 | face->normals[j * 3 + 1] = | ||
364 | normals[face->vertex_indices[j] * 3 + 1]; | ||
365 | face->normals[j * 3 + 2] = | ||
366 | normals[face->vertex_indices[j] * 3 + 2]; | ||
367 | |||
368 | /* texture stuff */ | ||
369 | if(face->tex_image) | ||
370 | { | ||
371 | face->tex_vertex_data[j * 2 + 0] = | ||
372 | object->tex_vertex_data[face->vertex_indices[j] * 2 + 0]; | ||
373 | face->tex_vertex_data[j * 2 + 1] = | ||
374 | object->tex_vertex_data[face->vertex_indices[j] * 2 + 1]; | ||
375 | } | ||
376 | } | ||
377 | |||
378 | object->faces = g_slist_append(object->faces, face); | ||
379 | } | ||
380 | |||
381 | /* free unused data */ | ||
382 | if(object->tex_vertex_data) | ||
383 | { | ||
384 | g_free(object->tex_vertex_data); | ||
385 | object->tex_vertex_data = NULL; | ||
386 | } | ||
387 | if(normals) | ||
388 | g_free(normals); | ||
389 | |||
390 | model->objects = g_slist_append(model->objects, object); | ||
391 | |||
392 | g3d_stream_seek(stream, off_start + mlength, G_SEEK_SET); | ||
393 | |||
394 | return TRUE; | ||
395 | } | ||
396 | |||