4
libg3d - 3D object loading library
6
Copyright (C) 2005-2009 Markus Dahms <mad@automagically.de>
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.
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.
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
29
#include <g3d/context.h>
30
#include <g3d/types.h>
31
#include <g3d/material.h>
33
#include <g3d/stream.h>
35
#define OBJ_USE_GROUPING 0
43
static gboolean obj_tryloadmat(G3DModel *model, const gchar *filename);
44
static G3DMaterial *obj_usemat(G3DModel *model, const gchar *matname);
46
static G3DObject *obj_object_by_name(G3DModel *model, const gchar *name);
48
static G3DObject *obj_get_offset(GSList *group_list, guint32 *voffp,
49
guint32 index, G3DObject *defobj);
52
gboolean plugin_load_model_from_stream(G3DContext *context, G3DStream *stream,
53
G3DModel *model, gpointer user_data)
55
gchar line[2048], matname[128], matfile[1024];
57
G3DObject *object = NULL;
58
G3DMaterial *material = NULL;
59
gfloat pcnt, prev_pcnt = 0.0;
61
guint32 num_v, v_off = 1, v_cnt = 0;
64
ObjGroupOffset *grpoff;
65
GSList *group_list = NULL;
67
goffset global_vertex_count = 0;
69
setlocale(LC_NUMERIC, "C");
70
filename = g3d_stream_get_uri(stream);
72
strncpy(matfile, filename, strlen(filename) - 3);
73
matfile[strlen(filename)-3] = '\0';
74
strcat(matfile, "mtl");
75
obj_tryloadmat(model, matfile);
77
object = obj_object_by_name(model, "(default)");
79
while(!g3d_stream_eof(stream))
81
memset(line, 0, 2048);
82
g3d_stream_read_line(stream, line, 2048);
83
/* remove leading and trailing whitespace characters */
85
if(strlen(line) > 0) {
94
strcpy(oname, "(default)");
96
sscanf(line, "g %s", oname);
98
material = obj_usemat(model, oname);
100
grpoff = g_new0(ObjGroupOffset, 1);
101
grpoff->object = obj_object_by_name(model, oname);
102
grpoff->goff = global_vertex_count;
103
grpoff->ooff = grpoff->object->vertex_count;
104
group_list = g_slist_append(group_list, grpoff);
106
g_debug("[g] 0x%08x / 0x%08x: \"%s\"",
107
(guint32)grpoff->goff,
108
(guint32)grpoff->ooff, grpoff->object->name);
110
object = grpoff->object;
111
v_cnt = grpoff->ooff;
118
case 'o': /* object */
121
case 'v': /* vertex */
122
if(strncmp(line, "vn ", 3) == 0)
126
else if(strncmp(line, "vt ", 3) == 0)
130
else if(sscanf(line, "v %lf %lf %lf", &x, &y, &z) == 3)
132
object->vertex_count ++;
133
object->vertex_data = g_realloc(object->vertex_data,
134
object->vertex_count * 3 * sizeof(gfloat));
135
object->vertex_data[v_cnt * 3 + 0] = x;
136
object->vertex_data[v_cnt * 3 + 1] = y;
137
object->vertex_data[v_cnt * 3 + 2] = z;
140
global_vertex_count ++;
142
else g_warning("parse error in line: %s", line);
146
if(strncmp("f ", line, 2) == 0)
149
gchar **vertex, **vstrs = g_strsplit(line, " ", 0);
153
face = g_new0(G3DFace, 1);
155
face->material = material;
156
else face->material =
157
g_slist_nth_data(object->materials, 0);
159
/* find number of vertices in line */
161
while(*vertex != NULL) { num_v++; vertex++; }
162
face->vertex_count = num_v - 1;
164
/* next one if # of vertices < 3 */
165
if(face->vertex_count < 3) {
170
/* calculate object-local vertex offset, indices
171
* in .obj files are absolute */
172
i = strtol(vstrs[1], NULL, 10);
174
object = obj_get_offset(group_list, &v_off,
175
(i < 0) ? global_vertex_count - i - 1 : i,
181
g_warning("error: face before object");
187
face->vertex_indices = g_new0(guint32, num_v - 1);
188
for(i = 1; i < num_v; i ++) {
189
gint32 index = strtol(vstrs[i], NULL, 10);
192
face->vertex_indices[i - 1] =
193
global_vertex_count + index + v_off - 1;
195
face->vertex_indices[i - 1] = MIN(
197
object->vertex_count - 1);
200
object->faces = g_slist_prepend(object->faces, face);
203
g_warning("parse error in line: %s", line);
206
case 'u': /* usemat? */
209
if(sscanf(line, "usemtl %s", matname) == 1) {
210
material = obj_usemat(model, matname);
211
} else if(sscanf(line, "mtllib %s", matfile) == 1) {
212
/* loads external material library */
213
if(obj_tryloadmat(model, matfile) != TRUE)
214
g_warning("error loading material library '%s'",
220
g_debug("unknown type of line: %s", line);
227
pcnt = (gfloat)g3d_stream_tell(stream) /
228
(gfloat)g3d_stream_size(stream);
229
if((pcnt - prev_pcnt) > 0.01) {
231
g3d_context_update_progress_bar(context, pcnt, TRUE);
234
g3d_context_update_interface(context);
239
gchar *plugin_description(void)
242
"Import plugin for Maya .obj files\n");
245
gchar **plugin_extensions(void)
247
return g_strsplit("obj", ":", 0);
250
/*****************************************************************************/
252
/*****************************************************************************/
253
/* material file ops */
254
/*****************************************************************************/
256
int obj_tryloadmat(G3DModel *model, const char *filename)
259
G3DMaterial *material = NULL;
261
f = fopen(filename, "r");
264
g_warning("obj_tryloadmat: loading '%s' failed: %s", filename,
270
g_debug("loading material library %s", filename);
274
float r,g,b, t1,t2, ni;
277
fgets(line, 2048, f);
283
if(line[0] == '#') continue; /* comments */
284
if(line[0] == '\n') continue; /* empty lines */
286
if(sscanf(line, "newmtl %s", mname) == 1)
289
material = g3d_material_new();
290
material->name = g_strdup(mname);
291
model->materials = g_slist_append(model->materials, material);
293
else if(sscanf(line, " Kd %f %f %f", &r, &g, &b) == 3)
295
/* material color? */
303
else if(sscanf(line, " Ks %f %f %f", &r, &g, &b) == 3)
307
else if(sscanf(line, " Tf %f %f %d", &t1, &t2, &tf) == 3)
309
/* transparency ?? */
312
if(tf == 1) material->a = 1.0 - t1;
315
else if(sscanf(line, " Ns %d Ni %f", &ns, &ni) == 2)
319
else if(sscanf(line, " illum %d", &il) == 1)
325
g_warning("unknown type of line: %s", line);
333
G3DMaterial *obj_usemat(G3DModel *model, const gchar *matname)
335
/* sets new active material from named list */
336
GSList *mlist = model->materials;
339
G3DMaterial *mat = (G3DMaterial*)mlist->data;
340
if(strcmp(matname, mat->name) == 0)
350
static G3DObject *obj_object_by_name(G3DModel *model, const gchar *name)
353
G3DMaterial *material;
357
g_debug("looking for object '%s'", name);
360
for(oitem = model->objects; oitem != NULL; oitem = oitem->next) {
361
object = oitem->data;
362
if(strcmp(object->name, name) == 0)
366
material = g3d_material_new();
367
material->name = g_strdup("(default material)");
369
object = g_new0(G3DObject, 1);
370
object->name = g_strdup(name);
371
object->materials = g_slist_append(object->materials, material);
372
model->objects = g_slist_append(model->objects, object);
378
static G3DObject *obj_get_offset(GSList *group_list, guint32 *voffp,
379
guint32 index, G3DObject *defobj)
381
GSList *leitem, *gitem;
382
ObjGroupOffset *grpoff;
384
for(leitem = gitem = group_list; gitem != NULL; gitem = gitem->next) {
385
grpoff = gitem->data;
387
/* this one is too big */
388
if(grpoff->goff > index) {
389
grpoff = leitem->data;
390
*voffp = grpoff->ooff - grpoff->goff;
392
g_debug("[o]: i=%-6d, go=%-6d, oo=%-6d, vo=%-6d (%s, %d vtxs)",
393
index, (guint32)grpoff->goff, (guint32)grpoff->ooff, *voffp,
394
grpoff->object->name, grpoff->object->vertex_count);
396
return grpoff->object;