home *** CD-ROM | disk | FTP | other *** search
/ Virtual Reality Zone / VRZONE.ISO / mac / PC / REND386 / UTILS / SOCCER / SOCCER.C < prev    next >
Text File  |  1993-04-10  |  13KB  |  323 lines

  1.  
  2. /*    Soccer - generate a "soccer ball" .plg file for Rend386
  3.  
  4.     Written March 1993 by John T. Bell
  5.  
  6.     Syntax: soccer side out_hex_color out_pent_color do_inside
  7.             in_hex_color in_pent_color
  8.  
  9.     where the arguments are all optional and have the following default
  10.     values.  ( Note that arguments may only be left off of the end,
  11.     not from the beginning. )
  12.  
  13.     Parameter    Default        Meaning
  14.     =========    =======        =======
  15.     side        100        Length of a side joining two polys
  16.     out_hex_color    0x1FFF        Color of outer hexagons ( Base 16! )
  17.     out_pent_color    0x1E0F        Color of outer pentagons (  "   "  )
  18.     do_inside    not present    The inside of the soccer ball is
  19.                     generated if this argument has a value
  20.     in_hex_color    0x11FF        Color of inner hexagons ( Base 16! )
  21.     in_pent_color    0x1AFF        Color of inner pentagons (  "   "  )
  22.  
  23.     The original purpose in generating this program was to create a
  24.     faster sphere than the one I had previously, by generating a sphere
  25.     with the fewest possible number of vertices.  On my machine the 
  26.     soccer ball is rendered two and a half times faster than the sphere
  27.     which I started with, so on that score the program is a definite
  28.     success.  ( 30 frames / sec vs 12, "twirling", with neither sphere 
  29.     having an "inside" ).
  30.  
  31.     An additional beneficial side effect, is the creation of some pretty
  32.     neat spheres with the right combinations of surfaces and colors.
  33.     For example, try using a "glass" surface for the outer pentagons,
  34.     along with some contrasting inner colors.  Also, in the output
  35.     file, soccer.plg, the lines for an outer polygon and it's
  36.     corresponding inner mate are always adjacent lines, so by editing
  37.     the soccer.plg file and deleting a pair of lines you can create
  38.     a soccer ball with a "hole" in it.  Or if you just need a simple
  39.     sphere, use identical colors for outer hexagons and pentagons and
  40.     don't do the inside.
  41.  
  42.     There's not a whole lot of documentation here, for two reasons.
  43.     1. It's nearly impossible to document the trigonometry and geometry
  44.     without drawings of some kind, and 2. without documenting the trig,
  45.     there's really not much point in documenting anything else!  Most
  46.     of the documentation which is here was added to preserve my own
  47.     sanity while coding.  One point to note:  Whenever some of the
  48.     vertices of a polygon are already known, the remaining vertices
  49.     are calculated by reflection through the polygons center.  This
  50.     is straightforward for hexagons, but requires factored steps for
  51.     pentagons ( factors determined via trig. )
  52. */
  53.  
  54. #include <stdlib.h>
  55. #include <stdio.h>
  56. #include <math.h>
  57.  
  58. #define NVERTEX    60
  59. #define NPOLY    64
  60.  
  61. main( int argc, char *argv[] ) {
  62.  
  63.     double s = 100.0, r_p, theta, theta_p, R, h;
  64.     double centerx, centery, centerz, factor, factor2, yfactor;
  65.     double centerx2, centerz2;
  66.  
  67.     int inhex = 0x11FF, inpent = 0x1AFF, outhex = 0x1FFF, outpent = 0x1E0F,
  68.         do_inside = 0, i;
  69.  
  70.     FILE *outfile;
  71.  
  72.     struct vertex { double x, y, z; } vertices[ NVERTEX ];
  73.  
  74.     inhex  = 0x11FF;
  75.     inpent = 0x1AFF;
  76.     outhex = 0x1FFF;
  77.     outpent = 0x1E0F;
  78.  
  79.     outfile = fopen( "soccer.plg", "w" );
  80.  
  81.     if( argc > 1 ) s = atoi( argv[ 1 ] );
  82.     if( argc > 2 ) sscanf( argv[ 2 ], "%x", &outhex );
  83.     if( argc > 3 ) sscanf( argv[ 3 ], "%x", &outpent );
  84.     if( argc > 4 ) do_inside = 1;
  85.     if( argc > 5 ) sscanf( argv[ 5 ], "%x", &inhex );
  86.     if( argc > 6 ) sscanf( argv[ 6 ], "%x", &inpent );
  87.  
  88.     if( do_inside )
  89.         fprintf( outfile, "soccer    %d    %d\n", NVERTEX, NPOLY );
  90.     else
  91.         fprintf( outfile, "soccer    %d    %d\n", NVERTEX, NPOLY / 2 );
  92.  
  93.     theta_p = 0.4 * M_PI;    /* Angle of arc of a section of a pentagon */
  94.     r_p = s / sqrt( 2 - 2 * cos( theta_p ) ); /* pent radius, given side */
  95.  
  96.     /* The base is a pentagon.  Start with the five base vertices */
  97.  
  98.     for( i = 0, theta = 0.0; i < 5; i++, theta += theta_p ) {
  99.         vertices[ i ].x = r_p * cos( theta );
  100.         vertices[ i ].y = 0.0;
  101.         vertices[ i ].z = r_p * sin( theta );
  102.     }
  103.  
  104.     /* Then five more at height h and radius R.  These are at the 
  105.        mid-points of the first set of hexagons. */
  106.  
  107.     R = 2 * r_p;
  108.     h = sqrt( s * s - r_p * r_p );
  109.     for( i = 0, theta = 0.0; i < 5; i++, theta += theta_p ) {
  110.         vertices[ i + 5 ].x = R * cos( theta );
  111.         vertices[ i + 5 ].y = h;
  112.         vertices[ i + 5 ].z = R * sin( theta );
  113.     }
  114.  
  115.     /* The next level is at the top of the first hexagons.
  116.        Vertices are determined by reflection through the hex center */
  117.     
  118.     h *= 2;
  119.     for( i = 0; i < 5; i++ ) {
  120.         vertices[ 10 + i * 2 ].y = vertices[ 11 + i * 2 ].y = h;
  121.         centerx = vertices[ i + 5 ].x + vertices[ ( i + 1 ) % 5 + 5 ].x;
  122.         centerz = vertices[ i + 5 ].z + vertices[ ( i + 1 ) % 5 + 5 ].z;
  123.         vertices[ 10 + i * 2 ].x = centerx - vertices[ ( i + 1 ) % 5 ].x;
  124.         vertices[ 10 + i * 2 ].z = centerz - vertices[ ( i + 1 ) % 5 ].z;
  125.         vertices[ 11 + i * 2 ].x = centerx - vertices[ i ].x;
  126.         vertices[ 11 + i * 2 ].z = centerz - vertices[ i ].z;
  127.     }
  128.  
  129.     /* The next level is the top ( bottom? ) of inverted pentagons.
  130.        Three vertices are known, and the remaining two must be
  131.        calculated by reflection.  Half the work is finding the center. */
  132.  
  133.     factor = r_p / ( s * cos( ( M_PI - theta_p ) / 2 ) );
  134.     factor2 = 1 / sin( ( M_PI - theta_p ) / 2 );
  135.  
  136.     yfactor = ( r_p + sqrt( r_p * r_p - ( s / 2 ) * ( s / 2 ) ) ) 
  137.            / ( s * cos( ( M_PI - theta_p ) / 2 ) );
  138.     h = vertices[ 5 ].y + ( vertices[ 10 ].y - vertices[ 5 ].y ) * yfactor;
  139.     for ( i = 0; i < 5; i++ ) {
  140.  
  141.         vertices[ 20 + i * 2 ].y = vertices[ 21 + i * 2 ].y = h;
  142.  
  143.         /* First find the center of the chord connecting the two 
  144.            non-adjacent vertices */
  145.         centerx = ( vertices[ 10 + 2 * i ].x + 
  146.             vertices[ 10 + ( 9 + 2 * i ) % 10 ].x ) / 2.0;
  147.         centerz = ( vertices[ 10 + 2 * i ].z + 
  148.             vertices[ 10 + ( 9 + 2 * i ) % 10 ].z ) / 2.0;
  149.  
  150.         /* Then the center of the pentagon is a factored step from 
  151.         the remaining known vertex through the bisector center 
  152.         just found */
  153.         centerx = vertices[ 5 + i ].x + 
  154.         ( centerx - vertices[ 5 + i ].x ) * factor;
  155.         centerz = vertices[ 5 + i ].z + 
  156.         ( centerz - vertices[ 5 + i ].z ) * factor;
  157.  
  158.         /* Finally step from a bisection point connecting two
  159.         adjacent known vertices through the pentagon center */
  160.  
  161.         vertices[ 20 + i * 2 ].x = centerx + ( centerx - 
  162.         ( vertices[ 5 + i ].x + vertices[ 10 + 2 * i ].x ) / 2 )
  163.         * factor2;
  164.         vertices[ 20 + i * 2 ].z = centerz + ( centerz - 
  165.         ( vertices[ 5 + i ].z + vertices[ 10 + 2 * i ].z ) / 2 )
  166.         * factor2;
  167.  
  168.         vertices[ 21 + i * 2 ].x = centerx + ( centerx - 
  169.         ( vertices[ 5 + i ].x + vertices[ 10 + ( 9 + 2 * i ) % 10 ].x )
  170.         / 2 ) * factor2;
  171.         vertices[ 21 + i * 2 ].z = centerz + ( centerz - 
  172.         ( vertices[ 5 + i ].z + vertices[ 10 + ( 9 + 2 * i ) % 10 ].z )
  173.         / 2 ) * factor2;
  174.  
  175.     } /* End of for loop for inverted pentagons. Whew! */
  176.  
  177.     /* Now for some more hexagons.  Invert through centers again. */
  178.  
  179.     h = 2.0 * vertices[ 20 ].y - vertices[ 10 ].y;
  180.     for( i = 0; i < 5; i++ ) {
  181.         vertices[ 30 + i * 2 ].y = vertices[ 31 + i * 2 ].y = h;
  182.         centerx = vertices[ 21 + 2 * i ].x 
  183.             + vertices[ 20 + ( i + 1 ) * 2 % 10 ].x;
  184.         centerz = vertices[ 21 + 2 * i ].z 
  185.             + vertices[ 20 + ( i + 1 ) * 2 % 10 ].z;
  186.         vertices[ 30 + i * 2 ].x = centerx - vertices[ 11 + i * 2 ].x;
  187.         vertices[ 30 + i * 2 ].z = centerz - vertices[ 11 + i * 2 ].z;
  188.         vertices[ 31 + i * 2 ].x = centerx - vertices[ 10 + i * 2 ].x;
  189.         vertices[ 31 + i * 2 ].z = centerz - vertices[ 10 + i * 2 ].z;
  190.  
  191.     } /* End of loop calculating second batch of hexagons */
  192.  
  193.     /* Now for the third row of hexagons.  Invert through centers again. */
  194.  
  195.     h = 2.0 * vertices[ 30 ].y - vertices[ 20 ].y;
  196.     for( i = 0; i < 5; i++ ) {
  197.         vertices[ 40 + i * 2 ].y = vertices[ 41 + i * 2 ].y = h;
  198.         centerx = vertices[ 30 + 2 * i ].x 
  199.             + vertices[ 30 + ( 9 + i * 2 ) % 10 ].x;
  200.         centerz = vertices[ 30 + 2 * i ].z 
  201.             + vertices[ 30 + ( 9 + i * 2 ) % 10 ].z;
  202.         vertices[ 40 + i * 2 ].x = centerx - vertices[ 21 + i * 2 ].x;
  203.         vertices[ 40 + i * 2 ].z = centerz - vertices[ 21 + i * 2 ].z;
  204.         vertices[ 41 + i * 2 ].x = centerx - vertices[ 20 + i * 2 ].x;
  205.         vertices[ 41 + i * 2 ].z = centerz - vertices[ 20 + i * 2 ].z;
  206.  
  207.     } /* End of loop calculating third batch of hexagons */
  208.  
  209.     /* Now for a row of pentagons right side up. Four vertices are
  210.        already known, so this is a ( relatively ) simple factored
  211.        step from one chord bisector through another. */
  212.  
  213.     factor = s * cos( ( M_PI - theta_p ) / 2 ) 
  214.          / ( r_p + sqrt( r_p * r_p - s * s / 4 ) 
  215.          - s * cos( ( M_PI - theta_p ) / 2 ) );
  216.     h = vertices[ 40 ].y + ( vertices[ 40 ].y - vertices[ 30 ].y ) * factor;
  217.  
  218.     for( i = 0; i < 5; i++ ) {
  219.         vertices[ 50 + i ].y = h;
  220.         centerx = ( vertices[ 41 + 2 * i ].x 
  221.               + vertices[ 40 + ( 2 * i + 2 ) % 10 ].x ) / 2;
  222.         centerx2 = ( vertices[ 30 + i * 2 ].x 
  223.              + vertices[ 31 + i * 2 ].x ) / 2;
  224.         vertices[ 50 + i ].x = centerx + ( centerx - centerx2 ) * factor;
  225.         centerz = ( vertices[ 41 + 2 * i ].z 
  226.               + vertices[ 40 + ( 2 * i + 2 ) % 10 ].z ) / 2;
  227.         centerz2 = ( vertices[ 30 + i * 2 ].z 
  228.              + vertices[ 31 + i * 2 ].z ) / 2;
  229.         vertices[ 50 + i ].z = centerz + ( centerz - centerz2 ) * factor;
  230.     } /* End of loop for right side up pentagons */
  231.  
  232.     /* Finally the five base vertices on the top.  This is another
  233.        simple pentagon like the base, but offset by half a pent segment. */
  234.  
  235.     h = 2 * vertices[ 50 ].y - vertices[ 40 ].y;
  236.     for( i = 0, theta = theta_p / 2; i < 5; i++, theta += theta_p ) {
  237.         vertices[ 55 + i ].x = r_p * cos( theta );
  238.         vertices[ 55 + i ].y = h;
  239.         vertices[ 55 + i ].z = r_p * sin( theta );
  240.     }
  241.  
  242.     for( i = 0; i < NVERTEX; i++ )
  243.         fprintf( outfile, "%20.5g %20.5g %20.5g\n", 
  244.         vertices[ i ].x, vertices[ i ].y, vertices[ i ].z );
  245.  
  246. /*    End of calculating vertices.  Now on to polygons */
  247.  
  248.     /* Base is a pentagon */
  249.     fprintf( outfile, "0x%X    5    0 4 3 2 1\n", outpent );
  250.     if( do_inside ) fprintf( outfile, "0x%X    5    0 1 2 3 4\n", inpent );
  251.  
  252.     /* First row of hexagons */
  253.     for( i = 0; i < 5; i++ ) {
  254.         fprintf( outfile, "0x%X    6    %5d %5d %5d %5d %5d %5d\n",
  255.         outhex, i, ( i + 1 ) % 5, 5 + ( i + 1 ) % 5, 11 + 2 * i,
  256.         10 + 2 * i, 5 + i );
  257.         if( do_inside )
  258.           fprintf( outfile, "0x%X    6    %5d %5d %5d %5d %5d %5d\n",
  259.         inhex, 5 + i, 10 + 2 * i, 11 + 2 * i, 5 + ( i + 1 ) % 5,
  260.         ( i + 1 ) % 5, i );
  261.     }
  262.  
  263.     /* Row of inverted pentagons */
  264.     for( i = 0; i < 5; i++ ) {
  265.         fprintf( outfile, "0x%X    5    %5d %5d %5d %5d %5d\n",
  266.         outpent, 10 + 2 * i, 21 + 2 * i, 20 + 2 * i, 
  267.         10 + ( 9 + 2 * i ) % 10, 5 + i );
  268.         if( do_inside )
  269.           fprintf( outfile, "0x%X    5    %5d %5d %5d %5d %5d\n",
  270.         inpent, 5 + i, 10 + ( 9 + 2 * i ) % 10, 20 + 2 * i, 
  271.         21 + 2 * i, 10 + 2 * i );
  272.     }
  273.  
  274.     /* Second row of hexagons */
  275.     for( i = 0; i < 5; i++ ) {
  276.         fprintf( outfile, "0x%X    6    %5d %5d %5d %5d %5d %5d\n",
  277.         outhex, 11 +  2 * i, 20 + ( i + 1 ) * 2 % 10, 31 +  2 * i, 
  278.         30 +  2 * i, 21 + 2 * i, 10 +  2 * i );
  279.         if( do_inside )
  280.           fprintf( outfile, "0x%X    6    %5d %5d %5d %5d %5d %5d\n",
  281.         inhex, 10 +  2 * i, 21 + 2 * i, 30 +  2 * i, 31 +  2 * i,
  282.         20 + ( i + 1 ) * 2 % 10, 11 +  2 * i );  
  283.     }
  284.  
  285.     /* Third row of hexagons */
  286.     for( i = 0; i < 5; i++ ) {
  287.         fprintf( outfile, "0x%X    6    %5d %5d %5d %5d %5d %5d\n",
  288.         outhex, 21 +  2 * i, 30 + i * 2, 41 +  2 * i, 
  289.         40 +  2 * i, 30 + ( 9 + 2 * i ) % 10, 20 +  2 * i );
  290.         if( do_inside )
  291.           fprintf( outfile, "0x%X    6    %5d %5d %5d %5d %5d %5d\n",
  292.         inhex, 20 +  2 * i, 30 + ( 9 + 2 * i ) % 10, 40 +  2 * i, 
  293.         41 +  2 * i, 30 + i * 2, 21 +  2 * i );  
  294.     }
  295.  
  296.     /* Right side up pentagons */
  297.     for( i = 0; i < 5; i++ ) {
  298.         fprintf( outfile, "0x%X    5    %5d %5d %5d %5d %5d\n",
  299.         outpent, 30 + i * 2, 31 + i * 2, 40 + ( 2 + i * 2 ) % 10, 
  300.         50 + i, 41 + 2 * i );
  301.         if( do_inside )
  302.           fprintf( outfile, "0x%X    5    %5d %5d %5d %5d %5d\n",
  303.         inpent, 41 + 2 * i, 50 + i, 40 + ( i * 2 + 2 ) % 10,
  304.         31 + i * 2, 30 + i * 2 );
  305.     }
  306.  
  307.     /* Last row of hexagons */
  308.     for( i = 0; i < 5; i++ ) {
  309.         fprintf( outfile, "0x%X    6    %5d %5d %5d %5d %5d %5d\n",
  310.         outhex, 40 + i * 2, 41 + i * 2, 50 + i, 55 + i,
  311.         55 + ( i + 4 ) % 5, 50 + ( i + 4 ) % 5 );
  312.         if( do_inside )
  313.           fprintf( outfile, "0x%X    6    %5d %5d %5d %5d %5d %5d\n",
  314.         inhex, 50 + ( i + 4 ) % 5, 55 + ( i + 4 ) % 5, 55 + i,
  315.         50 + i, 41 + i * 2, 40 + i * 2 );
  316.     }
  317.  
  318.     /* And finally the top */
  319.     fprintf( outfile, "0x%X    5    55 56 57 58 59\n", outpent );
  320.     if( do_inside )
  321.         fprintf( outfile, "0x%X    5    59 58 57 56 55\n", inpent );
  322. }
  323.