cbec90699f
- creato il progetto in Visual Studio per compilare come libreria statica - modifiche al codice originale per integrarlo nelle nostre librerie.
954 lines
37 KiB
C++
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;
|
|
}
|
|
|