#include #include #include #include #include int iob_read_directory(FILE *f, guint32 nbytes, G3DModel *model, void *pobject, guint32 parentid, int level); int plugin_load(const char *filename, G3DModel *model) { guint32 id, len; FILE *f; f = g3d_iff_open(filename, &id, &len); if(id != G3D_IFF_MKID('T','D','D','D')) { g_warning("file is not an .iob (TDDD) file %s", filename); fclose(f); return EXIT_FAILURE; } iob_read_directory(f, len, model, NULL, id, 1); return EXIT_SUCCESS; } char *plugin_description(void) { return g_strdup( "import plugin for Impulse Turbo Silver / Imagine objects\n"); } char **plugin_extensions(void) { return g_strsplit("iob", ":", 0); } /*****************************************************************************/ /* IOB specific */ /*****************************************************************************/ int iob_read_pnts(FILE *f, int nbytes, G3DObject* object, int type); int *iob_read_edges(FILE *f, int nbytes, G3DObject* object, int type); int iob_read_mat_lists(FILE *f, int nbytes, G3DObject* object, int type); int iob_read_faces(FILE *f, int nbytes, G3DObject* object, int *edges, int type); GLfloat iob_read_fract(FILE *f); int iob_read_directory(FILE *f, guint32 nbytes, G3DModel *model, void *pobject, guint32 parentid, int level) { guint32 id, len; gint32 toread = nbytes; #if DEBUG > 0 int i; #endif int *iob_edges = NULL; guint32 typeShape, typeLamp; gdouble offx, offy, offz; G3DObject *iob_object = NULL; G3DMaterial *material; while(toread > 0) { toread -= g3d_iff_readchunk(f, &id, &len); #if DEBUG > 0 for(i=0; i> 24) & 0xFF, (id >> 16) & 0xFF, (id >> 8) & 0xFF, id & 0xFF, len); #endif switch(id) { case G3D_IFF_MKID('A','X','I','S'): /* direction vectors for coordinate system */ /* x */ iob_read_fract(f); iob_read_fract(f); iob_read_fract(f); /* y */ iob_read_fract(f); iob_read_fract(f); iob_read_fract(f); /* z */ iob_read_fract(f); iob_read_fract(f); iob_read_fract(f); break; case G3D_IFF_MKID('O','B','J',' '): iob_read_directory(f, len, model, NULL, id, level+1); break; case G3D_IFF_MKID('D','E','S','C'): iob_object = g_new0(G3DObject, 1); model->objects = g_slist_append(model->objects, iob_object); material = g3d_new_G3DMaterial(); material->flags |= G3D_FLAG_MAT_TWOSIDE; iob_object->materials = g_slist_append(iob_object->materials, material); material->name = g_strdup("material"); iob_read_directory(f, len, model, iob_object, id, level+1); break; case G3D_IFF_MKID('N','A','M','E'): ((G3DObject*)pobject)->name = g_malloc0(19); fread(((G3DObject*)pobject)->name, 1, len, f); break; case G3D_IFF_MKID('S','H','P','2'): typeShape = g3d_read_int16_be(f); typeLamp = g3d_read_int16_be(f); #if DEBUG > 3 g_printerr("shapes: shape: 0x%4.4X lamp 0x%4.4X\n", typeShape, typeLamp); #endif break; case G3D_IFF_MKID('P','O','S','I'): offx = (gdouble)g3d_read_int32_be(f) / 0xFFFF; offy = (gdouble)g3d_read_int32_be(f) / 0xFFFF; offz = (gdouble)g3d_read_int32_be(f) / 0xFFFF; break; case G3D_IFF_MKID('P','N','T','S'): case G3D_IFF_MKID('P','N','T','2'): iob_read_pnts(f,len,(G3DObject*)pobject, id); break; case G3D_IFF_MKID('E','D','G','E'): case G3D_IFF_MKID('E','D','G','2'): iob_edges = iob_read_edges(f, len, (G3DObject*)pobject, id); break; case G3D_IFF_MKID('F','A','C','E'): case G3D_IFF_MKID('F','A','C','2'): iob_read_faces(f, len, (G3DObject*)pobject, iob_edges, id); break; #if 0 /* too slow and maybe buggy for now */ case G3D_IFF_MKID('C','L','S','T'): case G3D_IFF_MKID('R','L','S','T'): case G3D_IFF_MKID('T','L','S','T'): case G3D_IFF_MKID('C','L','S','2'): case G3D_IFF_MKID('R','L','S','2'): case G3D_IFF_MKID('T','L','S','2'): iob_read_mat_lists(f, len, (G3DObject*)pobject, id); break; #endif case G3D_IFF_MKID('C','O','L','R'): material = g_slist_nth_data(((G3DObject*)pobject)->materials, 0); g3d_read_int8(f); material->r = (float)g3d_read_int8(f) / 255.0; material->g = (float)g3d_read_int8(f) / 255.0; material->b = (float)g3d_read_int8(f) / 255.0; #if DEBUG > 3 g_printerr("rgb: %f,%f,%f\n", material->r, material->g, material->b); #endif break; case G3D_IFF_MKID('R','E','F','L'): { int r,g,b; material = g_slist_nth_data(((G3DObject*)pobject)->materials, 0); g3d_read_int8(f); r = g3d_read_int8(f); g = g3d_read_int8(f); b = g3d_read_int8(f); material->specular[0] = (float)r / 255.0; material->specular[1] = (float)g / 255.0; material->specular[2] = (float)b / 255.0; } break; case G3D_IFF_MKID('T','O','B','J'): /* end of child objects */ break; case G3D_IFF_MKID('T','R','A','N'): { int r,g,b; material = g_slist_nth_data(((G3DObject*)pobject)->materials, 0); g3d_read_int8(f); r = g3d_read_int8(f); g = g3d_read_int8(f); b = g3d_read_int8(f); #if DEBUG > 3 g_printerr("rgb: %d,%d,%d\n", r, g, b); #endif material->a = 1.0 - ((float)r / 255.0); } break; default: #if DEBUG > 0 g_printerr("*** unhandled ***\n"); #endif fseek(f, len+(len%2), SEEK_CUR); } g3d_interface_update(); } if(iob_edges != NULL) g_free(iob_edges); return EXIT_SUCCESS; } GLfloat iob_read_fract(FILE *f) { gint32 i = g3d_read_int32_be(f); return (GLfloat)(i / 0xFFFF); } int iob_read_pnts(FILE *f, int nbytes, G3DObject* object, int type) { int i, toread = nbytes; g_return_val_if_fail(object != NULL, EXIT_FAILURE); if(type == G3D_IFF_MKID('P','N','T','S')) { object->vertex_count = g3d_read_int16_be(f); toread -= 2; } else { object->vertex_count = g3d_read_int32_be(f); toread -= 4; } object->vertices = g_malloc0(object->vertex_count * 3 * sizeof(GLfloat)); #if DEBUG > 3 g_printerr("iob_read_pnts: malloc'ed object->vertices (%d vertices)\n", object->vertex_count); #endif for(i=0; ivertex_count; i++) { object->vertices[i*3+0] = iob_read_fract(f); object->vertices[i*3+1] = iob_read_fract(f); object->vertices[i*3+2] = iob_read_fract(f); toread -= 12; #if DEBUG > 3 g_printerr("iob_read_pnts: reading vertex #%d (%le|%le|%le)\n", i+1, object->vertices[i*3+0], object->vertices[i*3+1], object->vertices[i*3+2]); #endif } if(toread != 0) { g_printerr("error in PNTS chunk (%d bytes to read)\n", toread); fseek(f, toread, SEEK_CUR); return EXIT_FAILURE; } return EXIT_SUCCESS; } int *iob_read_edges(FILE *f, int nbytes, G3DObject* object, int type) { int i, nedges; int toread = nbytes; int *edges = NULL; if(type == G3D_IFF_MKID('E','D','G','E')) { nedges = g3d_read_int16_be(f); toread -= 2; } else { nedges = g3d_read_int32_be(f); toread -= 4; } #if DEBUG > 3 g_printerr("iob_read_edges: %d edges\n", nedges); #endif edges = g_malloc(nedges * 2 * sizeof(int)); for(i=0; i 0 g_print("IOB: xLST / xLS2: %d items\n", nitems); #endif for(i = 0; i < nitems; i ++) { /* default material + nth */ material = g_slist_nth_data(object->materials, i + 1); if(material == NULL) { material = g3d_new_G3DMaterial(); material->name = g_strdup_printf("per face material #%d", i); object->materials = g_slist_append(object->materials, material); /* assign to face */ face = g_slist_nth_data(object->faces, i); if(face) { face->material = material; } } switch(type) { case G3D_IFF_MKID('C', 'L', 'S', 'T'): case G3D_IFF_MKID('C', 'L', 'S', '2'): material->r = (GLfloat)(g3d_read_int8(f) / 255.0); material->g = (GLfloat)(g3d_read_int8(f) / 255.0); material->b = (GLfloat)(g3d_read_int8(f) / 255.0); break; case G3D_IFF_MKID('R', 'L', 'S', 'T'): case G3D_IFF_MKID('R', 'L', 'S', '2'): material->specular[0] = (GLfloat)(g3d_read_int8(f) / 255.0); material->specular[1] = (GLfloat)(g3d_read_int8(f) / 255.0); material->specular[2] = (GLfloat)(g3d_read_int8(f) / 255.0); break; case G3D_IFF_MKID('T', 'L', 'S', 'T'): case G3D_IFF_MKID('T', 'L', 'S', '2'): material->a = 1.0 - ( (GLfloat)(g3d_read_int8(f) / 255.0) + (GLfloat)(g3d_read_int8(f) / 255.0) + (GLfloat)(g3d_read_int8(f) / 255.0)) / 3.0; break; } } /* padding */ if(nitems % 2) g3d_read_int8(f); return EXIT_SUCCESS; } void iob_order_array(int *array, int numelems) { int elem = 0; while(elem < numelems) { int i; for(i=elem+1; i array[i]) { int bottle = array[elem]; array[elem] = array[i]; array[i] = bottle; } } elem++; } } int iob_read_faces(FILE *f, int nbytes, G3DObject* object, int *edges, int type) { int i, nfaces; int toread = nbytes; int v1, v2, v3; int e[3]; if(type == G3D_IFF_MKID('F','A','C','E')) { nfaces = g3d_read_int16_be(f); toread -= 2; } else { nfaces = g3d_read_int32_be(f); toread -= 4; } for(i=0; inum_vertices = 3; face->index_vertex = g_malloc0(3 * sizeof(int)); if(type == G3D_IFF_MKID('F','A','C','E')) { e[0] = g3d_read_int16_be(f); e[1] = g3d_read_int16_be(f); e[2] = g3d_read_int16_be(f); toread -= 6; } else { e[0] = g3d_read_int32_be(f); e[1] = g3d_read_int32_be(f); e[2] = g3d_read_int32_be(f); toread -= 12; } #if DEBUG > 3 g_printerr("iob_read_faces: #%d (%d|%d)-(%d|%d)-(%d|%d)\n", i, edges[e[0]*2], edges[e[0]*2+1], edges[e[1]*2], edges[e[1]*2+1], edges[e[2]*2], edges[e[2]*2+1]); #endif #if 0 /* all mats twoside */ iob_order_array(e, 3); #endif face->index_vertex[0] = v1 = edges[e[0]*2+0]; face->index_vertex[1] = v2 = edges[e[0]*2+1]; if((v1!=edges[e[1]*2+0]) && (v2!=edges[e[1]*2+0])) v3=edges[e[1]*2+0]; else if((v1!=edges[e[1]*2+1]) && (v2!=edges[e[1]*2+1])) v3=edges[e[1]*2+1]; else if((v1!=edges[e[2]*2+0]) && (v2!=edges[e[2]*2+0])) v3=edges[e[2]*2+0]; else v3 = edges[e[2]*2+1]; face->index_vertex[2] = v3; face->material = g_slist_nth_data(object->materials, 0); object->faces = g_slist_prepend(object->faces, face); #if DEBUG > 3 g_printerr("iob_read_faces: face: #%d (%d/%d/%d)\n", i+1, face->index_vertex[0], face->index_vertex[1], face->index_vertex[2]); #endif } if(toread != 0) { g_printerr("error in FACE chunk (%d bytes to read)\n", toread); fseek(f, toread, SEEK_CUR); return EXIT_FAILURE; } return EXIT_SUCCESS; }