home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Virtual Reality Zone
/
VRZONE.ISO
/
mac
/
PC
/
REND386
/
UTILS
/
SOCCER
/
SOCCER.C
< prev
next >
Wrap
Text File
|
1993-04-10
|
13KB
|
323 lines
/* Soccer - generate a "soccer ball" .plg file for Rend386
Written March 1993 by John T. Bell
Syntax: soccer side out_hex_color out_pent_color do_inside
in_hex_color in_pent_color
where the arguments are all optional and have the following default
values. ( Note that arguments may only be left off of the end,
not from the beginning. )
Parameter Default Meaning
========= ======= =======
side 100 Length of a side joining two polys
out_hex_color 0x1FFF Color of outer hexagons ( Base 16! )
out_pent_color 0x1E0F Color of outer pentagons ( " " )
do_inside not present The inside of the soccer ball is
generated if this argument has a value
in_hex_color 0x11FF Color of inner hexagons ( Base 16! )
in_pent_color 0x1AFF Color of inner pentagons ( " " )
The original purpose in generating this program was to create a
faster sphere than the one I had previously, by generating a sphere
with the fewest possible number of vertices. On my machine the
soccer ball is rendered two and a half times faster than the sphere
which I started with, so on that score the program is a definite
success. ( 30 frames / sec vs 12, "twirling", with neither sphere
having an "inside" ).
An additional beneficial side effect, is the creation of some pretty
neat spheres with the right combinations of surfaces and colors.
For example, try using a "glass" surface for the outer pentagons,
along with some contrasting inner colors. Also, in the output
file, soccer.plg, the lines for an outer polygon and it's
corresponding inner mate are always adjacent lines, so by editing
the soccer.plg file and deleting a pair of lines you can create
a soccer ball with a "hole" in it. Or if you just need a simple
sphere, use identical colors for outer hexagons and pentagons and
don't do the inside.
There's not a whole lot of documentation here, for two reasons.
1. It's nearly impossible to document the trigonometry and geometry
without drawings of some kind, and 2. without documenting the trig,
there's really not much point in documenting anything else! Most
of the documentation which is here was added to preserve my own
sanity while coding. One point to note: Whenever some of the
vertices of a polygon are already known, the remaining vertices
are calculated by reflection through the polygons center. This
is straightforward for hexagons, but requires factored steps for
pentagons ( factors determined via trig. )
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#define NVERTEX 60
#define NPOLY 64
main( int argc, char *argv[] ) {
double s = 100.0, r_p, theta, theta_p, R, h;
double centerx, centery, centerz, factor, factor2, yfactor;
double centerx2, centerz2;
int inhex = 0x11FF, inpent = 0x1AFF, outhex = 0x1FFF, outpent = 0x1E0F,
do_inside = 0, i;
FILE *outfile;
struct vertex { double x, y, z; } vertices[ NVERTEX ];
inhex = 0x11FF;
inpent = 0x1AFF;
outhex = 0x1FFF;
outpent = 0x1E0F;
outfile = fopen( "soccer.plg", "w" );
if( argc > 1 ) s = atoi( argv[ 1 ] );
if( argc > 2 ) sscanf( argv[ 2 ], "%x", &outhex );
if( argc > 3 ) sscanf( argv[ 3 ], "%x", &outpent );
if( argc > 4 ) do_inside = 1;
if( argc > 5 ) sscanf( argv[ 5 ], "%x", &inhex );
if( argc > 6 ) sscanf( argv[ 6 ], "%x", &inpent );
if( do_inside )
fprintf( outfile, "soccer %d %d\n", NVERTEX, NPOLY );
else
fprintf( outfile, "soccer %d %d\n", NVERTEX, NPOLY / 2 );
theta_p = 0.4 * M_PI; /* Angle of arc of a section of a pentagon */
r_p = s / sqrt( 2 - 2 * cos( theta_p ) ); /* pent radius, given side */
/* The base is a pentagon. Start with the five base vertices */
for( i = 0, theta = 0.0; i < 5; i++, theta += theta_p ) {
vertices[ i ].x = r_p * cos( theta );
vertices[ i ].y = 0.0;
vertices[ i ].z = r_p * sin( theta );
}
/* Then five more at height h and radius R. These are at the
mid-points of the first set of hexagons. */
R = 2 * r_p;
h = sqrt( s * s - r_p * r_p );
for( i = 0, theta = 0.0; i < 5; i++, theta += theta_p ) {
vertices[ i + 5 ].x = R * cos( theta );
vertices[ i + 5 ].y = h;
vertices[ i + 5 ].z = R * sin( theta );
}
/* The next level is at the top of the first hexagons.
Vertices are determined by reflection through the hex center */
h *= 2;
for( i = 0; i < 5; i++ ) {
vertices[ 10 + i * 2 ].y = vertices[ 11 + i * 2 ].y = h;
centerx = vertices[ i + 5 ].x + vertices[ ( i + 1 ) % 5 + 5 ].x;
centerz = vertices[ i + 5 ].z + vertices[ ( i + 1 ) % 5 + 5 ].z;
vertices[ 10 + i * 2 ].x = centerx - vertices[ ( i + 1 ) % 5 ].x;
vertices[ 10 + i * 2 ].z = centerz - vertices[ ( i + 1 ) % 5 ].z;
vertices[ 11 + i * 2 ].x = centerx - vertices[ i ].x;
vertices[ 11 + i * 2 ].z = centerz - vertices[ i ].z;
}
/* The next level is the top ( bottom? ) of inverted pentagons.
Three vertices are known, and the remaining two must be
calculated by reflection. Half the work is finding the center. */
factor = r_p / ( s * cos( ( M_PI - theta_p ) / 2 ) );
factor2 = 1 / sin( ( M_PI - theta_p ) / 2 );
yfactor = ( r_p + sqrt( r_p * r_p - ( s / 2 ) * ( s / 2 ) ) )
/ ( s * cos( ( M_PI - theta_p ) / 2 ) );
h = vertices[ 5 ].y + ( vertices[ 10 ].y - vertices[ 5 ].y ) * yfactor;
for ( i = 0; i < 5; i++ ) {
vertices[ 20 + i * 2 ].y = vertices[ 21 + i * 2 ].y = h;
/* First find the center of the chord connecting the two
non-adjacent vertices */
centerx = ( vertices[ 10 + 2 * i ].x +
vertices[ 10 + ( 9 + 2 * i ) % 10 ].x ) / 2.0;
centerz = ( vertices[ 10 + 2 * i ].z +
vertices[ 10 + ( 9 + 2 * i ) % 10 ].z ) / 2.0;
/* Then the center of the pentagon is a factored step from
the remaining known vertex through the bisector center
just found */
centerx = vertices[ 5 + i ].x +
( centerx - vertices[ 5 + i ].x ) * factor;
centerz = vertices[ 5 + i ].z +
( centerz - vertices[ 5 + i ].z ) * factor;
/* Finally step from a bisection point connecting two
adjacent known vertices through the pentagon center */
vertices[ 20 + i * 2 ].x = centerx + ( centerx -
( vertices[ 5 + i ].x + vertices[ 10 + 2 * i ].x ) / 2 )
* factor2;
vertices[ 20 + i * 2 ].z = centerz + ( centerz -
( vertices[ 5 + i ].z + vertices[ 10 + 2 * i ].z ) / 2 )
* factor2;
vertices[ 21 + i * 2 ].x = centerx + ( centerx -
( vertices[ 5 + i ].x + vertices[ 10 + ( 9 + 2 * i ) % 10 ].x )
/ 2 ) * factor2;
vertices[ 21 + i * 2 ].z = centerz + ( centerz -
( vertices[ 5 + i ].z + vertices[ 10 + ( 9 + 2 * i ) % 10 ].z )
/ 2 ) * factor2;
} /* End of for loop for inverted pentagons. Whew! */
/* Now for some more hexagons. Invert through centers again. */
h = 2.0 * vertices[ 20 ].y - vertices[ 10 ].y;
for( i = 0; i < 5; i++ ) {
vertices[ 30 + i * 2 ].y = vertices[ 31 + i * 2 ].y = h;
centerx = vertices[ 21 + 2 * i ].x
+ vertices[ 20 + ( i + 1 ) * 2 % 10 ].x;
centerz = vertices[ 21 + 2 * i ].z
+ vertices[ 20 + ( i + 1 ) * 2 % 10 ].z;
vertices[ 30 + i * 2 ].x = centerx - vertices[ 11 + i * 2 ].x;
vertices[ 30 + i * 2 ].z = centerz - vertices[ 11 + i * 2 ].z;
vertices[ 31 + i * 2 ].x = centerx - vertices[ 10 + i * 2 ].x;
vertices[ 31 + i * 2 ].z = centerz - vertices[ 10 + i * 2 ].z;
} /* End of loop calculating second batch of hexagons */
/* Now for the third row of hexagons. Invert through centers again. */
h = 2.0 * vertices[ 30 ].y - vertices[ 20 ].y;
for( i = 0; i < 5; i++ ) {
vertices[ 40 + i * 2 ].y = vertices[ 41 + i * 2 ].y = h;
centerx = vertices[ 30 + 2 * i ].x
+ vertices[ 30 + ( 9 + i * 2 ) % 10 ].x;
centerz = vertices[ 30 + 2 * i ].z
+ vertices[ 30 + ( 9 + i * 2 ) % 10 ].z;
vertices[ 40 + i * 2 ].x = centerx - vertices[ 21 + i * 2 ].x;
vertices[ 40 + i * 2 ].z = centerz - vertices[ 21 + i * 2 ].z;
vertices[ 41 + i * 2 ].x = centerx - vertices[ 20 + i * 2 ].x;
vertices[ 41 + i * 2 ].z = centerz - vertices[ 20 + i * 2 ].z;
} /* End of loop calculating third batch of hexagons */
/* Now for a row of pentagons right side up. Four vertices are
already known, so this is a ( relatively ) simple factored
step from one chord bisector through another. */
factor = s * cos( ( M_PI - theta_p ) / 2 )
/ ( r_p + sqrt( r_p * r_p - s * s / 4 )
- s * cos( ( M_PI - theta_p ) / 2 ) );
h = vertices[ 40 ].y + ( vertices[ 40 ].y - vertices[ 30 ].y ) * factor;
for( i = 0; i < 5; i++ ) {
vertices[ 50 + i ].y = h;
centerx = ( vertices[ 41 + 2 * i ].x
+ vertices[ 40 + ( 2 * i + 2 ) % 10 ].x ) / 2;
centerx2 = ( vertices[ 30 + i * 2 ].x
+ vertices[ 31 + i * 2 ].x ) / 2;
vertices[ 50 + i ].x = centerx + ( centerx - centerx2 ) * factor;
centerz = ( vertices[ 41 + 2 * i ].z
+ vertices[ 40 + ( 2 * i + 2 ) % 10 ].z ) / 2;
centerz2 = ( vertices[ 30 + i * 2 ].z
+ vertices[ 31 + i * 2 ].z ) / 2;
vertices[ 50 + i ].z = centerz + ( centerz - centerz2 ) * factor;
} /* End of loop for right side up pentagons */
/* Finally the five base vertices on the top. This is another
simple pentagon like the base, but offset by half a pent segment. */
h = 2 * vertices[ 50 ].y - vertices[ 40 ].y;
for( i = 0, theta = theta_p / 2; i < 5; i++, theta += theta_p ) {
vertices[ 55 + i ].x = r_p * cos( theta );
vertices[ 55 + i ].y = h;
vertices[ 55 + i ].z = r_p * sin( theta );
}
for( i = 0; i < NVERTEX; i++ )
fprintf( outfile, "%20.5g %20.5g %20.5g\n",
vertices[ i ].x, vertices[ i ].y, vertices[ i ].z );
/* End of calculating vertices. Now on to polygons */
/* Base is a pentagon */
fprintf( outfile, "0x%X 5 0 4 3 2 1\n", outpent );
if( do_inside ) fprintf( outfile, "0x%X 5 0 1 2 3 4\n", inpent );
/* First row of hexagons */
for( i = 0; i < 5; i++ ) {
fprintf( outfile, "0x%X 6 %5d %5d %5d %5d %5d %5d\n",
outhex, i, ( i + 1 ) % 5, 5 + ( i + 1 ) % 5, 11 + 2 * i,
10 + 2 * i, 5 + i );
if( do_inside )
fprintf( outfile, "0x%X 6 %5d %5d %5d %5d %5d %5d\n",
inhex, 5 + i, 10 + 2 * i, 11 + 2 * i, 5 + ( i + 1 ) % 5,
( i + 1 ) % 5, i );
}
/* Row of inverted pentagons */
for( i = 0; i < 5; i++ ) {
fprintf( outfile, "0x%X 5 %5d %5d %5d %5d %5d\n",
outpent, 10 + 2 * i, 21 + 2 * i, 20 + 2 * i,
10 + ( 9 + 2 * i ) % 10, 5 + i );
if( do_inside )
fprintf( outfile, "0x%X 5 %5d %5d %5d %5d %5d\n",
inpent, 5 + i, 10 + ( 9 + 2 * i ) % 10, 20 + 2 * i,
21 + 2 * i, 10 + 2 * i );
}
/* Second row of hexagons */
for( i = 0; i < 5; i++ ) {
fprintf( outfile, "0x%X 6 %5d %5d %5d %5d %5d %5d\n",
outhex, 11 + 2 * i, 20 + ( i + 1 ) * 2 % 10, 31 + 2 * i,
30 + 2 * i, 21 + 2 * i, 10 + 2 * i );
if( do_inside )
fprintf( outfile, "0x%X 6 %5d %5d %5d %5d %5d %5d\n",
inhex, 10 + 2 * i, 21 + 2 * i, 30 + 2 * i, 31 + 2 * i,
20 + ( i + 1 ) * 2 % 10, 11 + 2 * i );
}
/* Third row of hexagons */
for( i = 0; i < 5; i++ ) {
fprintf( outfile, "0x%X 6 %5d %5d %5d %5d %5d %5d\n",
outhex, 21 + 2 * i, 30 + i * 2, 41 + 2 * i,
40 + 2 * i, 30 + ( 9 + 2 * i ) % 10, 20 + 2 * i );
if( do_inside )
fprintf( outfile, "0x%X 6 %5d %5d %5d %5d %5d %5d\n",
inhex, 20 + 2 * i, 30 + ( 9 + 2 * i ) % 10, 40 + 2 * i,
41 + 2 * i, 30 + i * 2, 21 + 2 * i );
}
/* Right side up pentagons */
for( i = 0; i < 5; i++ ) {
fprintf( outfile, "0x%X 5 %5d %5d %5d %5d %5d\n",
outpent, 30 + i * 2, 31 + i * 2, 40 + ( 2 + i * 2 ) % 10,
50 + i, 41 + 2 * i );
if( do_inside )
fprintf( outfile, "0x%X 5 %5d %5d %5d %5d %5d\n",
inpent, 41 + 2 * i, 50 + i, 40 + ( i * 2 + 2 ) % 10,
31 + i * 2, 30 + i * 2 );
}
/* Last row of hexagons */
for( i = 0; i < 5; i++ ) {
fprintf( outfile, "0x%X 6 %5d %5d %5d %5d %5d %5d\n",
outhex, 40 + i * 2, 41 + i * 2, 50 + i, 55 + i,
55 + ( i + 4 ) % 5, 50 + ( i + 4 ) % 5 );
if( do_inside )
fprintf( outfile, "0x%X 6 %5d %5d %5d %5d %5d %5d\n",
inhex, 50 + ( i + 4 ) % 5, 55 + ( i + 4 ) % 5, 55 + i,
50 + i, 41 + i * 2, 40 + i * 2 );
}
/* And finally the top */
fprintf( outfile, "0x%X 5 55 56 57 58 59\n", outpent );
if( do_inside )
fprintf( outfile, "0x%X 5 59 58 57 56 55\n", inpent );
}