/*****************************************************************************/ /* */ /* F I S T : Fast, Industrial-Strength Triangulation */ /* */ /*****************************************************************************/ /* */ /* (C) Martin Held */ /* (C) Universitaet Salzburg, Salzburg, Austria */ /* */ /* This code is not in the public domain. All rights reserved! Please make */ /* sure to read the full copyright statement contained in api_functions.cpp. */ /* */ /*****************************************************************************/ /* */ /* ReadPolyhedron() is based on code by Jeff Katcher, katcher@netcom.com. */ /* */ /*****************************************************************************/ /* */ /* get standard libraries */ /* */ #include #include #include #include #include #include /* */ /* get my header files */ /* */ #include "fpkernel.h" #include "martin.h" #include "defs.h" #include "list.h" #include "basic.h" #include "header.h" #include "ipe_io.h" #include "sgo.h" /* */ /* function prototypes of functions provided in this file */ /* */ void WriteGeomOutput(global_struct *all); void WriteFaces(global_struct *all, char output_file[]); void ReadPolyhedron(global_struct *all, char input_file[]); #define LINE_LENGTH 1000000 #define NEWLINE '\n' #ifdef NORMALS #define WriteObjVertex(list,io3d,fp, i) \ {\ if (io3d->tex_norm_data_exists) { \ if (io3d->vertex_normals && io3d->texture_vertices) { \ fprintf(fp, " %d/%d/%d", GetOriginal(list, i) + 1, \ GetTextureIndex(list, i) + 1, GetNormalIndex(list, i) + 1); \ }\ else if (io3d->vertex_normals) { \ fprintf(fp, " %d//%d", GetOriginal(list, i) + 1, GetNormalIndex(list, i) + 1);\ }\ else if (io3d->texture_vertices) { \ fprintf(fp, " %d/%d", GetOriginal(list, i) + 1, GetTextureIndex(list, i) + 1);\ }\ else { \ fprintf(fp, " %d", GetOriginal(list, i) + 1); \ }\ }\ else { \ fprintf(fp, " %d", GetOriginal(list, i) + 1); \ }\ } #endif #ifdef NORMALS #define WriteObjTri(list, vert, io3d, fp, i) \ {\ assert(InVertexList(vert,vert->triangles[i].v1)); \ assert(InVertexList(vert,vert->triangles[i].v2)); \ assert(InVertexList(vert,vert->triangles[i].v3)); \ if (io3d->tex_norm_data_exists) { \ if (io3d->vertex_normals && io3d->texture_vertices) { \ fprintf(fp, "f %d/%d/%d %d/%d/%d %d/%d/%d\n", \ vert->triangles[i].v1 + 1, GetTextureIndex(list, vert->i_triangles[i].i1)+1, \ GetNormalIndex(list, vert->i_triangles[i].i1)+1, \ vert->triangles[i].v2 + 1, GetTextureIndex(list, vert->i_triangles[i].i2)+1, \ GetNormalIndex(list, vert->i_triangles[i].i2)+1, \ vert->triangles[i].v3 + 1, GetTextureIndex(list, vert->i_triangles[i].i3)+1, \ GetNormalIndex(list, vert->i_triangles[i].i3)+1); \ }\ else if (io3d->vertex_normals) { \ fprintf(fp, "f %d//%d %d//%d %d//%d\n", \ vert->triangles[i].v1 + 1, GetNormalIndex(list, vert->i_triangles[i].i1)+1, \ vert->triangles[i].v2 + 1, GetNormalIndex(list, vert->i_triangles[i].i2)+1, \ vert->triangles[i].v3 + 1, GetNormalIndex(list, vert->i_triangles[i].i3)+1); \ }\ else if (io3d->texture_vertices) { \ fprintf(fp, "f %d/%d %d/%d %d/%d\n", \ vert->triangles[i].v1 + 1, GetTextureIndex(list, vert->i_triangles[i].i1)+1, \ vert->triangles[i].v2 + 1, GetTextureIndex(list, vert->i_triangles[i].i2)+1, \ vert->triangles[i].v3 + 1, GetTextureIndex(list, vert->i_triangles[i].i3)+1); \ }\ else {\ fprintf(fp, "f %d %d %d\n", vert->triangles[i].v1 + 1, vert->triangles[i].v2 + 1, vert->triangles[i].v3 + 1); \ }\ }\ else { \ fprintf(fp, "f %d %d %d\n", vert->triangles[i].v1 + 1, vert->triangles[i].v2 + 1, vert->triangles[i].v3 + 1); \ }\ } #else #define WriteObjTri(vert, io3d, fp, i) \ {\ assert(InVertexList(vert,vert->triangles[i].v1)); \ assert(InVertexList(vert,vert->triangles[i].v2)); \ assert(InVertexList(vert,vert->triangles[i].v3)); \ fprintf(fp, "f %d %d %d\n", vert->triangles[i].v1 + 1, vert->triangles[i].v2 + 1, vert->triangles[i].v3 + 1); \ } #endif #define WriteObjQuad(vert, fp, i) \ {\ assert(InVertexList(vert, vert->quads[i].v1)); \ assert(InVertexList(vert, vert->quads[i].v2)); \ assert(InVertexList(vert, vert->quads[i].v3)); \ assert(InVertexList(vert, vert->quads[i].v4)); \ fprintf(fp, "f %d %d %d %d\n", vert->quads[i].v1 + 1, vert->quads[i].v2 + 1, vert->quads[i].v3 + 1, vert->quads[i].v4 + 1); } #define WriteObjTriQuad(vert, fp, i) \ {\ assert(InVertexList(vert, vert->quads[i].v1)); \ assert(InVertexList(vert, vert->quads[i].v2)); \ assert(InVertexList(vert, vert->quads[i].v3)); \ assert(InVertexList(vert, vert->quads[i].v4)); \ fprintf(fp, "f %d %d %d\n", vert->quads[i].v1 + 1, vert->quads[i].v2 + 1, vert->quads[i].v3 + 1); \ fprintf(fp, "f %d %d %d\n", vert->quads[i].v1 + 1, vert->quads[i].v3 + 1, vert->quads[i].v4 + 1); } void Init3dDefaults(io_3ddef *io3d) { io3d->draw_concave = false; io3d->sgi_output = false; io3d->draw_groups = false; #ifdef NORMALS io3d->tex_norm_data_exists = false; io3d->vertex_normals = false; io3d->texture_vertices = false; #endif } void GetNewColor(io_3ddef *io3d) { machine_double my_random; UniformRandom(my_random); io3d->color.r = (int) (256 * my_random); UniformRandom(my_random); io3d->color.g = (int) (256 * my_random); UniformRandom(my_random); io3d->color.b = (int) (256 * my_random); return; } /* */ /* this function writes the triangulation in GEOMVIEW's OFF-format to a file.*/ /* */ /* the vertices of the triangulation are contained in the array */ /* `vertices[0,..,num_vertices-1]', and the triangles (i.e., triples of */ /* indices) are contained in `triangles[0,..,num_triangles]. quads, encoded */ /* as 2-triangle strips, are contained in `quads[0,..,num_quads]'. */ /* */ /* for polyhedral input, "--color" instructs FIST to color the output */ /* triangles according to the type of input face. blue denotes triangles */ /* that are part of convex faces. red denotes triangles that are part of */ /* concave faces. green is used for triangles belonging to input (or output) */ /* quads, and magenta denotes singleton triangles (that were input as */ /* triangles). */ /* */ void WriteGeomOutput(global_struct *all) { vertexdef *vert = &all->c_vertex; io_3ddef *io3d = &all->c_io3d; eardef *ear = &all->c_ear; FILE *fp; int i, j, k2, k3; int tri_to_draw = 0; fp = OpenFile("triang.geo", "w"); fprintf(fp, "OFF\n"); if (ear->use_colors && io3d->draw_concave) { /* */ /* draw only the triangles belonging to concave faces. we have to */ /* count them first... */ /* */ for (i = 0; i < vert->num_triangles; ++i) { #ifdef PARTITION_FIST if(vert->triangles[i].disabled) continue; #endif assert(InVertexList(vert, vert->triangles[i].v1)); assert(InVertexList(vert, vert->triangles[i].v2)); assert(InVertexList(vert, vert->triangles[i].v3)); if (vert->triangles[i].color == TriCveColor) ++tri_to_draw; } fprintf(fp, "%d %d %d\n", vert->num_vertices, tri_to_draw,3 * tri_to_draw); } else { fprintf(fp, "%d %d %d\n", vert->num_vertices, GetNumTriangles(vert) + 2 * vert->num_quads, 3 * (GetNumTriangles(vert) + 2 * vert->num_quads)); } for (i = 0; i < vert->num_vertices; ++i) { fprintf(fp, "%f %f %f\n", DOUBLE_TO_IOMDOUBLE(vert->vertices[i].x), DOUBLE_TO_IOMDOUBLE(vert->vertices[i].y), DOUBLE_TO_IOMDOUBLE(vert->vertices[i].z)); } if (ear->use_colors) { if (!io3d->draw_concave) { for (i = 0; i < vert->num_quads; ++i) { assert(InVertexList(vert, vert->quads[i].v1)); assert(InVertexList(vert, vert->quads[i].v2)); assert(InVertexList(vert, vert->quads[i].v3)); assert(InVertexList(vert, vert->quads[i].v4)); fprintf(fp, "3 %d %d %d 0 0 255\n", vert->quads[i].v1, vert->quads[i].v2, vert->quads[i].v3); /* green */ fprintf(fp, "3 %d %d %d 0 0 255\n", vert->quads[i].v1, vert->quads[i].v3, vert->quads[i].v4); /* green */ } } for (i = 0; i < vert->num_triangles; ++i) { #ifdef PARTITION_FIST if(vert->triangles[i].disabled) continue; #endif assert(InVertexList(vert, vert->triangles[i].v1)); assert(InVertexList(vert, vert->triangles[i].v2)); assert(InVertexList(vert, vert->triangles[i].v3)); if (!io3d->draw_concave && (vert->triangles[i].color == TriTriColor)) { /* magenta */ fprintf(fp, "3 %d %d %d 255 0 255\n", vert->triangles[i].v1, vert->triangles[i].v2, vert->triangles[i].v3); } else if (!io3d->draw_concave && (vert->triangles[i].color == TriQuadColor)) { /* green */ fprintf(fp, "3 %d %d %d 0 255 0\n", vert->triangles[i].v1, vert->triangles[i].v2, vert->triangles[i].v3); } else if (!io3d->draw_concave && (vert->triangles[i].color == TriCvxColor)) { /* blue */ fprintf(fp, "3 %d %d %d 0 0 255\n", vert->triangles[i].v1, vert->triangles[i].v2, vert->triangles[i].v3); } else if (vert->triangles[i].color == TriCveColor) { /* red */ fprintf(fp, "3 %d %d %d 255 0 0\n", vert->triangles[i].v1, vert->triangles[i].v2, vert->triangles[i].v3); } else if (!io3d->draw_concave) { fprintf(stderr, "The color coding of the tris is incorrect!\n"); fprintf(fp, "3 %d %d %d 255 0 0\n", vert->triangles[i].v1, vert->triangles[i].v2, vert->triangles[i].v3); } } } else if (io3d->draw_groups && (vert->num_groups > 1)) { k2 = k3 = 0; for (j = 0; j < vert->num_groups; ++j) { assert(InGroupList(vert, j)); GetNewColor(io3d); for (i = k2; i < vert->group_tris[j]; ++i) { assert(InVertexList(vert, vert->triangles[i].v1)); assert(InVertexList(vert, vert->triangles[i].v2)); assert(InVertexList(vert, vert->triangles[i].v3)); fprintf(fp, "3 %d %d %d %d %d %d\n", vert->triangles[i].v1, vert->triangles[i].v2, vert->triangles[i].v3, io3d->color.r, io3d->color.g, io3d->color.b); } for (i = k3; i < vert->group_quads[j]; ++i) { assert(InVertexList(vert, vert->quads[i].v1)); assert(InVertexList(vert, vert->quads[i].v2)); assert(InVertexList(vert, vert->quads[i].v3)); assert(InVertexList(vert, vert->quads[i].v4)); fprintf(fp, "3 %d %d %d %d %d %d\n", vert->quads[i].v1, vert->quads[i].v2, vert->quads[i].v3, io3d->color.r, io3d->color.g, io3d->color.b); fprintf(fp, "3 %d %d %d %d %d %d\n", vert->quads[i].v1, vert->quads[i].v3, vert->quads[i].v4, io3d->color.r, io3d->color.g, io3d->color.b); } k2 = vert->group_tris[j]; k3 = vert->group_quads[j]; } } else { for (i = 0; i < vert->num_quads; ++i) { assert(InVertexList(vert, vert->quads[i].v1)); assert(InVertexList(vert, vert->quads[i].v2)); assert(InVertexList(vert, vert->quads[i].v3)); assert(InVertexList(vert, vert->quads[i].v4)); fprintf(fp, "3 %d %d %d 0 255 0\n", vert->quads[i].v1, vert->quads[i].v2, vert->quads[i].v3); /* green */ fprintf(fp, "3 %d %d %d 0 255 0\n", vert->quads[i].v1, vert->quads[i].v3, vert->quads[i].v4); /* green */ } for (i = 0; i < vert->num_triangles; ++i) { #ifdef PARTITION_FIST if(vert->triangles[i].disabled) continue; #endif assert(InVertexList(vert, vert->triangles[i].v1)); assert(InVertexList(vert, vert->triangles[i].v2)); assert(InVertexList(vert, vert->triangles[i].v3)); fprintf(fp, "3 %d %d %d 0 255 0\n", vert->triangles[i].v1, vert->triangles[i].v2, vert->triangles[i].v3); /* green */ } } fclose(fp); return; } void WriteConvexFace(global_struct *all, FILE *fp, loop_list entry) { #ifndef NDEBUG vertexdef *vert = &all->c_vertex; #endif #ifdef NORMALS io_3ddef *io3d = &all->c_io3d; #endif listdef *list = &all->c_list; list_ind ind, ind1; fprintf(fp, "f"); assert(InLoopList(list, entry.ind)); ind = list->loops[entry.ind]; ind1 = ind; assert(InPolyList(list, ind1)); assert(InVertexList(vert, GetOriginal(list, ind1))); #ifdef NORMALS WriteObjVertex(list, io3d, fp, ind1); #else fprintf(fp, " %d", GetOriginal(list, ind1) + 1); #endif if (entry.ccw) { ind1 = GetNextNode(list, ind1); while (ind1 != ind) { assert(InPolyList(list, ind1)); assert(InVertexList(vert, GetOriginal(list, ind1))); #ifdef NORMALS WriteObjVertex(list, io3d, fp, ind1); #else fprintf(fp, " %d", GetOriginal(list, ind1) + 1); #endif ind1 = GetNextNode(list, ind1); } } else { ind1 = GetPrevNode(list, ind1); while (ind1 != ind) { assert(InPolyList(list, ind1)); assert(InVertexList(vert, GetOriginal(list, ind1))); #ifdef NORMALS WriteObjVertex(list, io3d, fp, ind1); #else fprintf(fp, " %d", GetOriginal(list, ind1) + 1); #endif ind1 = GetPrevNode(list, ind1); } } fprintf(fp, "\n"); return; } /* */ /* this function writes the triangulation in OBJ-format or SGO-format to a */ /* file. note that some faces may be non-convex if keep_convex is true. */ /* */ /* the vertices of the triangulation are contained in the array */ /* `vertices[0,..,num_vertices-1]', and the triangles (i.e., triples of */ /* indices) are contained in `triangles[0,..,num_triangles]. quads are */ /* contained in `quads[0,..,num_quads]'. the start indices for all convex */ /* faces are in convex_loops[0,..,num_convex_loops]. */ /* */ /* note that my indices start at 0, whereas OBJ's indices start at 1! */ /* */ void WriteFaces(global_struct *all, char output_file[]) { vertexdef *vert = &all->c_vertex; #ifdef NORMALS listdef *list = &all->c_list; #endif io_3ddef *io3d = &all->c_io3d; FILE *fp; int i, j, k1, k2, k3; float sgi_tri[3][3]; fp = OpenFile(output_file, "w"); if (io3d->sgi_output) { /* */ /* write data in SGI-format. note that we will use dummy colors and */ /* normals */ /* */ WriteFileMagic(fp); WriteObjType(fp, GetNumTriangles(vert) + 2 * vert->num_quads); for (i = 0; i < vert->num_triangles; ++i) { #ifdef PARTITION_FIST if(vert->triangles[i].disabled) continue; #endif assert(InVertexList(vert, vert->triangles[i].v1)); assert(InVertexList(vert, vert->triangles[i].v2)); assert(InVertexList(vert, vert->triangles[i].v3)); sgi_tri[0][0] = REAL_TO_FLOAT(vert->vertices[vert->triangles[i].v1].x); sgi_tri[0][1] = REAL_TO_FLOAT(vert->vertices[vert->triangles[i].v1].y); sgi_tri[0][2] = REAL_TO_FLOAT(vert->vertices[vert->triangles[i].v1].z); sgi_tri[1][0] = REAL_TO_FLOAT(vert->vertices[vert->triangles[i].v2].x); sgi_tri[1][1] = REAL_TO_FLOAT(vert->vertices[vert->triangles[i].v2].y); sgi_tri[1][2] = REAL_TO_FLOAT(vert->vertices[vert->triangles[i].v2].z); sgi_tri[2][0] = REAL_TO_FLOAT(vert->vertices[vert->triangles[i].v3].x); sgi_tri[2][1] = REAL_TO_FLOAT(vert->vertices[vert->triangles[i].v3].y); sgi_tri[2][2] = REAL_TO_FLOAT(vert->vertices[vert->triangles[i].v3].z); WriteSgiTri(fp, sgi_tri); } for (i = 0; i < vert->num_quads; ++i) { assert(InVertexList(vert, vert->quads[i].v1)); assert(InVertexList(vert, vert->quads[i].v2)); assert(InVertexList(vert, vert->quads[i].v3)); assert(InVertexList(vert, vert->quads[i].v4)); /* write first triangle */ sgi_tri[0][0] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v1].x); sgi_tri[0][1] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v1].y); sgi_tri[0][2] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v1].z); sgi_tri[1][0] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v2].x); sgi_tri[1][1] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v2].y); sgi_tri[1][2] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v2].z); sgi_tri[2][0] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v3].x); sgi_tri[2][1] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v3].y); sgi_tri[2][2] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v3].z); WriteSgiTri(fp, sgi_tri); /* write second triangle */ sgi_tri[0][0] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v1].x); sgi_tri[0][1] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v1].y); sgi_tri[0][2] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v1].z); sgi_tri[1][0] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v3].x); sgi_tri[1][1] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v3].y); sgi_tri[1][2] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v3].z); sgi_tri[2][0] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v4].x); sgi_tri[2][1] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v4].y); sgi_tri[2][2] = REAL_TO_FLOAT(vert->vertices[vert->quads[i].v4].z); WriteSgiTri(fp, sgi_tri); } WriteFileEnd(fp); } else { /* */ /* write data in OBJ-format */ /* */ fprintf(fp, "# .obj file generated by tesselating an .obj model "); fprintf(fp, "by means of\n"); fprintf(fp, "# Martin Held's FIST. "); fprintf(fp, "email address: held@cs.sbg.ac.at.\n"); if (all->rt_opt.keep_convex) fprintf(fp, "# all faces of this model are convex.\n"); else if (vert->num_quads > 0) fprintf(fp, "# all faces of this model are triangles or quads.\n"); else fprintf(fp, "# all faces of this model are triangles.\n"); fprintf(fp, "# the z-coordinates may be dummy values for "); fprintf(fp, "data that was originally 2D!\n"); for (i = 0; i < vert->num_vertices; ++i) { fprintf(fp, "v %f %f %f\n", DOUBLE_TO_IOMDOUBLE(vert->vertices[i].x), DOUBLE_TO_IOMDOUBLE(vert->vertices[i].y), DOUBLE_TO_IOMDOUBLE(vert->vertices[i].z)); } fprintf(fp, "# %d vertices\n\n", vert->num_vertices); #ifdef NORMALS if (io3d->tex_norm_data_exists) { for (i = 0; i < vert->num_t_vertices; ++i) { fprintf(fp, "vt %f %f %f\n", DOUBLE_TO_IOMDOUBLE(vert->t_vertices[i].x), DOUBLE_TO_IOMDOUBLE(vert->t_vertices[i].y), DOUBLE_TO_IOMDOUBLE(vert->t_vertices[i].z)); } fprintf(fp, "# %d texture vertices\n\n", vert->num_t_vertices); for (i = 0; i < vert->num_v_normals; ++i) { fprintf(fp, "vn %f %f %f\n", DOUBLE_TO_IOMDOUBLE(vert->v_normals[i].x), DOUBLE_TO_IOMDOUBLE(vert->v_normals[i].y), DOUBLE_TO_IOMDOUBLE(vert->v_normals[i].z)); } fprintf(fp, "# %d vertex normals\n\n", vert->num_v_normals); } #endif if (vert->num_groups <= 1) { fprintf(fp, "g GROUP.1\n"); for (i = 0; i < vert->num_triangles; ++i) { #ifdef PARTITION_FIST if(vert->triangles[i].disabled) continue; #endif #ifdef NORMALS WriteObjTri(list, vert, io3d, fp, i); #else WriteObjTri(vert, io3d, fp, i); #endif } if (all->rt_opt.keep_convex) { for (i = 0; i < vert->num_quads; ++i) { WriteObjQuad(vert, fp, i); } for (i = 0; i < vert->num_convex_loops; ++i) { WriteConvexFace(all, fp, vert->convex_loops[i]); } fprintf(fp, "# %d elements\n\n", GetNumTriangles(vert) + vert->num_quads + vert->num_convex_loops); } else { assert(vert->num_convex_loops == 0); for (i = 0; i < vert->num_quads; ++i) { WriteObjTriQuad(vert, fp, i); } fprintf(fp, "# %d elements\n\n", GetNumTriangles(vert) + 2 * vert->num_quads); } } else { k1 = k2 = k3 = 0; for (j = 0; j < vert->num_groups; ++j) { assert(InGroupList(vert, j)); fprintf(fp, "g GROUP.%d\n", j + 1); for (i = k2; i < vert->group_tris[j]; ++i) { #ifdef NORMALS WriteObjTri(list, vert, io3d, fp, i); #else WriteObjTri(vert, io3d, fp, i); #endif } if (all->rt_opt.keep_convex) { for (i = k3; i < vert->group_quads[j]; ++i) { WriteObjQuad(vert, fp, i); } for (i = k1; i < vert->group_loops[j]; ++i) { WriteConvexFace(all, fp, vert->convex_loops[i]); } fprintf(fp, "# %d elements\n\n", vert->group_tris[j] + vert->group_quads[j] + vert->group_loops[j] - k1 - k2 - k3); k1 = vert->group_loops[j]; } else { assert(vert->num_convex_loops == 0); for (i = k3; i < vert->group_quads[j]; ++i) { WriteObjTriQuad(vert, fp, i); } fprintf(fp, "# %d elements\n\n", vert->group_tris[j] + 2 * vert->group_quads[j] - k2 - 2 * k3); } k2 = vert->group_tris[j]; k3 = vert->group_quads[j]; } } } fclose(fp); return; } /* */ /* this is a minimum interface to OBJ-files. it recognizes lines starting */ /* with `v', `f' or `g'. */ /* */ /* warning: every line of the file may contain at most `LINE_LENGTH' many */ /* characters. */ /* */ /* march 30, 1998: I have introduced an OBJ key "H" which indicates the */ /* number of holes of a "multiply-connected" 3D polygon encoded in the */ /* OBJ-format. note that this key is not supported by the OBJ-format!! */ /* */ /* this function is based on code by Jeff Katcher, katcher@netcom.com. */ /* */ void ReadPolyhedron(global_struct *all, char input_file[]) { vertexdef *vert = &all->c_vertex; listdef *list = &all->c_list; #ifdef NORMALS io_3ddef *io3d = &all->c_io3d; #endif FILE *fp; char line[LINE_LENGTH + 1]; void StripNewline(char *line); void HandleFace(global_struct *all, char *line, int *num_holes, boolean *new_face); void HandleVertex(vertexdef *vert, char *line); #ifdef NORMALS void HandleT_Vertex(vertexdef *vert, char *line); void HandleV_Normal(vertexdef *vert, char *line); #endif void HandleHole(char *line, int *num_holes); int num_holes = 0; boolean new_face = true; #ifdef NORMALS io3d->tex_norm_data_exists = false; io3d->vertex_normals = false; io3d->texture_vertices = false; #endif fp = OpenFile(input_file, "r"); while (fgets(line, LINE_LENGTH, fp)) { StripNewline(line); switch (*line) { case 'H': /* */ /* this is my new key for indicating holes in a 3D polyhedron; H 5 */ /* means that this is a boundary loop with 4 holes. this key will */ /* only effect the face that follows right after it. */ /* */ switch (*(line+1)) { case ' ': HandleHole(line, &num_holes); break; default: break; } break; case 'v': /* */ /* vertex: */ /* */ switch (*(line+1)) { case ' ': /* */ /* a regular vertex 'v' */ /* */ HandleVertex(vert, line); break; case 'n': /* */ /* a vertex normal 'vn' */ /* */ #ifdef NORMALS HandleV_Normal(vert, line); io3d->vertex_normals = true; #endif break; case 'p': /* */ /* a vertex for a free-form surface; skip it */ /* */ break; case 't': /* */ /* a texture vertex */ /* */ #ifdef NORMALS HandleT_Vertex(vert, line); io3d->texture_vertices = true; #endif break; default: /* */ /* an unknown vertex type */ /* */ break; } break; case 'f': /* */ /* a polyhedral face */ /* */ HandleFace(all, line, &num_holes, &new_face); break; case '#': /* */ /* comment; skip it */ /* */ break; case '$': /* */ /* seems to be a comment, too; skip it */ /* */ break; case 'g': /* */ /* a group statement */ /* */ if (list->num_faces > 0) StoreGroupNumber(list, vert); break; case 's': /* */ /* smoothing group; skip it */ /* */ break; case 'l': /* */ /* a line; skip it */ /* */ break; default: /* */ /* an unknown data field */ /* */ break; } } StoreGroupNumber(list, vert); fclose(fp); return; } void HandleVertex(vertexdef *vert, char *line) { double x, y, z; if (FP_sscanf(line, "v %lf %lf %lf", &x, &y, &z) != 3) { FIST_Warning("3D OBJ input format error: v coordinate mismatch"); throw WRONG_OBJ_FORMAT; } #ifdef EXT_APPL_SITES (void) StoreVertex(vert,x, y, z, eas_NIL); #else (void) StoreVertex(vert,x, y, z); #endif return; } #ifdef NORMALS void HandleT_Vertex(vertexdef *vert, char *line) { double x, y, z; int result; result = FP_sscanf(line, "vt %lf %lf %lf", &x, &y, &z); if (result == 3) (void) StoreT_Vertex(vert, x, y, z); else if (result == 2) (void) StoreT_Vertex(vert, x, y, C_0_0); else if (result == 1) (void) StoreT_Vertex(vert, x, C_0_0, C_0_0); else { FIST_Warning("3D OBJ input format error: vt coordinate mismatch"); throw WRONG_OBJ_FORMAT; } return; } void HandleV_Normal(vertexdef *vert, char *line) { double x, y, z; if (FP_sscanf(line, "vn %lf %lf %lf", &x, &y, &z) != 3){ FIST_Warning("3D OBJ input format error: vn coordinate mismatch"); throw WRONG_OBJ_FORMAT; } (void) StoreV_Normal(vert, x, y, z); return; } #endif void HandleHole(char *line, int *num_holes) { if (sscanf(line, "H %d", num_holes) != 1) { FIST_Warning("3D OBJ input format error: no hole number specified"); throw WRONG_OBJ_FORMAT; } if (*num_holes < 0) { FIST_Warning("3D OBJ input format error: negative hole number"); *num_holes = 0; } return; } void HandleFace(global_struct *all, char *line, int *num_holes, boolean *new_face) { vertexdef *vert = &all->c_vertex; listdef *list = &all->c_list; char *token; int curr_loop; list_ind ind = NIL, last_ind; int index; #ifdef NORMALS io_3ddef *io3d = &all->c_io3d; boolean n_exists = false; int t_index, n_index; char *first, *last; #endif curr_loop = MakeLoopHeader(list); if (*num_holes == 0) { InitFace(list, 1); /* set the number of loops for the face */ } else if (*new_face) { InitFace(list, *num_holes + 1);/* set the number of loops for the face */ *new_face = false; } else { /* no new face yet */ --(*num_holes); assert(*num_holes >= 0); *new_face = (*num_holes == 0); } last_ind = list->loops[curr_loop]; /* */ /* check whether this face refers to texture vertices and vertex normals */ /* */ #ifdef NORMALS n_exists = (NULL != strstr(line, "/")); if (n_exists) io3d->tex_norm_data_exists = true; #endif /* */ /* skip the 'f' identifier */ /* */ strtok(line, " "); /* */ /* break the string into the individual numbers */ /* */ while ((token = strtok(NULL," "))) { /* */ /* get and store the index of the vertex */ /* */ index = atoi(token); if (index < 0) index = vert->num_vertices + index; else if (index == 0) break; else --index; ind = MakeNode(list, index); InsertAfter(list, last_ind, ind); SetOriginal(list, ind, index); last_ind = ind; #ifdef NORMALS if (n_exists) { first = strchr(token, '/'); last = strrchr(token, '/'); if (last == first) { /* */ /* this token is of the form "v/vn" or "v/vt" */ /* */ if (io3d->texture_vertices) { t_index = atoi(first+1); if (t_index < 0) t_index = vert->num_t_vertices + t_index; else --t_index; n_index = NIL; } else if (io3d->vertex_normals) { t_index = NIL; n_index = atoi(first+1); if (n_index < 0) n_index = vert->num_v_normals + n_index; else --n_index; } else { t_index = NIL; n_index = NIL; } } else if (last == (first + 1)) { /* */ /* this token is of the form "v//vn" */ /* */ t_index = NIL; n_index = atoi(last+1); if (n_index < 0) n_index = vert->num_v_normals + n_index; else --n_index; } else { /* */ /* this token is of the form "v/vt/vn" */ /* */ t_index = atoi(first+1); if (t_index < 0) t_index = vert->num_t_vertices + t_index; else --t_index; n_index = atoi(last+1); if (n_index < 0) n_index = vert->num_v_normals + n_index; else --n_index; } SetTexNormData(list, ind, t_index, n_index); } else { SetTexNormData(list, ind, NIL, NIL); } #endif } if (ind != NIL) DeleteHook(list, curr_loop); else { /* this was a loop without vertices... */ DecrementLoops(list); DecrementFaces(list); } return; } void StripNewline(char *line) { char *s; if ((s = strrchr(line, NEWLINE))) *s = '\0'; return; }