home *** CD-ROM | disk | FTP | other *** search
/ Black Art of 3D Game Programming / Black_Art_of_3D_Game_Programming.iso / source / borland / chap_17 / black17.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-25  |  88.9 KB  |  3,126 lines

  1.  
  2. // I N C L U D E S ///////////////////////////////////////////////////////////
  3.  
  4. #include <io.h>
  5. #include <conio.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <dos.h>
  9. #include <bios.h>
  10. #include <fcntl.h>
  11. #include <memory.h>
  12. #include <malloc.h>
  13. #include <math.h>
  14. #include <string.h>
  15. #include <search.h>             // this one is needed for qsort()
  16.  
  17. // include all of our stuff
  18.  
  19. #include "black3.h"
  20. #include "black4.h"
  21. #include "black5.h"
  22. #include "black6.h"
  23. #include "black8.h"
  24. #include "black9.h"
  25. #include "black17.h"
  26.  
  27. // G L O B A L S //////////////////////////////////////////////////////////////
  28.  
  29. float  clip_near_z   = 100,       // the near or hither clipping plane
  30.        clip_far_z    = 3200,      // the far or yon clipping plane
  31.        screen_width  = 320,       // dimensions of the screen
  32.        screen_heigth = 200;
  33.  
  34. float viewing_distance = 200;     // distance of projection plane from camera
  35.  
  36. point_3d view_point  = {0,0,0,1}; // position of camera
  37.  
  38. vector_3d light_source = {-0.913913,0.389759,-0.113369}; // position of point light source
  39.  
  40. float ambient_light = 6;          // ambient light level
  41.  
  42. dir_3d view_angle = {0,0,0};      // angle of camera
  43.  
  44. matrix_4x4 global_view;           // the global inverse wortld to camera
  45.                                   // matrix
  46.  
  47. RGB_palette color_palette_3d;     // the color palette used for the 3D system
  48.  
  49. int num_objects;                  // number of objects in the world
  50.  
  51. object_ptr world_object_list[MAX_OBJECTS];  // the objects in the world
  52.  
  53. int num_polys_frame;                        // the number of polys in this frame
  54.  
  55. facet_ptr world_polys[MAX_POLYS_PER_FRAME]; // the visible polygons for this frame
  56.  
  57. facet world_poly_storage[MAX_POLYS_PER_FRAME];  // the storage for the visible
  58.                                                 // polygons is pre-allocated
  59.                                                 // so it doesn't need to be
  60.                                                 // allocated frame by frame
  61.  
  62. // look up tables
  63.  
  64. float sin_look[360+1],                          // SIN from 0 to 360
  65.       cos_look[360+1];                          // COSINE from 0 to 360
  66.  
  67. // the clipping region, set it to default on start up
  68.  
  69. int poly_clip_min_x = POLY_CLIP_MIN_X,          // the minimum boundaries
  70.     poly_clip_min_y = POLY_CLIP_MIN_Y,
  71.  
  72.     poly_clip_max_x = POLY_CLIP_MAX_X,          // the maximum boundaries
  73.     poly_clip_max_y = POLY_CLIP_MAX_Y;
  74.  
  75.  
  76. sprite textures;                                // this holds the textures
  77.  
  78. // F U N C T I O N S /////////////////////////////////////////////////////////
  79.  
  80. void Triangle_Line(unsigned char far *dest_addr,
  81.                    unsigned int xs,
  82.                    unsigned int xe,
  83.                    int color)
  84. {
  85.  
  86. // this function draws a fast horizontal line by using WORD size writes
  87. // the assembly language version is called  Triangle_16Line();
  88.  
  89.  
  90. // plot pixels at ends of line first
  91.  
  92. if (xs & 0x0001)
  93.    {
  94.    // plot a single starting pixel and move xs to an even boundary
  95.  
  96.    dest_addr[xs++] = (unsigned char)color;
  97.  
  98.    } // end if
  99.  
  100. if (!(xe & 0x0001))
  101.    {
  102.    // plot a single terminating pixel and move xe back to an odd boundary
  103.  
  104.    dest_addr[xe--] = (unsigned char)color;
  105.  
  106.    } // end if
  107.  
  108. // now plot the line
  109.  
  110. dest_addr+=xs;
  111.  
  112. // now blast the middle part of the line a WORD at a time, later use
  113. // an external assembly program to do it a DOUBLE WORD at a time!
  114.  
  115. _asm   {
  116.     les di,dest_addr      // point es:di at data area
  117.  
  118.     mov al,BYTE PTR color // move into al and ah the color
  119.     mov ah,al
  120.  
  121.     mov cx,xe             // compute number of words to move  (xe-xs+1)/2
  122.     sub cx,xs
  123.     inc cx
  124.     shr cx,1              //divide by 2
  125.  
  126.     rep stosw             // draw the line
  127.  
  128.     } // end asm
  129.  
  130. } // end Triangle_Line
  131.  
  132. ////////////////////////////////////////////////////////////////////////////////
  133.  
  134. void Triangle_QLine(unsigned char far *dest_addr,
  135.                     unsigned int xs,
  136.                     unsigned int xe,
  137.                     unsigned int color)
  138. {
  139. // this is the C version of the quad byte line renderer, not much faster than
  140. // the word version...not worth the extra complexity. the assembly language
  141. // version is called Triangle_32Line()
  142.  
  143. long length,
  144.      lcolor;
  145.  
  146. // test special cases
  147.  
  148. switch(xe-xs)
  149.       {
  150.       case 0:
  151.          {
  152.  
  153.          dest_addr[xs] = color;
  154.          return;
  155.  
  156.             } break;
  157.  
  158.       case 1:
  159.          {
  160.  
  161.          dest_addr[xs++] = color;
  162.          dest_addr[xs]   = color;
  163.          return;
  164.  
  165.          } break;
  166.  
  167.       case 2:
  168.          {
  169.  
  170.          dest_addr[xs++] = color;
  171.          dest_addr[xs++] = color;
  172.          dest_addr[xs]   = color;
  173.          return;
  174.  
  175.          } break;
  176.  
  177.       case 3:
  178.          {
  179.          dest_addr[xs++] = color;
  180.          dest_addr[xs++] = color;
  181.          dest_addr[xs++] = color;
  182.          dest_addr[xs]   = color;
  183.          return;
  184.  
  185.          } break;
  186.  
  187.       default:break;
  188.  
  189.       } // end switch
  190.  
  191. // line is longer than 4 pixels, so we can use algorithm
  192.  
  193. // process left side
  194.  
  195. switch(xs & 0x03)
  196.       {
  197.  
  198.       case 1:
  199.            {
  200.            dest_addr[xs++] = color;
  201.            dest_addr[xs++] = color;
  202.            dest_addr[xs++] = color;
  203.            } break;
  204.  
  205.       case 2:
  206.            {
  207.            dest_addr[xs++] = color;
  208.            dest_addr[xs++] = color;
  209.            } break;
  210.  
  211.       case 3:
  212.            {
  213.            dest_addr[xs++] = color;
  214.            } break;
  215.  
  216.  
  217.       default: break;
  218.  
  219.       } // end switch
  220.  
  221. // process right side
  222.  
  223. switch(xe & 0x03)
  224.       {
  225.  
  226.       case 0:
  227.            {
  228.            dest_addr[xe--] = color;
  229.            } break;
  230.  
  231.       case 1:
  232.            {
  233.            dest_addr[xe--] = color;
  234.            dest_addr[xe--] = color;
  235.            } break;
  236.  
  237.       case 2:
  238.            {
  239.  
  240.            dest_addr[xe--] = color;
  241.            dest_addr[xe--] = color;
  242.            dest_addr[xe--] = color;
  243.  
  244.            } break;
  245.  
  246.       default: break;
  247.  
  248.       } // end switch
  249.  
  250.  
  251. // draw the middle part of the line now using words
  252.  
  253. // now plot the line
  254.  
  255. dest_addr+=xs;
  256.  
  257. lcolor = (color << 8 | color);
  258. lcolor = (lcolor << 16 | lcolor);
  259. length = ((xe-xs+1) >> 2);
  260.  
  261. fquadset(dest_addr,lcolor,length);
  262.  
  263. } // end Triangle_QLine
  264.  
  265. //////////////////////////////////////////////////////////////////////////////
  266.  
  267. void Draw_Top_Triangle(int x1,int y1, int x2,int y2, int x3,int y3,int color)
  268. {
  269. // this function draws a triangle that has a flat top
  270.  
  271. float dx_right,    // the dx/dy ratio of the right edge of line
  272.       dx_left,     // the dx/dy ratio of the left edge of line
  273.       xs,xe,       // the starting and ending points of the edges
  274.       height;      // the height of the triangle
  275.  
  276. int temp_x,        // used during sorting as temps
  277.     temp_y,
  278.     right,         // used by clipping
  279.     left;
  280.  
  281. unsigned char far *dest_addr;
  282.  
  283. // test order of x1 and x2
  284.  
  285. if (x2 < x1)
  286.    {
  287.    temp_x = x2;
  288.    x2     = x1;
  289.    x1     = temp_x;
  290.  
  291.    } // end if swap
  292.  
  293. // compute delta's
  294.  
  295. height = y3-y1;
  296.  
  297. dx_left  = (x3-x1)/height;
  298. dx_right = (x3-x2)/height;
  299.  
  300. // set starting points
  301.  
  302. xs = (float)x1;
  303. xe = (float)x2+(float)0.5;
  304.  
  305. // perform y clipping
  306.  
  307. if (y1<poly_clip_min_y)
  308.    {
  309.    // compute new xs and ys
  310.  
  311.    xs = xs+dx_left*(float)(-y1+poly_clip_min_y);
  312.    xe = xe+dx_right*(float)(-y1+poly_clip_min_y);
  313.  
  314.    // reset y1
  315.  
  316.    y1=poly_clip_min_y;
  317.  
  318.    } // end if top is off screen
  319.  
  320. if (y3>poly_clip_max_y)
  321.    y3=poly_clip_max_y;
  322.  
  323.  
  324. // compute starting address in video memory
  325.  
  326. dest_addr = double_buffer+(y1<<8)+(y1<<6);
  327.  
  328. // test if x clipping is needed
  329.  
  330. if (x1>=poly_clip_min_x && x1<=poly_clip_max_x &&
  331.     x2>=poly_clip_min_x && x2<=poly_clip_max_x &&
  332.     x3>=poly_clip_min_x && x3<=poly_clip_max_x)
  333.     {
  334.     // draw the triangle
  335.  
  336. #if 0
  337.  
  338.      for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=320)
  339.           {
  340.  
  341.           Triangle_16Line(dest_addr,(unsigned int)xs,(unsigned int)xe,color);
  342.  
  343.           // adjust starting point and ending point
  344.  
  345.           xs+=dx_left;
  346.           xe+=dx_right;
  347.  
  348.           } // end for
  349.  
  350. #endif
  351.  
  352. #if 1
  353.  
  354.      // use the external assembly language triangle engine based on fixed point
  355.  
  356.      if (y3>y1)
  357.          Triangle_Asm(dest_addr,y1,y3,xs,xe,dx_left,dx_right,color);
  358.  
  359.  
  360. #endif
  361.  
  362.      } // end if no x clipping needed
  363. else
  364.     {
  365.     // clip x axis with slower version
  366.  
  367.     // draw the triangle
  368.  
  369.    for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=320)
  370.        {
  371.  
  372.        // do x clip
  373.  
  374.        left  = (int)xs;
  375.        right = (int)xe;
  376.  
  377.          // adjust starting point and ending point
  378.  
  379.          xs+=dx_left;
  380.        xe+=dx_right;
  381.  
  382.        // clip line
  383.  
  384.        if (left < poly_clip_min_x)
  385.           {
  386.           left = poly_clip_min_x;
  387.  
  388.           if (right < poly_clip_min_x)
  389.                  continue;
  390.  
  391.              }
  392.  
  393.        if (right > poly_clip_max_x)
  394.           {
  395.           right = poly_clip_max_x;
  396.  
  397.           if (left > poly_clip_max_x)
  398.              continue;
  399.  
  400.           }
  401.  
  402.           Triangle_16Line(dest_addr,(unsigned int)left,(unsigned int)right,color);
  403.  
  404.        } // end for
  405.  
  406.    } // end else x clipping needed
  407.  
  408. } // end Draw_Top_Triangle
  409.  
  410. /////////////////////////////////////////////////////////////////////////////
  411.  
  412. void Draw_Bottom_Triangle(int x1,int y1, int x2,int y2, int x3,int y3,int color)
  413. {
  414.  
  415. // this function draws a triangle that has a flat bottom
  416.  
  417. float dx_right,    // the dx/dy ratio of the right edge of line
  418.       dx_left,     // the dx/dy ratio of the left edge of line
  419.       xs,xe,       // the starting and ending points of the edges
  420.       height;      // the height of the triangle
  421.  
  422. int temp_x,        // used during sorting as temps
  423.     temp_y,
  424.     right,         // used by clipping
  425.     left;
  426.  
  427. unsigned char far *dest_addr;
  428.  
  429. // test order of x1 and x2
  430.  
  431. if (x3 < x2)
  432.    {
  433.    temp_x = x2;
  434.    x2     = x3;
  435.    x3     = temp_x;
  436.  
  437.    } // end if swap
  438.  
  439. // compute delta's
  440.  
  441. height = y3-y1;
  442.  
  443. dx_left  = (x2-x1)/height;
  444. dx_right = (x3-x1)/height;
  445.  
  446. // set starting points
  447.  
  448. xs = (float)x1;
  449. xe = (float)x1+(float)0.5;
  450.  
  451. // perform y clipping
  452.  
  453. if (y1<poly_clip_min_y)
  454.    {
  455.    // compute new xs and ys
  456.  
  457.    xs = xs+dx_left*(float)(-y1+poly_clip_min_y);
  458.    xe = xe+dx_right*(float)(-y1+poly_clip_min_y);
  459.  
  460.    // reset y1
  461.  
  462.     y1=poly_clip_min_y;
  463.  
  464.    } // end if top is off screen
  465.  
  466. if (y3>poly_clip_max_y)
  467.    y3=poly_clip_max_y;
  468.  
  469. // compute starting address in video memory
  470.  
  471. dest_addr = double_buffer+(y1<<8)+(y1<<6);
  472.  
  473. // test if x clipping is needed
  474.  
  475. if (x1>=poly_clip_min_x && x1<=poly_clip_max_x &&
  476.     x2>=poly_clip_min_x && x2<=poly_clip_max_x &&
  477.     x3>=poly_clip_min_x && x3<=poly_clip_max_x)
  478.     {
  479.     // draw the triangle
  480.  
  481.  
  482. #if 0
  483.  
  484.      for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=320)
  485.           {
  486.  
  487.           Triangle_16Line(dest_addr,(unsigned int)xs,(unsigned int)xe,color);
  488.  
  489.           // adjust starting point and ending point
  490.  
  491.           xs+=dx_left;
  492.           xe+=dx_right;
  493.  
  494.           } // end for
  495.  
  496. #endif
  497.  
  498. #if 1
  499.  
  500.      // use the external assembly language triangle engine based on fixed point
  501.  
  502.      if (y3>y1)
  503.         Triangle_Asm(dest_addr,y1,y3,xs,xe,dx_left,dx_right,color);
  504.  
  505. #endif
  506.  
  507.     } // end if no x clipping needed
  508. else
  509.    {
  510.    // clip x axis with slower version
  511.  
  512.    // draw the triangle
  513.  
  514.    for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=320)
  515.        {
  516.        // do x clip
  517.  
  518.        left  = (int)xs;
  519.        right = (int)xe;
  520.  
  521.        // adjust starting point and ending point
  522.  
  523.          xs+=dx_left;
  524.        xe+=dx_right;
  525.  
  526.        // clip line
  527.  
  528.        if (left < poly_clip_min_x)
  529.           {
  530.           left = poly_clip_min_x;
  531.  
  532.           if (right < poly_clip_min_x)
  533.              continue;
  534.  
  535.              }
  536.  
  537.        if (right > poly_clip_max_x)
  538.           {
  539.           right = poly_clip_max_x;
  540.  
  541.           if (left > poly_clip_max_x)
  542.              continue;
  543.           }
  544.  
  545.        Triangle_16Line(dest_addr,(unsigned int)left,(unsigned int)right,color);
  546.  
  547.          } // end for
  548.  
  549.    } // end else x clipping needed
  550.  
  551. } // end Draw_Bottom_Triangle
  552.  
  553. ///////////////////////////////////////////////////////////////////////////////
  554.  
  555. void Draw_Triangle_2D(int x1,int y1,
  556.                       int x2,int y2,
  557.                       int x3,int y3,int color)
  558. {
  559. int temp_x,
  560.     temp_y,
  561.     new_x;
  562.  
  563. // test for h lines and v lines
  564.  
  565. if ((x1==x2 && x2==x3)  ||  (y1==y2 && y2==y3))
  566.    return;
  567.  
  568. // sort p1,p2,p3 in ascending y order
  569.  
  570. if (y2<y1)
  571.    {
  572.    temp_x = x2;
  573.    temp_y = y2;
  574.    x2     = x1;
  575.    y2     = y1;
  576.    x1     = temp_x;
  577.    y1     = temp_y;
  578.    } // end if
  579.  
  580. // now we know that p1 and p2 are in order
  581.  
  582. if (y3<y1)
  583.    {
  584.    temp_x = x3;
  585.    temp_y = y3;
  586.    x3     = x1;
  587.    y3     = y1;
  588.    x1     = temp_x;
  589.    y1     = temp_y;
  590.    } // end if
  591.  
  592. // finally test y3 against y2
  593.  
  594. if (y3<y2)
  595.    {
  596.    temp_x = x3;
  597.    temp_y = y3;
  598.    x3     = x2;
  599.    y3     = y2;
  600.    x2     = temp_x;
  601.    y2     = temp_y;
  602.  
  603.    } // end if
  604.  
  605. // do trivial rejection tests
  606.  
  607. if ( y3<poly_clip_min_y || y1>poly_clip_max_y ||
  608.     (x1<poly_clip_min_x && x2<poly_clip_min_x && x3<poly_clip_min_x) ||
  609.     (x1>poly_clip_max_x && x2>poly_clip_max_x && x3>poly_clip_max_x) )
  610.    return;
  611.  
  612. // test if top of triangle is flat
  613.  
  614. if (y1==y2)
  615.    {
  616.  
  617.    Draw_Top_Triangle(x1,y1,x2,y2,x3,y3,color);
  618.  
  619.    } // end if
  620. else
  621. if (y2==y3)
  622.    {
  623.  
  624.    Draw_Bottom_Triangle(x1,y1,x2,y2,x3,y3,color);
  625.  
  626.  
  627.    } // end if bottom is flat
  628. else
  629.    {
  630.    // general triangle that's needs to be broken up along long edge
  631.  
  632.    new_x = x1 + (int)((float)(y2-y1)*(float)(x3-x1)/(float)(y3-y1));
  633.  
  634.    // draw each sub-triangle
  635.  
  636.    Draw_Bottom_Triangle(x1,y1,new_x,y2,x2,y2,color);
  637.  
  638.    Draw_Top_Triangle(x2,y2,new_x,y2,x3,y3,color);
  639.  
  640.    } // end else
  641.  
  642. } // end Draw_Triangle_2D
  643.  
  644. ////////////////////////////////////////////////////////////////////////////////
  645.  
  646. void Build_Look_Up_Tables(void)
  647. {
  648. // this function builds all the look up tables for the engine
  649.  
  650. int angle;  // the current angle being computed
  651.  
  652. float rad;  // used in conversion from degrees to radians
  653.  
  654.  // generate sin/cos look up tables
  655.  
  656. for (angle=0; angle<=360; angle++)
  657.     {
  658.  
  659.     rad = (float) (3.14159*(float)angle/(float)180);
  660.  
  661.     cos_look[angle] = (float)cos(rad);
  662.     sin_look[angle] = (float)sin(rad);
  663.  
  664.     } // end for angle
  665.  
  666. } // end Build_Look_Up_Tables
  667.  
  668. //////////////////////////////////////////////////////////////////////////////
  669.  
  670. float Dot_Product_3D(vector_3d_ptr u,vector_3d_ptr v)
  671. {
  672. // this function computes the dot product of two vectors
  673.  
  674. return( (u->x * v->x) + (u->y * v->y) + (u->z * v->z));
  675.  
  676. } // end Dot_Product
  677.  
  678. //////////////////////////////////////////////////////////////////////////////
  679.  
  680. void Make_Vector_3D(point_3d_ptr init,
  681.                     point_3d_ptr term,
  682.                     vector_3d_ptr result)
  683. {
  684. // this function creates a vector from two points in 3D space
  685.  
  686. result->x = term->x - init->x;
  687. result->y = term->y - init->y;
  688. result->z = term->z - init->z;
  689.  
  690. } // end Make_Vector
  691.  
  692. //////////////////////////////////////////////////////////////////////////////
  693.  
  694. void Cross_Product_3D(vector_3d_ptr u,
  695.                       vector_3d_ptr v,
  696.                       vector_3d_ptr normal)
  697. {
  698. // this function computes the cross product between two vectors
  699.  
  700. normal->x =  (u->y*v->z - u->z*v->y);
  701. normal->y = -(u->x*v->z - u->z*v->x);
  702. normal->z =  (u->x*v->y - u->y*v->x);
  703.  
  704. } // end Cross_Product_3D
  705.  
  706. ///////////////////////////////////////////////////////////////////////////////
  707.  
  708. float Vector_Mag_3D(vector_3d_ptr v)
  709. {
  710. // computes the magnitude of a vector
  711.  
  712. return((float)sqrt(v->x*v->x + v->y*v->y + v->z*v->z));
  713.  
  714. } // end Vector_Mag_3D
  715.  
  716. ///////////////////////////////////////////////////////////////////////////////
  717.  
  718. void Mat_Print_4x4(matrix_4x4 a)
  719. {
  720. // this function prints out a 4x4 matrix
  721.  
  722. int row,      // looping variables
  723.     column;
  724.  
  725. for (row=0; row<4; row++)
  726.     {
  727.     printf("\n");
  728.  
  729.     for (column=0; column<4; column++)
  730.         printf("%f ",a[row][column]);
  731.  
  732.     } // end for row
  733.  
  734. printf("\n");
  735.  
  736. } // end Mat_Print_4x4
  737.  
  738. //////////////////////////////////////////////////////////////////////////////
  739.  
  740. void Mat_Print_1x4(matrix_1x4 a)
  741. {
  742. // this function prints out a 1x4 matrix
  743.  
  744. int column;     // looping variable
  745.  
  746. printf("\n");
  747.  
  748. for (column=0; column<4; column++)
  749.     printf("%f ",a[column]);
  750.  
  751. printf("\n");
  752.  
  753. } // end Mat_Print_1x4
  754.  
  755. //////////////////////////////////////////////////////////////////////////////
  756.  
  757. void Mat_Mul_4x4_4x4 (matrix_4x4 a,
  758.                       matrix_4x4 b,
  759.                       matrix_4x4 result)
  760. {
  761. // this function multiplies a 4x4 by a 4x4 and stores the result in a 4x4
  762.  
  763. // first row
  764.  
  765. result[0][0]=a[0][0]*b[0][0]+a[0][1]*b[1][0]+a[0][2]*b[2][0];
  766. result[0][1]=a[0][0]*b[0][1]+a[0][1]*b[1][1]+a[0][2]*b[2][1];
  767. result[0][2]=a[0][0]*b[0][2]+a[0][1]*b[1][2]+a[0][2]*b[2][2];
  768. result[0][3]=0;  // can probably get rid of this too, it's always 0
  769.  
  770. // second row
  771.  
  772. result[1][0]=a[1][0]*b[0][0]+a[1][1]*b[1][0]+a[1][2]*b[2][0];
  773. result[1][1]=a[1][0]*b[0][1]+a[1][1]*b[1][1]+a[1][2]*b[2][1];
  774. result[1][2]=a[1][0]*b[0][2]+a[1][1]*b[1][2]+a[1][2]*b[2][2];
  775. result[1][3]=0; // can probably get rid of this too, it's always 0
  776.  
  777. // third row
  778.  
  779. result[2][0]=a[2][0]*b[0][0]+a[2][1]*b[1][0]+a[2][2]*b[2][0];
  780. result[2][1]=a[2][0]*b[0][1]+a[2][1]*b[1][1]+a[2][2]*b[2][1];
  781. result[2][2]=a[2][0]*b[0][2]+a[2][1]*b[1][2]+a[2][2]*b[2][2];
  782. result[2][3]=0; // can probably get rid of this too, it's always 0
  783.  
  784. // fourth row
  785.  
  786. result[3][0]=a[3][0]*b[0][0]+a[3][1]*b[1][0]+a[3][2]*b[2][0]+b[3][0];
  787. result[3][1]=a[3][0]*b[0][1]+a[3][1]*b[1][1]+a[3][2]*b[2][1]+b[3][1];
  788. result[3][2]=a[3][0]*b[0][2]+a[3][1]*b[1][2]+a[3][2]*b[2][2]+b[3][2];
  789. result[3][3]=1; // can probably get rid of this too, it's always 0
  790.  
  791.  
  792. } // end Mat_Mul_4x4_4x4
  793.  
  794. //////////////////////////////////////////////////////////////////////////////
  795.  
  796. void Mat_Mul_1x4_4x4(matrix_1x4 a,
  797.                      matrix_4x4 b,
  798.                      matrix_1x4 result)
  799. {
  800. // this function multiplies a 1x4 by a 4x4 and stores the result in a 1x4
  801.  
  802. int index_j,    // column index
  803.     index_k;    // row index
  804.  
  805. float sum;    // temp used to hold sum of products
  806.  
  807. // loop thru columns of b
  808.  
  809. for (index_j=0; index_j<4; index_j++)
  810.     {
  811.  
  812.     // multiply ith row of a by jth column of b and store the sum
  813.     // of products in the position i,j of result
  814.  
  815.     sum=0;
  816.  
  817.     for (index_k=0; index_k<4; index_k++)
  818.         sum+=a[index_k]*b[index_k][index_j];
  819.  
  820.     // store result
  821.  
  822.     result[index_j] = sum;
  823.  
  824.     } // end for index_j
  825.  
  826. } // end Mat_Mul_1x4_4x4
  827.  
  828. //////////////////////////////////////////////////////////////////////////////
  829.  
  830. void Mat_Identity_4x4(matrix_4x4 a)
  831. {
  832. // this function creates a 4x4 identity matrix
  833.  
  834. memset((void *)a,0,sizeof(float)*16);
  835.  
  836. // set main diagonal to 1's
  837.  
  838. a[0][0] = a[1][1] = a[2][2] = a[3][3] = 1;
  839.  
  840. } // end Mat_Identity_4x4
  841.  
  842. /////////////////////////////////////////////////////////////////////////////
  843.  
  844. void Mat_Zero_4x4(matrix_4x4 a)
  845. {
  846. // this function zero's out a 4x4 matrix
  847.  
  848. memset((void *)a,0,sizeof(float)*16);
  849.  
  850. } // end Mat_Zero_4x4
  851.  
  852. /////////////////////////////////////////////////////////////////////////////
  853.  
  854. void Mat_Copy_4x4(matrix_4x4 source, matrix_4x4 destination)
  855. {
  856. // this function copies one 4x4 matrix to another
  857.  
  858. memcpy((void *)destination,(void *)source,sizeof(float)*16);
  859.  
  860. } // end Mat_Copy_4x4
  861.  
  862. /////////////////////////////////////////////////////////////////////////////
  863.  
  864. void Local_To_World_Object(object_ptr the_object)
  865. {
  866. // this function converts an objects local coordinates to world coordinates
  867. // by translating each point in the object by the objects current position
  868.  
  869. int index;  // looping variable
  870.  
  871. // move object from local position to world position
  872.  
  873. for (index=0; index<the_object->num_vertices; index++)
  874.     {
  875.  
  876.     the_object->vertices_world[index].x = the_object->vertices_local[index].x +
  877.                                           the_object->world_pos.x;
  878.  
  879.     the_object->vertices_world[index].y = the_object->vertices_local[index].y +
  880.                                           the_object->world_pos.y;
  881.  
  882.     the_object->vertices_world[index].z = the_object->vertices_local[index].z +
  883.                                           the_object->world_pos.z;
  884.  
  885.     } // end for index
  886.  
  887. // reset visibility flags for all polys
  888.  
  889. for (index=0; index<the_object->num_polys; index++)
  890.     {
  891.     the_object->polys[index].visible = 1;
  892.     the_object->polys[index].clipped = 0;
  893.     } // end for
  894.  
  895. } // end Local_To_World_Object
  896.  
  897. /////////////////////////////////////////////////////////////////////////////
  898.  
  899. void Create_World_To_Camera(void)
  900. {
  901. // this function creates the global inverse transformation matrix
  902. // used to transform world coordinate to camera coordinates
  903.  
  904. matrix_4x4 translate,   // the translation matrix
  905.  
  906.            rotate_x,    // the x,y and z rotation matrices
  907.            rotate_y,
  908.            rotate_z,
  909.            result_1,
  910.            result_2;
  911.  
  912. int active_axes=0;
  913.  
  914. // create identity matrices
  915.  
  916. Mat_Identity_4x4(translate);
  917.  
  918. // make a translation matrix based on the inverse of the viewpoint
  919.  
  920. translate[3][0] = -view_point.x;
  921. translate[3][1] = -view_point.y;
  922. translate[3][2] = -view_point.z;
  923.  
  924. // test if there is any X rotation in view angles
  925.  
  926. if (view_angle.ang_x)
  927.    {
  928.    Mat_Identity_4x4(rotate_x);
  929.  
  930.    // x matrix
  931.  
  932.    rotate_x[1][1] =  ( cos_look[view_angle.ang_x]);
  933.    rotate_x[1][2] = -( sin_look[view_angle.ang_x]);
  934.    rotate_x[2][1] = -(-sin_look[view_angle.ang_x]);
  935.    rotate_x[2][2] =  ( cos_look[view_angle.ang_x]);
  936.  
  937.    active_axes += 1;
  938.  
  939.    } // end if
  940.  
  941. if (view_angle.ang_y)
  942.    {
  943.    Mat_Identity_4x4(rotate_y);
  944.  
  945.    // y matrix
  946.  
  947.    rotate_y[0][0] =  ( cos_look[view_angle.ang_y]);
  948.    rotate_y[0][2] = -(-sin_look[view_angle.ang_y]);
  949.    rotate_y[2][0] = -( sin_look[view_angle.ang_y]);
  950.    rotate_y[2][2] =  ( cos_look[view_angle.ang_y]);
  951.  
  952.    active_axes += 2;
  953.  
  954.    } // end if
  955.  
  956.  
  957. if (view_angle.ang_z)
  958.    {
  959.    Mat_Identity_4x4(rotate_z);
  960.  
  961.    // z matrix
  962.  
  963.    rotate_z[0][0] =  ( cos_look[view_angle.ang_z]);
  964.    rotate_z[0][1] = -( sin_look[view_angle.ang_z]);
  965.    rotate_z[1][0] = -(-sin_look[view_angle.ang_z]);
  966.    rotate_z[1][1] =  ( cos_look[view_angle.ang_z]);
  967.  
  968.    active_axes += 4;
  969.  
  970.    } // end if
  971.  
  972. // multiply all the matrices together to obtain a final world to camera
  973. // viewing transformation matrix i.e.
  974. // translation * rotate_x * rotate_y * rotate_z, however, only, multiply
  975. // matrices that can possible add to the final view
  976.  
  977. switch(active_axes)
  978.       {
  979.  
  980.       case 0: // translation only
  981.            {
  982.            Mat_Copy_4x4(translate,global_view);
  983.            } break;
  984.  
  985.       case 1: // translation and X axis
  986.            {
  987.            // since only a single axis is active manually set up the matrix
  988.  
  989.            // Mat_Mul_4x4_4x4(translate,rotate_x,global_view);
  990.  
  991.            // manually create matrix using knowledge that final product is
  992.            // of the form
  993.  
  994.            // | 1            0            0          0|
  995.            // | 0            c            -s         0|
  996.            // | 0            s            c          0|
  997.            // |(-tx)       (-ty*c-tz*s) (ty*s-tz*c)  1|
  998.  
  999.            Mat_Copy_4x4(rotate_x,global_view);
  1000.  
  1001.            // now copy last row into global_view
  1002.  
  1003.  
  1004.            global_view[3][0] = (-view_point.x);
  1005.  
  1006.            global_view[3][1] = (-view_point.y*cos_look[view_angle.ang_y] -
  1007.                                  view_point.z*sin_look[view_angle.ang_y]);
  1008.  
  1009.            global_view[3][2] = (view_point.y*sin_look[view_angle.ang_y] -
  1010.                                 view_point.z*cos_look[view_angle.ang_y]);
  1011.  
  1012.  
  1013.            } break;
  1014.  
  1015.  
  1016.       case 2: // translation and Y axis
  1017.            {
  1018.            // Mat_Mul_4x4_4x4(translate,rotate_y,global_view);
  1019.  
  1020.            // manually create matrix using knowledge that final product is
  1021.            // of the form
  1022.  
  1023.            // | c            0            s          0|
  1024.            // | 0            1            0          0|
  1025.            // | -s           0            c          0|
  1026.            // |(tx*c+tz*s) (-ty)        (-tx*s-tz*c) 1|
  1027.  
  1028.            Mat_Copy_4x4(rotate_y,global_view);
  1029.  
  1030.            // now copy last row into global_view
  1031.  
  1032.            global_view[3][0] = (-view_point.x*cos_look[view_angle.ang_y] +
  1033.                                  view_point.z*sin_look[view_angle.ang_y]);
  1034.  
  1035.            global_view[3][1] = (-view_point.y);
  1036.  
  1037.            global_view[3][2] = (-view_point.x*sin_look[view_angle.ang_y] -
  1038.                                  view_point.z*cos_look[view_angle.ang_y]);
  1039.  
  1040.  
  1041.            } break;
  1042.  
  1043.  
  1044.       case 3: // translation and X and Y
  1045.            {
  1046.            Mat_Mul_4x4_4x4(translate,rotate_x,result_1);
  1047.            Mat_Mul_4x4_4x4(result_1,rotate_y,global_view);
  1048.            } break;
  1049.  
  1050.  
  1051.       case 4: // translation and Z
  1052.            {
  1053.             // Mat_Mul_4x4_4x4(translate,rotate_z,global_view);
  1054.  
  1055.            // manually create matrix using knowledge that final product is
  1056.            // of the form
  1057.  
  1058.            // | c            -s           0          0|
  1059.            // | s            c            0          0|
  1060.            // | 0            s            c          0|
  1061.            // |(-tx*c-ty*s) (tx*s-ty*c)  (-tz)       1|
  1062.  
  1063.            Mat_Copy_4x4(rotate_z,global_view);
  1064.  
  1065.            // now copy last row into global_view
  1066.  
  1067.  
  1068.            global_view[3][0] = (-view_point.x*cos_look[view_angle.ang_z] -
  1069.                                  view_point.y*sin_look[view_angle.ang_z]);
  1070.  
  1071.            global_view[3][1] = (view_point.x*sin_look[view_angle.ang_z] -
  1072.                                 view_point.y*cos_look[view_angle.ang_z]);
  1073.  
  1074.  
  1075.            global_view[3][2] = (-view_point.z);
  1076.  
  1077.            } break;
  1078.  
  1079.  
  1080.       case 5: // translation and X and Z
  1081.            {
  1082.            Mat_Mul_4x4_4x4(translate,rotate_x,result_1);
  1083.            Mat_Mul_4x4_4x4(result_1,rotate_z,global_view);
  1084.            } break;
  1085.  
  1086.       case 6: // translation and Y and Z
  1087.            {
  1088.            Mat_Mul_4x4_4x4(translate,rotate_y,result_1);
  1089.            Mat_Mul_4x4_4x4(result_1,rotate_z,global_view);
  1090.            } break;
  1091.  
  1092.       case 7: // translation and X and Y and Z
  1093.  
  1094.            {
  1095.  
  1096.            Mat_Mul_4x4_4x4(translate,rotate_x,result_1);
  1097.            Mat_Mul_4x4_4x4(result_1,rotate_y,result_2);
  1098.            Mat_Mul_4x4_4x4(result_2,rotate_z,global_view);
  1099.  
  1100.            } break;
  1101.  
  1102.       default:break;
  1103.  
  1104.       } // end switch
  1105.  
  1106. } // end Create_World_To_Camera
  1107.  
  1108. ////////////////////////////////////////////////////////////////////////////////
  1109.  
  1110. void World_To_Camera_Object(object_ptr the_object)
  1111. {
  1112. // this function converts an objects world coordinates to camera coordinates
  1113. // by multiplying each point of the object by the inverse viewing transformation
  1114. // matrix which is generated by concatenating the inverse of the view position
  1115. // and the view angles the result of which is in global_view
  1116.  
  1117. int index; // looping variable
  1118.  
  1119. int active_axes = 0;
  1120.  
  1121. if (view_angle.ang_x)
  1122.    active_axes+=1;
  1123.  
  1124. if (view_angle.ang_y)
  1125.    active_axes+=2;
  1126.  
  1127. if (view_angle.ang_z)
  1128.    active_axes+=4;
  1129.  
  1130. // based on active angles only compute what's neccessary
  1131.  
  1132. switch(active_axes)
  1133.       {
  1134.       case 0:   // T-1
  1135.            {
  1136.  
  1137.            for (index=0; index<=the_object->num_vertices; index++)
  1138.                {
  1139.                // multiply the point by the viewing transformation matrix
  1140.  
  1141.                // x component
  1142.  
  1143.                the_object->vertices_camera[index].x =
  1144.  
  1145.                              the_object->vertices_world[index].x +
  1146.                                                                    global_view[3][0];
  1147.                // y component
  1148.  
  1149.                the_object->vertices_camera[index].y =
  1150.  
  1151.                              the_object->vertices_world[index].y +
  1152.                                                                    global_view[3][1];
  1153.                // z component
  1154.  
  1155.                the_object->vertices_camera[index].z =
  1156.  
  1157.                              the_object->vertices_world[index].z +
  1158.                                                                    global_view[3][2];
  1159.                } // end for index
  1160.  
  1161.            } break;
  1162.  
  1163.       case 1:   // T-1 * Rx-1
  1164.            {
  1165.            for (index=0; index<=the_object->num_vertices; index++)
  1166.                {
  1167.                // multiply the point by the viewing transformation matrix
  1168.                // x component
  1169.  
  1170.                the_object->vertices_camera[index].x =
  1171.  
  1172.                              the_object->vertices_world[index].x +
  1173.                                                                    global_view[3][0];
  1174.                // y component
  1175.  
  1176.                the_object->vertices_camera[index].y =
  1177.  
  1178.                              the_object->vertices_world[index].y * global_view[1][1] +
  1179.                              the_object->vertices_world[index].z * global_view[2][1] +
  1180.                                                                    global_view[3][1];
  1181.                // z component
  1182.  
  1183.                the_object->vertices_camera[index].z =
  1184.  
  1185.                              the_object->vertices_world[index].y * global_view[1][2] +
  1186.                              the_object->vertices_world[index].z * global_view[2][2] +
  1187.                                                                    global_view[3][2];
  1188.                } // end for index
  1189.  
  1190.  
  1191.  
  1192.            } break;
  1193.  
  1194.       case 2:  // T-1 * Ry-1 , this is the standard rotation in a plane
  1195.            {
  1196.  
  1197.            for (index=0; index<=the_object->num_vertices; index++)
  1198.                {
  1199.                // multiply the point by the viewing transformation matrix
  1200.  
  1201.                // x component
  1202.                the_object->vertices_camera[index].x =
  1203.  
  1204.                              the_object->vertices_world[index].x * global_view[0][0] +
  1205.                              the_object->vertices_world[index].z * global_view[2][0] +
  1206.                                                                    global_view[3][0];
  1207.                // y component
  1208.                the_object->vertices_camera[index].y =
  1209.  
  1210.                              the_object->vertices_world[index].y +
  1211.                                                                    global_view[3][1];
  1212.                // z component
  1213.                the_object->vertices_camera[index].z =
  1214.  
  1215.                              the_object->vertices_world[index].x * global_view[0][2] +
  1216.                              the_object->vertices_world[index].z * global_view[2][2] +
  1217.                                                                    global_view[3][2];
  1218.                } // end for index
  1219.  
  1220.  
  1221.  
  1222.            } break;
  1223.  
  1224.       case 4:   // T-1 * Rz-1
  1225.            {
  1226.  
  1227.            for (index=0; index<=the_object->num_vertices; index++)
  1228.                {
  1229.                // multiply the point by the viewing transformation matrix
  1230.  
  1231.                // x component
  1232.  
  1233.                the_object->vertices_camera[index].x =
  1234.  
  1235.                              the_object->vertices_world[index].x * global_view[0][0] +
  1236.                              the_object->vertices_world[index].y * global_view[1][0] +
  1237.                                                                    global_view[3][0];
  1238.                // y component
  1239.  
  1240.                the_object->vertices_camera[index].y =
  1241.  
  1242.                              the_object->vertices_world[index].x * global_view[0][1] +
  1243.                              the_object->vertices_world[index].y * global_view[1][1] +
  1244.                                                                    global_view[3][1];
  1245.                // z component
  1246.  
  1247.                the_object->vertices_camera[index].z =
  1248.  
  1249.                              the_object->vertices_world[index].z +
  1250.                                                                    global_view[3][2];
  1251.                } // end for index
  1252.  
  1253.  
  1254.            } break;
  1255.  
  1256.  
  1257.       // these can all be optimized by pre-computing the form of the world
  1258.       // to camera matrix and using the same logic as the cases above
  1259.  
  1260.       case 3:  // T-1 * Rx-1 * Ry-1
  1261.       case 5:  // T-1 * Rx-1 * Rz-1
  1262.       case 6:  // T-1 * Ry-1 * Rz-1
  1263.       case 7:  // T-1 * Rx-1 * Ry-1 * Rz-1
  1264.            {
  1265.  
  1266.            for (index=0; index<=the_object->num_vertices; index++)
  1267.                {
  1268.                // multiply the point by the viewing transformation matrix
  1269.  
  1270.                // x component
  1271.  
  1272.                the_object->vertices_camera[index].x =
  1273.  
  1274.                              the_object->vertices_world[index].x * global_view[0][0] +
  1275.                              the_object->vertices_world[index].y * global_view[1][0] +
  1276.                              the_object->vertices_world[index].z * global_view[2][0] +
  1277.                                                                    global_view[3][0];
  1278.                // y component
  1279.  
  1280.                the_object->vertices_camera[index].y =
  1281.  
  1282.                              the_object->vertices_world[index].x * global_view[0][1] +
  1283.                              the_object->vertices_world[index].y * global_view[1][1] +
  1284.                              the_object->vertices_world[index].z * global_view[2][1] +
  1285.                                                                    global_view[3][1];
  1286.                // z component
  1287.  
  1288.                the_object->vertices_camera[index].z =
  1289.  
  1290.                              the_object->vertices_world[index].x * global_view[0][2] +
  1291.                              the_object->vertices_world[index].y * global_view[1][2] +
  1292.                              the_object->vertices_world[index].z * global_view[2][2] +
  1293.                                                                    global_view[3][2];
  1294.                } // end for index
  1295.  
  1296.  
  1297.  
  1298.            } break;
  1299.  
  1300.       default: break;
  1301.  
  1302.       } // end switch
  1303.  
  1304. } // end World_To_Camera_Object
  1305.  
  1306. ////////////////////////////////////////////////////////////////////////////
  1307.  
  1308. void Rotate_Object(object_ptr the_object,int angle_x,int angle_y,int angle_z)
  1309. {
  1310. // this function rotates an object relative to it's own local coordinate system
  1311. // and allows simultaneous rotations
  1312.  
  1313. int index,       //  looping variable
  1314.     product=0;   // used to determine which matrices need multiplying
  1315.  
  1316. matrix_4x4 rotate_x,    // the x,y and z rotation matrices
  1317.            rotate_y,
  1318.            rotate_z,
  1319.            rotate,      // the final rotation matrix
  1320.            temp;        // temporary working matrix
  1321.  
  1322. float temp_x, // used to hold intermediate results during rotation
  1323.       temp_y,
  1324.       temp_z;
  1325.  
  1326. // test if we need to rotate at all
  1327.  
  1328. if (angle_x==0 && angle_y==0 && angle_z==0)
  1329.    return;
  1330.  
  1331. // create identity matrix
  1332.  
  1333. Mat_Identity_4x4(rotate);
  1334.  
  1335. // figure out which axes are active
  1336.  
  1337. if (angle_x)
  1338.    product+=4;
  1339.  
  1340. if (angle_y)
  1341.    product+=2;
  1342.  
  1343. if (angle_z)
  1344.    product+=1;
  1345.  
  1346. // compute final rotation matrix and perform rotation all in one!
  1347.  
  1348. switch(product)
  1349.       {
  1350.  
  1351.       case 1: // final matrix = z
  1352.            {
  1353.            // set up matrix
  1354.  
  1355.            rotate[0][0] = ( cos_look[angle_z]);
  1356.            rotate[0][1] = ( sin_look[angle_z]);
  1357.            rotate[1][0] = (-sin_look[angle_z]);
  1358.            rotate[1][1] = ( cos_look[angle_z]);
  1359.  
  1360.            // matrix is of the form
  1361.  
  1362.            // | cos   sin  0     0 |
  1363.            // | -sin  cos  0     0 |
  1364.            // | 0     0    1     0 |
  1365.            // | 0     0    0     1 |
  1366.  
  1367.            // hence we can remove a number of multiplications during the
  1368.            // computations of x,y and z since many times each variable
  1369.            // isn't a function of the other two
  1370.  
  1371.  
  1372.            // perform rotation
  1373.  
  1374.            // now multiply each point in object by transformation matrix
  1375.  
  1376.            for (index=0; index<the_object->num_vertices; index++)
  1377.                {
  1378.  
  1379.                // x component
  1380.  
  1381.                temp_x = the_object->vertices_local[index].x * rotate[0][0] +
  1382.                         the_object->vertices_local[index].y * rotate[1][0];
  1383.                        // the_object->vertices_local[index].z * rotate[2][0];
  1384.  
  1385.                // y component
  1386.  
  1387.                temp_y = the_object->vertices_local[index].x * rotate[0][1] +
  1388.                         the_object->vertices_local[index].y * rotate[1][1];
  1389.                         // the_object->vertices_local[index].z * rotate[2][1];
  1390.  
  1391.                // z component
  1392.  
  1393.                temp_z =
  1394.  
  1395.                         the_object->vertices_local[index].z;
  1396.  
  1397.                // store rotated point back into local array
  1398.  
  1399.                the_object->vertices_local[index].x = temp_x;
  1400.                the_object->vertices_local[index].y = temp_y;
  1401.                the_object->vertices_local[index].z = temp_z;
  1402.  
  1403.                } // end for index
  1404.  
  1405.  
  1406.            } break;
  1407.  
  1408.       case 2: // final matrix = y
  1409.            {
  1410.  
  1411.            rotate[0][0] = ( cos_look[angle_y]);
  1412.            rotate[0][2] = (-sin_look[angle_y]);
  1413.            rotate[2][0] = ( sin_look[angle_y]);
  1414.            rotate[2][2] = ( cos_look[angle_y]);
  1415.  
  1416.            // matrix is of the form
  1417.  
  1418.            // | cos   0    -sin  0 |
  1419.            // | 0     1    0     0 |
  1420.            // | sin   0    cos   0 |
  1421.            // | 0     0    0     1 |
  1422.  
  1423.            // hence we can remove a number of multiplications during the
  1424.            // computations of x,y and z since many times each variable
  1425.            // isn't a function of the other two
  1426.  
  1427.  
  1428.            // now multiply each point in object by transformation matrix
  1429.  
  1430.            for (index=0; index<the_object->num_vertices; index++)
  1431.                {
  1432.  
  1433.                // x component
  1434.  
  1435.                temp_x = the_object->vertices_local[index].x * rotate[0][0] +
  1436.                         // the_object->vertices_local[index].y * rotate[1][0] +
  1437.                         the_object->vertices_local[index].z * rotate[2][0];
  1438.  
  1439.                // y component
  1440.  
  1441.                temp_y =
  1442.                         the_object->vertices_local[index].y;
  1443.  
  1444.                // z component
  1445.  
  1446.                temp_z = the_object->vertices_local[index].x * rotate[0][2] +
  1447.                         // the_object->vertices_local[index].y * rotate[1][2] +
  1448.                         the_object->vertices_local[index].z * rotate[2][2];
  1449.  
  1450.                // store rotated point back into local array
  1451.  
  1452.                the_object->vertices_local[index].x = temp_x;
  1453.                the_object->vertices_local[index].y = temp_y;
  1454.                the_object->vertices_local[index].z = temp_z;
  1455.  
  1456.                } // end for index
  1457.  
  1458.            } break;
  1459.  
  1460.       case 3: // final matrix = y*z
  1461.            {
  1462.  
  1463.            // take advantage of the fact that the product of Ry*Rz is
  1464.            //
  1465.            // | (cos angy)*(cos angz)  (cos angy)*(sin angz) -sin angy 0|
  1466.            // | -sin angz              cos angz              0         0|
  1467.            // | (sin angy)*(cos angz)  (sin angy)*(sin angz) cos angy  0|
  1468.            // | 0                      0                     0         1|
  1469.  
  1470.            // also notice the 0 in the 3rd column, we can use it to get
  1471.            // rid of one multiplication in the for loop below per point
  1472.  
  1473.            rotate[0][0] = cos_look[angle_y]*cos_look[angle_z];
  1474.            rotate[0][1] = cos_look[angle_y]*sin_look[angle_z];
  1475.            rotate[0][2] = -sin_look[angle_y];
  1476.  
  1477.            rotate[1][0] = -sin_look[angle_z];
  1478.            rotate[1][1] = cos_look[angle_z];
  1479.  
  1480.            rotate[2][0] = sin_look[angle_y]*cos_look[angle_z];
  1481.            rotate[2][1] = sin_look[angle_y]*sin_look[angle_z];
  1482.            rotate[2][2] = cos_look[angle_y];
  1483.  
  1484.            // now multiply each point in object by transformation matrix
  1485.  
  1486.            for (index=0; index<the_object->num_vertices; index++)
  1487.                {
  1488.  
  1489.                // x component
  1490.  
  1491.                temp_x = the_object->vertices_local[index].x * rotate[0][0] +
  1492.                         the_object->vertices_local[index].y * rotate[1][0] +
  1493.                         the_object->vertices_local[index].z * rotate[2][0];
  1494.  
  1495.                // y component
  1496.  
  1497.                temp_y = the_object->vertices_local[index].x * rotate[0][1] +
  1498.                         the_object->vertices_local[index].y * rotate[1][1] +
  1499.                         the_object->vertices_local[index].z * rotate[2][1];
  1500.  
  1501.                // z component
  1502.  
  1503.                temp_z = the_object->vertices_local[index].x * rotate[0][2] +
  1504.                         // the_object->vertices_local[index].y * rotate[1][2] +
  1505.                         the_object->vertices_local[index].z * rotate[2][2];
  1506.  
  1507.                // store rotated point back into local array
  1508.  
  1509.                the_object->vertices_local[index].x = temp_x;
  1510.                the_object->vertices_local[index].y = temp_y;
  1511.                the_object->vertices_local[index].z = temp_z;
  1512.  
  1513.                } // end for index
  1514.  
  1515.            } break;
  1516.  
  1517.       case 4: // final matrix = x
  1518.            {
  1519.  
  1520.            rotate[1][1] = ( cos_look[angle_x]);
  1521.            rotate[1][2] = ( sin_look[angle_x]);
  1522.            rotate[2][1] = (-sin_look[angle_x]);
  1523.            rotate[2][2] = ( cos_look[angle_x]);
  1524.  
  1525.            // matrix is of the form
  1526.  
  1527.            // | 1     s    0     0 |
  1528.            // | 0     cos  sin   0 |
  1529.            // | 0    -sin  cos   0 |
  1530.            // | 0     0    0     1 |
  1531.  
  1532.            // hence we can remove a number of multiplications during the
  1533.            // computations of x,y and z since many times each variable
  1534.            // isn't a function of the other two
  1535.  
  1536.  
  1537.  
  1538.  
  1539.            // now multiply each point in object by transformation matrix
  1540.  
  1541.            for (index=0; index<the_object->num_vertices; index++)
  1542.                {
  1543.  
  1544.                // x component
  1545.  
  1546.                temp_x =
  1547.  
  1548.                         the_object->vertices_local[index].x;
  1549.  
  1550.                // y component
  1551.  
  1552.                temp_y = // the_object->vertices_local[index].x * rotate[0][1] +
  1553.                         the_object->vertices_local[index].y * rotate[1][1] +
  1554.                         the_object->vertices_local[index].z * rotate[2][1];
  1555.  
  1556.                // z component
  1557.  
  1558.                temp_z = // the_object->vertices_local[index].x * rotate[0][2] +
  1559.                         the_object->vertices_local[index].y * rotate[1][2] +
  1560.                         the_object->vertices_local[index].z * rotate[2][2];
  1561.  
  1562.                // store rotated point back into local array
  1563.  
  1564.                the_object->vertices_local[index].x = temp_x;
  1565.                the_object->vertices_local[index].y = temp_y;
  1566.                the_object->vertices_local[index].z = temp_z;
  1567.  
  1568.                } // end for index
  1569.  
  1570.            } break;
  1571.  
  1572.       case 5: // final matrix = x*z
  1573.            {
  1574.  
  1575.            // take advantage of the fact that the product of Rx*Rz is
  1576.            //
  1577.            // | cos angz                sin angz               0         0|
  1578.            // | -(cos angx)*(sin angz)  (cos angx)*(cos angz)  sin angx  0|
  1579.            // | (sin angx)*(sin angz)  -(sin angx)*(cos angz)  cos angx  0|
  1580.            // | 0                       0                      0         1|
  1581.  
  1582.            // also notice the 0 in the 3rd column, we can use it to get
  1583.            // rid of one multiplication in the for loop below per point
  1584.  
  1585.  
  1586.            rotate[0][0] = cos_look[angle_z];
  1587.            rotate[0][1] = sin_look[angle_z];
  1588.  
  1589.            rotate[1][0] = -cos_look[angle_x]*sin_look[angle_z];
  1590.            rotate[1][1] = cos_look[angle_x]*cos_look[angle_z];
  1591.            rotate[1][2] = sin_look[angle_x];
  1592.  
  1593.            rotate[2][0] = sin_look[angle_x]*sin_look[angle_z];
  1594.            rotate[2][1] = -sin_look[angle_x]*cos_look[angle_z];
  1595.            rotate[2][2] = cos_look[angle_x];
  1596.  
  1597.            // now multiply each point in object by transformation matrix
  1598.  
  1599.            for (index=0; index<the_object->num_vertices; index++)
  1600.                {
  1601.  
  1602.                // x component
  1603.  
  1604.                temp_x = the_object->vertices_local[index].x * rotate[0][0] +
  1605.                         the_object->vertices_local[index].y * rotate[1][0] +
  1606.                         the_object->vertices_local[index].z * rotate[2][0];
  1607.  
  1608.                // y component
  1609.  
  1610.                temp_y = the_object->vertices_local[index].x * rotate[0][1] +
  1611.                         the_object->vertices_local[index].y * rotate[1][1] +
  1612.                         the_object->vertices_local[index].z * rotate[2][1];
  1613.  
  1614.                // z component
  1615.  
  1616.                temp_z = // the_object->vertices_local[index].x * rotate[0][2] +
  1617.                         the_object->vertices_local[index].y * rotate[1][2] +
  1618.                         the_object->vertices_local[index].z * rotate[2][2];
  1619.  
  1620.                // store rotated point back into local array
  1621.  
  1622.                the_object->vertices_local[index].x = temp_x;
  1623.                the_object->vertices_local[index].y = temp_y;
  1624.                the_object->vertices_local[index].z = temp_z;
  1625.  
  1626.                } // end for index
  1627.  
  1628.            } break;
  1629.  
  1630.       case 6: // final matrix = x*y
  1631.            {
  1632.  
  1633.            // take advantage of the fact that the product of Rx*Ry is
  1634.            //
  1635.            // | cos angy                0          -sin angy             0|
  1636.            // | (sin angx)*(sin angy)   cos angx   (sin angx)*(cos angy) 0|
  1637.            // | (cos angx)*(sin angy)   -sin angx  (cos angx)*(cos angy) 0|
  1638.            // | 0                       0          0                     1|
  1639.  
  1640.            // also notice the 0 in the 2nd column, we can use it to get
  1641.            // rid of one multiplication in the for loop below per point
  1642.  
  1643.            rotate[0][0] = cos_look[angle_y];
  1644.            rotate[0][2] = -sin_look[angle_y];
  1645.  
  1646.            rotate[1][0] = sin_look[angle_x]*sin_look[angle_y];
  1647.            rotate[1][1] = cos_look[angle_x];
  1648.            rotate[1][2] = sin_look[angle_x]*cos_look[angle_y];
  1649.  
  1650.            rotate[2][0] = cos_look[angle_x]*sin_look[angle_y];
  1651.            rotate[2][1] = -sin_look[angle_x];
  1652.            rotate[2][2] = cos_look[angle_x]*cos_look[angle_y];
  1653.  
  1654.            // now multiply each point in object by transformation matrix
  1655.  
  1656.            for (index=0; index<the_object->num_vertices; index++)
  1657.                {
  1658.  
  1659.                // x component
  1660.  
  1661.                temp_x = the_object->vertices_local[index].x * rotate[0][0] +
  1662.                         the_object->vertices_local[index].y * rotate[1][0] +
  1663.                         the_object->vertices_local[index].z * rotate[2][0];
  1664.  
  1665.                // y component
  1666.  
  1667.                temp_y = //the_object->vertices_local[index].x * rotate[0][1] +
  1668.                         the_object->vertices_local[index].y * rotate[1][1] +
  1669.                         the_object->vertices_local[index].z * rotate[2][1];
  1670.  
  1671.                // z component
  1672.  
  1673.                temp_z = the_object->vertices_local[index].x * rotate[0][2] +
  1674.                         the_object->vertices_local[index].y * rotate[1][2] +
  1675.                         the_object->vertices_local[index].z * rotate[2][2];
  1676.  
  1677.                // store rotated point back into local array
  1678.  
  1679.                the_object->vertices_local[index].x = temp_x;
  1680.                the_object->vertices_local[index].y = temp_y;
  1681.                the_object->vertices_local[index].z = temp_z;
  1682.  
  1683.                } // end for index
  1684.  
  1685.            } break;
  1686.  
  1687.       case 7: // final matrix = x*y*z, do it the hard way
  1688.            {
  1689.            Mat_Identity_4x4(rotate_x);
  1690.  
  1691.            rotate_x[1][1] = ( cos_look[angle_x]);
  1692.            rotate_x[1][2] = ( sin_look[angle_x]);
  1693.            rotate_x[2][1] = (-sin_look[angle_x]);
  1694.            rotate_x[2][2] = ( cos_look[angle_x]);
  1695.  
  1696.            Mat_Identity_4x4(rotate_y);
  1697.  
  1698.            rotate_y[0][0] = ( cos_look[angle_y]);
  1699.            rotate_y[0][2] = (-sin_look[angle_y]);
  1700.            rotate_y[2][0] = ( sin_look[angle_y]);
  1701.            rotate_y[2][2] = ( cos_look[angle_y]);
  1702.  
  1703.            Mat_Identity_4x4(rotate_z);
  1704.  
  1705.            rotate_z[0][0] = ( cos_look[angle_z]);
  1706.            rotate_z[0][1] = ( sin_look[angle_z]);
  1707.            rotate_z[1][0] = (-sin_look[angle_z]);
  1708.            rotate_z[1][1] = ( cos_look[angle_z]);
  1709.  
  1710.            Mat_Mul_4x4_4x4(rotate_x,rotate_y,temp);
  1711.            Mat_Mul_4x4_4x4(temp,rotate_z,rotate);
  1712.  
  1713.            // now multiply each point in object by transformation matrix
  1714.  
  1715.            for (index=0; index<the_object->num_vertices; index++)
  1716.                {
  1717.  
  1718.                // x component
  1719.  
  1720.                temp_x = the_object->vertices_local[index].x * rotate[0][0] +
  1721.                         the_object->vertices_local[index].y * rotate[1][0] +
  1722.                         the_object->vertices_local[index].z * rotate[2][0];
  1723.  
  1724.                // y component
  1725.  
  1726.                temp_y = the_object->vertices_local[index].x * rotate[0][1] +
  1727.                         the_object->vertices_local[index].y * rotate[1][1] +
  1728.                         the_object->vertices_local[index].z * rotate[2][1];
  1729.  
  1730.                // z component
  1731.  
  1732.                temp_z = the_object->vertices_local[index].x * rotate[0][2] +
  1733.                         the_object->vertices_local[index].y * rotate[1][2] +
  1734.                         the_object->vertices_local[index].z * rotate[2][2];
  1735.  
  1736.                // store rotated point back into local array
  1737.  
  1738.                the_object->vertices_local[index].x = temp_x;
  1739.                the_object->vertices_local[index].y = temp_y;
  1740.                the_object->vertices_local[index].z = temp_z;
  1741.  
  1742.                } // end for index
  1743.  
  1744.            } break;
  1745.  
  1746.       default:break;
  1747.  
  1748.       } // end switch
  1749.  
  1750. } // end Rotate_Object
  1751.  
  1752. ////////////////////////////////////////////////////////////////////////////
  1753.  
  1754. void Position_Object(object_ptr the_object,int x,int y,int z)
  1755. {
  1756. // this function positions an object in the world
  1757.  
  1758. the_object->world_pos.x = x;
  1759. the_object->world_pos.y = y;
  1760. the_object->world_pos.z = z;
  1761.  
  1762. } // end Position_Object
  1763.  
  1764. ////////////////////////////////////////////////////////////////////////////
  1765.  
  1766. void Translate_Object(object_ptr the_object,int x_trans,int y_trans,int z_trans)
  1767. {
  1768. // this function translates an object relative to it's own local
  1769. // coordinate system
  1770.  
  1771. the_object->world_pos.x+=x_trans;
  1772. the_object->world_pos.y+=y_trans;
  1773. the_object->world_pos.z+=z_trans;
  1774.  
  1775. } // end Translate_Object
  1776.  
  1777. /////////////////////////////////////////////////////////////////////////////
  1778.  
  1779. void Scale_Object(object_ptr the_object,float scale_factor)
  1780. {
  1781. // this function scales an object relative to it's own local coordinate system
  1782. // equally in x,y and z
  1783.  
  1784. int curr_poly,    // the current polygon being processed
  1785.     curr_vertex;  // the current vertex being processed
  1786.  
  1787. float scale_2;    // holds the sqaure of the scaling factor, needed to
  1788.                   // resize the surface normal for lighting calculations
  1789.  
  1790. // multiply each vertex in the object definition by the scaling factor
  1791.  
  1792. for (curr_vertex=0; curr_vertex<the_object->num_vertices; curr_vertex++)
  1793.     {
  1794.  
  1795.     the_object->vertices_local[curr_vertex].x*=scale_factor;
  1796.     the_object->vertices_local[curr_vertex].y*=scale_factor;
  1797.     the_object->vertices_local[curr_vertex].z*=scale_factor;
  1798.  
  1799.     } // end for curr_vertex
  1800.  
  1801. // compute scaling factor squared
  1802.  
  1803. scale_2 = scale_factor*scale_factor;
  1804.  
  1805. // now scale all pre-computed normals
  1806.  
  1807. for (curr_poly=0; curr_poly<the_object->num_polys; curr_poly++)
  1808.     the_object->polys[curr_poly].normal_length*=scale_2;
  1809.  
  1810. // finally scale the radius up
  1811.  
  1812. the_object->radius*=scale_factor;
  1813.  
  1814. } // end Scale_Object
  1815.  
  1816. /////////////////////////////////////////////////////////////////////////////
  1817.  
  1818. int Objects_Collide(object_ptr object_1, object_ptr object_2)
  1819. {
  1820. // this function tests if the bounding spheres of two objects overlaps
  1821. // if a more accurate test is needed then polygons should be tested against
  1822. // polygons. note the function uses the fact that if x > y then x^2 > y^2
  1823. // to avoid using square roots. Finally, the function might be altered
  1824. // so that the bounding spheres are shrank to make sure that the collision
  1825. // is "solid"/ finally, soft and hard collisions are both detected
  1826.  
  1827. float dx,dy,dz,           // deltas in x,y and z
  1828.       radius_1,radius_2,  // radi of each object
  1829.       distance;           // distance between object centers
  1830.  
  1831. // compute delta's
  1832.  
  1833. dx = (object_1->world_pos.x - object_2->world_pos.x);
  1834. dy = (object_1->world_pos.y - object_2->world_pos.y);
  1835. dz = (object_1->world_pos.z - object_2->world_pos.z);
  1836.  
  1837. // compute length
  1838.  
  1839. distance = dx*dx + dy*dy + dz*dx;
  1840.  
  1841. // compute radius of each object squared
  1842.  
  1843. radius_1 = object_1->radius*object_1->radius;
  1844. radius_2 = object_2->radius*object_2->radius;
  1845.  
  1846. // test if distance is smaller than of radi
  1847.  
  1848. if (distance<radius_1 || distance <radius_2)
  1849.    return(HARD_COLLISION); // hard collision
  1850. else
  1851. if (distance < radius_1+radius_2)
  1852.    return(SOFT_COLLISION); // soft collision
  1853. else
  1854.    return(NO_COLLISION);
  1855.  
  1856. } // end Objects_Collide
  1857.  
  1858. /////////////////////////////////////////////////////////////////////////////
  1859.  
  1860. char *PLG_Get_Line(char *string, int max_length, FILE *fp)
  1861. {
  1862. // this function gets a line from a PLG file and strips comments
  1863. // just pretend it's a black box!
  1864.  
  1865. char buffer[80]; // temporary string storage
  1866.  
  1867. int length,      // length of line read
  1868.     index=0,     // looping variables
  1869.     index_2=0,
  1870.     parsed=0;    // has the current input line been parsed
  1871.  
  1872. // get the next line of input, make sure there is something on the line
  1873.  
  1874. while(1)
  1875.      {
  1876.      // get the line
  1877.  
  1878.      if (!fgets(buffer,max_length,fp))
  1879.         return(NULL);
  1880.  
  1881.      // get length of line
  1882.  
  1883.      length = strlen(buffer);
  1884.  
  1885.      // kill the carriage return
  1886.  
  1887.      buffer[length-1] = 0;
  1888.  
  1889.      // reset index
  1890.  
  1891.      index = 0;
  1892.  
  1893.      // eat leading white space
  1894.  
  1895.      while(buffer[index]==' ')
  1896.            index++;
  1897.  
  1898.      // read line into buffer, if "#" arrives in data stream then disregard
  1899.      // rest of line
  1900.  
  1901.      parsed=0;
  1902.      index_2=0;
  1903.  
  1904.      while(!parsed)
  1905.           {
  1906.  
  1907.           if (buffer[index]!='#' && buffer[index]!=';')
  1908.              {
  1909.              // insert character into output string
  1910.  
  1911.              string[index_2] = buffer[index];
  1912.  
  1913.              // test if this is a null terminator
  1914.  
  1915.              if (string[index_2]==0)
  1916.                 parsed=1;
  1917.  
  1918.              // move to next character
  1919.  
  1920.              index++;
  1921.              index_2++;
  1922.  
  1923.              } // end if not comment
  1924.           else
  1925.              {
  1926.              // insert a null termination since this is the end of the
  1927.              // string for all intense purposes
  1928.  
  1929.              string[index_2] = 0;
  1930.  
  1931.              parsed=1;
  1932.  
  1933.              } // end else
  1934.  
  1935.           } // end while parsing string
  1936.  
  1937.           // make sure we got a string and not a blank line
  1938.  
  1939.           if (strlen(string))
  1940.              return(string);
  1941.  
  1942.      } // end while
  1943.  
  1944. } // end PLG_Get_Line
  1945.  
  1946. /////////////////////////////////////////////////////////////////////////////
  1947.  
  1948. int PLG_Load_Object(object_ptr the_object,char *filename,float scale)
  1949. {
  1950. // this function loads an object off disk and allows it to be scaled, the files
  1951. // are in a slightly enhanced PLG format that allows polygons to be defined
  1952. // as one or two sided, this helps the hidden surface removal system. This
  1953. // extra functionality has been encoded in the 2nd nibble from the left of the
  1954. // color descriptor
  1955.  
  1956. FILE *fp; // disk file
  1957.  
  1958. static int id_number = 0; // used to set object id's
  1959.  
  1960. char buffer[80],          // holds input string
  1961.      object_name[32],     // name of 3-D object
  1962.      *token;              // current parsing token
  1963.  
  1964.  
  1965. unsigned int total_vertices,    // total vertices in object
  1966.              total_polys,       // total polygons per object
  1967.              num_vertices,      // number of vertices on a polygon
  1968.              color_des,         // the color descriptor of a polygon
  1969.              logical_color,     // the final color of polygon
  1970.              shading,           // the type of shading used on polygon
  1971.              two_sided,         // flags if poly has two sides
  1972.              index,             // looping variables
  1973.              index_2,
  1974.              vertex_num,        // vertex numbers
  1975.              vertex_0,
  1976.              vertex_1,
  1977.              vertex_2;
  1978.  
  1979. float x,y,z;                    // a single vertex
  1980.  
  1981. vector_3d u,v,normal;           // working vectors
  1982.  
  1983. // open the disk file
  1984.  
  1985. if ((fp=fopen(filename,"r"))==NULL)
  1986.    {
  1987.    printf("\nCouldn't open file %s",filename);
  1988.    return(0);
  1989.  
  1990.    } // end if
  1991.  
  1992. // first we are looking for the header line that has the object name and
  1993. // the number of vertices and polygons
  1994.  
  1995. if (!PLG_Get_Line(buffer, 80,fp))
  1996.    {
  1997.    printf("\nError with PLG file %s",filename);
  1998.    fclose(fp);
  1999.    return(0);
  2000.    } // end if error
  2001.  
  2002. // extract object name and number of vertices and polygons
  2003.  
  2004. sscanf(buffer,"%s %d %d",object_name, &total_vertices, &total_polys);
  2005.  
  2006. // set proper fields in object
  2007.  
  2008. the_object->num_vertices = total_vertices;
  2009. the_object->num_polys    = total_polys;
  2010. the_object->state        = 1;
  2011.  
  2012. the_object->world_pos.x  = 0;
  2013. the_object->world_pos.y  = 0;
  2014. the_object->world_pos.z  = 0;
  2015.  
  2016. // set id number, maybe later also add the name of object in the
  2017. // structure???
  2018.  
  2019. the_object->id = id_number++;
  2020.  
  2021. // based on number of vertices, read vertex list into object
  2022.  
  2023. for (index=0; index<total_vertices; index++)
  2024.     {
  2025.  
  2026.     // read in vertex
  2027.  
  2028.     if (!PLG_Get_Line(buffer, 80,fp))
  2029.        {
  2030.        printf("\nError with PLG file %s",filename);
  2031.        fclose(fp);
  2032.        return(0);
  2033.        } // end if error
  2034.  
  2035.     sscanf(buffer,"%f %f %f",&x,&y,&z);
  2036.  
  2037.     // insert vertex into object
  2038.  
  2039.     the_object->vertices_local[index].x = x*scale;
  2040.     the_object->vertices_local[index].y = y*scale;
  2041.     the_object->vertices_local[index].z = z*scale;
  2042.  
  2043.     } // end for index
  2044.  
  2045. // now read in polygon list
  2046.  
  2047. for (index=0; index<total_polys; index++)
  2048.     {
  2049.     // read in color and number of vertices for next polygon
  2050.  
  2051.     if (!PLG_Get_Line(buffer, 80,fp))
  2052.        {
  2053.        printf("\nError with PLG file %s",filename);
  2054.        fclose(fp);
  2055.        return(0);
  2056.        } // end if error
  2057.  
  2058.     // intialize token getter and get first token which is color descriptor
  2059.  
  2060.     if (!(token = strtok(buffer," ")) )
  2061.        {
  2062.        printf("\nError with PLG file %s",filename);
  2063.        fclose(fp);
  2064.        return(0);
  2065.        } // end if problem
  2066.  
  2067.     // test if number is hexadecimal
  2068.  
  2069.     if (token[0]=='0' && (token[1]=='x' || token[1]=='X'))
  2070.        {
  2071.  
  2072.        sscanf(&token[2],"%x",&color_des);
  2073.  
  2074.        } // end if hex color specifier
  2075.     else
  2076.        {
  2077.  
  2078.        color_des = atoi(token);
  2079.  
  2080.        } // end if decimal
  2081.  
  2082.     // extract base color and type of shading
  2083.  
  2084.     logical_color = color_des & 0x00ff;
  2085.     shading       = color_des >> 12;
  2086.     two_sided     = ((color_des >> 8) & 0x0f);
  2087.  
  2088.     // read number of vertices in polygon
  2089.  
  2090.     if (!(token = strtok(NULL," ")))
  2091.        {
  2092.        printf("\nError with PLG file %s",filename);
  2093.        fclose(fp);
  2094.        return(0);
  2095.        } // end if problem
  2096.  
  2097.     if ((num_vertices = atoi(token))<=0)
  2098.        {
  2099.        printf("\nError with PLG file (number of vertices) %s",filename);
  2100.        fclose(fp);
  2101.        return(0);
  2102.        } // end if no vertices or error
  2103.  
  2104.     // set fields in polygon structure
  2105.  
  2106.     the_object->polys[index].num_points = num_vertices;
  2107.     the_object->polys[index].color      = logical_color;
  2108.     the_object->polys[index].shading    = shading;
  2109.     the_object->polys[index].two_sided  = two_sided;
  2110.     the_object->polys[index].visible    = 1;
  2111.     the_object->polys[index].clipped    = 0;
  2112.     the_object->polys[index].active     = 1;
  2113.  
  2114.     // now read in polygon vertice list
  2115.  
  2116.     for (index_2=0; index_2<num_vertices; index_2++)
  2117.         {
  2118.  
  2119.         // read in next vertex number
  2120.  
  2121.           if (!(token = strtok(NULL," ")) )
  2122.            {
  2123.            printf("\nError with PLG file %s",filename);
  2124.            fclose(fp);
  2125.            return(0);
  2126.            } // end if problem
  2127.  
  2128.         vertex_num = atoi(token);
  2129.  
  2130.         // insert vertex number into polygon
  2131.  
  2132.         the_object->polys[index].vertex_list[index_2] = vertex_num;
  2133.  
  2134.         } // end for index_2
  2135.  
  2136.     // compute length of the two co-planer edges of the polygon, since they
  2137.     // will be used in the computation of the dot-product later
  2138.  
  2139.     vertex_0 = the_object->polys[index].vertex_list[0];
  2140.     vertex_1 = the_object->polys[index].vertex_list[1];
  2141.     vertex_2 = the_object->polys[index].vertex_list[2];
  2142.  
  2143.     // the vector u = vo->v1
  2144.  
  2145.     Make_Vector_3D((point_3d_ptr)&the_object->vertices_local[vertex_0],
  2146.                    (point_3d_ptr)&the_object->vertices_local[vertex_1],
  2147.                    (vector_3d_ptr)&u);
  2148.  
  2149.     // the vector v = vo->v2
  2150.  
  2151.     Make_Vector_3D((point_3d_ptr)&the_object->vertices_local[vertex_0],
  2152.                    (point_3d_ptr)&the_object->vertices_local[vertex_2],
  2153.                    (vector_3d_ptr)&v);
  2154.  
  2155.     Cross_Product_3D((vector_3d_ptr)&v,
  2156.                      (vector_3d_ptr)&u,
  2157.                      (vector_3d_ptr)&normal);
  2158.  
  2159.  
  2160.     // compute magnitude of normal, take its inverse and multiply it by
  2161.     // 15, this will change the shading calculation of 15*dp/normal into
  2162.     // dp*normal_length, removing one division
  2163.  
  2164.     the_object->polys[index].normal_length = 15.0/Vector_Mag_3D((vector_3d_ptr)&normal);
  2165.  
  2166.     } // end for index
  2167.  
  2168. // close the file
  2169.  
  2170. fclose(fp);
  2171.  
  2172. // compute object radius
  2173.  
  2174. Compute_Object_Radius(the_object);
  2175.  
  2176. // return success
  2177.  
  2178. return(1);
  2179.  
  2180. } // end PLG_Load_Object
  2181.  
  2182. ///////////////////////////////////////////////////////////////////////////////
  2183.  
  2184. float Compute_Object_Radius(object_ptr the_object)
  2185. {
  2186.  
  2187. // this function computes maximum radius of object, maybe a better method would
  2188. // use average radius? Note that this functiopn shouldn't be used during
  2189. // runtime but when an object is created
  2190.  
  2191. float new_radius,   // used in average radius calculation of object
  2192.       x,y,z;        // a single vertex
  2193.  
  2194. int index;          // looping variable
  2195.  
  2196. // reset object radius
  2197.  
  2198. the_object->radius=0;
  2199.  
  2200. for (index=0; index<the_object->num_vertices; index++)
  2201.     {
  2202.  
  2203.     x = the_object->vertices_local[index].x;
  2204.     y = the_object->vertices_local[index].y;
  2205.     z = the_object->vertices_local[index].z;
  2206.  
  2207.     // compute distance to point
  2208.  
  2209.     new_radius = (float)sqrt(x*x + y*y + z*z);
  2210.  
  2211.     // is this radius bigger than last?
  2212.  
  2213.     if (new_radius > the_object->radius)
  2214.        the_object->radius = new_radius;
  2215.  
  2216.     } // end for index
  2217.  
  2218. // return radius just in case
  2219.  
  2220. return(the_object->radius);
  2221.  
  2222. } // end Compute_Object_Radius
  2223.  
  2224. /////////////////////////////////////////////////////////////////////////////
  2225.  
  2226. void Clip_Object_3D(object_ptr the_object, int mode)
  2227. {
  2228. // this function clips an object in camera coordinates against the 3D viewing
  2229. // volume. the function has two modes of operation. In CLIP_Z_MODE the
  2230. // function performs only a simple z extend clip with the near and far clipping
  2231. // planes. In CLIP_XYZ_MODE mode the function performs a full 3-D clip
  2232.  
  2233. int curr_poly;    // the current polygon being processed
  2234.  
  2235. float x1,y1,z1,
  2236.       x2,y2,z2,
  2237.       x3,y3,z3,
  2238.       x4,y4,z4,   // working variables used to hold vertices
  2239.  
  2240.       x1_compare, // used to hold clipping points on x and y
  2241.       y1_compare,
  2242.       x2_compare,
  2243.       y2_compare,
  2244.       x3_compare,
  2245.       y3_compare,
  2246.       x4_compare,
  2247.       y4_compare,
  2248.       fov_width,  // width and height of projected viewing plane
  2249.       fov_height; // used to speed up computations, since it's constant
  2250.                   // for any frame
  2251.  
  2252.  
  2253. // test if trivial z clipping is being requested
  2254.  
  2255. if (mode==CLIP_Z_MODE)
  2256.    {
  2257.    // attempt to clip each polygon against viewing volume
  2258.  
  2259.    for (curr_poly=0; curr_poly<the_object->num_polys; curr_poly++)
  2260.        {
  2261.  
  2262.        // extract z components
  2263.  
  2264.        z1=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[0]].z;
  2265.        z2=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[1]].z;
  2266.        z3=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[2]].z;
  2267.  
  2268.        // test if this is a quad
  2269.  
  2270.        if (the_object->polys[curr_poly].num_points==4)
  2271.           {
  2272.           // extract 4th z component
  2273.  
  2274.           z4=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[3]].z;
  2275.  
  2276.           } // end if quad
  2277.        else
  2278.          z4=z3;
  2279.  
  2280.        // perform near and far z clipping test
  2281.  
  2282.        if ( (z1<clip_near_z && z2<clip_near_z && z3<clip_near_z && z4<clip_near_z) ||
  2283.             (z1>clip_far_z && z2>clip_far_z && z3>clip_far_z && z4>clip_far_z) )
  2284.           {
  2285.           // set clipped flag
  2286.  
  2287.           the_object->polys[curr_poly].clipped=1;
  2288.  
  2289.           } // end if clipped
  2290.  
  2291.        } // end for curr_poly
  2292.  
  2293.     } // end if CLIP_Z_MODE
  2294. else
  2295.    {
  2296.    // CLIP_XYZ_MODE, perform full 3D viewing volume clip
  2297.  
  2298.    // compute dimensions of clipping extents at current viewing distance
  2299.  
  2300.    fov_width  = ((float)HALF_SCREEN_WIDTH/viewing_distance);
  2301.    fov_height = ((float)HALF_SCREEN_HEIGHT/viewing_distance);
  2302.  
  2303.  
  2304.    // process each polygon
  2305.  
  2306.    for (curr_poly=0; curr_poly<the_object->num_polys; curr_poly++)
  2307.        {
  2308.  
  2309.        // extract x,y and z components
  2310.  
  2311.        x1=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[0]].x;
  2312.        y1=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[0]].y;
  2313.        z1=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[0]].z;
  2314.  
  2315.        x2=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[1]].x;
  2316.        y2=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[1]].y;
  2317.        z2=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[1]].z;
  2318.  
  2319.        x3=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[2]].x;
  2320.        y3=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[2]].y;
  2321.        z3=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[2]].z;
  2322.  
  2323.        // test if this is a quad
  2324.  
  2325.        if (the_object->polys[curr_poly].num_points==4)
  2326.           {
  2327.           // extract 4th vertex
  2328.  
  2329.           x4=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[3]].x;
  2330.           y4=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[3]].y;
  2331.           z4=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[3]].z;
  2332.  
  2333.           // do clipping tests
  2334.  
  2335.           // perform near and far z clipping test first
  2336.  
  2337.           if (!((z1>clip_near_z || z2>clip_near_z || z3>clip_near_z || z4>clip_near_z) &&
  2338.                 (z1<clip_far_z || z2<clip_far_z || z3<clip_far_z || z4<clip_far_z)) )
  2339.              {
  2340.              // set clipped flag
  2341.  
  2342.              the_object->polys[curr_poly].clipped=1;
  2343.              continue;
  2344.  
  2345.              } // end if clipped
  2346.  
  2347.           // pre-compute x comparision ranges
  2348.  
  2349.           x1_compare = fov_width*z1;
  2350.           x2_compare = fov_width*z2;
  2351.           x3_compare = fov_width*z3;
  2352.           x4_compare = fov_width*z4;
  2353.  
  2354.           // perform x test
  2355.  
  2356.           if (!((x1>-x1_compare || x2>-x1_compare || x3>-x3_compare || x4>-x4_compare) &&
  2357.                 (x1<x1_compare || x2<x2_compare || x3<x3_compare || x4<x4_compare))  )
  2358.              {
  2359.              // set clipped flag
  2360.  
  2361.              the_object->polys[curr_poly].clipped=1;
  2362.              continue;
  2363.  
  2364.              } // end if clipped
  2365.  
  2366.           // pre-compute x comparision ranges
  2367.  
  2368.           y1_compare = fov_height*z1;
  2369.           y2_compare = fov_height*z2;
  2370.           y3_compare = fov_height*z3;
  2371.           y4_compare = fov_height*z4;
  2372.  
  2373.           // perform x test
  2374.  
  2375.           if (!((y1>-y1_compare || y2>-y1_compare || y3>-y3_compare || y4>-y4_compare) &&
  2376.                 (y1<y1_compare || y2<y2_compare || y3<y3_compare || y4<y4_compare))  )
  2377.              {
  2378.              // set clipped flag
  2379.  
  2380.              the_object->polys[curr_poly].clipped=1;
  2381.              continue;
  2382.  
  2383.              } // end if clipped
  2384.  
  2385.           } // end if quad
  2386.        else
  2387.           {
  2388.           // must be triangle, perform clipping tests on only 3 vertices
  2389.  
  2390.           // do clipping tests
  2391.  
  2392.           // perform near and far z clipping test first
  2393.  
  2394.           if (!((z1>clip_near_z || z2>clip_near_z || z3>clip_near_z) &&
  2395.                 (z1<clip_far_z || z2<clip_far_z || z3<clip_far_z)) )
  2396.              {
  2397.              // set clipped flag
  2398.  
  2399.              the_object->polys[curr_poly].clipped=1;
  2400.              continue;
  2401.  
  2402.              } // end if clipped
  2403.  
  2404.           // pre-compute x comparision ranges
  2405.  
  2406.           x1_compare = fov_width*z1;
  2407.           x2_compare = fov_width*z2;
  2408.           x3_compare = fov_width*z3;
  2409.  
  2410.           // perform x test
  2411.  
  2412.           if (!((x1>-x1_compare || x2>-x1_compare || x3>-x3_compare ) &&
  2413.                 (x1<x1_compare || x2<x2_compare || x3<x3_compare ))  )
  2414.              {
  2415.              // set clipped flag
  2416.  
  2417.              the_object->polys[curr_poly].clipped=1;
  2418.              continue;
  2419.  
  2420.              } // end if clipped
  2421.  
  2422.           // pre-compute x comparision ranges
  2423.  
  2424.           y1_compare = fov_height*z1;                                            (HALF_SCREEN_HEIGHT*z1)/viewing_distance;
  2425.           y2_compare = fov_height*z2;                                            (HALF_SCREEN_HEIGHT*z2)/viewing_distance;
  2426.           y3_compare = fov_height*z3;                                            (HALF_SCREEN_HEIGHT*z3)/viewing_distance;
  2427.  
  2428.           // perform x test
  2429.  
  2430.           if (!((y1>-y1_compare || y2>-y1_compare || y3>-y3_compare) &&
  2431.                 (y1<y1_compare || y2<y2_compare || y3<y3_compare ))  )
  2432.              {
  2433.              // set clipped flag
  2434.  
  2435.              the_object->polys[curr_poly].clipped=1;
  2436.              continue;
  2437.  
  2438.              } // end if clipped
  2439.  
  2440.            } // end else triangle
  2441.  
  2442.        } // end for curr_poly
  2443.  
  2444.    } // end else clip everything
  2445.  
  2446. } // end Clip_Object_3D
  2447.  
  2448. //////////////////////////////////////////////////////////////////////////////
  2449.  
  2450. void Remove_Backfaces_And_Shade(object_ptr the_object)
  2451. {
  2452. // this function removes all the backfaces of an object by setting the visibility
  2453. // flag. This function assumes that the object has been transformed into
  2454. // camera coordinates. Also, the function takes into consideration is the
  2455. // polygons are one or two sided and executed the minimum amount of code
  2456. // in addition to perform the shading calculations
  2457.  
  2458.  
  2459. int vertex_0,         // vertex indices
  2460.     vertex_1,
  2461.     vertex_2,
  2462.     curr_poly;        // current polygon
  2463.  
  2464. float dp,             // the result of the dot product
  2465.       intensity;      // the final intensity of the surface
  2466.  
  2467. vector_3d u,v,        // general working vectors
  2468.           normal,     // the normal to the surface begin processed
  2469.           sight;      // line of sight vector
  2470.  
  2471. // for each polygon in the object determine if it is pointing away from the
  2472. // viewpoint and direction
  2473.  
  2474. for (curr_poly=0; curr_poly<the_object->num_polys; curr_poly++)
  2475.     {
  2476.  
  2477.     // is this polygon two sised or one sided
  2478.  
  2479.     if (the_object->polys[curr_poly].two_sided == ONE_SIDED)
  2480.        {
  2481.  
  2482.        // compute two vectors on polygon that have the same intial points
  2483.  
  2484.        vertex_0 = the_object->polys[curr_poly].vertex_list[0];
  2485.        vertex_1 = the_object->polys[curr_poly].vertex_list[1];
  2486.        vertex_2 = the_object->polys[curr_poly].vertex_list[2];
  2487.  
  2488.        // the vector u = vo->v1
  2489.  
  2490.        Make_Vector_3D((point_3d_ptr)&the_object->vertices_world[vertex_0],
  2491.                       (point_3d_ptr)&the_object->vertices_world[vertex_1],
  2492.                       (vector_3d_ptr)&u);
  2493.  
  2494.        // the vector v = vo-v2
  2495.  
  2496.        Make_Vector_3D((point_3d_ptr)&the_object->vertices_world[vertex_0],
  2497.                       (point_3d_ptr)&the_object->vertices_world[vertex_2],
  2498.                       (vector_3d_ptr)&v);
  2499.  
  2500.        // compute the normal to polygon v x u
  2501.  
  2502.        Cross_Product_3D((vector_3d_ptr)&v,
  2503.                         (vector_3d_ptr)&u,
  2504.                         (vector_3d_ptr)&normal);
  2505.  
  2506.        // compute the line of sight vector, since all coordinates are world all
  2507.        // object vertices are already relative to (0,0,0), thus
  2508.  
  2509.        sight.x = view_point.x-the_object->vertices_world[vertex_0].x;
  2510.        sight.y = view_point.y-the_object->vertices_world[vertex_0].y;
  2511.        sight.z = view_point.z-the_object->vertices_world[vertex_0].z;
  2512.  
  2513.        // compute the dot product between line of sight vector and normal to surface
  2514.  
  2515.        dp = Dot_Product_3D((vector_3d_ptr)&normal,(vector_3d_ptr)&sight);
  2516.  
  2517.        // is surface visible
  2518.  
  2519.        if (dp>0)
  2520.           {
  2521.           // set visible flag
  2522.  
  2523.           the_object->polys[curr_poly].visible = 1;
  2524.  
  2525.           // compute light intensity if needed
  2526.  
  2527.           if (the_object->polys[curr_poly].shading==FLAT_SHADING)
  2528.              {
  2529.  
  2530.              // compute the dot product between the light source vector
  2531.              // and normal vector to surface
  2532.  
  2533.              dp = Dot_Product_3D((vector_3d_ptr)&normal,
  2534.                                  (vector_3d_ptr)&light_source);
  2535.  
  2536.              // test if light ray is reflecting off surface
  2537.  
  2538.              if (dp>0)
  2539.                 {
  2540.                 // now cos 0 = (u.v)/|u||v| or
  2541.  
  2542.                 intensity = ambient_light + (dp*(the_object->polys[curr_poly].normal_length));
  2543.  
  2544.                 // test if intensity has overflowed
  2545.  
  2546.                 if (intensity > 15)
  2547.                     intensity = 15;
  2548.  
  2549.                 // intensity now varies from 0-1, 0 being black or grazing and 1 being
  2550.                 // totally illuminated. use the value to index into color table
  2551.  
  2552.                 the_object->polys[curr_poly].shade =
  2553.                            the_object->polys[curr_poly].color - (int)intensity;
  2554.  
  2555.                 } // end if light is reflecting off surface
  2556.              else
  2557.                 the_object->polys[curr_poly].shade =
  2558.                 the_object->polys[curr_poly].color - (int)ambient_light;
  2559.  
  2560.              } // end if use flat shading
  2561.           else
  2562.              {
  2563.              // assume constant shading and simply assign color to shade
  2564.  
  2565.              the_object->polys[curr_poly].shade = the_object->polys[curr_poly].color;
  2566.  
  2567.              } // end else constant shading
  2568.  
  2569.           } // end if dp>0
  2570.        else
  2571.           the_object->polys[curr_poly].visible = 0;
  2572.  
  2573.  
  2574.        } // end if one sided
  2575.     else
  2576.        {
  2577.        // else polygon is always visible i.e. two sided, set visibility flag
  2578.        // so engine renders it
  2579.  
  2580.        // set visibility
  2581.  
  2582.        the_object->polys[curr_poly].visible = 1;
  2583.  
  2584.        // perform shading calculation
  2585.  
  2586.        if (the_object->polys[curr_poly].shading==FLAT_SHADING)
  2587.           {
  2588.           // compute normal
  2589.  
  2590.           // compute two vectors on polygon that have the same intial points
  2591.  
  2592.           vertex_0 = the_object->polys[curr_poly].vertex_list[0];
  2593.           vertex_1 = the_object->polys[curr_poly].vertex_list[1];
  2594.           vertex_2 = the_object->polys[curr_poly].vertex_list[2];
  2595.  
  2596.           // the vector u = vo->v1
  2597.  
  2598.           Make_Vector_3D((point_3d_ptr)&the_object->vertices_world[vertex_0],
  2599.                          (point_3d_ptr)&the_object->vertices_world[vertex_1],
  2600.                          (vector_3d_ptr)&u);
  2601.  
  2602.           // the vector v = vo-v2
  2603.  
  2604.           Make_Vector_3D((point_3d_ptr)&the_object->vertices_world[vertex_0],
  2605.                          (point_3d_ptr)&the_object->vertices_world[vertex_2],
  2606.                          (vector_3d_ptr)&v);
  2607.  
  2608.           // compute the normal to polygon v x u
  2609.  
  2610.           Cross_Product_3D((vector_3d_ptr)&v,
  2611.                            (vector_3d_ptr)&u,
  2612.                            (vector_3d_ptr)&normal);
  2613.  
  2614.  
  2615.           // compute the dot product between the light source vector
  2616.           // and normal vector to surface
  2617.  
  2618.           dp = Dot_Product_3D((vector_3d_ptr)&normal,
  2619.                               (vector_3d_ptr)&light_source);
  2620.  
  2621.           // test if light ray is reflecting off surface
  2622.  
  2623.           if (dp>0)
  2624.              {
  2625.              // now cos 0 = (u.v)/|u||v| or
  2626.  
  2627.              intensity = ambient_light + (dp*(the_object->polys[curr_poly].normal_length));
  2628.  
  2629.              // test if intensity has overflowed
  2630.  
  2631.              if (intensity > 15)
  2632.                  intensity = 15;
  2633.  
  2634.              // intensity now varies from 0-1, 0 being black or grazing and 1 being
  2635.              // totally illuminated. use the value to index into color table
  2636.  
  2637.              the_object->polys[curr_poly].shade =
  2638.                         the_object->polys[curr_poly].color - (int)intensity;
  2639.  
  2640.              } // end if light is reflecting off surface
  2641.           else
  2642.              the_object->polys[curr_poly].shade =
  2643.              the_object->polys[curr_poly].color - (int)ambient_light;
  2644.  
  2645.           } // end if use flat shading
  2646.        else
  2647.           {
  2648.           // assume constant shading and simply assign color to shade
  2649.  
  2650.           the_object->polys[curr_poly].shade = the_object->polys[curr_poly].color;
  2651.  
  2652.           } // end else constant shading
  2653.  
  2654.        } // end else two sided
  2655.  
  2656.     } // end for curr_poly
  2657.  
  2658. } // end Remove_Backfaces_And_Shade
  2659.  
  2660. //////////////////////////////////////////////////////////////////////////////
  2661.  
  2662. int Remove_Object(object_ptr the_object, int mode)
  2663. {
  2664. // this function determines if an entire object is within the viewing volume
  2665. // or not by testing if the bounding sphere of the object in question
  2666. // is within the viewing volume.In essence, this function "culls" entire objects
  2667.  
  2668. float x_bsphere,   // the x,y and z components of the projected center of object
  2669.       y_bsphere,
  2670.       z_bsphere,
  2671.       radius,     // the radius of object
  2672.       x_compare,  // the extents of the clipping volume in x and y at the
  2673.       y_compare;  // bounding spheres current z
  2674.  
  2675. // first transform world position of object into camera coordinates
  2676.  
  2677. // compute x component
  2678.  
  2679. x_bsphere = the_object->world_pos.x * global_view[0][0] +
  2680.             the_object->world_pos.y * global_view[1][0] +
  2681.             the_object->world_pos.z * global_view[2][0] +
  2682.                                       global_view[3][0];
  2683.  
  2684. // compute y component
  2685.  
  2686. y_bsphere = the_object->world_pos.x * global_view[0][1] +
  2687.             the_object->world_pos.y * global_view[1][1] +
  2688.             the_object->world_pos.z * global_view[2][1] +
  2689.                                       global_view[3][1];
  2690. // compute z component
  2691.  
  2692. z_bsphere = the_object->world_pos.x * global_view[0][2] +
  2693.             the_object->world_pos.y * global_view[1][2] +
  2694.             the_object->world_pos.z * global_view[2][2] +
  2695.                                       global_view[3][2];
  2696.  
  2697. // extract radius of object
  2698.  
  2699. radius = the_object->radius;
  2700.  
  2701. if (mode==OBJECT_CULL_Z_MODE)
  2702.    {
  2703.    // first test against near and far z planes
  2704.  
  2705.    if ( ((z_bsphere-radius) > clip_far_z) ||
  2706.         ((z_bsphere+radius) < clip_near_z) )
  2707.         return(1);
  2708.    else
  2709.         return(0);
  2710.  
  2711.    } // end if z only
  2712. else
  2713.    {
  2714.    // perform full x,y,z test
  2715.  
  2716.    if ( ((z_bsphere-radius) > clip_far_z) ||
  2717.         ((z_bsphere+radius) < clip_near_z) )
  2718.         return(1);
  2719.  
  2720.    // test against x right and left planes, first compute viewing volume
  2721.    // extents at position z position of bounding sphere
  2722.  
  2723.    x_compare = (HALF_SCREEN_WIDTH*z_bsphere)/viewing_distance;
  2724.  
  2725.    if ( ((x_bsphere-radius) > x_compare) ||
  2726.         ((x_bsphere+radius) < -x_compare) )
  2727.       return(1);
  2728.  
  2729.    // finally test against y top and bottom planes
  2730.  
  2731.    y_compare = (INVERSE_ASPECT_RATIO*HALF_SCREEN_HEIGHT*z_bsphere)/viewing_distance;
  2732.  
  2733.    if ( ((y_bsphere-radius) > y_compare) ||
  2734.         ((y_bsphere+radius) < -y_compare) )
  2735.       return(1);
  2736.  
  2737.    // else it just can't be removed!!!
  2738.  
  2739.    return(0);
  2740.  
  2741.    } // end else
  2742.  
  2743. } // end Remove_Object
  2744.  
  2745. //////////////////////////////////////////////////////////////////////////////
  2746.  
  2747. void Generate_Poly_List(object_ptr the_object,int mode)
  2748. {
  2749. // this function is used to generate the final polygon list that will be
  2750. // rendered. Object by object the list is built up
  2751.  
  2752.  
  2753. int vertex,
  2754.     curr_vertex,
  2755.     curr_poly;
  2756.  
  2757. // test if this is the first object to be inserted
  2758.  
  2759. if (mode==RESET_POLY_LIST)
  2760.    {
  2761.    // reset number of polys to zero
  2762.  
  2763.    num_polys_frame=0;
  2764.    return;
  2765.  
  2766.    } // end if first
  2767.  
  2768. // insert all visible polygons into polygon list
  2769.  
  2770. for (curr_poly=0; curr_poly<the_object->num_polys; curr_poly++)
  2771.     {
  2772.  
  2773.     // test if this poly is visible, if so add it to poly list
  2774.  
  2775.     if (the_object->polys[curr_poly].visible &&
  2776.         !the_object->polys[curr_poly].clipped)
  2777.        {
  2778.        // add this poly to poly list
  2779.  
  2780.        // first copy data and vertices into an open slot in storage area
  2781.  
  2782.        world_poly_storage[num_polys_frame].num_points = the_object->polys[curr_poly].num_points;
  2783.        world_poly_storage[num_polys_frame].color      = the_object->polys[curr_poly].color;
  2784.        world_poly_storage[num_polys_frame].shade      = the_object->polys[curr_poly].shade;
  2785.        world_poly_storage[num_polys_frame].shading    = the_object->polys[curr_poly].shading;
  2786.        world_poly_storage[num_polys_frame].two_sided  = the_object->polys[curr_poly].two_sided;
  2787.        world_poly_storage[num_polys_frame].visible    = the_object->polys[curr_poly].visible;
  2788.        world_poly_storage[num_polys_frame].clipped    = the_object->polys[curr_poly].clipped;
  2789.        world_poly_storage[num_polys_frame].active     = the_object->polys[curr_poly].active;
  2790.  
  2791.        // now copy vertices
  2792.  
  2793.        for (curr_vertex=0; curr_vertex<the_object->polys[curr_poly].num_points; curr_vertex++)
  2794.            {
  2795.            // extract vertex number
  2796.  
  2797.            vertex=the_object->polys[curr_poly].vertex_list[curr_vertex];
  2798.  
  2799.            // extract x,y and z
  2800.  
  2801.            world_poly_storage[num_polys_frame].vertex_list[curr_vertex].x
  2802.                                     = the_object->vertices_camera[vertex].x;
  2803.  
  2804.            world_poly_storage[num_polys_frame].vertex_list[curr_vertex].y
  2805.                                     = the_object->vertices_camera[vertex].y;
  2806.  
  2807.            world_poly_storage[num_polys_frame].vertex_list[curr_vertex].z
  2808.                                     = the_object->vertices_camera[vertex].z;
  2809.  
  2810.  
  2811.            } // end for curr_vertex
  2812.  
  2813.        // assign pointer to it
  2814.  
  2815.        world_polys[num_polys_frame] = &world_poly_storage[num_polys_frame];
  2816.  
  2817.        // increment number of polys
  2818.  
  2819.        num_polys_frame++;
  2820.  
  2821.        } // end if poly visible
  2822.  
  2823.     } // end for curr_poly
  2824.  
  2825. } // end Generate_Poly_List
  2826.  
  2827. //////////////////////////////////////////////////////////////////////////////
  2828.  
  2829. void Draw_Poly_List(void)
  2830. {
  2831.  
  2832. // this function draws the global polygon list generated by calls to
  2833. // Generate_Poly_List
  2834.  
  2835. int curr_poly;          // the current polygon
  2836.  
  2837. float x1,y1,z1,         // working variables
  2838.       x2,y2,z2,
  2839.       x3,y3,z3,
  2840.       x4,y4,z4,
  2841.       viewing_distance_aspect;  // the y axis corrected viewing distance
  2842.  
  2843.  
  2844. viewing_distance_aspect = viewing_distance*ASPECT_RATIO;
  2845.  
  2846. // draw each polygon in list
  2847.  
  2848. for (curr_poly=0; curr_poly<num_polys_frame; curr_poly++)
  2849.     {
  2850.     // get z's for perspective
  2851.  
  2852.     z1=world_polys[curr_poly]->vertex_list[0].z;
  2853.     z2=world_polys[curr_poly]->vertex_list[1].z;
  2854.     z3=world_polys[curr_poly]->vertex_list[2].z;
  2855.  
  2856.     // test if this is a quad
  2857.  
  2858.     if (world_polys[curr_poly]->num_points==4)
  2859.        {
  2860.        // extract vertex number and z component for clipping and projection
  2861.  
  2862.        z4=world_polys[curr_poly]->vertex_list[3].z;
  2863.  
  2864.        } // end if quad
  2865.     else
  2866.       z4=z3;
  2867.  
  2868. #if 0
  2869.  
  2870.     // perform z clipping test
  2871.  
  2872.     if ( (z1<clip_near_z && z2<clip_near_z && z3<clip_near_z && z4<clip_near_z) ||
  2873.          (z1>clip_far_z && z2>clip_far_z && z3>clip_far_z && z4>clip_far_z) )
  2874.        continue;
  2875.  
  2876. #endif
  2877.  
  2878.         // extract points of polygon
  2879.  
  2880.         x1 = world_polys[curr_poly]->vertex_list[0].x;
  2881.         y1 = world_polys[curr_poly]->vertex_list[0].y;
  2882.  
  2883.         x2 = world_polys[curr_poly]->vertex_list[1].x;
  2884.         y2 = world_polys[curr_poly]->vertex_list[1].y;
  2885.  
  2886.         x3 = world_polys[curr_poly]->vertex_list[2].x;
  2887.         y3 = world_polys[curr_poly]->vertex_list[2].y;
  2888.  
  2889.         // compute screen position of points
  2890.  
  2891.         x1=(HALF_SCREEN_WIDTH  + x1*viewing_distance/z1);
  2892.         y1=(HALF_SCREEN_HEIGHT - y1*viewing_distance_aspect/z1);
  2893.  
  2894.         x2=(HALF_SCREEN_WIDTH  + x2*viewing_distance/z2);
  2895.         y2=(HALF_SCREEN_HEIGHT - y2*viewing_distance_aspect/z2);
  2896.  
  2897.         x3=(HALF_SCREEN_WIDTH  + x3*viewing_distance/z3);
  2898.         y3=(HALF_SCREEN_HEIGHT - y3*viewing_distance_aspect/z3);
  2899.  
  2900.         // draw triangle
  2901.  
  2902.         Draw_Triangle_2D((int)x1,(int)y1,(int)x2,(int)y2,(int)x3,(int)y3,
  2903.                          world_polys[curr_poly]->shade);
  2904.  
  2905.         // draw second poly if this is a quad
  2906.  
  2907.         if (world_polys[curr_poly]->num_points==4)
  2908.            {
  2909.            // extract the point
  2910.  
  2911.            x4 = world_polys[curr_poly]->vertex_list[3].x;
  2912.            y4 = world_polys[curr_poly]->vertex_list[3].y;
  2913.  
  2914.            // poject to screen
  2915.  
  2916.            x4=(HALF_SCREEN_WIDTH  + x4*viewing_distance/z4);
  2917.            y4=(HALF_SCREEN_HEIGHT - y4*viewing_distance_aspect/z4);
  2918.  
  2919.            // draw triangle
  2920.  
  2921.            Draw_Triangle_2D((int)x1,(int)y1,(int)x3,(int)y3,(int)x4,(int)y4,
  2922.                             world_polys[curr_poly]->shade);
  2923.  
  2924.            } // end if quad
  2925.  
  2926.     } // end for curr_poly
  2927.  
  2928. } // end Draw_Poly_List
  2929.  
  2930. /////////////////////////////////////////////////////////////////////////////
  2931.  
  2932. void Compute_Average_Z(void)
  2933. {
  2934. // this function pre-computes the average z of each polygon, so that the
  2935. // polygon sorter doesn't compute each z more than once
  2936.  
  2937. int index;
  2938.  
  2939. for (index=0; index<num_polys_frame; index++)
  2940.     {
  2941.  
  2942.     if (world_poly_storage[index].num_points==3)
  2943.        {
  2944.        world_poly_storage[index].average_z =
  2945.  
  2946.                    (int)(0.3333*(world_poly_storage[index].vertex_list[0].z+
  2947.                                  world_poly_storage[index].vertex_list[1].z+
  2948.                                  world_poly_storage[index].vertex_list[2].z));
  2949.  
  2950.        } // end if
  2951.     else
  2952.        {
  2953.        world_poly_storage[index].average_z =
  2954.  
  2955.                       (int)(0.25*(world_poly_storage[index].vertex_list[0].z+
  2956.                                   world_poly_storage[index].vertex_list[1].z+
  2957.                                   world_poly_storage[index].vertex_list[2].z+
  2958.                                   world_poly_storage[index].vertex_list[3].z));
  2959.  
  2960.        } // end if
  2961.  
  2962.     } // end for index
  2963.  
  2964. } // end Compute_Average_Z
  2965.  
  2966. //////////////////////////////////////////////////////////////////////////////
  2967.  
  2968. int Poly_Compare(facet **arg1, facet **arg2)
  2969. {
  2970. // this function comapares the average z's of two polygons and is used by the
  2971. // depth sort surface ordering algorithm
  2972.  
  2973. facet_ptr poly_1,poly_2;
  2974.  
  2975. // dereference the poly pointers
  2976.  
  2977. poly_1 = (facet_ptr)*arg1;
  2978. poly_2 = (facet_ptr)*arg2;
  2979.  
  2980. if (poly_1->average_z>poly_2->average_z)
  2981.    return(-1);
  2982. else
  2983. if (poly_1->average_z<poly_2->average_z)
  2984.    return(1);
  2985. else
  2986.    return(0);
  2987.  
  2988. } // end Poly_Compare
  2989.  
  2990. /////////////////////////////////////////////////////////////////////////////
  2991.  
  2992. void Sort_Poly_List(void)
  2993. {
  2994. // this function does a simple z sort on the poly list to order surfaces
  2995. // the list is sorted in descending order, i.e. farther polygons first
  2996.  
  2997. Compute_Average_Z();
  2998.  
  2999. qsort((void *)world_polys,num_polys_frame, sizeof(facet_ptr), (qsort_cast)Poly_Compare);
  3000.  
  3001. } // end Sort_Poly_List
  3002.  
  3003. ///////////////////////////////////////////////////////////////////////////////
  3004.  
  3005. int Load_Palette_Disk(char *filename, RGB_palette_ptr the_palette)
  3006. {
  3007. // this function loads a color palette from disk
  3008.  
  3009. int index; // used for looping
  3010.  
  3011. RGB_color color;
  3012.  
  3013. FILE *fp;
  3014.  
  3015. // open the disk file
  3016.  
  3017. if (!(fp = fopen(filename,"r")))
  3018.    return(0);
  3019.  
  3020. // load in all the colors
  3021.  
  3022. for (index=0; index<=255; index++)
  3023.     {
  3024.     // get the next color
  3025.  
  3026.     fscanf(fp,"%d %d %d",&color.red,&color.green,&color.blue);
  3027.  
  3028.     // store the color in next element of palette
  3029.  
  3030.     the_palette->colors[index].red   = color.red;
  3031.     the_palette->colors[index].green = color.green;
  3032.     the_palette->colors[index].blue  = color.blue;
  3033.  
  3034.     } // end for index
  3035.  
  3036. // set palette size to a full palette
  3037.  
  3038. the_palette->start_reg = 0;
  3039. the_palette->end_reg   = 255;
  3040.  
  3041. // close the file and return success
  3042.  
  3043. fclose(fp);
  3044.  
  3045. return(1);
  3046.  
  3047. } // end Load_Palette_Disk
  3048.  
  3049. ///////////////////////////////////////////////////////////////////////////////
  3050.  
  3051. int Save_Palette_Disk(char *filename, RGB_palette_ptr the_palette)
  3052. {
  3053. // this function saves a palette to disk
  3054.  
  3055. int index; // used for looping
  3056.  
  3057. RGB_color color;
  3058.  
  3059. FILE *fp;
  3060.  
  3061. // open the disk file
  3062.  
  3063. if (!(fp = fopen(filename,"w")))
  3064.    return(0);
  3065.  
  3066. // write 255 lines of r g b
  3067.  
  3068. for (index=0; index<=255; index++)
  3069.     {
  3070.     // get the next color
  3071.  
  3072.     // store the color in next element of palette
  3073.  
  3074.     color.red   = the_palette->colors[index].red;
  3075.     color.green = the_palette->colors[index].green;
  3076.     color.blue  = the_palette->colors[index].blue;
  3077.  
  3078.     // write the color to disk file
  3079.  
  3080.     fprintf(fp,"\n%d %d %d",color.red, color.green, color.blue);
  3081.  
  3082.     } // end for index
  3083.  
  3084. // close the file and return success
  3085.  
  3086. fclose(fp);
  3087.  
  3088. return(1);
  3089.  
  3090. } // end Save_Palette_Disk
  3091.  
  3092. ///////////////////////////////////////////////////////////////////////////////
  3093.  
  3094. void Fill_Double_Buffer_32(int icolor)
  3095. {
  3096. // this function fills in the double buffer with the sent color a QUAD at
  3097. // a time
  3098.  
  3099. long color;  // used to create a 4 byte color descriptor
  3100.  
  3101. color = icolor | (icolor << 8);
  3102.  
  3103. // replicate color into all four bytes of quad
  3104.  
  3105. color = color | (color<<16);
  3106.  
  3107. fquadset((void far *)double_buffer,color,(double_buffer_size >> 1));
  3108.  
  3109. } // end Fill_Double_Buffer_32
  3110.  
  3111. //////////////////////////////////////////////////////////////////////////////
  3112.  
  3113. void Display_Double_Buffer_32(unsigned char far *buffer,int y)
  3114. {
  3115. // this functions copies the double buffer into the video buffer at the
  3116. // starting y location using quad byte transfers
  3117.  
  3118. fquadcpy((void far *)(video_buffer+y*320),
  3119.             (void far *)double_buffer,
  3120.             (double_buffer_size >> 1));
  3121.  
  3122.  
  3123. } // end Display_Double_Buffer_32
  3124.  
  3125.  
  3126.