561 lines
15 KiB
C
561 lines
15 KiB
C
|
/********************************************************************/
|
||
|
/* STRIPE: converting a polygonal model to triangle strips
|
||
|
Francine Evans, 1996.
|
||
|
SUNY @ Stony Brook
|
||
|
Advisors: Steven Skiena and Amitabh Varshney
|
||
|
*/
|
||
|
/********************************************************************/
|
||
|
|
||
|
/*---------------------------------------------------------------------*/
|
||
|
/* STRIPE: bands.c
|
||
|
This file contains the main procedure code that will read in the
|
||
|
object and then call the routines that produce the triangle strips.
|
||
|
*/
|
||
|
/*---------------------------------------------------------------------*/
|
||
|
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
# include <config.h>
|
||
|
#endif
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <math.h>
|
||
|
#include <string.h>
|
||
|
#include "global.h"
|
||
|
#include "polverts.h"
|
||
|
#include "triangulate.h"
|
||
|
#include "ties.h"
|
||
|
#include "outputex.h"
|
||
|
#include "options.h"
|
||
|
#include "local.h"
|
||
|
#include "init.h"
|
||
|
#include "free.h"
|
||
|
#include "add.h"
|
||
|
|
||
|
/* TIMING for Windows */
|
||
|
#ifdef WIN32
|
||
|
#include <sys/timeb.h>
|
||
|
#include <time.h>
|
||
|
/* TIMING for UNIX */
|
||
|
#else
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/param.h>
|
||
|
#include <sys/times.h>
|
||
|
extern long times( );
|
||
|
long elapsed()
|
||
|
{
|
||
|
static long total = 0;
|
||
|
long cpu_time, dummy;
|
||
|
struct tms buffer;
|
||
|
times(&buffer);
|
||
|
dummy = buffer.tms_utime + buffer.tms_stime +
|
||
|
buffer.tms_cutime + buffer.tms_cstime;
|
||
|
cpu_time = ((dummy - total) * 1000) / HZ;
|
||
|
total = dummy;
|
||
|
return(cpu_time);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
int norms[STRIP_MAX];
|
||
|
int *vert_norms;
|
||
|
int *vert_texture;
|
||
|
|
||
|
|
||
|
void get_time()
|
||
|
{
|
||
|
/* For timing */
|
||
|
#ifdef WIN32
|
||
|
struct timeb timebuffer;
|
||
|
char *timeline;
|
||
|
#else
|
||
|
long timer;
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#ifdef WIN32
|
||
|
ftime( &timebuffer );
|
||
|
timeline = ctime( & ( timebuffer.time ) );
|
||
|
printf( "The time is %.19s.%hu %s", timeline, timebuffer.millitm, &timeline[20] );
|
||
|
#else
|
||
|
timer = elapsed();
|
||
|
printf("The time is %ld\n",timer);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
**
|
||
|
Here the main program begins. It will start by loading in a .obj file
|
||
|
then it will convert the polygonal model into triangle strips.
|
||
|
**
|
||
|
*/
|
||
|
|
||
|
int main (int argc,char *argv[])
|
||
|
{
|
||
|
char *fname,*all,buff[255], *ptr, *ptr2;
|
||
|
FILE *file, *bands;
|
||
|
int face_id=0;
|
||
|
int vert_count=0;
|
||
|
int loop=0;
|
||
|
int num=0;
|
||
|
int num2=0;
|
||
|
|
||
|
float center[3];
|
||
|
int temp[STRIP_MAX],vertex,strips, swaps,tempi,cost,triangles;
|
||
|
int f,t,tr,g;
|
||
|
char *file_open;
|
||
|
int num_vert = 0,
|
||
|
num_faces = 0,
|
||
|
num_nvert = 0,
|
||
|
num_edges = 0,
|
||
|
num_texture = 0,
|
||
|
num_tris = 0;
|
||
|
double fra = 0.0;
|
||
|
BOOL texture, normal, normal_and_texture,quads = FALSE;
|
||
|
|
||
|
/* Options variables */
|
||
|
double norm_difference;
|
||
|
|
||
|
/* Structures for the object */
|
||
|
struct vert_struct *vertices = NULL,
|
||
|
*nvertices = NULL,
|
||
|
*pvertices = NULL,
|
||
|
*pnvertices = NULL;
|
||
|
|
||
|
get_time();
|
||
|
|
||
|
/* File that will contain the triangle strip data */
|
||
|
bands = fopen("stripe.objf","w");
|
||
|
|
||
|
/*
|
||
|
Scan the file once to find out the number of vertices,
|
||
|
vertice normals, and faces so we can set up some memory
|
||
|
structures
|
||
|
*/
|
||
|
/* Interpret the options specified */
|
||
|
norm_difference = get_options(argc,argv,&f,&t,&tr,&g);
|
||
|
if (f == BINARY)
|
||
|
file_open = "rb";
|
||
|
else
|
||
|
file_open = "r";
|
||
|
|
||
|
fname = argv[argc-1];
|
||
|
|
||
|
printf ("File: %s\n",fname);
|
||
|
printf ("Scanning...%s ",file_open);
|
||
|
|
||
|
|
||
|
/* File can be in binary for faster reading */
|
||
|
if (file = fopen (fname,file_open))
|
||
|
{
|
||
|
while (!feof (file))
|
||
|
{
|
||
|
/* Read a line */
|
||
|
if (f == BINARY)
|
||
|
fread (buff,sizeof(char) * 255,1, file);
|
||
|
else
|
||
|
fgets (buff, sizeof(char) * 255, file);
|
||
|
num++;
|
||
|
|
||
|
printf("%d\r",num);
|
||
|
|
||
|
|
||
|
/* At a vertex */
|
||
|
if (*buff == 'v')
|
||
|
{
|
||
|
/* At a normal */
|
||
|
if (*(buff+1)=='n')
|
||
|
num_nvert++;
|
||
|
else if (*(buff+1)=='t')
|
||
|
num_texture++;
|
||
|
/* At a regular vertex */
|
||
|
else
|
||
|
num_vert++;
|
||
|
}
|
||
|
/* At a face */
|
||
|
else if (*buff == 'f')
|
||
|
{
|
||
|
num_faces++;
|
||
|
strtok(buff, " ");
|
||
|
tempi = 0;
|
||
|
while (strtok(NULL, " ") != NULL) tempi++;
|
||
|
num_tris += tempi - 2;
|
||
|
}
|
||
|
}
|
||
|
fclose (file);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
printf("Error in the file name\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
printf("%s pass 1\n",fname);
|
||
|
|
||
|
/* Allocate structures for the information */
|
||
|
Start_Face_Struct(num_faces);
|
||
|
vertices = (struct vert_struct *)
|
||
|
malloc (sizeof (struct vert_struct) * num_vert);
|
||
|
|
||
|
if (num_nvert > 0) {
|
||
|
nvertices = (struct vert_struct *)
|
||
|
malloc (sizeof (struct vert_struct) * num_nvert);
|
||
|
vert_norms = (int *) malloc (sizeof (int) * num_vert);
|
||
|
/*
|
||
|
Initialize entries to zero, in case there are 2 hits
|
||
|
to the same vertex we will know it - used for determining
|
||
|
the normal difference
|
||
|
*/
|
||
|
init_vert_norms(num_vert);
|
||
|
} else {
|
||
|
nvertices = NULL;
|
||
|
}
|
||
|
|
||
|
if (num_texture > 0) {
|
||
|
vert_texture = (int *) malloc (sizeof(int) * num_vert);
|
||
|
init_vert_texture(num_vert);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
Set up the temporary 'p' pointers
|
||
|
*/
|
||
|
pvertices = vertices;
|
||
|
pnvertices = nvertices;
|
||
|
|
||
|
/* Load the object into memory */
|
||
|
/*printf (" Loading...");*/
|
||
|
|
||
|
fprintf(bands,"#%s: a triangle strip representation created by STRIPE.\n#This is a .objf file\n#by Francine Evans\n",fname);
|
||
|
|
||
|
/* File will be put in a list for faster execution if file is in binary */
|
||
|
if (file = fopen(fname,file_open)) {
|
||
|
if (f == BINARY) {
|
||
|
all = (char *) malloc (sizeof(char) * 255 * num);
|
||
|
fread(all,sizeof(char) * 255 * num, 1, file);
|
||
|
ptr = all;
|
||
|
} else {
|
||
|
ptr = (char *) malloc (sizeof(char) * 255 * num);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
while (num > 0) {
|
||
|
num--;
|
||
|
|
||
|
printf("%d\r",num);
|
||
|
|
||
|
if (f == ASCII) {
|
||
|
fgets (ptr, sizeof(char) * 255, file);
|
||
|
} else {
|
||
|
ptr = ptr + 255;
|
||
|
}
|
||
|
|
||
|
/* Load in vertices/normals */
|
||
|
if (*ptr == 'v') {
|
||
|
if (*(ptr+1)=='n') {
|
||
|
sscanf (ptr+3,"%lf%lf%lf",
|
||
|
&(pnvertices->x),
|
||
|
&(pnvertices->y),
|
||
|
&(pnvertices->z));
|
||
|
fprintf(bands,"vn %f %f %f\n",
|
||
|
pnvertices->x,pnvertices->y,pnvertices->z);
|
||
|
++pnvertices;
|
||
|
} else if (*(ptr+1)=='t') {
|
||
|
sscanf (ptr+3,"%f%f%f",¢er[0],¢er[1],¢er[2]);
|
||
|
fprintf(bands,"vt %f %f %f\n",center[0],center[1],center[2]);
|
||
|
} else {
|
||
|
sscanf (ptr+2,"%lf%lf%lf",
|
||
|
&(pvertices->x),
|
||
|
&(pvertices->y),
|
||
|
&(pvertices->z));
|
||
|
fprintf(bands,"v %f %f %f\n",
|
||
|
pvertices->x,pvertices->y,pvertices->z);
|
||
|
++pvertices;
|
||
|
}
|
||
|
} else if (*ptr == 'f') {
|
||
|
/* Read in faces */
|
||
|
num2 = 0;
|
||
|
face_id++;
|
||
|
ptr2 = ptr+1;
|
||
|
normal = FALSE; texture = FALSE, normal_and_texture = FALSE;
|
||
|
while (*ptr2) {
|
||
|
if (*ptr2 >='0' && *ptr2 <='9') {
|
||
|
num2++;
|
||
|
++ptr2;
|
||
|
while (*ptr2 && (*ptr2!=' ' && *ptr2!='/')) {
|
||
|
ptr2++;
|
||
|
}
|
||
|
/* There are normals in this line */
|
||
|
if (*ptr2 == '/') {
|
||
|
if (*(ptr2+1) == '/') {
|
||
|
normal = TRUE;
|
||
|
} else {
|
||
|
texture = TRUE;
|
||
|
}
|
||
|
} else if (*ptr2 == ' ') {
|
||
|
if ((num2 == 3) && (texture)) {
|
||
|
normal_and_texture = TRUE;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
++ptr2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ptr2 = ptr+1;
|
||
|
|
||
|
/*
|
||
|
loop on the number of numbers in this line of face data
|
||
|
*/
|
||
|
vert_count = 0;
|
||
|
|
||
|
for (loop=0;loop<num2;loop++) {
|
||
|
/* skip the whitespace */
|
||
|
while (*ptr2<'0' || *ptr2>'9') {
|
||
|
if (*ptr2 == '-') {
|
||
|
break;
|
||
|
}
|
||
|
ptr2++;
|
||
|
}
|
||
|
vertex = atoi(ptr2)-1;
|
||
|
if (vertex < 0) {
|
||
|
vertex = num_vert + vertex;
|
||
|
*ptr2 = ' ';
|
||
|
ptr2++;
|
||
|
}
|
||
|
/*
|
||
|
If there are either normals or textures with the vertices
|
||
|
in this file, the data alternates so we must read it this way
|
||
|
*/
|
||
|
if ( (normal) && (!normal_and_texture)) {
|
||
|
if (loop%2) {
|
||
|
add_norm_id(vertex,vert_count);
|
||
|
/*
|
||
|
Test here to see if we added a new vertex, since the
|
||
|
vertex has more than one normal and the 2 normals are greater
|
||
|
than the threshold specified
|
||
|
*/
|
||
|
if (norm_array(vertex,0,norm_difference,nvertices,num_vert)) {
|
||
|
/*
|
||
|
Add a new vertex and change the
|
||
|
id of the vertex that we just read to the id of the new
|
||
|
vertex that we just added
|
||
|
*/
|
||
|
/*
|
||
|
Put it in the output file, note the added vertices will
|
||
|
be after the normals and separated from the rest of the
|
||
|
vertices. Will not affect our viewer
|
||
|
*/
|
||
|
fprintf(bands,"v %f %f %f\n",
|
||
|
(vertices + temp[vert_count - 1])->x,
|
||
|
(vertices + temp[vert_count - 1])->y,
|
||
|
(vertices + temp[vert_count - 1])->z);
|
||
|
num_vert++;
|
||
|
temp[vert_count - 1] = num_vert - 1;
|
||
|
if (!(add_vert_id(num_vert - 1,vert_count))) {
|
||
|
vert_count--;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
/* the vertex */
|
||
|
temp[vert_count] = vertex ;
|
||
|
vert_count++;
|
||
|
if (!(add_vert_id(vertex,vert_count))) {
|
||
|
vert_count--;
|
||
|
}
|
||
|
norm_array(vertex,1,norm_difference,nvertices,num_vert);
|
||
|
}
|
||
|
} else if (normal_and_texture) {
|
||
|
/* Else there are vertices and textures with the data */
|
||
|
if( !((loop+1)%3)) {
|
||
|
add_norm_id(vertex,vert_count);
|
||
|
/*
|
||
|
Test here to see if we added a new vertex, since the
|
||
|
vertex has more than one normal and the 2 normals are greater
|
||
|
than the threshold specified
|
||
|
*/
|
||
|
if (norm_array(vertex,0,norm_difference,nvertices,num_vert)) {
|
||
|
/*
|
||
|
Add a new vertex and change the
|
||
|
id of the vertex that we just read to the id of the new
|
||
|
vertex that we just added
|
||
|
*/
|
||
|
/*
|
||
|
Put it in the output file, note the added vertices will
|
||
|
be after the normals and separated from the rest of the
|
||
|
vertices. Will not affect our viewer
|
||
|
*/
|
||
|
fprintf(bands,"v %f %f %f\n",
|
||
|
(vertices + temp[vert_count - 1])->x,
|
||
|
(vertices + temp[vert_count - 1])->y,
|
||
|
(vertices + temp[vert_count - 1])->z);
|
||
|
num_vert++;
|
||
|
temp[vert_count - 1] = num_vert - 1;
|
||
|
if (!(add_vert_id(num_vert - 1,vert_count))) {
|
||
|
vert_count--;
|
||
|
}
|
||
|
}
|
||
|
} else if ((loop == 0) || (*(ptr2-1) == ' ')) {
|
||
|
/* the vertex */
|
||
|
temp[vert_count] = vertex ;
|
||
|
vert_count++;
|
||
|
if (vert_count == 4) {
|
||
|
quads = TRUE;
|
||
|
}
|
||
|
if (!(add_vert_id(vertex,vert_count))) {
|
||
|
vert_count--;
|
||
|
}
|
||
|
add_texture(vertex,TRUE);
|
||
|
norm_array(vertex,1,norm_difference,nvertices,num_vert);
|
||
|
} else {
|
||
|
/* The texture */
|
||
|
add_texture(vertex,FALSE);
|
||
|
}
|
||
|
} else if ( texture ) {
|
||
|
/* the vertex */
|
||
|
if (!(loop%2)) {
|
||
|
temp[vert_count] = vertex ;
|
||
|
vert_count++;
|
||
|
if (vert_count == 4)
|
||
|
quads = TRUE;
|
||
|
add_texture(vertex,TRUE);
|
||
|
if (!(add_vert_id(vertex,vert_count)))
|
||
|
vert_count--;
|
||
|
norm_array(vertex,1,norm_difference,nvertices,num_vert);
|
||
|
} else {
|
||
|
/* texture */
|
||
|
add_texture(vertex,FALSE);
|
||
|
}
|
||
|
} else {
|
||
|
/*** no nvertices ***/
|
||
|
temp[vert_count] = vertex ;
|
||
|
vert_count++;
|
||
|
if (vert_count == 4)
|
||
|
quads = TRUE;
|
||
|
if (!(add_vert_id(vertex,vert_count)))
|
||
|
vert_count--;
|
||
|
}
|
||
|
while (*ptr2>='0' && *ptr2<='9')
|
||
|
ptr2++;
|
||
|
}
|
||
|
/* Done with the polygon */
|
||
|
num_edges += vert_count;
|
||
|
/* add it to face structure */
|
||
|
if (vert_count >= 3)
|
||
|
AddNewFace(ids,vert_count,face_id,norms);
|
||
|
else
|
||
|
face_id--;
|
||
|
if (vert_count == 4)
|
||
|
quads = TRUE;
|
||
|
}
|
||
|
else if ((g == TRUE) && (face_id > 0)
|
||
|
&& ((*ptr == 'g') || (*ptr == 's') || (*ptr == 'm') || (*ptr == 'o')))
|
||
|
{
|
||
|
/*
|
||
|
The user specified that the strips will be contained in each group
|
||
|
from the data file, so we just finished a group and will find the
|
||
|
triangle strips in it.
|
||
|
*/
|
||
|
Start_Edge_Struct(num_vert);
|
||
|
Find_Adjacencies(face_id);
|
||
|
if (quads)
|
||
|
{
|
||
|
Init_Table_SGI();
|
||
|
Build_SGI_Table(num_vert,face_id);
|
||
|
/* Code for lengths of walks in each direction */
|
||
|
/* Save_Walks(face_id,TRUE); */
|
||
|
Save_Walks(face_id);
|
||
|
|
||
|
/* Code for finding the bands */
|
||
|
Find_Bands(face_id,bands,&swaps,&strips,&cost,&triangles,num_nvert,vert_norms,num_texture,vert_texture);
|
||
|
|
||
|
/*
|
||
|
Remove the faces that we did so that we can
|
||
|
run the strip code on the rest of the faces that are left
|
||
|
*/
|
||
|
if (cost != 0)
|
||
|
{
|
||
|
printf("Total %d triangles with %d cost\n",triangles,cost);
|
||
|
Save_Rest(&face_id);
|
||
|
printf("We saved %d .... now doing the local algorithm\n",face_id);
|
||
|
fprintf(bands,"\n#local\n");
|
||
|
End_Edge_Struct(num_vert);
|
||
|
Start_Edge_Struct(num_vert);
|
||
|
Find_Adjacencies(face_id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SGI_Strip(num_vert,face_id,bands,t,tr);
|
||
|
|
||
|
/* Get the total cost */
|
||
|
Output_TriEx(-1,-2,-3,NULL,-1,-20,cost);
|
||
|
|
||
|
End_Face_Struct(num_faces);
|
||
|
End_Edge_Struct(num_vert);
|
||
|
cost = 0;
|
||
|
face_id = 0;
|
||
|
quads = FALSE;
|
||
|
Start_Face_Struct(num_faces-face_id);
|
||
|
num_faces = num_faces - face_id;
|
||
|
Free_Strips();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Done reading in all the information into data structures */
|
||
|
num_faces = face_id;
|
||
|
fclose (file);
|
||
|
|
||
|
printf("Input Done.\n\n");
|
||
|
|
||
|
free(vertices);
|
||
|
free(nvertices);
|
||
|
|
||
|
printf ("Vertices: %d\nNormals: %d\nFaces: %d\n",num_vert,num_nvert,num_faces);
|
||
|
|
||
|
Start_Edge_Struct(num_vert);
|
||
|
Find_Adjacencies(num_faces);
|
||
|
|
||
|
/* Initialize it */
|
||
|
Init_Table_SGI();
|
||
|
/* Build it */
|
||
|
Build_SGI_Table(num_vert,num_faces);
|
||
|
|
||
|
InitStripTable();
|
||
|
|
||
|
if (quads) {
|
||
|
/* Code for lengths of walks in each direction */
|
||
|
/* Save_Walks(num_faces,TRUE); */
|
||
|
Save_Walks(num_faces);
|
||
|
|
||
|
/* Code for finding the bands */
|
||
|
Find_Bands(num_faces,bands,&swaps,&strips,&cost,&triangles,num_nvert,vert_norms,num_texture,vert_texture);
|
||
|
/*printf("Total %d triangles with %d cost\n",triangles,cost);*/
|
||
|
|
||
|
/*
|
||
|
Remove the faces that we did so that we can
|
||
|
run the strip code on the rest of the faces that are left
|
||
|
*/
|
||
|
Save_Rest(&num_faces);
|
||
|
/*printf("We saved %d .... now doing the local algorithm\n",num_faces);*/
|
||
|
fprintf(bands,"\n#local\n");
|
||
|
End_Edge_Struct(num_vert);
|
||
|
Start_Edge_Struct(num_vert);
|
||
|
Find_Adjacencies(num_faces);
|
||
|
}
|
||
|
|
||
|
SGI_Strip(num_vert,num_faces,bands,t,tr);
|
||
|
|
||
|
/* Get the total cost */
|
||
|
Output_TriEx(-1,-2,-3,NULL,-1,-20,cost);
|
||
|
|
||
|
End_Face_Struct(num_faces);
|
||
|
End_Edge_Struct(num_vert);
|
||
|
fclose(bands);
|
||
|
|
||
|
get_time();
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|