aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/mimesh/libg3d-0.0.8/src/model.c
diff options
context:
space:
mode:
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.c406
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
32EAPI
33G3DModel *g3d_model_new(void)
34{
35 G3DModel *model;
36
37 model = g_new0(G3DModel, 1);
38
39 return model;
40}
41
42static 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
66static 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
88static 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
134EAPI
135gboolean g3d_model_check(G3DModel *model)
136{
137 return objects_check(model->objects);
138}
139
140EAPI
141G3DModel *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
203EAPI
204G3DModel *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
210static 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
246static 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
270EAPI
271gboolean 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
291static 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
307static 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
324EAPI
325void 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
355EAPI
356void 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
369static 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
391EAPI
392G3DObject *g3d_model_get_object_by_name(G3DModel *model, const gchar *name)
393{
394 return objects_get_by_name(model->objects, name);
395}
396
397EAPI
398gboolean 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