Polygon to triangles
/*
* poly_tri.c
*
* Program to take a polygon definition and convert it into triangles
* that may then be rendered by the standard triangle rendering
* algorithms. This assumes all transformations have been performed
* already and cuts them up into optimal triangles based on their
* screen-space representation.
*
* Copyright (c) 1988, Evans & Sutherland Computer Corporation
*
* Permission to use all or part of this program without fee is
* granted provided that it is not used or distributed for direct
* commercial gain, the above copyright notice appears, and
* notice is given that use is by permission of Evans & Sutherland
* Computer Corporation.
*
* Written by Reid Judd and Scott R. Nelson at
* Evans & Sutherland Computer Corporation (January, 1988)
*
* To use this program, either write your own "draw_triangle" routine
* that can draw triangles from the definitions below, or modify the
* code to call your own triangle or polygon rendering code. Call
* "draw_poly" from your main program.
*/
#include
/* A single vertex */
typedef struct {
int color; /* RGB */
float x;
float y;
float z;
} vertex;
/* A triangle made up of three vertices */
typedef vertex triangle[3];
#define V_MAX 100 /* Maximum number of vertices allowed (arbitrary) */
#define BIG 1.0e30 /* A number bigger than we expect to find here */
#define COUNTER_CLOCKWISE 0
#define CLOCKWISE 1
/*
* orientation
*
* Return either clockwise or counter_clockwise for the orientation
* of the polygon.
*/
int orientation( n, v )
int n; /* Number of vertices */
vertex v[]; /* The vertex list */
{
float area;
int i;
/* Do the wrap-around first */
area = v[n-1].x * v[0].y - v[0].x * v[n-1].y;
/* Compute the area (times 2) of the polygon */
for (i = 0; i < n-1; i++)
area += v.x * v[i+1].y - v[i+1].x * v.y;
if (area >= 0.0)
return COUNTER_CLOCKWISE;
else
return CLOCKWISE;
} /* End of orientation */
/*
* determinant
*
* Computes the determinant of the three points.
* Returns whether the triangle is clockwise or counter-clockwise.
*/
int determinant( p1, p2, p3, v )
int p1, p2, p3; /* The vertices to consider */
vertex v[]; /* The vertex list */
{
float x1, x2, x3, y1, y2, y3;
float determ;
x1 = v[p1].x;
y1 = v[p1].y;
x2 = v[p2].x;
y2 = v[p2].y;
x3 = v[p3].x;
y3 = v[p3].y;
determ = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
if (determ >= 0.0)
return COUNTER_CLOCKWISE;
else
return CLOCKWISE;
} /* End of determinant */
/*
* distance2
*
* Returns the square of the distance between the two points
*/
float distance2( x1, y1, x2, y2 )
float x1, y1, x2, y2;
{
float xd, yd; /* The distances in X and Y */
float dist2; /* The square of the actual distance */
xd = x1 - x2;
yd = y1 - y2;
dist2 = xd * xd + yd * yd;
return dist2;
} /* End of distance2 */
/*
* no_interior
*
* Returns 1 if no other point in the vertex list is inside
* the triangle specified by the three points. Returns
* 0 otherwise.
*/
int no_interior( p1, p2, p3, v, vp, n, poly_or )
int p1, p2, p3; /* The vertices to consider */
vertex v[]; /* The vertex list */
int vp[]; /* The vertex pointers (which are left) */
int n; /* Number of vertices */
int poly_or; /* Polygon orientation */
{
int i; /* Iterative counter */
int p; /* The test point */
for (i = 0; i < n; i++) {
p = vp; /* The point to test */
if ((p == p1) || (p == p2) || (p == p3))
continue; /* Don't bother checking against yourself */
if ( (determinant( p2, p1, p, v ) == poly_or)
|| (determinant( p1, p3, p, v ) == poly_or)
|| (determinant( p3, p2, p, v ) == poly_or) ) {
continue; /* This point is outside */
} else {
return 0; /* The point is inside */
}
}
return 1; /* No points inside this triangle */
} /* End of no_interior */
/*
* draw_poly
*
* Call this procedure with a polygon, this divides it into triangles
* and calls the triangle routine once for each triangle.
*
* Note that this does not work for polygons with holes or self
* penetrations.
*/
draw_poly( n, v )
int n; /* Number of vertices in triangle */
vertex v[]; /* The vertex list (implicit closure) */
{
int prev, cur, next; /* Three points currently being considered */
int vp[V_MAX]; /* Pointers to vertices still left */
int count; /* How many vertices left */
int min_vert; /* Vertex with minimum distance */
int i; /* Iterative counter */
float dist; /* Distance across this one */
float min_dist; /* Minimum distance so far */
int poly_orientation; /* Polygon orientation */
triangle t; /* Triangle structure */
if (n > V_MAX) {
fprintf( stderr, "Error, more than %d vertices.\n", V_MAX);
return;
}
poly_orientation = orientation( n, v );
for (i = 0; i < n; i++)
vp = i; /* Put vertices in order to begin */
/* Slice off clean triangles until nothing remains */
count = n;
while (count > 3) {
min_dist = BIG; /* A real big number */
min_vert = 0; /* Just in case we don't find one... */
for (cur = 0; cur < count; cur++) {
prev = cur - 1;
next = cur + 1;
if (cur == 0) /* Wrap around on the ends */
prev = count - 1;
else if (cur == count - 1)
next = 0;
/* Pick out shortest distance that forms a good triangle */
if ( (determinant( vp[prev], vp[cur], vp[next], v ) == poly_orientation)
/* Same orientation as polygon */
&& no_interior( vp[prev], vp[cur], vp[next], v, vp, count, poly_orientation )
/* No points inside */
&& ((dist = distance2( v[vp[prev]].x, v[vp[prev]].y,
v[vp[next]].x, v[vp[next]].y )) < min_dist) )
/* Better than any so far */
{
min_dist = dist;
min_vert = cur;
}
} /* End of for each vertex (cur) */
/* The following error should "never happen". */
if (min_dist == BIG)
fprintf( stderr, "Error: Didn't find a triangle.\n" );
prev = min_vert - 1;
next = min_vert + 1;
if (min_vert == 0) /* Wrap around on the ends */
prev = count - 1;
else if (min_vert == count - 1)
next = 0;
/* Output this triangle */
t[0].x = v[vp[prev]].x;
t[0].y = v[vp[prev]].y;
t[0].z = v[vp[prev]].z;
t[0].color = v[vp[prev]].color;
t[1].x = v[vp[min_vert]].x;
t[1].y = v[vp[min_vert]].y;
t[1].z = v[vp[min_vert]].z;
t[1].color = v[vp[min_vert]].color;
t[2].x = v[vp[next]].x;
t[2].y = v[vp[next]].y;
t[2].z = v[vp[next]].z;
t[2].color = v[vp[next]].color;
draw_triangle( t );
/* Remove the triangle from the polygon */
count -= 1;
for (i = min_vert; i < count; i++)
vp = vp[i+1];
}
/* Output the final triangle */
t[0].x = v[vp[0]].x;
t[0].y = v[vp[0]].y;
t[0].z = v[vp[0]].z;
t[0].color = v[vp[0]].color;
t[1].x = v[vp[1]].x;
t[1].y = v[vp[1]].y;
t[1].z = v[vp[1]].z;
t[1].color = v[vp[1]].color;
t[2].x = v[vp[2]].x;
t[2].y = v[vp[2]].y;
t[2].z = v[vp[2]].z;
t[2].color = v[vp[2]].color;
draw_triangle( t );
} /* End of draw_poly */
/* End of poly_tri.c */
Related Tutorials
A Day As A Game Designer
The fabled game designer. The man, the myth, the legend behind the game. An inspiration to young creatives who wish to …
Kai Wüest
So You Want to be a Game Developer?
Battletech tools developer Chris Eck describes his journey and advice for getting a job in the industry.
A Quick Guide to Gamification and Gamification Careers
If you find yourself slightly stumped over the ever-growing buzz around gamification, and unsure whether there is any o…
Sophie Jackson
Raph Koster's Postmortems: Una Carrera
This excerpt from Raph Koster's Postmortems is an adaptation from a speech he delivered at GameDay Peru in early 2015. …
Raph Koster
Negotiating Sign-On Bonuses in the Games Industry
A quick blurb on signing bonuses in the games industry and how to approach asking for one.
A LinkedIn Profile for Job Hunting and Networking
Marc Mencher is founder and CEO of GameRecruiter and author of Get in the Game!, an instructional book on building a ca…
Discussion
More from Unknown Author
Comparing Shadow Mapping Techniques with Shadow Explorer
New Incentives and a Whole New Platform From The Intel AppUp developer program
The final installment in this series on Intel's AppUp program details additional incentives and opportunities for devel…
The Game Maker
This book excerpt contains the first chapter of the book that introduces beginning game developers to the Game Maker pr…
Discussion