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