#ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #define AC3D_FLAG_ACC 0x01 struct ac3d_transform { GLfloat offx, offy, offz; }; static int ac3d_read_object(FILE *f, G3DModel *model, char *line, struct ac3d_transform *transform, guint32 flags); int plugin_load(const char *filename, G3DModel *model) { struct ac3d_transform *transform; FILE *f; gchar buffer[2049], namebuf[257]; guint32 version, ti1, flags = 0; G3DMaterial *material; GLfloat tf1, tf2, tf3, tf4, tf5, tf6, trans; setlocale(LC_NUMERIC, "C"); f = fopen(filename, "r"); if(f == NULL) { g_printerr("could not open file '%s'", filename); return EXIT_FAILURE; } fgets(buffer, 2048, f); if(strncmp(buffer, "AC3D", 4) != 0) { g_printerr("file '%s' is not a AC3D model", filename); fclose(f); return EXIT_FAILURE; } if(g_ascii_strcasecmp(filename + strlen(filename) - 4, ".acc") == 0) { #if DEBUG > 0 g_print("AC3D: .acc file\n"); #endif flags |= AC3D_FLAG_ACC; } version = strtoul(buffer + 4, NULL, 16); #if DEBUG > 0 g_print("AC3D: version %d\n", version); #endif while(fgets(buffer, 2048, f)) { if(strncmp(buffer, "MATERIAL", 8) == 0) { material = g3d_new_G3DMaterial(); if(sscanf(buffer, "MATERIAL %s " "rgb %f %f %f " "amb %f %f %f " "emis %f %f %f " "spec %f %f %f " "shi %d " "trans %f", namebuf, &(material->r), &(material->g), &(material->b), &tf1, &tf2, &tf3, &tf4, &tf5, &tf6, &(material->specular[0]), &(material->specular[1]), &(material->specular[2]), &ti1, &trans) != 15) { g_warning("AC3D: error reading material line (%s)", buffer); } material->name = g_strdup(namebuf); material->a = 1.0 - trans; model->materials = g_slist_append(model->materials, material); } else if(strncmp(buffer, "OBJECT", 6) == 0) { transform = g_new0(struct ac3d_transform, 1); ac3d_read_object(f, model, buffer, transform, flags); } else { #if DEBUG > 0 g_print("AC3D: unhandled line: %s\n", buffer); #endif } } fclose(f); return EXIT_SUCCESS; } char *plugin_description(void) { return g_strdup("import plugin for AC3D models\n"); } char **plugin_extensions(void) { return g_strsplit("ac:acc", ":", 0); } /* * AC3D specific */ static gchar *ac3d_remove_quotes(gchar *text) { if(text[0] == '"') { return g_strndup(text + 1, strlen(text) - 2); } else { return g_strdup(text); } } static int ac3d_read_object(FILE *f, G3DModel *model, char *line, struct ac3d_transform *parent_transform, guint32 flags) { struct ac3d_transform *transform; G3DObject *object; G3DMaterial *material = NULL; G3DFace *face; static gchar buffer[2049], namebuf[257]; guint32 nkids, ti1, i, surf_flags, surf_done; guint32 i1, i2, i3; GLfloat u1, u2, u3, v1, v2, v3; GLfloat locx = 0.0, locy = 0.0, locz = 0.0; GLfloat texrepu = 1.0, texrepv = 1.0, texoffu = 0.0, texoffv = 0.0; GLfloat texscaleu = 1.0, texscalev = 1.0; GLfloat crease = 0.0; gchar *filename; static guint32 texid = 1; if(sscanf(line, "OBJECT %s", namebuf) != 1) { g_warning("AC3D: error reading object line (%s)", line); } transform = g_new0(struct ac3d_transform, 1); memcpy(transform, parent_transform, sizeof(struct ac3d_transform)); object = g_new0(G3DObject, 1); model->objects = g_slist_append(model->objects, object); while(fgets(buffer, 2048, f)) { if(strncmp(buffer, "kids", 4) == 0) { /* final line of object */ if(sscanf(buffer, "kids %d", &nkids) != 1) { g_warning("AC3D: error reading kids line (%s)", buffer); return EXIT_FAILURE; } for(i = 0; i < nkids; i ++) { /* read kids */ fgets(buffer, 2048, f); ac3d_read_object(f, model, buffer, transform, flags); } if(crease > 0.0) { /* doesn't really work */ #if 0 g3d_object_smooth(object, crease); #endif } return EXIT_SUCCESS; } else if(strncmp(buffer, "name", 4) == 0) { if(sscanf(buffer, "name %s", namebuf) != 1) { g_warning("AC3D: error reading name line (%s)", buffer); } else { object->name = g_strdup(namebuf); } } else if(strncmp(buffer, "loc", 3) == 0) { if(sscanf(buffer, "loc %f %f %f", &locx, &locy, &locz) != 3) { g_warning("AC3D: error reading loc line (%s)", buffer); locx = locy = locz = 0.0; } transform->offx += locx; transform->offy += locy; transform->offz += locz; } else if(strncmp(buffer, "numvert", 7) == 0) { if(sscanf(buffer, "numvert %d", &(object->vertex_count)) != 1) { g_warning("AC3D: error reading numvert line (%s)", buffer); object->vertex_count = 0; } else { object->vertices = g_new0(GLfloat, object->vertex_count * 3); for(i = 0; i < object->vertex_count; i ++) { if(fgets(buffer, 2048, f)) { if(sscanf(buffer, "%f %f %f", &(object->vertices[i * 3 + 0]), &(object->vertices[i * 3 + 1]), &(object->vertices[i * 3 + 2])) != 3) { g_warning("AC3D: error reading vertex (%s)", buffer); } object->vertices[i * 3 + 0] += transform->offx; object->vertices[i * 3 + 1] += transform->offy; object->vertices[i * 3 + 2] += transform->offz; } } } /* END numvert */ } else if(strncmp(buffer, "numsurf", 7) == 0) { /* ignore for now */ } else if(strncmp(buffer, "SURF", 4) == 0) { surf_done = 0; if(sscanf(buffer, "SURF %x", &surf_flags) != 1) { g_warning("AC3D: error reading surf (%s)", buffer); } while(!surf_done) { if(!fgets(buffer, 2048, f)) return EXIT_FAILURE; if(sscanf(buffer, "refs %d", &ti1) == 1) { if(!(flags & AC3D_FLAG_ACC)) { face = g_new0(G3DFace, 1); face->num_vertices = ti1; face->index_vertex = g_new0(guint32, face->num_vertices); face->material = material; face->tex_image = object->tex_image; if(face->tex_image) { face->flags |= G3D_FLAG_FAC_TEXMAP; } face->tex_ncoords = ti1; face->tex_coords = g_new0(GLfloat, 2 * face->tex_ncoords); /* normal face */ for(i = 0; i < face->num_vertices; i ++) { if(!fgets(buffer, 2048, f)) return EXIT_FAILURE; if(sscanf(buffer, "%d %f %f", &(face->index_vertex[i]), &(face->tex_coords[i * 2 + 0]), &(face->tex_coords[i * 2 + 1])) != 3) { g_warning( "AC3D: error reading vertex index (%s)", buffer); } face->tex_coords[i * 2 + 0] *= (texrepu * texscaleu); face->tex_coords[i * 2 + 1] *= (texrepv * texscalev); face->tex_coords[i * 2 + 0] += texoffu; face->tex_coords[i * 2 + 1] += texoffv; #if 0 face->tex_coords[i * 2 + 0] *= texscaleu; face->tex_coords[i * 2 + 1] *= texscalev; #endif } if(face->material && (face->num_vertices >= 3)) object->faces = g_slist_prepend(object->faces, face); } /* not .acc */ else { /* triangle stripes */ i = 0; while(i < ti1) { face = g_new0(G3DFace, 1); face->num_vertices = 3; face->index_vertex = g_new0(guint32, 3); face->material = material; face->tex_image = object->tex_image; if(face->tex_image) { face->flags |= G3D_FLAG_FAC_TEXMAP; } face->tex_ncoords = 3; face->tex_coords = g_new0(GLfloat, 2 * face->tex_ncoords); if(i == 0) { /* TODO: error handling */ fgets(buffer, 2048, f); sscanf(buffer, "%d %f %f", &i1, &u1, &v1); fgets(buffer, 2048, f); sscanf(buffer, "%d %f %f", &i2, &u2, &v2); fgets(buffer, 2048, f); sscanf(buffer, "%d %f %f", &i3, &u3, &v3); i += 3; } else { /* TODO: error handling */ i1 = i2; u1 = u2; v1 = v2; i2 = i3; u2 = u3; v2 = v3; fgets(buffer, 2048, f); sscanf(buffer, "%d %f %f", &i3, &u3, &v3); i ++; } face->index_vertex[0] = i1; face->index_vertex[1] = i2; face->index_vertex[2] = i3; face->tex_coords[0] = u1; face->tex_coords[1] = v1; face->tex_coords[2] = u2; face->tex_coords[3] = v2; face->tex_coords[4] = u3; face->tex_coords[5] = v3; object->faces = g_slist_prepend(object->faces, face); } } /* .acc */ surf_done = 1; } else if(sscanf(buffer, "mat %d", &ti1) == 1) { material = g_slist_nth_data(model->materials, ti1); } } material = NULL; /* END SURF */ } else if(strncmp(buffer, "texture", 7) == 0) { if(sscanf(buffer, "texture %s", namebuf) == 1) { filename = ac3d_remove_quotes(namebuf); object->tex_image = g3d_texture_load_cached(model, filename); if(object->tex_image) { if(object->tex_image->gl_texid == 0) { object->tex_image->gl_texid = texid; texid ++; } g3d_texture_prepare(object->tex_image); texscaleu = object->tex_image->scaleu; texscalev = object->tex_image->scalev; } } else { g_warning("error reading texture line (%s)", buffer); } } else if(strncmp(buffer, "texrep", 6) == 0) { if(sscanf(buffer, "texrep %f %f", &texrepu, &texrepv) != 2) { g_warning("error reading texrep line (%s)", buffer); texrepu = 1.0; texrepv = 1.0; } if(texrepu == 0.0) texrepu = 1.0; if(texrepv == 0.0) texrepv = 1.0; } else if(strncmp(buffer, "texoff", 6) == 0) { if(sscanf(buffer, "texoff %f %f", &texoffu, &texoffv) != 2) { g_warning("error reading texoff line (%s)", buffer); } } else if(strncmp(buffer, "crease", 6) == 0) { if(sscanf(buffer, "crease %f", &crease) != 1) { g_warning("error reading crease line (%s)", buffer); } } else { #if DEBUG > 0 g_print("AC3D: unhandled line: %s\n", buffer); #endif } } return EXIT_FAILURE; }