Files
SaraP cbec90699f FIST 6.8 :
- creato il progetto in Visual Studio per compilare come libreria statica
- modifiche al codice originale per integrarlo nelle nostre librerie.
2025-03-04 16:19:35 +01:00

954 lines
37 KiB
C++

/*****************************************************************************/
/* */
/* 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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <float.h>
#include <assert.h>
#include <time.h>
/* */
/* 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;
}