diff options
Diffstat (limited to 'src/others/mimesh/libg3d-0.0.8/src/model.c')
-rw-r--r-- | src/others/mimesh/libg3d-0.0.8/src/model.c | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/src/others/mimesh/libg3d-0.0.8/src/model.c b/src/others/mimesh/libg3d-0.0.8/src/model.c new file mode 100644 index 0000000..39cdc79 --- /dev/null +++ b/src/others/mimesh/libg3d-0.0.8/src/model.c | |||
@@ -0,0 +1,406 @@ | |||
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/model.h> | ||
28 | #include <g3d/object.h> | ||
29 | #include <g3d/material.h> | ||
30 | #include <g3d/plugins.h> | ||
31 | |||
32 | EAPI | ||
33 | G3DModel *g3d_model_new(void) | ||
34 | { | ||
35 | G3DModel *model; | ||
36 | |||
37 | model = g_new0(G3DModel, 1); | ||
38 | |||
39 | return model; | ||
40 | } | ||
41 | |||
42 | static gdouble objects_max_radius(GSList *objects) | ||
43 | { | ||
44 | G3DObject *object; | ||
45 | GSList *oitem; | ||
46 | gdouble radius, max_rad = 0.0; | ||
47 | |||
48 | oitem = objects; | ||
49 | while(oitem) | ||
50 | { | ||
51 | object = (G3DObject *)oitem->data; | ||
52 | radius = g3d_object_radius(object); | ||
53 | if(radius > max_rad) | ||
54 | max_rad = radius; | ||
55 | |||
56 | radius = objects_max_radius(object->objects); | ||
57 | if(radius > max_rad) | ||
58 | max_rad = radius; | ||
59 | |||
60 | oitem = oitem->next; | ||
61 | } | ||
62 | |||
63 | return max_rad; | ||
64 | } | ||
65 | |||
66 | static void objects_post_load(GSList *objects, gdouble max_rad, guint32 flags) | ||
67 | { | ||
68 | G3DObject *object; | ||
69 | GSList *oitem; | ||
70 | |||
71 | oitem = objects; | ||
72 | while(oitem) | ||
73 | { | ||
74 | object = (G3DObject *)oitem->data; | ||
75 | |||
76 | if(flags & G3D_MODEL_SCALE) | ||
77 | g3d_object_scale(object, (0.5 / max_rad)); /* For non real meshes, 1.0 works about right. Trying 0.5 for real meshes. */ | ||
78 | |||
79 | if(flags & G3D_MODEL_OPTIMIZE) | ||
80 | g3d_object_optimize(object); | ||
81 | |||
82 | objects_post_load(object->objects, max_rad, flags); | ||
83 | |||
84 | oitem = oitem->next; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | static gboolean objects_check(GSList *objects) | ||
89 | { | ||
90 | G3DFace *face; | ||
91 | G3DObject *object; | ||
92 | GSList *fitem, *oitem; | ||
93 | guint32 i, no = 0, nf; | ||
94 | |||
95 | for(oitem = objects; oitem != NULL; oitem = oitem->next) { | ||
96 | object = (G3DObject *)oitem->data; | ||
97 | |||
98 | for(nf = 0, fitem = object->faces; fitem != NULL; | ||
99 | fitem = fitem->next, nf ++) { | ||
100 | face = (G3DFace *)fitem->data; | ||
101 | |||
102 | if(face->material == NULL) { | ||
103 | g_warning("g3d_object_check: face->material is NULL" | ||
104 | " (o: %d, %s; f: %d)", | ||
105 | no, object->name ? object->name : "(unnamed)", nf); | ||
106 | return FALSE; | ||
107 | } | ||
108 | |||
109 | if(face->vertex_count < 3) { | ||
110 | g_warning("g3d_object_check: face->num_vertices < 3 (%d)" | ||
111 | " (o: %d, %s; f: %d)", face->vertex_count, | ||
112 | no, object->name ? object->name : "(unnamed)", nf); | ||
113 | return FALSE; | ||
114 | } | ||
115 | |||
116 | for(i = 0; i < face->vertex_count; i ++) | ||
117 | if(face->vertex_indices[i] >= object->vertex_count) { | ||
118 | g_warning("g3d_object_check: " | ||
119 | "vertex_indices[%d] >= vertex_count (%d >= %d)" | ||
120 | " (o: %d, %s; f: %d)", | ||
121 | i, face->vertex_indices[i], object->vertex_count, | ||
122 | no, object->name ? object->name : "(unnamed)", nf); | ||
123 | return FALSE; | ||
124 | } | ||
125 | } /* (fitem) */ | ||
126 | |||
127 | if(objects_check(object->objects) == FALSE) | ||
128 | return FALSE; | ||
129 | } /* (oitem) */ | ||
130 | return TRUE; | ||
131 | |||
132 | } | ||
133 | |||
134 | EAPI | ||
135 | gboolean g3d_model_check(G3DModel *model) | ||
136 | { | ||
137 | return objects_check(model->objects); | ||
138 | } | ||
139 | |||
140 | EAPI | ||
141 | G3DModel *g3d_model_load_full(G3DContext *context, const gchar *filename, | ||
142 | guint32 flags) | ||
143 | { | ||
144 | G3DModel *model; | ||
145 | gdouble max_rad; | ||
146 | |||
147 | /* create hash table if it does not exist yet */ | ||
148 | if(context->modelCache == NULL) | ||
149 | context->modelCache = g_hash_table_new(g_str_hash, g_str_equal); | ||
150 | |||
151 | /* if already loaded, return cached model */ | ||
152 | model = g_hash_table_lookup(context->modelCache, filename); | ||
153 | if(model != NULL) | ||
154 | { | ||
155 | model->refCount++; | ||
156 | return model; | ||
157 | } | ||
158 | |||
159 | model = g3d_model_new(); | ||
160 | |||
161 | g3d_context_update_progress_bar(context, 0.0, TRUE); | ||
162 | |||
163 | if(g3d_plugins_load_model(context, filename, model)) | ||
164 | { | ||
165 | model->refCount = 1; | ||
166 | model->context = context; | ||
167 | /* save filename */ | ||
168 | if(model->filename == NULL) | ||
169 | model->filename = g_strdup(filename); | ||
170 | g_hash_table_insert(context->modelCache, (gpointer) model->filename, model); | ||
171 | g3d_context_update_progress_bar(context, 0.0, FALSE); | ||
172 | |||
173 | /* check model */ | ||
174 | if(!(flags & G3D_MODEL_NOCHECK)) | ||
175 | if(!g3d_model_check(model)) | ||
176 | { | ||
177 | g3d_model_free(model); | ||
178 | return NULL; | ||
179 | } | ||
180 | |||
181 | /* center model */ | ||
182 | if(flags & G3D_MODEL_CENTER) | ||
183 | g3d_model_center(model); | ||
184 | |||
185 | /* get maximum radius of all objects */ | ||
186 | max_rad = objects_max_radius(model->objects); | ||
187 | |||
188 | /* scale and optimize objects */ | ||
189 | objects_post_load(model->objects, max_rad, flags); | ||
190 | |||
191 | return model; | ||
192 | } | ||
193 | else | ||
194 | { | ||
195 | g3d_context_update_progress_bar(context, 0.0, FALSE); | ||
196 | g3d_model_free(model); | ||
197 | } | ||
198 | |||
199 | return NULL; | ||
200 | |||
201 | } | ||
202 | |||
203 | EAPI | ||
204 | G3DModel *g3d_model_load(G3DContext *context, const gchar *filename) | ||
205 | { | ||
206 | return g3d_model_load_full(context, filename, | ||
207 | G3D_MODEL_SCALE | G3D_MODEL_CENTER | G3D_MODEL_OPTIMIZE); | ||
208 | } | ||
209 | |||
210 | static void objects_max_extension(GSList *objects, | ||
211 | gdouble *min_x, gdouble *min_y, gdouble *min_z, | ||
212 | gdouble *max_x, gdouble *max_y, gdouble *max_z) | ||
213 | { | ||
214 | GSList *oitem; | ||
215 | G3DObject *object; | ||
216 | guint32 i; | ||
217 | |||
218 | oitem = objects; | ||
219 | while(oitem) | ||
220 | { | ||
221 | object = (G3DObject *)oitem->data; | ||
222 | for(i = 0; i < object->vertex_count; i ++) | ||
223 | { | ||
224 | if(object->vertex_data[i * 3 + 0] < *min_x) | ||
225 | *min_x = object->vertex_data[i * 3 + 0]; | ||
226 | if(object->vertex_data[i * 3 + 1] < *min_y) | ||
227 | *min_y = object->vertex_data[i * 3 + 1]; | ||
228 | if(object->vertex_data[i * 3 + 2] < *min_z) | ||
229 | *min_z = object->vertex_data[i * 3 + 2]; | ||
230 | |||
231 | if(object->vertex_data[i * 3 + 0] > *max_x) | ||
232 | *max_x = object->vertex_data[i * 3 + 0]; | ||
233 | if(object->vertex_data[i * 3 + 1] > *max_y) | ||
234 | *max_y = object->vertex_data[i * 3 + 1]; | ||
235 | if(object->vertex_data[i * 3 + 2] > *max_z) | ||
236 | *max_z = object->vertex_data[i * 3 + 2]; | ||
237 | } | ||
238 | |||
239 | objects_max_extension(object->objects, | ||
240 | min_x, min_y, min_z, max_x, max_y, max_z); | ||
241 | |||
242 | oitem = oitem->next; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | static void objects_move(GSList *objects, | ||
247 | gdouble off_x, gdouble off_y, gdouble off_z) | ||
248 | { | ||
249 | GSList *oitem; | ||
250 | G3DObject *object; | ||
251 | guint32 i; | ||
252 | |||
253 | oitem = objects; | ||
254 | while(oitem) | ||
255 | { | ||
256 | object = (G3DObject *)oitem->data; | ||
257 | for(i = 0; i < object->vertex_count; i ++) | ||
258 | { | ||
259 | object->vertex_data[i * 3 + 0] -= off_x; | ||
260 | object->vertex_data[i * 3 + 1] -= off_y; | ||
261 | object->vertex_data[i * 3 + 2] -= off_z; | ||
262 | } | ||
263 | |||
264 | objects_move(object->objects, off_x, off_y, off_z); | ||
265 | |||
266 | oitem = oitem->next; | ||
267 | } | ||
268 | } | ||
269 | |||
270 | EAPI | ||
271 | gboolean g3d_model_center(G3DModel *model) | ||
272 | { | ||
273 | gdouble min_x = 10.0e99, min_y = 10.0e99, min_z = 10.0e99; | ||
274 | gdouble max_x = -9.9e99, max_y = -9.9e99, max_z = -9.9e99; | ||
275 | gdouble off_x, off_y, off_z; | ||
276 | |||
277 | /* determine maximum extension */ | ||
278 | objects_max_extension(model->objects, | ||
279 | &min_x, &min_y, &min_z, &max_x, &max_y, &max_z); | ||
280 | |||
281 | /* move model */ | ||
282 | off_x = max_x - ((max_x - min_x) / 2.0); | ||
283 | off_y = max_y - ((max_y - min_y) / 2.0); | ||
284 | off_z = max_z - ((max_z - min_z) / 2.0); | ||
285 | |||
286 | objects_move(model->objects, off_x, off_y, off_z); | ||
287 | |||
288 | return TRUE; | ||
289 | } | ||
290 | |||
291 | static gboolean remove_teximg(gpointer key, gpointer value, gpointer data) | ||
292 | { | ||
293 | G3DImage *image; | ||
294 | |||
295 | image = (G3DImage *)value; | ||
296 | if(image->name) | ||
297 | g_free(image->name); | ||
298 | if(image->pixeldata) | ||
299 | g_free(image->pixeldata); | ||
300 | g_free(image); | ||
301 | |||
302 | g_free(key); | ||
303 | |||
304 | return TRUE; | ||
305 | } | ||
306 | |||
307 | static void objects_clear(GSList *objects) | ||
308 | { | ||
309 | GSList *list, *next; | ||
310 | G3DObject *object; | ||
311 | |||
312 | list = objects; | ||
313 | while(list) | ||
314 | { | ||
315 | object = (G3DObject*)list->data; | ||
316 | objects_clear(object->objects); | ||
317 | g3d_object_free(object); | ||
318 | next = list->next; | ||
319 | g_slist_free_1(list); | ||
320 | list = next; | ||
321 | } | ||
322 | } | ||
323 | |||
324 | EAPI | ||
325 | void g3d_model_clear(G3DModel *model) | ||
326 | { | ||
327 | GSList *list, *next; | ||
328 | G3DMaterial *mat; | ||
329 | |||
330 | /* lights */ | ||
331 | /* TODO */ | ||
332 | |||
333 | /* objects */ | ||
334 | objects_clear(model->objects); | ||
335 | model->objects = NULL; | ||
336 | |||
337 | /* materials */ | ||
338 | list = model->materials; | ||
339 | while(list) | ||
340 | { | ||
341 | mat = (G3DMaterial*)list->data; | ||
342 | g3d_material_free(mat); | ||
343 | next = list->next; | ||
344 | g_slist_free_1(list); | ||
345 | list = next; | ||
346 | } | ||
347 | model->materials = NULL; | ||
348 | |||
349 | if(model->tex_images) | ||
350 | { | ||
351 | g_hash_table_foreach_remove(model->tex_images, remove_teximg, NULL); | ||
352 | } | ||
353 | } | ||
354 | |||
355 | EAPI | ||
356 | void g3d_model_free(G3DModel *model) | ||
357 | { | ||
358 | model->refCount--; | ||
359 | if (0 == model->refCount) | ||
360 | { | ||
361 | g_hash_table_remove(model->context->modelCache, model->filename); | ||
362 | g3d_model_clear(model); | ||
363 | if(model->filename) | ||
364 | g_free(model->filename); | ||
365 | g_free(model); | ||
366 | } | ||
367 | } | ||
368 | |||
369 | static G3DObject *objects_get_by_name(GSList *objects, const gchar *name) | ||
370 | { | ||
371 | GSList *olist; | ||
372 | G3DObject *object; | ||
373 | |||
374 | olist = objects; | ||
375 | while(olist) | ||
376 | { | ||
377 | object = (G3DObject *)olist->data; | ||
378 | |||
379 | if((object->name != NULL) && (strcmp(object->name, name) == 0)) | ||
380 | return object; | ||
381 | |||
382 | object = objects_get_by_name(object->objects, name); | ||
383 | if(object != NULL) | ||
384 | return object; | ||
385 | |||
386 | olist = olist->next; | ||
387 | } | ||
388 | return NULL; | ||
389 | } | ||
390 | |||
391 | EAPI | ||
392 | G3DObject *g3d_model_get_object_by_name(G3DModel *model, const gchar *name) | ||
393 | { | ||
394 | return objects_get_by_name(model->objects, name); | ||
395 | } | ||
396 | |||
397 | EAPI | ||
398 | gboolean g3d_model_transform(G3DModel *model, G3DMatrix *matrix) | ||
399 | { | ||
400 | GSList *oitem; | ||
401 | |||
402 | for(oitem = model->objects; oitem != NULL; oitem = oitem->next) | ||
403 | g3d_object_transform(oitem->data, matrix); | ||
404 | return TRUE; | ||
405 | } | ||
406 | |||