home *** CD-ROM | disk | FTP | other *** search
/ Black Art of 3D Game Programming / Black_Art_of_3D_Game_Programming.iso / source / borland / chap_18 / black18.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-25  |  102.0 KB  |  3,703 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 "black18.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_Line(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.     // use the external assembly language triangle engine based on fixed point
  353.  
  354.     if (y3>y1)
  355.        Triangle_Asm(dest_addr,y1,y3,xs,xe,dx_left,dx_right,color);
  356.  
  357.     } // end if no x clipping needed
  358. else
  359.    {
  360.    // clip x axis with slower version
  361.  
  362.    // draw the triangle
  363.  
  364.    for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=320)
  365.        {
  366.  
  367.        // do x clip
  368.  
  369.        left  = (int)xs;
  370.        right = (int)xe;
  371.  
  372.        // adjust starting point and ending point
  373.  
  374.        xs+=dx_left;
  375.        xe+=dx_right;
  376.  
  377.        // clip line
  378.  
  379.        if (left < poly_clip_min_x)
  380.           {
  381.           left = poly_clip_min_x;
  382.  
  383.           if (right < poly_clip_min_x)
  384.              continue;
  385.  
  386.           }
  387.  
  388.        if (right > poly_clip_max_x)
  389.           {
  390.           right = poly_clip_max_x;
  391.  
  392.           if (left > poly_clip_max_x)
  393.              continue;
  394.  
  395.           }
  396.  
  397.         Triangle_16Line(dest_addr,(unsigned int)left,(unsigned int)right,color);
  398.  
  399.        } // end for
  400.  
  401.    } // end else x clipping needed
  402.  
  403. } // end Draw_Top_Triangle
  404.  
  405. /////////////////////////////////////////////////////////////////////////////
  406.  
  407. void Draw_Bottom_Triangle(int x1,int y1, int x2,int y2, int x3,int y3,int color)
  408. {
  409.  
  410. // this function draws a triangle that has a flat bottom
  411.  
  412. float dx_right,    // the dx/dy ratio of the right edge of line
  413.       dx_left,     // the dx/dy ratio of the left edge of line
  414.       xs,xe,       // the starting and ending points of the edges
  415.       height;      // the height of the triangle
  416.  
  417. int temp_x,        // used during sorting as temps
  418.     temp_y,
  419.     right,         // used by clipping
  420.     left;
  421.  
  422. unsigned char far *dest_addr;
  423.  
  424. // test order of x1 and x2
  425.  
  426. if (x3 < x2)
  427.    {
  428.    temp_x = x2;
  429.    x2     = x3;
  430.    x3     = temp_x;
  431.  
  432.    } // end if swap
  433.  
  434. // compute delta's
  435.  
  436. height = y3-y1;
  437.  
  438. dx_left  = (x2-x1)/height;
  439. dx_right = (x3-x1)/height;
  440.  
  441. // set starting points
  442.  
  443. xs = (float)x1;
  444. xe = (float)x1+(float)0.5;
  445.  
  446. // perform y clipping
  447.  
  448. if (y1<poly_clip_min_y)
  449.    {
  450.    // compute new xs and ys
  451.  
  452.    xs = xs+dx_left*(float)(-y1+poly_clip_min_y);
  453.    xe = xe+dx_right*(float)(-y1+poly_clip_min_y);
  454.  
  455.    // reset y1
  456.  
  457.    y1=poly_clip_min_y;
  458.  
  459.    } // end if top is off screen
  460.  
  461. if (y3>poly_clip_max_y)
  462.    y3=poly_clip_max_y;
  463.  
  464. // compute starting address in video memory
  465.  
  466. dest_addr = double_buffer+(y1<<8)+(y1<<6);
  467.  
  468. // test if x clipping is needed
  469.  
  470. if (x1>=poly_clip_min_x && x1<=poly_clip_max_x &&
  471.     x2>=poly_clip_min_x && x2<=poly_clip_max_x &&
  472.     x3>=poly_clip_min_x && x3<=poly_clip_max_x)
  473.     {
  474.     // draw the triangle
  475.  
  476.  
  477. #if 0
  478.  
  479.     for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=320)
  480.         {
  481.  
  482.         Triangle_16Line(dest_addr,(unsigned int)xs,(unsigned int)xe,color);
  483.  
  484.         // adjust starting point and ending point
  485.  
  486.         xs+=dx_left;
  487.         xe+=dx_right;
  488.  
  489.         } // end for
  490.  
  491. #endif
  492.  
  493.      // use the external assembly language triangle engine based on fixed point
  494.  
  495.      if (y3>y1)
  496.         Triangle_Asm(dest_addr,y1,y3,xs,xe,dx_left,dx_right,color);
  497.  
  498.  
  499.     } // end if no x clipping needed
  500. else
  501.    {
  502.    // clip x axis with slower version
  503.  
  504.    // draw the triangle
  505.  
  506.    for (temp_y=y1; temp_y<=y3; temp_y++,dest_addr+=320)
  507.        {
  508.        // do x clip
  509.  
  510.        left  = (int)xs;
  511.        right = (int)xe;
  512.  
  513.        // adjust starting point and ending point
  514.  
  515.        xs+=dx_left;
  516.        xe+=dx_right;
  517.  
  518.        // clip line
  519.  
  520.        if (left < poly_clip_min_x)
  521.           {
  522.           left = poly_clip_min_x;
  523.  
  524.           if (right < poly_clip_min_x)
  525.              continue;
  526.  
  527.           }
  528.  
  529.        if (right > poly_clip_max_x)
  530.           {
  531.           right = poly_clip_max_x;
  532.  
  533.           if (left > poly_clip_max_x)
  534.              continue;
  535.           }
  536.  
  537.        Triangle_16Line(dest_addr,(unsigned int)left,(unsigned int)right,color);
  538.  
  539.        } // end for
  540.  
  541.    } // end else x clipping needed
  542.  
  543. } // end Draw_Bottom_Triangle
  544.  
  545. ///////////////////////////////////////////////////////////////////////////////
  546.  
  547. void Draw_Triangle_2D(int x1,int y1,
  548.                       int x2,int y2,
  549.                       int x3,int y3,int color)
  550. {
  551. int temp_x,
  552.     temp_y,
  553.     new_x;
  554.  
  555. // test for h lines and v lines
  556.  
  557. if ((x1==x2 && x2==x3)  ||  (y1==y2 && y2==y3))
  558.    return;
  559.  
  560. // sort p1,p2,p3 in ascending y order
  561.  
  562. if (y2<y1)
  563.    {
  564.    temp_x = x2;
  565.    temp_y = y2;
  566.    x2     = x1;
  567.    y2     = y1;
  568.    x1     = temp_x;
  569.    y1     = temp_y;
  570.    } // end if
  571.  
  572. // now we know that p1 and p2 are in order
  573.  
  574. if (y3<y1)
  575.    {
  576.    temp_x = x3;
  577.    temp_y = y3;
  578.    x3     = x1;
  579.    y3     = y1;
  580.    x1     = temp_x;
  581.    y1     = temp_y;
  582.    } // end if
  583.  
  584. // finally test y3 against y2
  585.  
  586. if (y3<y2)
  587.    {
  588.    temp_x = x3;
  589.    temp_y = y3;
  590.    x3     = x2;
  591.    y3     = y2;
  592.    x2     = temp_x;
  593.    y2     = temp_y;
  594.  
  595.    } // end if
  596.  
  597. // do trivial rejection tests
  598.  
  599. if ( y3<poly_clip_min_y || y1>poly_clip_max_y ||
  600.     (x1<poly_clip_min_x && x2<poly_clip_min_x && x3<poly_clip_min_x) ||
  601.     (x1>poly_clip_max_x && x2>poly_clip_max_x && x3>poly_clip_max_x) )
  602.    return;
  603.  
  604. // test if top of triangle is flat
  605.  
  606. if (y1==y2)
  607.    {
  608.  
  609.    Draw_Top_Triangle(x1,y1,x2,y2,x3,y3,color);
  610.  
  611.    } // end if
  612. else
  613. if (y2==y3)
  614.    {
  615.  
  616.    Draw_Bottom_Triangle(x1,y1,x2,y2,x3,y3,color);
  617.  
  618.  
  619.    } // end if bottom is flat
  620. else
  621.    {
  622.    // general triangle that's needs to be broken up along long edge
  623.  
  624.    new_x = x1 + (int)((float)(y2-y1)*(float)(x3-x1)/(float)(y3-y1));
  625.  
  626.    // draw each sub-triangle
  627.  
  628.    Draw_Bottom_Triangle(x1,y1,new_x,y2,x2,y2,color);
  629.  
  630.    Draw_Top_Triangle(x2,y2,new_x,y2,x3,y3,color);
  631.  
  632.    } // end else
  633.  
  634. } // end Draw_Triangle_2D
  635.  
  636. ////////////////////////////////////////////////////////////////////////////////
  637.  
  638. void Build_Look_Up_Tables(void)
  639. {
  640. // this function builds all the look up tables for the engine
  641.  
  642. int angle;  // the current angle being computed
  643.  
  644. float rad;  // used in conversion from degrees to radians
  645.  
  646.  // generate sin/cos look up tables
  647.  
  648. for (angle=0; angle<=360; angle++)
  649.     {
  650.  
  651.     rad = (float) (3.14159*(float)angle/(float)180);
  652.  
  653.     cos_look[angle] = (float)cos(rad);
  654.     sin_look[angle] = (float)sin(rad);
  655.  
  656.     } // end for angle
  657.  
  658. } // end Build_Look_Up_Tables
  659.  
  660. //////////////////////////////////////////////////////////////////////////////
  661.  
  662. float Dot_Product_3D(vector_3d_ptr u,vector_3d_ptr v)
  663. {
  664. // this function computes the dot product of two vectors
  665.  
  666. return( (u->x * v->x) + (u->y * v->y) + (u->z * v->z));
  667.  
  668. } // end Dot_Product
  669.  
  670. //////////////////////////////////////////////////////////////////////////////
  671.  
  672. void Make_Vector_3D(point_3d_ptr init,
  673.                     point_3d_ptr term,
  674.                     vector_3d_ptr result)
  675. {
  676. // this function creates a vector from two points in 3D space
  677.  
  678. result->x = term->x - init->x;
  679. result->y = term->y - init->y;
  680. result->z = term->z - init->z;
  681.  
  682. } // end Make_Vector
  683.  
  684. //////////////////////////////////////////////////////////////////////////////
  685.  
  686. void Cross_Product_3D(vector_3d_ptr u,
  687.                       vector_3d_ptr v,
  688.                       vector_3d_ptr normal)
  689. {
  690. // this function computes the cross product between two vectors
  691.  
  692. normal->x =  (u->y*v->z - u->z*v->y);
  693. normal->y = -(u->x*v->z - u->z*v->x);
  694. normal->z =  (u->x*v->y - u->y*v->x);
  695.  
  696. } // end Cross_Product_3D
  697.  
  698. ///////////////////////////////////////////////////////////////////////////////
  699.  
  700. float Vector_Mag_3D(vector_3d_ptr v)
  701. {
  702. // computes the magnitude of a vector
  703.  
  704. return((float)sqrt(v->x*v->x + v->y*v->y + v->z*v->z));
  705.  
  706. } // end Vector_Mag_3D
  707.  
  708. ///////////////////////////////////////////////////////////////////////////////
  709.  
  710. void Mat_Print_4x4(matrix_4x4 a)
  711. {
  712. // this function prints out a 4x4 matrix
  713.  
  714. int row,      // looping variables
  715.     column;
  716.  
  717. for (row=0; row<4; row++)
  718.     {
  719.     printf("\n");
  720.  
  721.     for (column=0; column<4; column++)
  722.         printf("%f ",a[row][column]);
  723.  
  724.     } // end for row
  725.  
  726. printf("\n");
  727.  
  728. } // end Mat_Print_4x4
  729.  
  730. //////////////////////////////////////////////////////////////////////////////
  731.  
  732. void Mat_Print_1x4(matrix_1x4 a)
  733. {
  734. // this function prints out a 1x4 matrix
  735.  
  736. int column;     // looping variable
  737.  
  738. printf("\n");
  739.  
  740. for (column=0; column<4; column++)
  741.     printf("%f ",a[column]);
  742.  
  743. printf("\n");
  744.  
  745. } // end Mat_Print_1x4
  746.  
  747. //////////////////////////////////////////////////////////////////////////////
  748.  
  749. void Mat_Mul_4x4_4x4 (matrix_4x4 a,
  750.                       matrix_4x4 b,
  751.                       matrix_4x4 result)
  752. {
  753. // this function multiplies a 4x4 by a 4x4 and stores the result in a 4x4
  754.  
  755. // first row
  756.  
  757. result[0][0]=a[0][0]*b[0][0]+a[0][1]*b[1][0]+a[0][2]*b[2][0];
  758. result[0][1]=a[0][0]*b[0][1]+a[0][1]*b[1][1]+a[0][2]*b[2][1];
  759. result[0][2]=a[0][0]*b[0][2]+a[0][1]*b[1][2]+a[0][2]*b[2][2];
  760. result[0][3]=0;  // can probably get rid of this too, it's always 0
  761.  
  762. // second row
  763.  
  764. result[1][0]=a[1][0]*b[0][0]+a[1][1]*b[1][0]+a[1][2]*b[2][0];
  765. result[1][1]=a[1][0]*b[0][1]+a[1][1]*b[1][1]+a[1][2]*b[2][1];
  766. result[1][2]=a[1][0]*b[0][2]+a[1][1]*b[1][2]+a[1][2]*b[2][2];
  767. result[1][3]=0; // can probably get rid of this too, it's always 0
  768.  
  769. // third row
  770.  
  771. result[2][0]=a[2][0]*b[0][0]+a[2][1]*b[1][0]+a[2][2]*b[2][0];
  772. result[2][1]=a[2][0]*b[0][1]+a[2][1]*b[1][1]+a[2][2]*b[2][1];
  773. result[2][2]=a[2][0]*b[0][2]+a[2][1]*b[1][2]+a[2][2]*b[2][2];
  774. result[2][3]=0; // can probably get rid of this too, it's always 0
  775.  
  776. // fourth row
  777.  
  778. result[3][0]=a[3][0]*b[0][0]+a[3][1]*b[1][0]+a[3][2]*b[2][0]+b[3][0];
  779. result[3][1]=a[3][0]*b[0][1]+a[3][1]*b[1][1]+a[3][2]*b[2][1]+b[3][1];
  780. result[3][2]=a[3][0]*b[0][2]+a[3][1]*b[1][2]+a[3][2]*b[2][2]+b[3][2];
  781. result[3][3]=1; // can probably get rid of this too, it's always 0
  782.  
  783.  
  784. } // end Mat_Mul_4x4_4x4
  785.  
  786. //////////////////////////////////////////////////////////////////////////////
  787.  
  788. void Mat_Mul_1x4_4x4(matrix_1x4 a,
  789.                      matrix_4x4 b,
  790.                      matrix_1x4 result)
  791. {
  792. // this function multiplies a 1x4 by a 4x4 and stores the result in a 1x4
  793.  
  794. int index_j,    // column index
  795.     index_k;    // row index
  796.  
  797. float sum;    // temp used to hold sum of products
  798.  
  799. // loop thru columns of b
  800.  
  801. for (index_j=0; index_j<4; index_j++)
  802.     {
  803.  
  804.     // multiply ith row of a by jth column of b and store the sum
  805.     // of products in the position i,j of result
  806.  
  807.     sum=0;
  808.  
  809.     for (index_k=0; index_k<4; index_k++)
  810.         sum+=a[index_k]*b[index_k][index_j];
  811.  
  812.     // store result
  813.  
  814.     result[index_j] = sum;
  815.  
  816.     } // end for index_j
  817.  
  818. } // end Mat_Mul_1x4_4x4
  819.  
  820. //////////////////////////////////////////////////////////////////////////////
  821.  
  822. void Mat_Identity_4x4(matrix_4x4 a)
  823. {
  824. // this function creates a 4x4 identity matrix
  825.  
  826. memset((void *)a,0,sizeof(float)*16);
  827.  
  828. // set main diagonal to 1's
  829.  
  830. a[0][0] = a[1][1] = a[2][2] = a[3][3] = 1;
  831.  
  832. } // end Mat_Identity_4x4
  833.  
  834. /////////////////////////////////////////////////////////////////////////////
  835.  
  836. void Mat_Zero_4x4(matrix_4x4 a)
  837. {
  838. // this function zero's out a 4x4 matrix
  839.  
  840. memset((void *)a,0,sizeof(float)*16);
  841.  
  842. } // end Mat_Zero_4x4
  843.  
  844. /////////////////////////////////////////////////////////////////////////////
  845.  
  846. void Mat_Copy_4x4(matrix_4x4 source, matrix_4x4 destination)
  847. {
  848. // this function copies one 4x4 matrix to another
  849.  
  850. memcpy((void *)destination,(void *)source,sizeof(float)*16);
  851.  
  852. } // end Mat_Copy_4x4
  853.  
  854. /////////////////////////////////////////////////////////////////////////////
  855.  
  856. void Local_To_World_Object(object_ptr the_object)
  857. {
  858. // this function converts an objects local coordinates to world coordinates
  859. // by translating each point in the object by the objects current position
  860.  
  861. int index;  // looping variable
  862.  
  863. // move object from local position to world position
  864.  
  865. for (index=0; index<the_object->num_vertices; index++)
  866.     {
  867.  
  868.     the_object->vertices_world[index].x = the_object->vertices_local[index].x +
  869.                                           the_object->world_pos.x;
  870.  
  871.     the_object->vertices_world[index].y = the_object->vertices_local[index].y +
  872.                                           the_object->world_pos.y;
  873.  
  874.     the_object->vertices_world[index].z = the_object->vertices_local[index].z +
  875.                                           the_object->world_pos.z;
  876.  
  877.     } // end for index
  878.  
  879. // reset visibility flags for all polys
  880.  
  881. for (index=0; index<the_object->num_polys; index++)
  882.     {
  883.     the_object->polys[index].visible = 1;
  884.     the_object->polys[index].clipped = 0;
  885.     } // end for
  886.  
  887. } // end Local_To_World_Object
  888.  
  889. /////////////////////////////////////////////////////////////////////////////
  890.  
  891. void Create_World_To_Camera(void)
  892. {
  893. // this function creates the global inverse transformation matrix
  894. // used to transform world coordinate to camera coordinates
  895.  
  896. matrix_4x4 translate,   // the translation matrix
  897.  
  898.            rotate_x,    // the x,y and z rotation matrices
  899.            rotate_y,
  900.            rotate_z,
  901.            result_1,
  902.            result_2;
  903.  
  904. int active_axes=0;
  905.  
  906. // create identity matrices
  907.  
  908. Mat_Identity_4x4(translate);
  909.  
  910. // make a translation matrix based on the inverse of the viewpoint
  911.  
  912. translate[3][0] = -view_point.x;
  913. translate[3][1] = -view_point.y;
  914. translate[3][2] = -view_point.z;
  915.  
  916. // test if there is any X rotation in view angles
  917.  
  918. if (view_angle.ang_x)
  919.    {
  920.    Mat_Identity_4x4(rotate_x);
  921.  
  922.    // x matrix
  923.  
  924.    rotate_x[1][1] =  ( cos_look[view_angle.ang_x]);
  925.    rotate_x[1][2] = -( sin_look[view_angle.ang_x]);
  926.    rotate_x[2][1] = -(-sin_look[view_angle.ang_x]);
  927.    rotate_x[2][2] =  ( cos_look[view_angle.ang_x]);
  928.  
  929.    active_axes += 1;
  930.  
  931.    } // end if
  932.  
  933. if (view_angle.ang_y)
  934.    {
  935.    Mat_Identity_4x4(rotate_y);
  936.  
  937.    // y matrix
  938.  
  939.    rotate_y[0][0] =  ( cos_look[view_angle.ang_y]);
  940.    rotate_y[0][2] = -(-sin_look[view_angle.ang_y]);
  941.    rotate_y[2][0] = -( sin_look[view_angle.ang_y]);
  942.    rotate_y[2][2] =  ( cos_look[view_angle.ang_y]);
  943.  
  944.    active_axes += 2;
  945.  
  946.    } // end if
  947.  
  948.  
  949. if (view_angle.ang_z)
  950.    {
  951.    Mat_Identity_4x4(rotate_z);
  952.  
  953.    // z matrix
  954.  
  955.    rotate_z[0][0] =  ( cos_look[view_angle.ang_z]);
  956.    rotate_z[0][1] = -( sin_look[view_angle.ang_z]);
  957.    rotate_z[1][0] = -(-sin_look[view_angle.ang_z]);
  958.    rotate_z[1][1] =  ( cos_look[view_angle.ang_z]);
  959.  
  960.    active_axes += 4;
  961.  
  962.    } // end if
  963.  
  964. // multiply all the matrices together to obtain a final world to camera
  965. // viewing transformation matrix i.e.
  966. // translation * rotate_x * rotate_y * rotate_z, however, only, multiply
  967. // matrices that can possible add to the final view
  968.  
  969. switch(active_axes)
  970.       {
  971.  
  972.       case 0: // translation only
  973.            {
  974.            Mat_Copy_4x4(translate,global_view);
  975.            } break;
  976.  
  977.       case 1: // translation and X axis
  978.            {
  979.            // since only a single axis is active manually set up the matrix
  980.  
  981.            // Mat_Mul_4x4_4x4(translate,rotate_x,global_view);
  982.  
  983.            // manually create matrix using knowledge that final product is
  984.            // of the form
  985.  
  986.            // | 1            0            0          0|
  987.            // | 0            c            -s         0|
  988.            // | 0            s            c          0|
  989.            // |(-tx)       (-ty*c-tz*s) (ty*s-tz*c)  1|
  990.  
  991.            Mat_Copy_4x4(rotate_x,global_view);
  992.  
  993.            // now copy last row into global_view
  994.  
  995.  
  996.            global_view[3][0] = (-view_point.x);
  997.  
  998.            global_view[3][1] = (-view_point.y*cos_look[view_angle.ang_y] -
  999.                                  view_point.z*sin_look[view_angle.ang_y]);
  1000.  
  1001.            global_view[3][2] = (view_point.y*sin_look[view_angle.ang_y] -
  1002.                                 view_point.z*cos_look[view_angle.ang_y]);
  1003.  
  1004.  
  1005.            } break;
  1006.  
  1007.  
  1008.       case 2: // translation and Y axis
  1009.            {
  1010.            // Mat_Mul_4x4_4x4(translate,rotate_y,global_view);
  1011.  
  1012.            // manually create matrix using knowledge that final product is
  1013.            // of the form
  1014.  
  1015.            // | c            0            s          0|
  1016.            // | 0            1            0          0|
  1017.            // | -s           0            c          0|
  1018.            // |(tx*c+tz*s) (-ty)        (-tx*s-tz*c) 1|
  1019.  
  1020.            Mat_Copy_4x4(rotate_y,global_view);
  1021.  
  1022.            // now copy last row into global_view
  1023.  
  1024.            global_view[3][0] = (-view_point.x*cos_look[view_angle.ang_y] +
  1025.                                  view_point.z*sin_look[view_angle.ang_y]);
  1026.  
  1027.            global_view[3][1] = (-view_point.y);
  1028.  
  1029.            global_view[3][2] = (-view_point.x*sin_look[view_angle.ang_y] -
  1030.                                  view_point.z*cos_look[view_angle.ang_y]);
  1031.  
  1032.  
  1033.            } break;
  1034.  
  1035.  
  1036.       case 3: // translation and X and Y
  1037.            {
  1038.            Mat_Mul_4x4_4x4(translate,rotate_x,result_1);
  1039.            Mat_Mul_4x4_4x4(result_1,rotate_y,global_view);
  1040.            } break;
  1041.  
  1042.  
  1043.       case 4: // translation and Z
  1044.            {
  1045.             // Mat_Mul_4x4_4x4(translate,rotate_z,global_view);
  1046.  
  1047.            // manually create matrix using knowledge that final product is
  1048.            // of the form
  1049.  
  1050.            // | c            -s           0          0|
  1051.            // | s            c            0          0|
  1052.            // | 0            s            c          0|
  1053.            // |(-tx*c-ty*s) (tx*s-ty*c)  (-tz)       1|
  1054.  
  1055.            Mat_Copy_4x4(rotate_z,global_view);
  1056.  
  1057.            // now copy last row into global_view
  1058.  
  1059.  
  1060.            global_view[3][0] = (-view_point.x*cos_look[view_angle.ang_z] -
  1061.                                  view_point.y*sin_look[view_angle.ang_z]);
  1062.  
  1063.            global_view[3][1] = (view_point.x*sin_look[view_angle.ang_z] -
  1064.                                 view_point.y*cos_look[view_angle.ang_z]);
  1065.  
  1066.  
  1067.            global_view[3][2] = (-view_point.z);
  1068.  
  1069.            } break;
  1070.  
  1071.  
  1072.       case 5: // translation and X and Z
  1073.            {
  1074.            Mat_Mul_4x4_4x4(translate,rotate_x,result_1);
  1075.            Mat_Mul_4x4_4x4(result_1,rotate_z,global_view);
  1076.            } break;
  1077.  
  1078.       case 6: // translation and Y and Z
  1079.            {
  1080.            Mat_Mul_4x4_4x4(translate,rotate_y,result_1);
  1081.            Mat_Mul_4x4_4x4(result_1,rotate_z,global_view);
  1082.            } break;
  1083.  
  1084.       case 7: // translation and X and Y and Z
  1085.  
  1086.            {
  1087.  
  1088.            Mat_Mul_4x4_4x4(translate,rotate_x,result_1);
  1089.            Mat_Mul_4x4_4x4(result_1,rotate_y,result_2);
  1090.            Mat_Mul_4x4_4x4(result_2,rotate_z,global_view);
  1091.  
  1092.            } break;
  1093.  
  1094.       default:break;
  1095.  
  1096.       } // end switch
  1097.  
  1098. } // end Create_World_To_Camera
  1099.  
  1100. ////////////////////////////////////////////////////////////////////////////////
  1101.  
  1102. void World_To_Camera_Object(object_ptr the_object)
  1103. {
  1104. // this function converts an objects world coordinates to camera coordinates
  1105. // by multiplying each point of the object by the inverse viewing transformation
  1106. // matrix which is generated by concatenating the inverse of the view position
  1107. // and the view angles the result of which is in global_view
  1108.  
  1109. int index; // looping variable
  1110.  
  1111. int active_axes = 0;
  1112.  
  1113. if (view_angle.ang_x)
  1114.    active_axes+=1;
  1115.  
  1116. if (view_angle.ang_y)
  1117.    active_axes+=2;
  1118.  
  1119. if (view_angle.ang_z)
  1120.    active_axes+=4;
  1121.  
  1122. // based on active angles only compute what's neccessary
  1123.  
  1124. switch(active_axes)
  1125.       {
  1126.       case 0:   // T-1
  1127.            {
  1128.  
  1129.            for (index=0; index<=the_object->num_vertices; index++)
  1130.                {
  1131.                // multiply the point by the viewing transformation matrix
  1132.  
  1133.                // x component
  1134.  
  1135.                the_object->vertices_camera[index].x =
  1136.  
  1137.                              the_object->vertices_world[index].x +
  1138.                                                                    global_view[3][0];
  1139.                // y component
  1140.  
  1141.                the_object->vertices_camera[index].y =
  1142.  
  1143.                              the_object->vertices_world[index].y +
  1144.                                                                    global_view[3][1];
  1145.                // z component
  1146.  
  1147.                the_object->vertices_camera[index].z =
  1148.  
  1149.                              the_object->vertices_world[index].z +
  1150.                                                                    global_view[3][2];
  1151.                } // end for index
  1152.  
  1153.            } break;
  1154.  
  1155.       case 1:   // T-1 * Rx-1
  1156.            {
  1157.            for (index=0; index<=the_object->num_vertices; index++)
  1158.                {
  1159.                // multiply the point by the viewing transformation matrix
  1160.                // x component
  1161.  
  1162.                the_object->vertices_camera[index].x =
  1163.  
  1164.                              the_object->vertices_world[index].x +
  1165.                                                                    global_view[3][0];
  1166.                // y component
  1167.  
  1168.                the_object->vertices_camera[index].y =
  1169.  
  1170.                              the_object->vertices_world[index].y * global_view[1][1] +
  1171.                              the_object->vertices_world[index].z * global_view[2][1] +
  1172.                                                                    global_view[3][1];
  1173.                // z component
  1174.  
  1175.                the_object->vertices_camera[index].z =
  1176.  
  1177.                              the_object->vertices_world[index].y * global_view[1][2] +
  1178.                              the_object->vertices_world[index].z * global_view[2][2] +
  1179.                                                                    global_view[3][2];
  1180.                } // end for index
  1181.  
  1182.  
  1183.  
  1184.            } break;
  1185.  
  1186.       case 2:  // T-1 * Ry-1 , this is the standard rotation in a plane
  1187.            {
  1188.  
  1189.            for (index=0; index<=the_object->num_vertices; index++)
  1190.                {
  1191.                // multiply the point by the viewing transformation matrix
  1192.  
  1193.                // x component
  1194.                the_object->vertices_camera[index].x =
  1195.  
  1196.                              the_object->vertices_world[index].x * global_view[0][0] +
  1197.                              the_object->vertices_world[index].z * global_view[2][0] +
  1198.                                                                    global_view[3][0];
  1199.                // y component
  1200.                the_object->vertices_camera[index].y =
  1201.  
  1202.                              the_object->vertices_world[index].y +
  1203.                                                                    global_view[3][1];
  1204.                // z component
  1205.                the_object->vertices_camera[index].z =
  1206.  
  1207.                              the_object->vertices_world[index].x * global_view[0][2] +
  1208.                              the_object->vertices_world[index].z * global_view[2][2] +
  1209.                                                                    global_view[3][2];
  1210.                } // end for index
  1211.  
  1212.  
  1213.  
  1214.            } break;
  1215.  
  1216.       case 4:   // T-1 * Rz-1
  1217.            {
  1218.  
  1219.            for (index=0; index<=the_object->num_vertices; index++)
  1220.                {
  1221.                // multiply the point by the viewing transformation matrix
  1222.  
  1223.                // x component
  1224.  
  1225.                the_object->vertices_camera[index].x =
  1226.  
  1227.                              the_object->vertices_world[index].x * global_view[0][0] +
  1228.                              the_object->vertices_world[index].y * global_view[1][0] +
  1229.                                                                    global_view[3][0];
  1230.                // y component
  1231.  
  1232.                the_object->vertices_camera[index].y =
  1233.  
  1234.                              the_object->vertices_world[index].x * global_view[0][1] +
  1235.                              the_object->vertices_world[index].y * global_view[1][1] +
  1236.                                                                    global_view[3][1];
  1237.                // z component
  1238.  
  1239.                the_object->vertices_camera[index].z =
  1240.  
  1241.                              the_object->vertices_world[index].z +
  1242.                                                                    global_view[3][2];
  1243.                } // end for index
  1244.  
  1245.  
  1246.            } break;
  1247.  
  1248.  
  1249.       // these can all be optimized by pre-computing the form of the world
  1250.       // to camera matrix and using the same logic as the cases above
  1251.  
  1252.       case 3:  // T-1 * Rx-1 * Ry-1
  1253.       case 5:  // T-1 * Rx-1 * Rz-1
  1254.       case 6:  // T-1 * Ry-1 * Rz-1
  1255.       case 7:  // T-1 * Rx-1 * Ry-1 * Rz-1
  1256.            {
  1257.  
  1258.            for (index=0; index<=the_object->num_vertices; index++)
  1259.                {
  1260.                // multiply the point by the viewing transformation matrix
  1261.  
  1262.                // x component
  1263.  
  1264.                the_object->vertices_camera[index].x =
  1265.  
  1266.                              the_object->vertices_world[index].x * global_view[0][0] +
  1267.                              the_object->vertices_world[index].y * global_view[1][0] +
  1268.                              the_object->vertices_world[index].z * global_view[2][0] +
  1269.                                                                    global_view[3][0];
  1270.                // y component
  1271.  
  1272.                the_object->vertices_camera[index].y =
  1273.  
  1274.                              the_object->vertices_world[index].x * global_view[0][1] +
  1275.                              the_object->vertices_world[index].y * global_view[1][1] +
  1276.                              the_object->vertices_world[index].z * global_view[2][1] +
  1277.                                                                    global_view[3][1];
  1278.                // z component
  1279.  
  1280.                the_object->vertices_camera[index].z =
  1281.  
  1282.                              the_object->vertices_world[index].x * global_view[0][2] +
  1283.                              the_object->vertices_world[index].y * global_view[1][2] +
  1284.                              the_object->vertices_world[index].z * global_view[2][2] +
  1285.                                                                    global_view[3][2];
  1286.                } // end for index
  1287.  
  1288.  
  1289.  
  1290.            } break;
  1291.  
  1292.       default: break;
  1293.  
  1294.       } // end switch
  1295.  
  1296. } // end World_To_Camera_Object
  1297.  
  1298. ////////////////////////////////////////////////////////////////////////////
  1299.  
  1300. void Rotate_Object(object_ptr the_object,int angle_x,int angle_y,int angle_z)
  1301. {
  1302. // this function rotates an object relative to it's own local coordinate system
  1303. // and allows simultaneous rotations
  1304.  
  1305. int index,       //  looping variable
  1306.     product=0;   // used to determine which matrices need multiplying
  1307.  
  1308. matrix_4x4 rotate_x,    // the x,y and z rotation matrices
  1309.            rotate_y,
  1310.            rotate_z,
  1311.            rotate,      // the final rotation matrix
  1312.            temp;        // temporary working matrix
  1313.  
  1314. float temp_x, // used to hold intermediate results during rotation
  1315.       temp_y,
  1316.       temp_z;
  1317.  
  1318. // test if we need to rotate at all
  1319.  
  1320. if (angle_x==0 && angle_y==0 && angle_z==0)
  1321.    return;
  1322.  
  1323. // create identity matrix
  1324.  
  1325. Mat_Identity_4x4(rotate);
  1326.  
  1327. // figure out which axes are active
  1328.  
  1329. if (angle_x)
  1330.    product+=4;
  1331.  
  1332. if (angle_y)
  1333.    product+=2;
  1334.  
  1335. if (angle_z)
  1336.    product+=1;
  1337.  
  1338. // compute final rotation matrix and perform rotation all in one!
  1339.  
  1340. switch(product)
  1341.       {
  1342.  
  1343.       case 1: // final matrix = z
  1344.            {
  1345.            // set up matrix
  1346.  
  1347.            rotate[0][0] = ( cos_look[angle_z]);
  1348.            rotate[0][1] = ( sin_look[angle_z]);
  1349.            rotate[1][0] = (-sin_look[angle_z]);
  1350.            rotate[1][1] = ( cos_look[angle_z]);
  1351.  
  1352.            // matrix is of the form
  1353.  
  1354.            // | cos   sin  0     0 |
  1355.            // | -sin  cos  0     0 |
  1356.            // | 0     0    1     0 |
  1357.            // | 0     0    0     1 |
  1358.  
  1359.            // hence we can remove a number of multiplications during the
  1360.            // computations of x,y and z since many times each variable
  1361.            // isn't a function of the other two
  1362.  
  1363.  
  1364.            // perform rotation
  1365.  
  1366.            // now multiply each point in object by transformation matrix
  1367.  
  1368.            for (index=0; index<the_object->num_vertices; index++)
  1369.                {
  1370.  
  1371.                // x component
  1372.  
  1373.                temp_x = the_object->vertices_local[index].x * rotate[0][0] +
  1374.                         the_object->vertices_local[index].y * rotate[1][0];
  1375.                        // the_object->vertices_local[index].z * rotate[2][0];
  1376.  
  1377.                // y component
  1378.  
  1379.                temp_y = the_object->vertices_local[index].x * rotate[0][1] +
  1380.                         the_object->vertices_local[index].y * rotate[1][1];
  1381.                         // the_object->vertices_local[index].z * rotate[2][1];
  1382.  
  1383.                // z component
  1384.  
  1385.                temp_z =
  1386.  
  1387.                         the_object->vertices_local[index].z;
  1388.  
  1389.                // store rotated point back into local array
  1390.  
  1391.                the_object->vertices_local[index].x = temp_x;
  1392.                the_object->vertices_local[index].y = temp_y;
  1393.                the_object->vertices_local[index].z = temp_z;
  1394.  
  1395.                } // end for index
  1396.  
  1397.  
  1398.            } break;
  1399.  
  1400.       case 2: // final matrix = y
  1401.            {
  1402.  
  1403.            rotate[0][0] = ( cos_look[angle_y]);
  1404.            rotate[0][2] = (-sin_look[angle_y]);
  1405.            rotate[2][0] = ( sin_look[angle_y]);
  1406.            rotate[2][2] = ( cos_look[angle_y]);
  1407.  
  1408.            // matrix is of the form
  1409.  
  1410.            // | cos   0    -sin  0 |
  1411.            // | 0     1    0     0 |
  1412.            // | sin   0    cos   0 |
  1413.            // | 0     0    0     1 |
  1414.  
  1415.            // hence we can remove a number of multiplications during the
  1416.            // computations of x,y and z since many times each variable
  1417.            // isn't a function of the other two
  1418.  
  1419.  
  1420.            // now multiply each point in object by transformation matrix
  1421.  
  1422.            for (index=0; index<the_object->num_vertices; index++)
  1423.                {
  1424.  
  1425.                // x component
  1426.  
  1427.                temp_x = the_object->vertices_local[index].x * rotate[0][0] +
  1428.                         // the_object->vertices_local[index].y * rotate[1][0] +
  1429.                         the_object->vertices_local[index].z * rotate[2][0];
  1430.  
  1431.                // y component
  1432.  
  1433.                temp_y =
  1434.                         the_object->vertices_local[index].y;
  1435.  
  1436.                // z component
  1437.  
  1438.                temp_z = the_object->vertices_local[index].x * rotate[0][2] +
  1439.                         // the_object->vertices_local[index].y * rotate[1][2] +
  1440.                         the_object->vertices_local[index].z * rotate[2][2];
  1441.  
  1442.                // store rotated point back into local array
  1443.  
  1444.                the_object->vertices_local[index].x = temp_x;
  1445.                the_object->vertices_local[index].y = temp_y;
  1446.                the_object->vertices_local[index].z = temp_z;
  1447.  
  1448.                } // end for index
  1449.  
  1450.            } break;
  1451.  
  1452.       case 3: // final matrix = y*z
  1453.            {
  1454.  
  1455.            // take advantage of the fact that the product of Ry*Rz is
  1456.            //
  1457.            // | (cos angy)*(cos angz)  (cos angy)*(sin angz) -sin angy 0|
  1458.            // | -sin angz              cos angz              0         0|
  1459.            // | (sin angy)*(cos angz)  (sin angy)*(sin angz) cos angy  0|
  1460.            // | 0                      0                     0         1|
  1461.  
  1462.            // also notice the 0 in the 3rd column, we can use it to get
  1463.            // rid of one multiplication in the for loop below per point
  1464.  
  1465.            rotate[0][0] = cos_look[angle_y]*cos_look[angle_z];
  1466.            rotate[0][1] = cos_look[angle_y]*sin_look[angle_z];
  1467.            rotate[0][2] = -sin_look[angle_y];
  1468.  
  1469.            rotate[1][0] = -sin_look[angle_z];
  1470.            rotate[1][1] = cos_look[angle_z];
  1471.  
  1472.            rotate[2][0] = sin_look[angle_y]*cos_look[angle_z];
  1473.            rotate[2][1] = sin_look[angle_y]*sin_look[angle_z];
  1474.            rotate[2][2] = cos_look[angle_y];
  1475.  
  1476.            // now multiply each point in object by transformation matrix
  1477.  
  1478.            for (index=0; index<the_object->num_vertices; index++)
  1479.                {
  1480.  
  1481.                // x component
  1482.  
  1483.                temp_x = the_object->vertices_local[index].x * rotate[0][0] +
  1484.                         the_object->vertices_local[index].y * rotate[1][0] +
  1485.                         the_object->vertices_local[index].z * rotate[2][0];
  1486.  
  1487.                // y component
  1488.  
  1489.                temp_y = the_object->vertices_local[index].x * rotate[0][1] +
  1490.                         the_object->vertices_local[index].y * rotate[1][1] +
  1491.                         the_object->vertices_local[index].z * rotate[2][1];
  1492.  
  1493.                // z component
  1494.  
  1495.                temp_z = the_object->vertices_local[index].x * rotate[0][2] +
  1496.                         // the_object->vertices_local[index].y * rotate[1][2] +
  1497.                         the_object->vertices_local[index].z * rotate[2][2];
  1498.  
  1499.                // store rotated point back into local array
  1500.  
  1501.                the_object->vertices_local[index].x = temp_x;
  1502.                the_object->vertices_local[index].y = temp_y;
  1503.                the_object->vertices_local[index].z = temp_z;
  1504.  
  1505.                } // end for index
  1506.  
  1507.            } break;
  1508.  
  1509.       case 4: // final matrix = x
  1510.            {
  1511.  
  1512.            rotate[1][1] = ( cos_look[angle_x]);
  1513.            rotate[1][2] = ( sin_look[angle_x]);
  1514.            rotate[2][1] = (-sin_look[angle_x]);
  1515.            rotate[2][2] = ( cos_look[angle_x]);
  1516.  
  1517.            // matrix is of the form
  1518.  
  1519.            // | 1     s    0     0 |
  1520.            // | 0     cos  sin   0 |
  1521.            // | 0    -sin  cos   0 |
  1522.            // | 0     0    0     1 |
  1523.  
  1524.            // hence we can remove a number of multiplications during the
  1525.            // computations of x,y and z since many times each variable
  1526.            // isn't a function of the other two
  1527.  
  1528.  
  1529.  
  1530.  
  1531.            // now multiply each point in object by transformation matrix
  1532.  
  1533.            for (index=0; index<the_object->num_vertices; index++)
  1534.                {
  1535.  
  1536.                // x component
  1537.  
  1538.                temp_x =
  1539.  
  1540.                         the_object->vertices_local[index].x;
  1541.  
  1542.                // y component
  1543.  
  1544.                temp_y = // the_object->vertices_local[index].x * rotate[0][1] +
  1545.                         the_object->vertices_local[index].y * rotate[1][1] +
  1546.                         the_object->vertices_local[index].z * rotate[2][1];
  1547.  
  1548.                // z component
  1549.  
  1550.                temp_z = // the_object->vertices_local[index].x * rotate[0][2] +
  1551.                         the_object->vertices_local[index].y * rotate[1][2] +
  1552.                         the_object->vertices_local[index].z * rotate[2][2];
  1553.  
  1554.                // store rotated point back into local array
  1555.  
  1556.                the_object->vertices_local[index].x = temp_x;
  1557.                the_object->vertices_local[index].y = temp_y;
  1558.                the_object->vertices_local[index].z = temp_z;
  1559.  
  1560.                } // end for index
  1561.  
  1562.            } break;
  1563.  
  1564.       case 5: // final matrix = x*z
  1565.            {
  1566.  
  1567.            // take advantage of the fact that the product of Rx*Rz is
  1568.            //
  1569.            // | cos angz                sin angz               0         0|
  1570.            // | -(cos angx)*(sin angz)  (cos angx)*(cos angz)  sin angx  0|
  1571.            // | (sin angx)*(sin angz)  -(sin angx)*(cos angz)  cos angx  0|
  1572.            // | 0                       0                      0         1|
  1573.  
  1574.            // also notice the 0 in the 3rd column, we can use it to get
  1575.            // rid of one multiplication in the for loop below per point
  1576.  
  1577.  
  1578.            rotate[0][0] = cos_look[angle_z];
  1579.            rotate[0][1] = sin_look[angle_z];
  1580.  
  1581.            rotate[1][0] = -cos_look[angle_x]*sin_look[angle_z];
  1582.            rotate[1][1] = cos_look[angle_x]*cos_look[angle_z];
  1583.            rotate[1][2] = sin_look[angle_x];
  1584.  
  1585.            rotate[2][0] = sin_look[angle_x]*sin_look[angle_z];
  1586.            rotate[2][1] = -sin_look[angle_x]*cos_look[angle_z];
  1587.            rotate[2][2] = cos_look[angle_x];
  1588.  
  1589.            // now multiply each point in object by transformation matrix
  1590.  
  1591.            for (index=0; index<the_object->num_vertices; index++)
  1592.                {
  1593.  
  1594.                // x component
  1595.  
  1596.                temp_x = the_object->vertices_local[index].x * rotate[0][0] +
  1597.                         the_object->vertices_local[index].y * rotate[1][0] +
  1598.                         the_object->vertices_local[index].z * rotate[2][0];
  1599.  
  1600.                // y component
  1601.  
  1602.                temp_y = the_object->vertices_local[index].x * rotate[0][1] +
  1603.                         the_object->vertices_local[index].y * rotate[1][1] +
  1604.                         the_object->vertices_local[index].z * rotate[2][1];
  1605.  
  1606.                // z component
  1607.  
  1608.                temp_z = // the_object->vertices_local[index].x * rotate[0][2] +
  1609.                         the_object->vertices_local[index].y * rotate[1][2] +
  1610.                         the_object->vertices_local[index].z * rotate[2][2];
  1611.  
  1612.                // store rotated point back into local array
  1613.  
  1614.                the_object->vertices_local[index].x = temp_x;
  1615.                the_object->vertices_local[index].y = temp_y;
  1616.                the_object->vertices_local[index].z = temp_z;
  1617.  
  1618.                } // end for index
  1619.  
  1620.            } break;
  1621.  
  1622.       case 6: // final matrix = x*y
  1623.            {
  1624.  
  1625.            // take advantage of the fact that the product of Rx*Ry is
  1626.            //
  1627.            // | cos angy                0          -sin angy             0|
  1628.            // | (sin angx)*(sin angy)   cos angx   (sin angx)*(cos angy) 0|
  1629.            // | (cos angx)*(sin angy)   -sin angx  (cos angx)*(cos angy) 0|
  1630.            // | 0                       0          0                     1|
  1631.  
  1632.            // also notice the 0 in the 2nd column, we can use it to get
  1633.            // rid of one multiplication in the for loop below per point
  1634.  
  1635.            rotate[0][0] = cos_look[angle_y];
  1636.            rotate[0][2] = -sin_look[angle_y];
  1637.  
  1638.            rotate[1][0] = sin_look[angle_x]*sin_look[angle_y];
  1639.            rotate[1][1] = cos_look[angle_x];
  1640.            rotate[1][2] = sin_look[angle_x]*cos_look[angle_y];
  1641.  
  1642.            rotate[2][0] = cos_look[angle_x]*sin_look[angle_y];
  1643.            rotate[2][1] = -sin_look[angle_x];
  1644.            rotate[2][2] = cos_look[angle_x]*cos_look[angle_y];
  1645.  
  1646.            // now multiply each point in object by transformation matrix
  1647.  
  1648.            for (index=0; index<the_object->num_vertices; index++)
  1649.                {
  1650.  
  1651.                // x component
  1652.  
  1653.                temp_x = the_object->vertices_local[index].x * rotate[0][0] +
  1654.                         the_object->vertices_local[index].y * rotate[1][0] +
  1655.                         the_object->vertices_local[index].z * rotate[2][0];
  1656.  
  1657.                // y component
  1658.  
  1659.                temp_y = //the_object->vertices_local[index].x * rotate[0][1] +
  1660.                         the_object->vertices_local[index].y * rotate[1][1] +
  1661.                         the_object->vertices_local[index].z * rotate[2][1];
  1662.  
  1663.                // z component
  1664.  
  1665.                temp_z = the_object->vertices_local[index].x * rotate[0][2] +
  1666.                         the_object->vertices_local[index].y * rotate[1][2] +
  1667.                         the_object->vertices_local[index].z * rotate[2][2];
  1668.  
  1669.                // store rotated point back into local array
  1670.  
  1671.                the_object->vertices_local[index].x = temp_x;
  1672.                the_object->vertices_local[index].y = temp_y;
  1673.                the_object->vertices_local[index].z = temp_z;
  1674.  
  1675.                } // end for index
  1676.  
  1677.            } break;
  1678.  
  1679.       case 7: // final matrix = x*y*z, do it the hard way
  1680.            {
  1681.            Mat_Identity_4x4(rotate_x);
  1682.  
  1683.            rotate_x[1][1] = ( cos_look[angle_x]);
  1684.            rotate_x[1][2] = ( sin_look[angle_x]);
  1685.            rotate_x[2][1] = (-sin_look[angle_x]);
  1686.            rotate_x[2][2] = ( cos_look[angle_x]);
  1687.  
  1688.            Mat_Identity_4x4(rotate_y);
  1689.  
  1690.            rotate_y[0][0] = ( cos_look[angle_y]);
  1691.            rotate_y[0][2] = (-sin_look[angle_y]);
  1692.            rotate_y[2][0] = ( sin_look[angle_y]);
  1693.            rotate_y[2][2] = ( cos_look[angle_y]);
  1694.  
  1695.            Mat_Identity_4x4(rotate_z);
  1696.  
  1697.            rotate_z[0][0] = ( cos_look[angle_z]);
  1698.            rotate_z[0][1] = ( sin_look[angle_z]);
  1699.            rotate_z[1][0] = (-sin_look[angle_z]);
  1700.            rotate_z[1][1] = ( cos_look[angle_z]);
  1701.  
  1702.            Mat_Mul_4x4_4x4(rotate_x,rotate_y,temp);
  1703.            Mat_Mul_4x4_4x4(temp,rotate_z,rotate);
  1704.  
  1705.            // now multiply each point in object by transformation matrix
  1706.  
  1707.            for (index=0; index<the_object->num_vertices; index++)
  1708.                {
  1709.  
  1710.                // x component
  1711.  
  1712.                temp_x = the_object->vertices_local[index].x * rotate[0][0] +
  1713.                         the_object->vertices_local[index].y * rotate[1][0] +
  1714.                         the_object->vertices_local[index].z * rotate[2][0];
  1715.  
  1716.                // y component
  1717.  
  1718.                temp_y = the_object->vertices_local[index].x * rotate[0][1] +
  1719.                         the_object->vertices_local[index].y * rotate[1][1] +
  1720.                         the_object->vertices_local[index].z * rotate[2][1];
  1721.  
  1722.                // z component
  1723.  
  1724.                temp_z = the_object->vertices_local[index].x * rotate[0][2] +
  1725.                         the_object->vertices_local[index].y * rotate[1][2] +
  1726.                         the_object->vertices_local[index].z * rotate[2][2];
  1727.  
  1728.                // store rotated point back into local array
  1729.  
  1730.                the_object->vertices_local[index].x = temp_x;
  1731.                the_object->vertices_local[index].y = temp_y;
  1732.                the_object->vertices_local[index].z = temp_z;
  1733.  
  1734.                } // end for index
  1735.  
  1736.            } break;
  1737.  
  1738.       default:break;
  1739.  
  1740.       } // end switch
  1741.  
  1742. } // end Rotate_Object
  1743.  
  1744. ////////////////////////////////////////////////////////////////////////////
  1745.  
  1746. void Position_Object(object_ptr the_object,int x,int y,int z)
  1747. {
  1748. // this function positions an object in the world
  1749.  
  1750. the_object->world_pos.x = x;
  1751. the_object->world_pos.y = y;
  1752. the_object->world_pos.z = z;
  1753.  
  1754. } // end Position_Object
  1755.  
  1756. ////////////////////////////////////////////////////////////////////////////
  1757.  
  1758. void Translate_Object(object_ptr the_object,int x_trans,int y_trans,int z_trans)
  1759. {
  1760. // this function translates an object relative to it's own local
  1761. // coordinate system
  1762.  
  1763. the_object->world_pos.x+=x_trans;
  1764. the_object->world_pos.y+=y_trans;
  1765. the_object->world_pos.z+=z_trans;
  1766.  
  1767. } // end Translate_Object
  1768.  
  1769. /////////////////////////////////////////////////////////////////////////////
  1770.  
  1771. void Scale_Object(object_ptr the_object,float scale_factor)
  1772. {
  1773. // this function scales an object relative to it's own local coordinate system
  1774. // equally in x,y and z
  1775.  
  1776. int curr_poly,    // the current polygon being processed
  1777.     curr_vertex;  // the current vertex being processed
  1778.  
  1779. float scale_2;    // holds the sqaure of the scaling factor, needed to
  1780.                   // resize the surface normal for lighting calculations
  1781.  
  1782. // multiply each vertex in the object definition by the scaling factor
  1783.  
  1784. for (curr_vertex=0; curr_vertex<the_object->num_vertices; curr_vertex++)
  1785.     {
  1786.  
  1787.     the_object->vertices_local[curr_vertex].x*=scale_factor;
  1788.     the_object->vertices_local[curr_vertex].y*=scale_factor;
  1789.     the_object->vertices_local[curr_vertex].z*=scale_factor;
  1790.  
  1791.     } // end for curr_vertex
  1792.  
  1793. // compute scaling factor squared
  1794.  
  1795. scale_2 = scale_factor*scale_factor;
  1796.  
  1797. // now scale all pre-computed normals
  1798.  
  1799. for (curr_poly=0; curr_poly<the_object->num_polys; curr_poly++)
  1800.     the_object->polys[curr_poly].normal_length*=scale_2;
  1801.  
  1802. // finally scale the radius up
  1803.  
  1804. the_object->radius*=scale_factor;
  1805.  
  1806. } // end Scale_Object
  1807.  
  1808. /////////////////////////////////////////////////////////////////////////////
  1809.  
  1810. int Objects_Collide(object_ptr object_1, object_ptr object_2)
  1811. {
  1812. // this function tests if the bounding spheres of two objects overlaps
  1813. // if a more accurate test is needed then polygons should be tested against
  1814. // polygons. note the function uses the fact that if x > y then x^2 > y^2
  1815. // to avoid using square roots. Finally, the function might be altered
  1816. // so that the bounding spheres are shrank to make sure that the collision
  1817. // is "solid"/ finally, soft and hard collisions are both detected
  1818.  
  1819. float dx,dy,dz,           // deltas in x,y and z
  1820.       radius_1,radius_2,  // radi of each object
  1821.       distance;           // distance between object centers
  1822.  
  1823. // compute delta's
  1824.  
  1825. dx = (object_1->world_pos.x - object_2->world_pos.x);
  1826. dy = (object_1->world_pos.y - object_2->world_pos.y);
  1827. dz = (object_1->world_pos.z - object_2->world_pos.z);
  1828.  
  1829. // compute length
  1830.  
  1831. distance = dx*dx + dy*dy + dz*dx;
  1832.  
  1833. // compute radius of each object squared
  1834.  
  1835. radius_1 = object_1->radius*object_1->radius;
  1836. radius_2 = object_2->radius*object_2->radius;
  1837.  
  1838. // test if distance is smaller than of radi
  1839.  
  1840. if (distance<radius_1 || distance <radius_2)
  1841.    return(HARD_COLLISION); // hard collision
  1842. else
  1843. if (distance < radius_1+radius_2)
  1844.    return(SOFT_COLLISION); // soft collision
  1845. else
  1846.    return(NO_COLLISION);
  1847.  
  1848. } // end Objects_Collide
  1849.  
  1850. /////////////////////////////////////////////////////////////////////////////
  1851.  
  1852. char *PLG_Get_Line(char *string, int max_length, FILE *fp)
  1853. {
  1854. // this function gets a line from a PLG file and strips comments
  1855. // just pretend it's a black box!
  1856.  
  1857. char buffer[80]; // temporary string storage
  1858.  
  1859. int length,      // length of line read
  1860.     index=0,     // looping variables
  1861.     index_2=0,
  1862.     parsed=0;    // has the current input line been parsed
  1863.  
  1864. // get the next line of input, make sure there is something on the line
  1865.  
  1866. while(1)
  1867.      {
  1868.      // get the line
  1869.  
  1870.      if (!fgets(buffer,max_length,fp))
  1871.         return(NULL);
  1872.  
  1873.      // get length of line
  1874.  
  1875.      length = strlen(buffer);
  1876.  
  1877.      // kill the carriage return
  1878.  
  1879.      buffer[length-1] = 0;
  1880.  
  1881.      // reset index
  1882.  
  1883.      index = 0;
  1884.  
  1885.      // eat leading white space
  1886.  
  1887.      while(buffer[index]==' ')
  1888.            index++;
  1889.  
  1890.      // read line into buffer, if "#" arrives in data stream then disregard
  1891.      // rest of line
  1892.  
  1893.      parsed=0;
  1894.      index_2=0;
  1895.  
  1896.      while(!parsed)
  1897.           {
  1898.  
  1899.           if (buffer[index]!='#' && buffer[index]!=';')
  1900.              {
  1901.              // insert character into output string
  1902.  
  1903.              string[index_2] = buffer[index];
  1904.  
  1905.              // test if this is a null terminator
  1906.  
  1907.              if (string[index_2]==0)
  1908.                 parsed=1;
  1909.  
  1910.              // move to next character
  1911.  
  1912.              index++;
  1913.              index_2++;
  1914.  
  1915.              } // end if not comment
  1916.           else
  1917.              {
  1918.              // insert a null termination since this is the end of the
  1919.              // string for all intense purposes
  1920.  
  1921.              string[index_2] = 0;
  1922.  
  1923.              parsed=1;
  1924.  
  1925.              } // end else
  1926.  
  1927.           } // end while parsing string
  1928.  
  1929.           // make sure we got a string and not a blank line
  1930.  
  1931.           if (strlen(string))
  1932.              return(string);
  1933.  
  1934.      } // end while
  1935.  
  1936. } // end PLG_Get_Line
  1937.  
  1938. /////////////////////////////////////////////////////////////////////////////
  1939.  
  1940. int PLG_Load_Object(object_ptr the_object,char *filename,float scale)
  1941. {
  1942. // this function loads an object off disk and allows it to be scaled, the files
  1943. // are in a slightly enhanced PLG format that allows polygons to be defined
  1944. // as one or two sided, this helps the hidden surface removal system. This
  1945. // extra functionality has been encoded in the 2nd nibble from the left of the
  1946. // color descriptor
  1947.  
  1948. FILE *fp; // disk file
  1949.  
  1950. static int id_number = 0; // used to set object id's
  1951.  
  1952. char buffer[80],          // holds input string
  1953.      object_name[32],     // name of 3-D object
  1954.      *token;              // current parsing token
  1955.  
  1956.  
  1957. unsigned int total_vertices,    // total vertices in object
  1958.              total_polys,       // total polygons per object
  1959.              num_vertices,      // number of vertices on a polygon
  1960.              color_des,         // the color descriptor of a polygon
  1961.              logical_color,     // the final color of polygon
  1962.              shading,           // the type of shading used on polygon
  1963.              two_sided,         // flags if poly has two sides
  1964.              index,             // looping variables
  1965.              index_2,
  1966.              vertex_num,        // vertex numbers
  1967.              vertex_0,
  1968.              vertex_1,
  1969.              vertex_2;
  1970.  
  1971. float x,y,z;                    // a single vertex
  1972.  
  1973. vector_3d u,v,normal;           // working vectors
  1974.  
  1975. // open the disk file
  1976.  
  1977. if ((fp=fopen(filename,"r"))==NULL)
  1978.    {
  1979.    printf("\nCouldn't open file %s",filename);
  1980.    return(0);
  1981.  
  1982.    } // end if
  1983.  
  1984. // first we are looking for the header line that has the object name and
  1985. // the number of vertices and polygons
  1986.  
  1987. if (!PLG_Get_Line(buffer, 80,fp))
  1988.    {
  1989.    printf("\nError with PLG file %s",filename);
  1990.    fclose(fp);
  1991.    return(0);
  1992.    } // end if error
  1993.  
  1994. // extract object name and number of vertices and polygons
  1995.  
  1996. sscanf(buffer,"%s %d %d",object_name, &total_vertices, &total_polys);
  1997.  
  1998. // set proper fields in object
  1999.  
  2000. the_object->num_vertices = total_vertices;
  2001. the_object->num_polys    = total_polys;
  2002. the_object->state        = 1;
  2003.  
  2004. the_object->world_pos.x  = 0;
  2005. the_object->world_pos.y  = 0;
  2006. the_object->world_pos.z  = 0;
  2007.  
  2008. // set id number, maybe later also add the name of object in the
  2009. // structure???
  2010.  
  2011. the_object->id = id_number++;
  2012.  
  2013. // based on number of vertices, read vertex list into object
  2014.  
  2015. for (index=0; index<total_vertices; index++)
  2016.     {
  2017.  
  2018.     // read in vertex
  2019.  
  2020.     if (!PLG_Get_Line(buffer, 80,fp))
  2021.        {
  2022.        printf("\nError with PLG file %s",filename);
  2023.        fclose(fp);
  2024.        return(0);
  2025.        } // end if error
  2026.  
  2027.     sscanf(buffer,"%f %f %f",&x,&y,&z);
  2028.  
  2029.     // insert vertex into object
  2030.  
  2031.     the_object->vertices_local[index].x = x*scale;
  2032.     the_object->vertices_local[index].y = y*scale;
  2033.     the_object->vertices_local[index].z = z*scale;
  2034.  
  2035.     } // end for index
  2036.  
  2037. // now read in polygon list
  2038.  
  2039. for (index=0; index<total_polys; index++)
  2040.     {
  2041.     // read in color and number of vertices for next polygon
  2042.  
  2043.     if (!PLG_Get_Line(buffer, 80,fp))
  2044.        {
  2045.        printf("\nError with PLG file %s",filename);
  2046.        fclose(fp);
  2047.        return(0);
  2048.        } // end if error
  2049.  
  2050.     // intialize token getter and get first token which is color descriptor
  2051.  
  2052.     if (!(token = strtok(buffer," ")) )
  2053.        {
  2054.        printf("\nError with PLG file %s",filename);
  2055.        fclose(fp);
  2056.        return(0);
  2057.        } // end if problem
  2058.  
  2059.     // test if number is hexadecimal
  2060.  
  2061.     if (token[0]=='0' && (token[1]=='x' || token[1]=='X'))
  2062.        {
  2063.  
  2064.        sscanf(&token[2],"%x",&color_des);
  2065.  
  2066.        } // end if hex color specifier
  2067.     else
  2068.        {
  2069.  
  2070.        color_des = atoi(token);
  2071.  
  2072.        } // end if decimal
  2073.  
  2074.     // extract base color and type of shading
  2075.  
  2076.     logical_color = color_des & 0x00ff;
  2077.     shading       = color_des >> 12;
  2078.     two_sided     = ((color_des >> 8) & 0x0f);
  2079.  
  2080.     // read number of vertices in polygon
  2081.  
  2082.     if (!(token = strtok(NULL," ")))
  2083.        {
  2084.        printf("\nError with PLG file %s",filename);
  2085.        fclose(fp);
  2086.        return(0);
  2087.        } // end if problem
  2088.  
  2089.     if ((num_vertices = atoi(token))<=0)
  2090.        {
  2091.        printf("\nError with PLG file (number of vertices) %s",filename);
  2092.        fclose(fp);
  2093.        return(0);
  2094.        } // end if no vertices or error
  2095.  
  2096.     // set fields in polygon structure
  2097.  
  2098.     the_object->polys[index].num_points = num_vertices;
  2099.     the_object->polys[index].color      = logical_color;
  2100.     the_object->polys[index].shading    = shading;
  2101.     the_object->polys[index].two_sided  = two_sided;
  2102.     the_object->polys[index].visible    = 1;
  2103.     the_object->polys[index].clipped    = 0;
  2104.     the_object->polys[index].active     = 1;
  2105.  
  2106.     // now read in polygon vertice list
  2107.  
  2108.     for (index_2=0; index_2<num_vertices; index_2++)
  2109.         {
  2110.  
  2111.         // read in next vertex number
  2112.  
  2113.         if (!(token = strtok(NULL," ")) )
  2114.            {
  2115.            printf("\nError with PLG file %s",filename);
  2116.            fclose(fp);
  2117.            return(0);
  2118.            } // end if problem
  2119.  
  2120.         vertex_num = atoi(token);
  2121.  
  2122.         // insert vertex number into polygon
  2123.  
  2124.         the_object->polys[index].vertex_list[index_2] = vertex_num;
  2125.  
  2126.         } // end for index_2
  2127.  
  2128.     // compute length of the two co-planer edges of the polygon, since they
  2129.     // will be used in the computation of the dot-product later
  2130.  
  2131.     vertex_0 = the_object->polys[index].vertex_list[0];
  2132.     vertex_1 = the_object->polys[index].vertex_list[1];
  2133.     vertex_2 = the_object->polys[index].vertex_list[2];
  2134.  
  2135.     // the vector u = vo->v1
  2136.  
  2137.     Make_Vector_3D((point_3d_ptr)&the_object->vertices_local[vertex_0],
  2138.                    (point_3d_ptr)&the_object->vertices_local[vertex_1],
  2139.                    (vector_3d_ptr)&u);
  2140.  
  2141.     // the vector v = vo->v2
  2142.  
  2143.     Make_Vector_3D((point_3d_ptr)&the_object->vertices_local[vertex_0],
  2144.                    (point_3d_ptr)&the_object->vertices_local[vertex_2],
  2145.                    (vector_3d_ptr)&v);
  2146.  
  2147.     Cross_Product_3D((vector_3d_ptr)&v,
  2148.                      (vector_3d_ptr)&u,
  2149.                      (vector_3d_ptr)&normal);
  2150.  
  2151.  
  2152.     // compute magnitude of normal, take its inverse and multiply it by
  2153.     // 15, this will change the shading calculation of 15*dp/normal into
  2154.     // dp*normal_length, removing one division
  2155.  
  2156.     the_object->polys[index].normal_length = 15.0/Vector_Mag_3D((vector_3d_ptr)&normal);
  2157.  
  2158.     } // end for index
  2159.  
  2160. // close the file
  2161.  
  2162. fclose(fp);
  2163.  
  2164. // compute object radius
  2165.  
  2166. Compute_Object_Radius(the_object);
  2167.  
  2168. // return success
  2169.  
  2170. return(1);
  2171.  
  2172. } // end PLG_Load_Object
  2173.  
  2174. ///////////////////////////////////////////////////////////////////////////////
  2175.  
  2176. float Compute_Object_Radius(object_ptr the_object)
  2177. {
  2178.  
  2179. // this function computes maximum radius of object, maybe a better method would
  2180. // use average radius? Note that this functiopn shouldn't be used during
  2181. // runtime but when an object is created
  2182.  
  2183. float new_radius,   // used in average radius calculation of object
  2184.       x,y,z;        // a single vertex
  2185.  
  2186. int index;          // looping variable
  2187.  
  2188. // reset object radius
  2189.  
  2190. the_object->radius=0;
  2191.  
  2192. for (index=0; index<the_object->num_vertices; index++)
  2193.     {
  2194.  
  2195.     x = the_object->vertices_local[index].x;
  2196.     y = the_object->vertices_local[index].y;
  2197.     z = the_object->vertices_local[index].z;
  2198.  
  2199.     // compute distance to point
  2200.  
  2201.     new_radius = (float)sqrt(x*x + y*y + z*z);
  2202.  
  2203.     // is this radius bigger than last?
  2204.  
  2205.     if (new_radius > the_object->radius)
  2206.        the_object->radius = new_radius;
  2207.  
  2208.     } // end for index
  2209.  
  2210. // return radius just in case
  2211.  
  2212. return(the_object->radius);
  2213.  
  2214. } // end Compute_Object_Radius
  2215.  
  2216. /////////////////////////////////////////////////////////////////////////////
  2217.  
  2218. void Clip_Object_3D(object_ptr the_object, int mode)
  2219. {
  2220. // this function clips an object in camera coordinates against the 3D viewing
  2221. // volume. the function has two modes of operation. In CLIP_Z_MODE the
  2222. // function performs only a simple z extend clip with the near and far clipping
  2223. // planes. In CLIP_XYZ_MODE mode the function performs a full 3-D clip
  2224.  
  2225. int curr_poly;    // the current polygon being processed
  2226.  
  2227. float x1,y1,z1,
  2228.       x2,y2,z2,
  2229.       x3,y3,z3,
  2230.       x4,y4,z4,   // working variables used to hold vertices
  2231.  
  2232.       x1_compare, // used to hold clipping points on x and y
  2233.       y1_compare,
  2234.       x2_compare,
  2235.       y2_compare,
  2236.       x3_compare,
  2237.       y3_compare,
  2238.       x4_compare,
  2239.       y4_compare,
  2240.       fov_width,  // width and height of projected viewing plane
  2241.       fov_height; // used to speed up computations, since it's constant
  2242.                   // for any frame
  2243.  
  2244.  
  2245. // test if trivial z clipping is being requested
  2246.  
  2247. if (mode==CLIP_Z_MODE)
  2248.    {
  2249.    // attempt to clip each polygon against viewing volume
  2250.  
  2251.    for (curr_poly=0; curr_poly<the_object->num_polys; curr_poly++)
  2252.        {
  2253.  
  2254.        // extract z components
  2255.  
  2256.        z1=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[0]].z;
  2257.        z2=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[1]].z;
  2258.        z3=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[2]].z;
  2259.  
  2260.        // test if this is a quad
  2261.  
  2262.        if (the_object->polys[curr_poly].num_points==4)
  2263.           {
  2264.           // extract 4th z component
  2265.  
  2266.           z4=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[3]].z;
  2267.  
  2268.           } // end if quad
  2269.        else
  2270.          z4=z3;
  2271.  
  2272.        // perform near and far z clipping test
  2273.  
  2274.        if ( (z1<clip_near_z && z2<clip_near_z && z3<clip_near_z && z4<clip_near_z) ||
  2275.             (z1>clip_far_z && z2>clip_far_z && z3>clip_far_z && z4>clip_far_z) )
  2276.           {
  2277.           // set clipped flag
  2278.  
  2279.           the_object->polys[curr_poly].clipped=1;
  2280.  
  2281.           } // end if clipped
  2282.  
  2283.        } // end for curr_poly
  2284.  
  2285.     } // end if CLIP_Z_MODE
  2286. else
  2287.    {
  2288.    // CLIP_XYZ_MODE, perform full 3D viewing volume clip
  2289.  
  2290.    // compute dimensions of clipping extents at current viewing distance
  2291.  
  2292.    fov_width  = ((float)HALF_SCREEN_WIDTH/viewing_distance);
  2293.    fov_height = ((float)HALF_SCREEN_HEIGHT/viewing_distance);
  2294.  
  2295.  
  2296.    // process each polygon
  2297.  
  2298.    for (curr_poly=0; curr_poly<the_object->num_polys; curr_poly++)
  2299.        {
  2300.  
  2301.        // extract x,y and z components
  2302.  
  2303.        x1=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[0]].x;
  2304.        y1=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[0]].y;
  2305.        z1=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[0]].z;
  2306.  
  2307.        x2=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[1]].x;
  2308.        y2=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[1]].y;
  2309.        z2=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[1]].z;
  2310.  
  2311.        x3=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[2]].x;
  2312.        y3=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[2]].y;
  2313.        z3=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[2]].z;
  2314.  
  2315.        // test if this is a quad
  2316.  
  2317.        if (the_object->polys[curr_poly].num_points==4)
  2318.           {
  2319.           // extract 4th vertex
  2320.  
  2321.           x4=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[3]].x;
  2322.           y4=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[3]].y;
  2323.           z4=the_object->vertices_camera[the_object->polys[curr_poly].vertex_list[3]].z;
  2324.  
  2325.           // do clipping tests
  2326.  
  2327.           // perform near and far z clipping test first
  2328.  
  2329.           if (!((z1>clip_near_z || z2>clip_near_z || z3>clip_near_z || z4>clip_near_z) &&
  2330.                 (z1<clip_far_z || z2<clip_far_z || z3<clip_far_z || z4<clip_far_z)) )
  2331.              {
  2332.              // set clipped flag
  2333.  
  2334.              the_object->polys[curr_poly].clipped=1;
  2335.              continue;
  2336.  
  2337.              } // end if clipped
  2338.  
  2339.           // pre-compute x comparision ranges
  2340.  
  2341.           x1_compare = fov_width*z1;
  2342.           x2_compare = fov_width*z2;
  2343.           x3_compare = fov_width*z3;
  2344.           x4_compare = fov_width*z4;
  2345.  
  2346.           // perform x test
  2347.  
  2348.           if (!((x1>-x1_compare || x2>-x1_compare || x3>-x3_compare || x4>-x4_compare) &&
  2349.                 (x1<x1_compare || x2<x2_compare || x3<x3_compare || x4<x4_compare))  )
  2350.              {
  2351.              // set clipped flag
  2352.  
  2353.              the_object->polys[curr_poly].clipped=1;
  2354.              continue;
  2355.  
  2356.              } // end if clipped
  2357.  
  2358.           // pre-compute x comparision ranges
  2359.  
  2360.           y1_compare = fov_height*z1;
  2361.           y2_compare = fov_height*z2;
  2362.           y3_compare = fov_height*z3;
  2363.           y4_compare = fov_height*z4;
  2364.  
  2365.           // perform x test
  2366.  
  2367.           if (!((y1>-y1_compare || y2>-y1_compare || y3>-y3_compare || y4>-y4_compare) &&
  2368.                 (y1<y1_compare || y2<y2_compare || y3<y3_compare || y4<y4_compare))  )
  2369.              {
  2370.              // set clipped flag
  2371.  
  2372.              the_object->polys[curr_poly].clipped=1;
  2373.              continue;
  2374.  
  2375.              } // end if clipped
  2376.  
  2377.           } // end if quad
  2378.        else
  2379.           {
  2380.           // must be triangle, perform clipping tests on only 3 vertices
  2381.  
  2382.           // do clipping tests
  2383.  
  2384.           // perform near and far z clipping test first
  2385.  
  2386.           if (!((z1>clip_near_z || z2>clip_near_z || z3>clip_near_z) &&
  2387.                 (z1<clip_far_z || z2<clip_far_z || z3<clip_far_z)) )
  2388.              {
  2389.              // set clipped flag
  2390.  
  2391.              the_object->polys[curr_poly].clipped=1;
  2392.              continue;
  2393.  
  2394.              } // end if clipped
  2395.  
  2396.           // pre-compute x comparision ranges
  2397.  
  2398.           x1_compare = fov_width*z1;
  2399.           x2_compare = fov_width*z2;
  2400.           x3_compare = fov_width*z3;
  2401.  
  2402.           // perform x test
  2403.  
  2404.           if (!((x1>-x1_compare || x2>-x1_compare || x3>-x3_compare ) &&
  2405.                 (x1<x1_compare || x2<x2_compare || x3<x3_compare ))  )
  2406.              {
  2407.              // set clipped flag
  2408.  
  2409.              the_object->polys[curr_poly].clipped=1;
  2410.              continue;
  2411.  
  2412.              } // end if clipped
  2413.  
  2414.           // pre-compute x comparision ranges
  2415.  
  2416.           y1_compare = fov_height*z1;                                            (HALF_SCREEN_HEIGHT*z1)/viewing_distance;
  2417.           y2_compare = fov_height*z2;                                            (HALF_SCREEN_HEIGHT*z2)/viewing_distance;
  2418.           y3_compare = fov_height*z3;                                            (HALF_SCREEN_HEIGHT*z3)/viewing_distance;
  2419.  
  2420.           // perform x test
  2421.  
  2422.           if (!((y1>-y1_compare || y2>-y1_compare || y3>-y3_compare) &&
  2423.                 (y1<y1_compare || y2<y2_compare || y3<y3_compare ))  )
  2424.              {
  2425.              // set clipped flag
  2426.  
  2427.              the_object->polys[curr_poly].clipped=1;
  2428.              continue;
  2429.  
  2430.              } // end if clipped
  2431.  
  2432.            } // end else triangle
  2433.  
  2434.        } // end for curr_poly
  2435.  
  2436.    } // end else clip everything
  2437.  
  2438. } // end Clip_Object_3D
  2439.  
  2440. //////////////////////////////////////////////////////////////////////////////
  2441.  
  2442. void Remove_Backfaces_And_Shade(object_ptr the_object, int force_color)
  2443. {
  2444. // this function removes all the backfaces of an object by setting the visibility
  2445. // flag. This function assumes that the object has been transformed into
  2446. // camera coordinates. Also, the function takes into consideration is the
  2447. // polygons are one or two sided and executed the minimum amount of code
  2448. // in addition to perform the shading calculations
  2449.  
  2450. // also, this function has been altered from the standard function found in
  2451. // black17.c by the addition of the parameter force_color, this is used
  2452. // to force all the polys to a specific color. this is needed for the
  2453. // explosion vaporization effect
  2454.  
  2455. int vertex_0,         // vertex indices
  2456.     vertex_1,
  2457.     vertex_2,
  2458.     curr_poly;        // current polygon
  2459.  
  2460. float dp,             // the result of the dot product
  2461.       intensity;      // the final intensity of the surface
  2462.  
  2463. vector_3d u,v,        // general working vectors
  2464.           normal,     // the normal to the surface begin processed
  2465.           sight;      // line of sight vector
  2466.  
  2467. // for each polygon in the object determine if it is pointing away from the
  2468. // viewpoint and direction
  2469.  
  2470. for (curr_poly=0; curr_poly<the_object->num_polys; curr_poly++)
  2471.     {
  2472.  
  2473.     // is this polygon two sised or one sided
  2474.  
  2475.     if (the_object->polys[curr_poly].two_sided == ONE_SIDED)
  2476.        {
  2477.  
  2478.        // compute two vectors on polygon that have the same intial points
  2479.  
  2480.        vertex_0 = the_object->polys[curr_poly].vertex_list[0];
  2481.        vertex_1 = the_object->polys[curr_poly].vertex_list[1];
  2482.        vertex_2 = the_object->polys[curr_poly].vertex_list[2];
  2483.  
  2484.        // the vector u = vo->v1
  2485.  
  2486.        Make_Vector_3D((point_3d_ptr)&the_object->vertices_world[vertex_0],
  2487.                       (point_3d_ptr)&the_object->vertices_world[vertex_1],
  2488.                       (vector_3d_ptr)&u);
  2489.  
  2490.        // the vector v = vo-v2
  2491.  
  2492.        Make_Vector_3D((point_3d_ptr)&the_object->vertices_world[vertex_0],
  2493.                       (point_3d_ptr)&the_object->vertices_world[vertex_2],
  2494.                       (vector_3d_ptr)&v);
  2495.  
  2496.        // compute the normal to polygon v x u
  2497.  
  2498.        Cross_Product_3D((vector_3d_ptr)&v,
  2499.                         (vector_3d_ptr)&u,
  2500.                         (vector_3d_ptr)&normal);
  2501.  
  2502.        // compute the line of sight vector, since all coordinates are world all
  2503.        // object vertices are already relative to (0,0,0), thus
  2504.  
  2505.        sight.x = view_point.x-the_object->vertices_world[vertex_0].x;
  2506.        sight.y = view_point.y-the_object->vertices_world[vertex_0].y;
  2507.        sight.z = view_point.z-the_object->vertices_world[vertex_0].z;
  2508.  
  2509.        // compute the dot product between line of sight vector and normal to surface
  2510.  
  2511.        dp = Dot_Product_3D((vector_3d_ptr)&normal,(vector_3d_ptr)&sight);
  2512.  
  2513.        // is surface visible
  2514.  
  2515.        if (dp>0)
  2516.           {
  2517.           // set visible flag
  2518.  
  2519.           the_object->polys[curr_poly].visible = 1;
  2520.  
  2521.  
  2522. // a little cludge
  2523.  
  2524.           // first test for a forced color
  2525.  
  2526.           if (force_color>-1)
  2527.              {
  2528.              the_object->polys[curr_poly].shade = force_color;
  2529.              continue;
  2530.  
  2531.              } // end if forced color
  2532.  
  2533. // end a little cludge
  2534.  
  2535.           // compute light intensity if needed
  2536.  
  2537.           if (the_object->polys[curr_poly].shading==FLAT_SHADING)
  2538.              {
  2539.  
  2540.              // compute the dot product between the light source vector
  2541.              // and normal vector to surface
  2542.  
  2543.              dp = Dot_Product_3D((vector_3d_ptr)&normal,
  2544.                                  (vector_3d_ptr)&light_source);
  2545.  
  2546.              // test if light ray is reflecting off surface
  2547.  
  2548.              if (dp>0)
  2549.                 {
  2550.                 // now cos 0 = (u.v)/|u||v| or
  2551.  
  2552.                 intensity = ambient_light + (dp*(the_object->polys[curr_poly].normal_length));
  2553.  
  2554.                 // test if intensity has overflowed
  2555.  
  2556.                 if (intensity > 15)
  2557.                     intensity = 15;
  2558.  
  2559.                 // intensity now varies from 0-1, 0 being black or grazing and 1 being
  2560.                 // totally illuminated. use the value to index into color table
  2561.  
  2562.                 the_object->polys[curr_poly].shade =
  2563.                            the_object->polys[curr_poly].color - (int)intensity;
  2564.  
  2565.                 } // end if light is reflecting off surface
  2566.              else
  2567.                 the_object->polys[curr_poly].shade =
  2568.                 the_object->polys[curr_poly].color - (int)ambient_light;
  2569.  
  2570.              } // end if use flat shading
  2571.           else
  2572.              {
  2573.              // assume constant shading and simply assign color to shade
  2574.  
  2575.              the_object->polys[curr_poly].shade = the_object->polys[curr_poly].color;
  2576.  
  2577.              } // end else constant shading
  2578.  
  2579.           } // end if dp>0
  2580.        else
  2581.           the_object->polys[curr_poly].visible = 0;
  2582.  
  2583.  
  2584.        } // end if one sided
  2585.     else
  2586.        {
  2587.        // else polygon is always visible i.e. two sided, set visibility flag
  2588.        // so engine renders it
  2589.  
  2590.        // set visibility
  2591.  
  2592.        the_object->polys[curr_poly].visible = 1;
  2593.  
  2594.  
  2595. // a little cludge
  2596.  
  2597.        // first test for a forced color
  2598.  
  2599.        if (force_color>-1)
  2600.           {
  2601.           the_object->polys[curr_poly].shade = force_color;
  2602.           continue;
  2603.  
  2604.           } // end if forced color
  2605.  
  2606. // end a little cludge
  2607.  
  2608.        // perform shading calculation
  2609.  
  2610.        if (the_object->polys[curr_poly].shading==FLAT_SHADING)
  2611.           {
  2612.           // compute normal
  2613.  
  2614.           // compute two vectors on polygon that have the same intial points
  2615.  
  2616.           vertex_0 = the_object->polys[curr_poly].vertex_list[0];
  2617.           vertex_1 = the_object->polys[curr_poly].vertex_list[1];
  2618.           vertex_2 = the_object->polys[curr_poly].vertex_list[2];
  2619.  
  2620.           // the vector u = vo->v1
  2621.  
  2622.           Make_Vector_3D((point_3d_ptr)&the_object->vertices_world[vertex_0],
  2623.                          (point_3d_ptr)&the_object->vertices_world[vertex_1],
  2624.                          (vector_3d_ptr)&u);
  2625.  
  2626.           // the vector v = vo-v2
  2627.  
  2628.           Make_Vector_3D((point_3d_ptr)&the_object->vertices_world[vertex_0],
  2629.                          (point_3d_ptr)&the_object->vertices_world[vertex_2],
  2630.                          (vector_3d_ptr)&v);
  2631.  
  2632.           // compute the normal to polygon v x u
  2633.  
  2634.           Cross_Product_3D((vector_3d_ptr)&v,
  2635.                            (vector_3d_ptr)&u,
  2636.                            (vector_3d_ptr)&normal);
  2637.  
  2638.  
  2639.           // compute the dot product between the light source vector
  2640.           // and normal vector to surface
  2641.  
  2642.           dp = Dot_Product_3D((vector_3d_ptr)&normal,
  2643.                               (vector_3d_ptr)&light_source);
  2644.  
  2645.           // test if light ray is reflecting off surface
  2646.  
  2647.           if (dp>0)
  2648.              {
  2649.              // now cos 0 = (u.v)/|u||v| or
  2650.  
  2651.              intensity = ambient_light + (dp*(the_object->polys[curr_poly].normal_length));
  2652.  
  2653.              // test if intensity has overflowed
  2654.  
  2655.              if (intensity > 15)
  2656.                  intensity = 15;
  2657.  
  2658.              // intensity now varies from 0-1, 0 being black or grazing and 1 being
  2659.              // totally illuminated. use the value to index into color table
  2660.  
  2661.              the_object->polys[curr_poly].shade =
  2662.                         the_object->polys[curr_poly].color - (int)intensity;
  2663.  
  2664.              } // end if light is reflecting off surface
  2665.           else
  2666.              the_object->polys[curr_poly].shade =
  2667.              the_object->polys[curr_poly].color - (int)ambient_light;
  2668.  
  2669.           } // end if use flat shading
  2670.        else
  2671.           {
  2672.           // assume constant shading and simply assign color to shade
  2673.  
  2674.           the_object->polys[curr_poly].shade = the_object->polys[curr_poly].color;
  2675.  
  2676.           } // end else constant shading
  2677.  
  2678.        } // end else two sided
  2679.  
  2680.     } // end for curr_poly
  2681.  
  2682. } // end Remove_Backfaces_And_Shade
  2683.  
  2684. //////////////////////////////////////////////////////////////////////////////
  2685.  
  2686. int Remove_Object(object_ptr the_object, int mode)
  2687. {
  2688. // this function determines if an entire object is within the viewing volume
  2689. // or not by testing if the bounding sphere of the object in question
  2690. // is within the viewing volume.In essence, this function "culls" entire objects
  2691.  
  2692. float x_bsphere,   // the x,y and z components of the projected center of object
  2693.       y_bsphere,
  2694.       z_bsphere,
  2695.       radius,     // the radius of object
  2696.       x_compare,  // the extents of the clipping volume in x and y at the
  2697.       y_compare;  // bounding spheres current z
  2698.  
  2699. // first transform world position of object into camera coordinates
  2700.  
  2701. // compute x component
  2702.  
  2703. x_bsphere = the_object->world_pos.x * global_view[0][0] +
  2704.             the_object->world_pos.y * global_view[1][0] +
  2705.             the_object->world_pos.z * global_view[2][0] +
  2706.                                       global_view[3][0];
  2707.  
  2708. // compute y component
  2709.  
  2710. y_bsphere = the_object->world_pos.x * global_view[0][1] +
  2711.             the_object->world_pos.y * global_view[1][1] +
  2712.             the_object->world_pos.z * global_view[2][1] +
  2713.                                       global_view[3][1];
  2714. // compute z component
  2715.  
  2716. z_bsphere = the_object->world_pos.x * global_view[0][2] +
  2717.             the_object->world_pos.y * global_view[1][2] +
  2718.             the_object->world_pos.z * global_view[2][2] +
  2719.                                       global_view[3][2];
  2720.  
  2721. // extract radius of object
  2722.  
  2723. radius = the_object->radius;
  2724.  
  2725. if (mode==OBJECT_CULL_Z_MODE)
  2726.    {
  2727.    // first test against near and far z planes
  2728.  
  2729.    if ( ((z_bsphere-radius) > clip_far_z) ||
  2730.         ((z_bsphere+radius) < clip_near_z) )
  2731.         return(1);
  2732.    else
  2733.         return(0);
  2734.  
  2735.    } // end if z only
  2736. else
  2737.    {
  2738.    // perform full x,y,z test
  2739.  
  2740.    if ( ((z_bsphere-radius) > clip_far_z) ||
  2741.         ((z_bsphere+radius) < clip_near_z) )
  2742.         return(1);
  2743.  
  2744.    // test against x right and left planes, first compute viewing volume
  2745.    // extents at position z position of bounding sphere
  2746.  
  2747.    x_compare = (HALF_SCREEN_WIDTH*z_bsphere)/viewing_distance;
  2748.  
  2749.    if ( ((x_bsphere-radius) > x_compare) ||
  2750.         ((x_bsphere+radius) < -x_compare) )
  2751.       return(1);
  2752.  
  2753.    // finally test against y top and bottom planes
  2754.  
  2755.    y_compare = (INVERSE_ASPECT_RATIO*HALF_SCREEN_HEIGHT*z_bsphere)/viewing_distance;
  2756.  
  2757.    if ( ((y_bsphere-radius) > y_compare) ||
  2758.         ((y_bsphere+radius) < -y_compare) )
  2759.       return(1);
  2760.  
  2761.    // else it just can't be removed!!!
  2762.  
  2763.    return(0);
  2764.  
  2765.    } // end else
  2766.  
  2767. } // end Remove_Object
  2768.  
  2769. //////////////////////////////////////////////////////////////////////////////
  2770.  
  2771. void Generate_Poly_List(object_ptr the_object,int mode)
  2772. {
  2773. // this function is used to generate the final polygon list that will be
  2774. // rendered. Object by object the list is built up
  2775.  
  2776.  
  2777. int vertex,
  2778.     curr_vertex,
  2779.     curr_poly;
  2780.  
  2781. // test if this is the first object to be inserted
  2782.  
  2783. if (mode==RESET_POLY_LIST)
  2784.    {
  2785.    // reset number of polys to zero
  2786.  
  2787.    num_polys_frame=0;
  2788.    return;
  2789.  
  2790.    } // end if first
  2791.  
  2792. // insert all visible polygons into polygon list
  2793.  
  2794. for (curr_poly=0; curr_poly<the_object->num_polys; curr_poly++)
  2795.     {
  2796.  
  2797.     // test if this poly is visible, if so add it to poly list
  2798.  
  2799.     if (the_object->polys[curr_poly].visible &&
  2800.         !the_object->polys[curr_poly].clipped)
  2801.        {
  2802.        // add this poly to poly list
  2803.  
  2804.        // first copy data and vertices into an open slot in storage area
  2805.  
  2806.        world_poly_storage[num_polys_frame].num_points = the_object->polys[curr_poly].num_points;
  2807.        world_poly_storage[num_polys_frame].color      = the_object->polys[curr_poly].color;
  2808.        world_poly_storage[num_polys_frame].shade      = the_object->polys[curr_poly].shade;
  2809.        world_poly_storage[num_polys_frame].shading    = the_object->polys[curr_poly].shading;
  2810.        world_poly_storage[num_polys_frame].two_sided  = the_object->polys[curr_poly].two_sided;
  2811.        world_poly_storage[num_polys_frame].visible    = the_object->polys[curr_poly].visible;
  2812.        world_poly_storage[num_polys_frame].clipped    = the_object->polys[curr_poly].clipped;
  2813.        world_poly_storage[num_polys_frame].active     = the_object->polys[curr_poly].active;
  2814.  
  2815.        // now copy vertices
  2816.  
  2817.        for (curr_vertex=0; curr_vertex<the_object->polys[curr_poly].num_points; curr_vertex++)
  2818.            {
  2819.            // extract vertex number
  2820.  
  2821.            vertex=the_object->polys[curr_poly].vertex_list[curr_vertex];
  2822.  
  2823.            // extract x,y and z
  2824.  
  2825.            world_poly_storage[num_polys_frame].vertex_list[curr_vertex].x
  2826.                                     = the_object->vertices_camera[vertex].x;
  2827.  
  2828.            world_poly_storage[num_polys_frame].vertex_list[curr_vertex].y
  2829.                                     = the_object->vertices_camera[vertex].y;
  2830.  
  2831.            world_poly_storage[num_polys_frame].vertex_list[curr_vertex].z
  2832.                                     = the_object->vertices_camera[vertex].z;
  2833.  
  2834.  
  2835.            } // end for curr_vertex
  2836.  
  2837.        // assign pointer to it
  2838.  
  2839.        world_polys[num_polys_frame] = &world_poly_storage[num_polys_frame];
  2840.  
  2841.        // increment number of polys
  2842.  
  2843.        num_polys_frame++;
  2844.  
  2845.        } // end if poly visible
  2846.  
  2847.     } // end for curr_poly
  2848.  
  2849. } // end Generate_Poly_List
  2850.  
  2851. //////////////////////////////////////////////////////////////////////////////
  2852.  
  2853. void Draw_Poly_List(void)
  2854. {
  2855.  
  2856. // this function draws the global polygon list generated by calls to
  2857. // Generate_Poly_List
  2858.  
  2859. int curr_poly;          // the current polygon
  2860.  
  2861. float x1,y1,z1,         // working variables
  2862.       x2,y2,z2,
  2863.       x3,y3,z3,
  2864.       x4,y4,z4,
  2865.       viewing_distance_aspect;  // the y axis corrected viewing distance
  2866.  
  2867.  
  2868. viewing_distance_aspect = viewing_distance*ASPECT_RATIO;
  2869.  
  2870. // draw each polygon in list
  2871.  
  2872. for (curr_poly=0; curr_poly<num_polys_frame; curr_poly++)
  2873.     {
  2874.     // get z's for perspective
  2875.  
  2876.     z1=world_polys[curr_poly]->vertex_list[0].z;
  2877.     z2=world_polys[curr_poly]->vertex_list[1].z;
  2878.     z3=world_polys[curr_poly]->vertex_list[2].z;
  2879.  
  2880.     // test if this is a quad
  2881.  
  2882.     if (world_polys[curr_poly]->num_points==4)
  2883.        {
  2884.        // extract vertex number and z component for clipping and projection
  2885.  
  2886.        z4=world_polys[curr_poly]->vertex_list[3].z;
  2887.  
  2888.        } // end if quad
  2889.     else
  2890.       z4=z3;
  2891.  
  2892. #if 0
  2893.  
  2894.     // perform z clipping test
  2895.  
  2896.     if ( (z1<clip_near_z && z2<clip_near_z && z3<clip_near_z && z4<clip_near_z) ||
  2897.          (z1>clip_far_z && z2>clip_far_z && z3>clip_far_z && z4>clip_far_z) )
  2898.        continue;
  2899.  
  2900. #endif
  2901.  
  2902.         // extract points of polygon
  2903.  
  2904.         x1 = world_polys[curr_poly]->vertex_list[0].x;
  2905.         y1 = world_polys[curr_poly]->vertex_list[0].y;
  2906.  
  2907.         x2 = world_polys[curr_poly]->vertex_list[1].x;
  2908.         y2 = world_polys[curr_poly]->vertex_list[1].y;
  2909.  
  2910.         x3 = world_polys[curr_poly]->vertex_list[2].x;
  2911.         y3 = world_polys[curr_poly]->vertex_list[2].y;
  2912.  
  2913.         // compute screen position of points
  2914.  
  2915.         x1=(HALF_SCREEN_WIDTH  + x1*viewing_distance/z1);
  2916.         y1=(HALF_SCREEN_HEIGHT - y1*viewing_distance_aspect/z1);
  2917.  
  2918.         x2=(HALF_SCREEN_WIDTH  + x2*viewing_distance/z2);
  2919.         y2=(HALF_SCREEN_HEIGHT - y2*viewing_distance_aspect/z2);
  2920.  
  2921.         x3=(HALF_SCREEN_WIDTH  + x3*viewing_distance/z3);
  2922.         y3=(HALF_SCREEN_HEIGHT - y3*viewing_distance_aspect/z3);
  2923.  
  2924.         // draw triangle
  2925.  
  2926.         Draw_Triangle_2D((int)x1,(int)y1,(int)x2,(int)y2,(int)x3,(int)y3,
  2927.                          world_polys[curr_poly]->shade);
  2928.  
  2929.         // draw second poly if this is a quad
  2930.  
  2931.         if (world_polys[curr_poly]->num_points==4)
  2932.            {
  2933.            // extract the point
  2934.  
  2935.            x4 = world_polys[curr_poly]->vertex_list[3].x;
  2936.            y4 = world_polys[curr_poly]->vertex_list[3].y;
  2937.  
  2938.            // poject to screen
  2939.  
  2940.            x4=(HALF_SCREEN_WIDTH  + x4*viewing_distance/z4);
  2941.            y4=(HALF_SCREEN_HEIGHT - y4*viewing_distance_aspect/z4);
  2942.  
  2943.            // draw triangle
  2944.  
  2945.            Draw_Triangle_2D((int)x1,(int)y1,(int)x3,(int)y3,(int)x4,(int)y4,
  2946.                             world_polys[curr_poly]->shade);
  2947.  
  2948.            } // end if quad
  2949.  
  2950.     } // end for curr_poly
  2951.  
  2952. } // end Draw_Poly_List
  2953.  
  2954. /////////////////////////////////////////////////////////////////////////////
  2955.  
  2956. void Compute_Average_Z(void)
  2957. {
  2958. // this function pre-computes the average z of each polygon, so that the
  2959. // polygon sorter doesn't compute each z more than once
  2960.  
  2961. int index;
  2962.  
  2963. for (index=0; index<num_polys_frame; index++)
  2964.     {
  2965.  
  2966.     if (world_poly_storage[index].num_points==3)
  2967.        {
  2968.        world_poly_storage[index].average_z =
  2969.  
  2970.                    (int)(0.3333*(world_poly_storage[index].vertex_list[0].z+
  2971.                                  world_poly_storage[index].vertex_list[1].z+
  2972.                                  world_poly_storage[index].vertex_list[2].z));
  2973.  
  2974.        } // end if
  2975.     else
  2976.        {
  2977.        world_poly_storage[index].average_z =
  2978.  
  2979.                       (int)(0.25*(world_poly_storage[index].vertex_list[0].z+
  2980.                                   world_poly_storage[index].vertex_list[1].z+
  2981.                                   world_poly_storage[index].vertex_list[2].z+
  2982.                                   world_poly_storage[index].vertex_list[3].z));
  2983.  
  2984.        } // end if
  2985.  
  2986.     } // end for index
  2987.  
  2988. } // end Compute_Average_Z
  2989.  
  2990. //////////////////////////////////////////////////////////////////////////////
  2991.  
  2992. int Poly_Compare(facet **arg1, facet **arg2)
  2993. {
  2994. // this function comapares the average z's of two polygons and is used by the
  2995. // depth sort surface ordering algorithm
  2996.  
  2997. facet_ptr poly_1,poly_2;
  2998.  
  2999. // dereference the poly pointers
  3000.  
  3001. poly_1 = (facet_ptr)*arg1;
  3002. poly_2 = (facet_ptr)*arg2;
  3003.  
  3004. if (poly_1->average_z>poly_2->average_z)
  3005.    return(-1);
  3006. else
  3007. if (poly_1->average_z<poly_2->average_z)
  3008.    return(1);
  3009. else
  3010.    return(0);
  3011.  
  3012. } // end Poly_Compare
  3013.  
  3014. /////////////////////////////////////////////////////////////////////////////
  3015.  
  3016. void Sort_Poly_List(void)
  3017. {
  3018. // this function does a simple z sort on the poly list to order surfaces
  3019. // the list is sorted in descending order, i.e. farther polygons first
  3020.  
  3021. Compute_Average_Z();
  3022.  
  3023. qsort((void *)world_polys,num_polys_frame, sizeof(facet_ptr), (qsort_cast)Poly_Compare);
  3024.  
  3025. } // end Sort_Poly_List
  3026.  
  3027. ///////////////////////////////////////////////////////////////////////////////
  3028.  
  3029. int Load_Palette_Disk(char *filename, RGB_palette_ptr the_palette)
  3030. {
  3031. // this function loads a color palette from disk
  3032.  
  3033. int index; // used for looping
  3034.  
  3035. RGB_color color;
  3036.  
  3037. FILE *fp;
  3038.  
  3039. // open the disk file
  3040.  
  3041. if (!(fp = fopen(filename,"r")))
  3042.    return(0);
  3043.  
  3044. // load in all the colors
  3045.  
  3046. for (index=0; index<=255; index++)
  3047.     {
  3048.     // get the next color
  3049.  
  3050.     fscanf(fp,"%d %d %d",&color.red,&color.green,&color.blue);
  3051.  
  3052.     // store the color in next element of palette
  3053.  
  3054.     the_palette->colors[index].red   = color.red;
  3055.     the_palette->colors[index].green = color.green;
  3056.     the_palette->colors[index].blue  = color.blue;
  3057.  
  3058.     } // end for index
  3059.  
  3060. // set palette size to a full palette
  3061.  
  3062. the_palette->start_reg = 0;
  3063. the_palette->end_reg   = 255;
  3064.  
  3065. // close the file and return success
  3066.  
  3067. fclose(fp);
  3068.  
  3069. return(1);
  3070.  
  3071. } // end Load_Palette_Disk
  3072.  
  3073. ///////////////////////////////////////////////////////////////////////////////
  3074.  
  3075. int Save_Palette_Disk(char *filename, RGB_palette_ptr the_palette)
  3076. {
  3077. // this function saves a palette to disk
  3078.  
  3079. int index; // used for looping
  3080.  
  3081. RGB_color color;
  3082.  
  3083. FILE *fp;
  3084.  
  3085. // open the disk file
  3086.  
  3087. if (!(fp = fopen(filename,"w")))
  3088.    return(0);
  3089.  
  3090. // write 255 lines of r g b
  3091.  
  3092. for (index=0; index<=255; index++)
  3093.     {
  3094.     // get the next color
  3095.  
  3096.     // store the color in next element of palette
  3097.  
  3098.     color.red   = the_palette->colors[index].red;
  3099.     color.green = the_palette->colors[index].green;
  3100.     color.blue  = the_palette->colors[index].blue;
  3101.  
  3102.     // write the color to disk file
  3103.  
  3104.     fprintf(fp,"\n%d %d %d",color.red, color.green, color.blue);
  3105.  
  3106.     } // end for index
  3107.  
  3108. // close the file and return success
  3109.  
  3110. fclose(fp);
  3111.  
  3112. return(1);
  3113.  
  3114. } // end Save_Palette_Disk
  3115.  
  3116. ///////////////////////////////////////////////////////////////////////////////
  3117.  
  3118. void Fill_Double_Buffer_32(int icolor)
  3119. {
  3120. // this function fills in the double buffer with the sent color a QUAD at
  3121. // a time
  3122.  
  3123. long color;  // used to create a 4 byte color descriptor
  3124.  
  3125. color = icolor | (icolor << 8);
  3126.  
  3127. // replicate color into all four bytes of quad
  3128.  
  3129. color = color | (color<<16);
  3130.  
  3131. fquadset((void far *)double_buffer,color,(double_buffer_size >> 1));
  3132.  
  3133. } // end Fill_Double_Buffer_32
  3134.  
  3135. //////////////////////////////////////////////////////////////////////////////
  3136.  
  3137. void Display_Double_Buffer_32(unsigned char far *buffer,int y)
  3138. {
  3139. // this functions copies the double buffer into the video buffer at the
  3140. // starting y location using quad byte transfers
  3141.  
  3142. fquadcpy((void far *)(video_buffer+y*320),
  3143.          (void far *)double_buffer,
  3144.          (double_buffer_size >> 1));
  3145.  
  3146. } // end Display_Double_Buffer_32
  3147.  
  3148. ///////////////////////////////////////////////////////////////////////////////
  3149.  
  3150. int Clip_Line(int *x1,int *y1,int *x2, int *y2)
  3151. {
  3152. // this function clips the sent line using the globally defined clipping
  3153. // region
  3154.  
  3155. int point_1 = 0, point_2 = 0;  // tracks if each end point is visible or invisible
  3156.  
  3157. int clip_always = 0;           // used for clipping override
  3158.  
  3159. int xi,yi;                     // point of intersection
  3160.  
  3161. int right_edge=0,              // which edges are the endpoints beyond
  3162.     left_edge=0,
  3163.     top_edge=0,
  3164.     bottom_edge=0;
  3165.  
  3166.  
  3167. int success = 0;               // was there a successfull clipping
  3168.  
  3169. float dx,dy;                   // used to holds slope deltas
  3170.  
  3171. // test if line is completely visible
  3172.  
  3173. if ( (*x1>=poly_clip_min_x) && (*x1<=poly_clip_max_x) &&
  3174.      (*y1>=poly_clip_min_y) && (*y1<=poly_clip_max_y) )
  3175.      point_1 = 1;
  3176.  
  3177.  
  3178. if ( (*x2>=poly_clip_min_x) && (*x2<=poly_clip_max_x) &&
  3179.      (*y2>=poly_clip_min_y) && (*y2<=poly_clip_max_y) )
  3180.      point_2 = 1;
  3181.  
  3182. // test endpoints
  3183.  
  3184. if (point_1==1 && point_2==1)
  3185.    return(1);
  3186.  
  3187. // test if line is completely invisible
  3188.  
  3189. if (point_1==0 && point_2==0)
  3190.    {
  3191.  
  3192.    // must test to see if each endpoint is on the same side of one of
  3193.    // the bounding planes created by each clipping region boundary
  3194.  
  3195.    if ( ((*x1<poly_clip_min_x) && (*x2<poly_clip_min_x)) || // to the left
  3196.         ((*x1>poly_clip_max_x) && (*x2>poly_clip_max_x)) || // to the right
  3197.  
  3198.         ((*y1<poly_clip_min_y) && (*y2<poly_clip_min_y)) || // above
  3199.         ((*y1>poly_clip_max_y) && (*y2>poly_clip_max_y)) )  // below
  3200.         {
  3201.         // no need to draw line
  3202.  
  3203.         return(0);
  3204.  
  3205.         } // end if invisible
  3206.  
  3207.    // if we got here we have the special case where the line cuts into and
  3208.    // out of the clipping region
  3209.  
  3210.    clip_always = 1;
  3211.  
  3212.    } // end if test for invisibly
  3213.  
  3214. // take care of case where either endpoint is in clipping region
  3215.  
  3216. if (( point_1==1) || (point_1==0 && point_2==0) )
  3217.    {
  3218.  
  3219.    // compute deltas
  3220.  
  3221.    dx = *x2 - *x1;
  3222.    dy = *y2 - *y1;
  3223.  
  3224.    // compute what boundary line need to be clipped against
  3225.  
  3226.    if (*x2 > poly_clip_max_x)
  3227.       {
  3228.       // flag right edge
  3229.  
  3230.       right_edge = 1;
  3231.  
  3232.       // compute intersection with right edge
  3233.  
  3234.       if (dx!=0)
  3235.          yi = (int)(.5 + (dy/dx) * (poly_clip_max_x - *x1) + *y1);
  3236.       else
  3237.          yi = -1;  // invalidate intersection
  3238.  
  3239.       } // end if to right
  3240.    else
  3241.    if (*x2 < poly_clip_min_x)
  3242.       {
  3243.       // flag left edge
  3244.  
  3245.       left_edge = 1;
  3246.  
  3247.       // compute intersection with left edge
  3248.  
  3249.       if (dx!=0)
  3250.          yi = (int)(.5 + (dy/dx) * (poly_clip_min_x - *x1) + *y1);
  3251.       else
  3252.          yi = -1;  // invalidate intersection
  3253.  
  3254.       } // end if to left
  3255.  
  3256.    // horizontal intersections
  3257.  
  3258.    if (*y2 > poly_clip_max_y)
  3259.       {
  3260.       // flag bottom edge
  3261.  
  3262.       bottom_edge = 1;
  3263.  
  3264.       // compute intersection with right edge
  3265.  
  3266.       if (dy!=0)
  3267.          xi = (int)(.5 + (dx/dy) * (poly_clip_max_y - *y1) + *x1);
  3268.       else
  3269.          xi = -1;  // invalidate inntersection
  3270.  
  3271.       } // end if bottom
  3272.    else
  3273.    if (*y2 < poly_clip_min_y)
  3274.       {
  3275.       // flag top edge
  3276.  
  3277.       top_edge = 1;
  3278.  
  3279.       // compute intersection with top edge
  3280.  
  3281.       if (dy!=0)
  3282.          xi = (int)(.5 + (dx/dy) * (poly_clip_min_y - *y1) + *x1);
  3283.       else
  3284.          xi = -1;  // invalidate intersection
  3285.  
  3286.       } // end if top
  3287.  
  3288.    // now we know where the line passed thru
  3289.    // compute which edge is the proper intersection
  3290.  
  3291.    if (right_edge==1 && (yi>=poly_clip_min_y && yi<=poly_clip_max_y) )
  3292.       {
  3293.  
  3294.       *x2 = poly_clip_max_x;
  3295.       *y2 = yi;
  3296.  
  3297.       success = 1;
  3298.  
  3299.       } // end if intersected right edge
  3300.    else
  3301.    if (left_edge==1 && (yi>=poly_clip_min_y && yi<=poly_clip_max_y) )
  3302.       {
  3303.  
  3304.       *x2 = poly_clip_min_x;
  3305.       *y2 = yi;
  3306.  
  3307.       success = 1;
  3308.  
  3309.       } // end if intersected left edge
  3310.  
  3311.    if (bottom_edge==1 && (xi>=poly_clip_min_x && xi<=poly_clip_max_x) )
  3312.       {
  3313.  
  3314.       *x2 = xi;
  3315.       *y2 = poly_clip_max_y;
  3316.  
  3317.       success = 1;
  3318.  
  3319.       } // end if intersected bottom edge
  3320.    else
  3321.    if (top_edge==1 && (xi>=poly_clip_min_x && xi<=poly_clip_max_x) )
  3322.       {
  3323.  
  3324.       *x2 = xi;
  3325.       *y2 = poly_clip_min_y;
  3326.  
  3327.       success = 1;
  3328.  
  3329.       } // end if intersected top edge
  3330.  
  3331.    } // end if point_1 is visible
  3332.  
  3333. // reset edge flags
  3334.  
  3335. right_edge = left_edge= top_edge = bottom_edge = 0;
  3336.  
  3337. // test second endpoint
  3338.  
  3339. if ( (point_2==1) || (point_1==0 && point_2==0))
  3340.    {
  3341.    // compute deltas
  3342.  
  3343.    dx = *x1 - *x2;
  3344.    dy = *y1 - *y2;
  3345.  
  3346.    // compute what boundary line need to be clipped against
  3347.  
  3348.    if (*x1 > poly_clip_max_x)
  3349.       {
  3350.       // flag right edge
  3351.  
  3352.       right_edge = 1;
  3353.  
  3354.       // compute intersection with right edge
  3355.  
  3356.       if (dx!=0)
  3357.          yi = (int)(.5 + (dy/dx) * (poly_clip_max_x - *x2) + *y2);
  3358.       else
  3359.          yi = -1;  // invalidate inntersection
  3360.  
  3361.       } // end if to right
  3362.    else
  3363.    if (*x1 < poly_clip_min_x)
  3364.       {
  3365.       // flag left edge
  3366.  
  3367.       left_edge = 1;
  3368.  
  3369.       // compute intersection with left edge
  3370.  
  3371.       if (dx!=0)
  3372.          yi = (int)(.5 + (dy/dx) * (poly_clip_min_x - *x2) + *y2);
  3373.       else
  3374.          yi = -1;  // invalidate intersection
  3375.  
  3376.       } // end if to left
  3377.  
  3378.    // horizontal intersections
  3379.  
  3380.    if (*y1 > poly_clip_max_y)
  3381.       {
  3382.       // flag bottom edge
  3383.  
  3384.       bottom_edge = 1;
  3385.  
  3386.       // compute intersection with right edge
  3387.  
  3388.       if (dy!=0)
  3389.          xi = (int)(.5 + (dx/dy) * (poly_clip_max_y - *y2) + *x2);
  3390.       else
  3391.          xi = -1;  // invalidate inntersection
  3392.  
  3393.       } // end if bottom
  3394.    else
  3395.    if (*y1 < poly_clip_min_y)
  3396.       {
  3397.       // flag top edge
  3398.  
  3399.       top_edge = 1;
  3400.  
  3401.       // compute intersection with top edge
  3402.  
  3403.       if (dy!=0)
  3404.          xi = (int)(.5 + (dx/dy) * (poly_clip_min_y - *y2) + *x2);
  3405.       else
  3406.          xi = -1;  // invalidate inntersection
  3407.  
  3408.       } // end if top
  3409.  
  3410.    // now we know where the line passed thru
  3411.    // compute which edge is the proper intersection
  3412.  
  3413.    if (right_edge==1 && (yi>=poly_clip_min_y && yi<=poly_clip_max_y) )
  3414.       {
  3415.  
  3416.       *x1 = poly_clip_max_x;
  3417.       *y1 = yi;
  3418.  
  3419.       success = 1;
  3420.  
  3421.       } // end if intersected right edge
  3422.    else
  3423.    if (left_edge==1 && (yi>=poly_clip_min_y && yi<=poly_clip_max_y) )
  3424.       {
  3425.  
  3426.       *x1 = poly_clip_min_x;
  3427.       *y1 = yi;
  3428.  
  3429.       success = 1;
  3430.  
  3431.       } // end if intersected left edge
  3432.  
  3433.    if (bottom_edge==1 && (xi>=poly_clip_min_x && xi<=poly_clip_max_x) )
  3434.       {
  3435.  
  3436.       *x1 = xi;
  3437.       *y1 = poly_clip_max_y;
  3438.  
  3439.       success = 1;
  3440.  
  3441.       } // end if intersected bottom edge
  3442.    else
  3443.    if (top_edge==1 && (xi>=poly_clip_min_x && xi<=poly_clip_max_x) )
  3444.       {
  3445.  
  3446.       *x1 = xi;
  3447.       *y1 = poly_clip_min_y;
  3448.  
  3449.       success = 1;
  3450.  
  3451.       } // end if intersected top edge
  3452.  
  3453.  
  3454.    } // end if point_2 is visible
  3455.  
  3456. return(success);
  3457.  
  3458. } // end Clip_Line
  3459.  
  3460. //////////////////////////////////////////////////////////////////////////////
  3461.  
  3462. void Draw_Line(int xo, int yo, int x1,int y1, unsigned char color,unsigned char far *vb_start)
  3463. {
  3464. // this function draws a line from xo,yo to x1,y1 using differential error
  3465. // terms (based on Bresenahams work)
  3466.  
  3467. int dx,             // difference in x's
  3468.     dy,             // difference in y's
  3469.     x_inc,          // amount in pixel space to move during drawing
  3470.     y_inc,          // amount in pixel space to move during drawing
  3471.     error=0,        // the discriminant i.e. error i.e. decision variable
  3472.     index;          // used for looping
  3473.  
  3474. // pre-compute first pixel address in video buffer
  3475.  
  3476. vb_start = vb_start + ((unsigned int)yo<<6) +
  3477.                       ((unsigned int)yo<<8) +
  3478.                       (unsigned int)xo;
  3479.  
  3480. // compute horizontal and vertical deltas
  3481.  
  3482. dx = x1-xo;
  3483. dy = y1-yo;
  3484.  
  3485. // test which direction the line is going in i.e. slope angle
  3486.  
  3487. if (dx>=0)
  3488.    {
  3489.    x_inc = 1;
  3490.  
  3491.    } // end if line is moving right
  3492. else
  3493.    {
  3494.    x_inc = -1;
  3495.    dx    = -dx;  // need absolute value
  3496.  
  3497.    } // end else moving left
  3498.  
  3499. // test y component of slope
  3500.  
  3501. if (dy>=0)
  3502.    {
  3503.    y_inc = 320; // 320 bytes per line
  3504.  
  3505.    } // end if line is moving down
  3506. else
  3507.    {
  3508.    y_inc = -320;
  3509.    dy    = -dy;  // need absolute value
  3510.  
  3511.    } // end else moving up
  3512.  
  3513. // now based on which delta is greater we can draw the line
  3514.  
  3515. if (dx>dy)
  3516.    {
  3517.  
  3518.    // draw the line
  3519.  
  3520.    for (index=0; index<=dx; index++)
  3521.        {
  3522.        // set the pixel
  3523.  
  3524.        *vb_start = color;
  3525.  
  3526.        // adjust the error term
  3527.  
  3528.        error+=dy;
  3529.  
  3530.        // test if error has overflowed
  3531.  
  3532.        if (error>dx)
  3533.           {
  3534.  
  3535.           error-=dx;
  3536.  
  3537.           // move to next line
  3538.  
  3539.           vb_start+=y_inc;
  3540.  
  3541.           } // end if error overflowed
  3542.  
  3543.        // move to the next pixel
  3544.  
  3545.        vb_start+=x_inc;
  3546.  
  3547.        } // end for
  3548.  
  3549.    } // end if |slope| <= 1
  3550. else
  3551.    {
  3552.  
  3553.    // draw the line
  3554.  
  3555.    for (index=0; index<=dy; index++)
  3556.        {
  3557.        // set the pixel
  3558.  
  3559.        *vb_start = color;
  3560.  
  3561.        // adjust the error term
  3562.  
  3563.        error+=dx;
  3564.  
  3565.        // test if error overflowed
  3566.  
  3567.        if (error>0)
  3568.           {
  3569.  
  3570.           error-=dy;
  3571.  
  3572.           // move to next line
  3573.  
  3574.           vb_start+=x_inc;
  3575.  
  3576.           } // end if error overflowed
  3577.  
  3578.        // move to the next pixel
  3579.  
  3580.        vb_start+=y_inc;
  3581.  
  3582.        } // end for
  3583.  
  3584.    } // end else |slope| > 1
  3585.  
  3586. } // end Draw_Line
  3587.  
  3588. ///////////////////////////////////////////////////////////////////////////////
  3589.  
  3590. void Draw_Object_Wire(object_ptr the_object, int color)
  3591. {
  3592. // this function draws an object out of wires
  3593.  
  3594. int curr_poly,      // the current polygon
  3595.     curr_vertex,    // the current vertex
  3596.     vertex;         // vertex index
  3597.  
  3598. float x1,y1,z1,     // working variables
  3599.       x2,y2,z2;
  3600.  
  3601. int ix1,iy1,        // integers used to hold screen coordinates
  3602.     ix2,iy2;
  3603.  
  3604. // compute position of object in world
  3605.  
  3606. for (curr_poly=0; curr_poly<the_object->num_polys; curr_poly++)
  3607.     {
  3608.  
  3609.     // is this polygon visible?
  3610.  
  3611.     if (the_object->polys[curr_poly].visible==0 ||
  3612.         the_object->polys[curr_poly].clipped )
  3613.        continue;
  3614.  
  3615.     // printf("\npolygon #%d",curr_poly);
  3616.  
  3617.     for (curr_vertex=0; curr_vertex<the_object->polys[curr_poly].num_points-1; curr_vertex++)
  3618.         {
  3619.  
  3620.         // extract two endpoints
  3621.  
  3622.         vertex=the_object->polys[curr_poly].vertex_list[curr_vertex];
  3623.  
  3624.         x1 = the_object->vertices_world[vertex].x;
  3625.         y1 = the_object->vertices_world[vertex].y;
  3626.         z1 = the_object->vertices_world[vertex].z;
  3627.  
  3628.         vertex=the_object->polys[curr_poly].vertex_list[curr_vertex+1];
  3629.  
  3630.         x2 = the_object->vertices_world[vertex].x;
  3631.         y2 = the_object->vertices_world[vertex].y;
  3632.         z2 = the_object->vertices_world[vertex].z;
  3633.  
  3634.         // convert to screen ccordinates
  3635.  
  3636.         x1=(HALF_SCREEN_WIDTH  + x1*viewing_distance/z1);
  3637.         y1=(HALF_SCREEN_HEIGHT - ASPECT_RATIO*y1*viewing_distance/z1);
  3638.  
  3639.  
  3640.         x2=(HALF_SCREEN_WIDTH  + x2*viewing_distance/z2);
  3641.         y2=(HALF_SCREEN_HEIGHT - ASPECT_RATIO*y2*viewing_distance/z2);
  3642.  
  3643.         // convert floats to integers for line clipper
  3644.  
  3645.         ix1=(int)x1;
  3646.         iy1=(int)y1;
  3647.         ix2=(int)x2;
  3648.         iy2=(int)y2;
  3649.  
  3650.  
  3651.         // draw clipped lines
  3652.  
  3653.         if (Clip_Line(&ix1,&iy1,&ix2,&iy2))
  3654.            {
  3655.            Draw_Line((int)ix1,(int)iy1,(int)ix2,(int)iy2,
  3656.                      (unsigned char)color,
  3657.                      double_buffer);
  3658.  
  3659.            } // end if clip
  3660.  
  3661.         } // end for vertex
  3662.  
  3663.     // close polygon
  3664.  
  3665.     ix1=(int)x2;
  3666.     iy1=(int)y2;
  3667.  
  3668.     // extract starting point again to close polygon
  3669.  
  3670.     vertex=the_object->polys[curr_poly].vertex_list[0];
  3671.  
  3672.     x2 = the_object->vertices_world[vertex].x;
  3673.     y2 = the_object->vertices_world[vertex].y;
  3674.     z2 = the_object->vertices_world[vertex].z;
  3675.  
  3676.     // compute screen coordinates
  3677.  
  3678.     x2=(HALF_SCREEN_WIDTH  + x2*viewing_distance/z2);
  3679.     y2=(HALF_SCREEN_HEIGHT - ASPECT_RATIO*y2*viewing_distance/z2);
  3680.  
  3681.     // convert floats to integers
  3682.  
  3683.     ix2=(int)x2;
  3684.     iy2=(int)y2;
  3685.  
  3686.     // draw clipped lines
  3687.  
  3688.     if (Clip_Line(&ix1,&iy1,&ix2,&iy2))
  3689.        {
  3690.        Draw_Line((int)ix1,(int)iy1,(int)ix2,(int)iy2,
  3691.                  (unsigned char)color,
  3692.                  double_buffer);
  3693.  
  3694.        } // end if clip
  3695.  
  3696.     } // end for curr_poly
  3697.  
  3698. } // end Draw_Object_Wire
  3699.  
  3700. ///////////////////////////////////////////////////////////////////////////////
  3701.  
  3702.  
  3703.