home *** CD-ROM | disk | FTP | other *** search
/ Teach Yourself Game Programming in 21 Days / TYGAMES_R.ISO / source / day_05 / graph5.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-06-13  |  16.6 KB  |  745 lines

  1.  
  2. // I N C L U D E S ///////////////////////////////////////////////////////////
  3.  
  4. #include <io.h>
  5. #include <conio.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <dos.h>
  9. #include <bios.h>
  10. #include <fcntl.h>
  11. #include <memory.h>
  12. #include <malloc.h>
  13. #include <math.h>
  14. #include <string.h>
  15.  
  16. #include "graph3.h"  // include our graphics stuff
  17. #include "graph4.h"
  18. #include "graph5.h"
  19.  
  20. // G L O B A L S  ////////////////////////////////////////////////////////////
  21.  
  22. float sin_look[361],   // look up tables for sin and cosine
  23.       cos_look[361];
  24.  
  25. // the clipping region, set it to default on start up
  26.  
  27. int poly_clip_min_x = POLY_CLIP_MIN_X,
  28.     poly_clip_min_y = POLY_CLIP_MIN_Y,
  29.  
  30.     poly_clip_max_x = POLY_CLIP_MAX_X,
  31.     poly_clip_max_y = POLY_CLIP_MAX_Y;
  32.  
  33. // F U N C T I O N S /////////////////////////////////////////////////////////
  34.  
  35. void Create_Tables(void)
  36. {
  37. // this function creates the sin and cosine lookup tables
  38.  
  39. int index;
  40.  
  41. // create the tables
  42.  
  43. for (index=0; index<=360; index++)
  44.     {
  45.  
  46.     cos_look[index] = (float)cos((double)(index*3.14159/180));
  47.     sin_look[index] = (float)sin((double)(index*3.14159/180));
  48.  
  49.     } // end for
  50.  
  51. } // end Create_Tables
  52.  
  53. //////////////////////////////////////////////////////////////////////////////
  54.  
  55. void Rotate_Polygon(polygon_ptr poly, int angle)
  56. {
  57.  
  58. int index;    // loop index
  59.  
  60. float si,cs,  // values of sin and cosine
  61.       rx,ry;  // roated points
  62.  
  63. // rotate each point of the poly gon around its local origin
  64. // note that angle is an integer and ranges from -360 to +360
  65.  
  66. // compute sin and cos of angle to be rotated
  67.  
  68. if (angle>=0)
  69.    {
  70.    // extract sin and cosine from look up table
  71.  
  72.    si = sin_look[angle];
  73.    cs = cos_look[angle];
  74.  
  75.  
  76.    } // end if positive angle
  77. else
  78.    {
  79.    // angle is negative to convert to positive
  80.  
  81.    // convert negative angle to positive angle and extract values
  82.  
  83.    si = sin_look[angle+360];
  84.    cs = cos_look[angle+360];
  85.  
  86.    } // end else
  87.  
  88. // using values for sin and cosine rotate the point
  89.  
  90. for (index=0; index<poly->num_vertices; index++)
  91.     {
  92.     // compute rotated values using rotation eqns.
  93.  
  94.     rx  = poly->vertices[index].x * cs -  poly->vertices[index].y * si;
  95.     ry  = poly->vertices[index].y * cs +  poly->vertices[index].x * si;
  96.  
  97.     // store the rotated vertex back into structure
  98.  
  99.     poly->vertices[index].x = rx;
  100.     poly->vertices[index].y = ry;
  101.  
  102.     } // end for
  103.  
  104. } // end Rotate_Polygon
  105.  
  106. ///////////////////////////////////////////////////////////////////////////////
  107.  
  108. void Scale_Polygon(polygon_ptr poly, float scale)
  109. {
  110.  
  111. int index;
  112.  
  113. // scale each vertex of the polygon
  114.  
  115. for (index=0; index<poly->num_vertices; index++)
  116.     {
  117.     // multiply by the scaling factor
  118.  
  119.     poly->vertices[index].x*=scale;
  120.     poly->vertices[index].y*=scale;
  121.  
  122.     } // end for
  123.  
  124. } // end Scale_Polygon
  125.  
  126. ///////////////////////////////////////////////////////////////////////////////
  127.  
  128. void Translate_Polygon(polygon_ptr poly, int dx,int dy)
  129. {
  130.  
  131. // translate the origin of the polygon
  132.  
  133. poly->lxo+=dx;
  134. poly->lyo+=dy;
  135.  
  136. // that was easy!
  137.  
  138. } // end Translate_Polygon
  139.  
  140. ///////////////////////////////////////////////////////////////////////////////
  141.  
  142. void Draw_Polygon(polygon_ptr poly)
  143. {
  144. // this function draws a polygon on the screen without clipping
  145. // caller should make sure that vertices are within bounds of clipping
  146. // rectangle, also the polygon will always be unfilled regardless
  147. // of the fill flag
  148.  
  149. int index,xo,yo;
  150.  
  151. // extract local origin
  152.  
  153. xo = poly->lxo;
  154. yo = poly->lyo;
  155.  
  156. // draw polygon
  157.  
  158. for (index=0; index<poly->num_vertices-1; index++)
  159.     {
  160.  
  161.     Bline(xo+(int)poly->vertices[index].x,yo+(int)poly->vertices[index].y,
  162.           xo+(int)poly->vertices[index+1].x,yo+(int)poly->vertices[index+1].y,
  163.           poly->b_color);
  164.  
  165.     } // end for index
  166.  
  167.     // close polygon?
  168.  
  169.     if (!poly->closed)
  170.        return;
  171.  
  172.     Bline(xo+(int)poly->vertices[index].x,yo+(int)poly->vertices[index].y,
  173.           xo+(int)poly->vertices[0].x,yo+(int)poly->vertices[0].y,
  174.           poly->b_color);
  175.  
  176.  
  177. } // end Draw_Polygon
  178.  
  179. //////////////////////////////////////////////////////////////////////////////
  180.  
  181. int Clip_Line(int *x1,int *y1,int *x2, int *y2)
  182. {
  183. // this function clips the sent line using the globally defined clipping
  184. // region
  185.  
  186. int point_1 = 0, point_2 = 0;  // tracks if each end point is visible or invisible
  187.  
  188. int clip_always = 0;           // used for clipping override
  189.  
  190. int xi,yi;                     // point of intersection
  191.  
  192. int right_edge=0,              // which edges are the endpoints beyond
  193.     left_edge=0,
  194.     top_edge=0,
  195.     bottom_edge=0;
  196.  
  197.  
  198. int success = 0;               // was there a successfull clipping
  199.  
  200. float dx,dy;                   // used to holds slope deltas
  201.  
  202. // SECTION 1 //////////////////////////////////////////////////////////////////
  203.  
  204. // test if line is completely visible
  205.  
  206. if ( (*x1>=poly_clip_min_x) && (*x1<=poly_clip_max_x) &&
  207.      (*y1>=poly_clip_min_y) && (*y1<=poly_clip_max_y) )
  208.      point_1 = 1;
  209.  
  210.  
  211. if ( (*x2>=poly_clip_min_x) && (*x2<=poly_clip_max_x) &&
  212.      (*y2>=poly_clip_min_y) && (*y2<=poly_clip_max_y) )
  213.      point_2 = 1;
  214.  
  215. // SECTION 2 /////////////////////////////////////////////////////////////////
  216.  
  217. // test endpoints
  218.  
  219. if (point_1==1 && point_2==1)
  220.    return(1);
  221.  
  222. // SECTION 3 /////////////////////////////////////////////////////////////////
  223.  
  224. // test if line is completely invisible
  225.  
  226. if (point_1==0 && point_2==0)
  227.    {
  228.  
  229.    // must test to see if each endpoint is on the same side of one of
  230.    // the bounding planes created by each clipping region boundary
  231.  
  232.    if ( ((*x1<poly_clip_min_x) && (*x2<poly_clip_min_x)) || // to the left
  233.         ((*x1>poly_clip_max_x) && (*x2>poly_clip_max_x)) || // to the right
  234.  
  235.         ((*y1<poly_clip_min_y) && (*y2<poly_clip_min_y)) || // above
  236.         ((*y1>poly_clip_max_y) && (*y2>poly_clip_max_y)) )  // below
  237.         {
  238.  
  239.         // no need to draw line
  240.  
  241.         return(0);
  242.  
  243.         } // end if invisible
  244.  
  245.    // if we got here we have the special case where the line cuts into and
  246.    // out of the clipping region
  247.  
  248.    clip_always = 1;
  249.  
  250.    } // end if test for invisibly
  251.  
  252. // SECTION 4 /////////////////////////////////////////////////////////////////
  253.  
  254. // take care of case where either endpoint is in clipping region
  255.  
  256. if (( point_1==1) || (point_1==0 && point_2==0) )
  257.    {
  258.  
  259.    // compute deltas
  260.  
  261.    dx = *x2 - *x1;
  262.    dy = *y2 - *y1;
  263.  
  264.    // compute what boundary line need to be clipped against
  265.  
  266.    if (*x2 > poly_clip_max_x)
  267.       {
  268.       // flag right edge
  269.  
  270.       right_edge = 1;
  271.  
  272.       // compute intersection with right edge
  273.  
  274.       if (dx!=0)
  275.          yi = (int)(.5 + (dy/dx) * (poly_clip_max_x - *x1) + *y1);
  276.       else
  277.          yi = -1;  // invalidate intersection
  278.  
  279.       } // end if to right
  280.    else
  281.    if (*x2 < poly_clip_min_x)
  282.       {
  283.       // flag left edge
  284.  
  285.       left_edge = 1;
  286.  
  287.       // compute intersection with left edge
  288.  
  289.       if (dx!=0)
  290.          yi = (int)(.5 + (dy/dx) * (poly_clip_min_x - *x1) + *y1);
  291.       else
  292.          yi = -1;  // invalidate intersection
  293.  
  294.       } // end if to left
  295.  
  296.    // horizontal intersections
  297.  
  298.    if (*y2 > poly_clip_max_y)
  299.       {
  300.       // flag bottom edge
  301.  
  302.       bottom_edge = 1;
  303.  
  304.       // compute intersection with right edge
  305.  
  306.       if (dy!=0)
  307.          xi = (int)(.5 + (dx/dy) * (poly_clip_max_y - *y1) + *x1);
  308.       else
  309.          xi = -1;  // invalidate inntersection
  310.  
  311.       } // end if bottom
  312.    else
  313.    if (*y2 < poly_clip_min_y)
  314.       {
  315.       // flag top edge
  316.  
  317.       top_edge = 1;
  318.  
  319.       // compute intersection with top edge
  320.  
  321.       if (dy!=0)
  322.          xi = (int)(.5 + (dx/dy) * (poly_clip_min_y - *y1) + *x1);
  323.       else
  324.          xi = -1;  // invalidate inntersection
  325.  
  326.       } // end if top
  327.  
  328. // SECTION 5 /////////////////////////////////////////////////////////////////
  329.  
  330.    // now we know where the line passed thru
  331.    // compute which edge is the proper intersection
  332.  
  333.    if (right_edge==1 && (yi>=poly_clip_min_y && yi<=poly_clip_max_y) )
  334.       {
  335.  
  336.       *x2 = poly_clip_max_x;
  337.       *y2 = yi;
  338.  
  339.       success = 1;
  340.  
  341.       } // end if intersected right edge
  342.    else
  343.    if (left_edge==1 && (yi>=poly_clip_min_y && yi<=poly_clip_max_y) )
  344.       {
  345.  
  346.       *x2 = poly_clip_min_x;
  347.       *y2 = yi;
  348.  
  349.       success = 1;
  350.  
  351.       } // end if intersected left edge
  352.  
  353.    if (bottom_edge==1 && (xi>=poly_clip_min_x && xi<=poly_clip_max_x) )
  354.       {
  355.  
  356.       *x2 = xi;
  357.       *y2 = poly_clip_max_y;
  358.  
  359.       success = 1;
  360.  
  361.       } // end if intersected bottom edge
  362.    else
  363.    if (top_edge==1 && (xi>=poly_clip_min_x && xi<=poly_clip_max_x) )
  364.       {
  365.  
  366.       *x2 = xi;
  367.       *y2 = poly_clip_min_y;
  368.  
  369.       success = 1;
  370.  
  371.       } // end if intersected top edge
  372.  
  373.    } // end if point_1 is visible
  374.  
  375. // SECTION 6 /////////////////////////////////////////////////////////////////
  376.  
  377. // reset edge flags
  378.  
  379. right_edge = left_edge= top_edge = bottom_edge = 0;
  380.  
  381. // test second endpoint
  382.  
  383. if ( (point_2==1) || (point_1==0 && point_2==0))
  384.    {
  385.  
  386.    // compute deltas
  387.  
  388.    dx = *x1 - *x2;
  389.    dy = *y1 - *y2;
  390.  
  391.    // compute what boundary line need to be clipped against
  392.  
  393.    if (*x1 > poly_clip_max_x)
  394.       {
  395.       // flag right edge
  396.  
  397.       right_edge = 1;
  398.  
  399.       // compute intersection with right edge
  400.  
  401.       if (dx!=0)
  402.          yi = (int)(.5 + (dy/dx) * (poly_clip_max_x - *x2) + *y2);
  403.       else
  404.          yi = -1;  // invalidate inntersection
  405.  
  406.       } // end if to right
  407.    else
  408.    if (*x1 < poly_clip_min_x)
  409.       {
  410.       // flag left edge
  411.  
  412.       left_edge = 1;
  413.  
  414.       // compute intersection with left edge
  415.  
  416.       if (dx!=0)
  417.          yi = (int)(.5 + (dy/dx) * (poly_clip_min_x - *x2) + *y2);
  418.       else
  419.          yi = -1;  // invalidate intersection
  420.  
  421.       } // end if to left
  422.  
  423.    // horizontal intersections
  424.  
  425.    if (*y1 > poly_clip_max_y)
  426.       {
  427.       // flag bottom edge
  428.  
  429.       bottom_edge = 1;
  430.  
  431.       // compute intersection with right edge
  432.  
  433.       if (dy!=0)
  434.          xi = (int)(.5 + (dx/dy) * (poly_clip_max_y - *y2) + *x2);
  435.       else
  436.          xi = -1;  // invalidate inntersection
  437.  
  438.       } // end if bottom
  439.    else
  440.    if (*y1 < poly_clip_min_y)
  441.       {
  442.       // flag top edge
  443.  
  444.       top_edge = 1;
  445.  
  446.       // compute intersection with top edge
  447.  
  448.       if (dy!=0)
  449.          xi = (int)(.5 + (dx/dy) * (poly_clip_min_y - *y2) + *x2);
  450.       else
  451.          xi = -1;  // invalidate inntersection
  452.  
  453.       } // end if top
  454.  
  455.    // now we know where the line passed thru
  456.    // compute which edge is the proper intersection
  457.  
  458.    if (right_edge==1 && (yi>=poly_clip_min_y && yi<=poly_clip_max_y) )
  459.       {
  460.  
  461.       *x1 = poly_clip_max_x;
  462.       *y1 = yi;
  463.  
  464.       success = 1;
  465.  
  466.       } // end if intersected right edge
  467.    else
  468.    if (left_edge==1 && (yi>=poly_clip_min_y && yi<=poly_clip_max_y) )
  469.       {
  470.  
  471.       *x1 = poly_clip_min_x;
  472.       *y1 = yi;
  473.  
  474.       success = 1;
  475.  
  476.       } // end if intersected left edge
  477.  
  478.    if (bottom_edge==1 && (xi>=poly_clip_min_x && xi<=poly_clip_max_x) )
  479.       {
  480.  
  481.       *x1 = xi;
  482.       *y1 = poly_clip_max_y;
  483.  
  484.       success = 1;
  485.  
  486.       } // end if intersected bottom edge
  487.    else
  488.    if (top_edge==1 && (xi>=poly_clip_min_x && xi<=poly_clip_max_x) )
  489.       {
  490.  
  491.       *x1 = xi;
  492.       *y1 = poly_clip_min_y;
  493.  
  494.       success = 1;
  495.  
  496.       } // end if intersected top edge
  497.  
  498.  
  499.    } // end if point_2 is visible
  500.  
  501. // SECTION 7 /////////////////////////////////////////////////////////////////
  502.  
  503. return(success);
  504.  
  505. } // end Clip_Line
  506.  
  507. //////////////////////////////////////////////////////////////////////////////
  508.  
  509. void Draw_Polygon_Clip(polygon_ptr poly)
  510. {
  511.  
  512. // this function draws a polygon on the screen with clipping
  513. // also the polygon will always be unfilled regardless
  514. // of the fill flag in the polygon structure
  515.  
  516. int index,  // loop index
  517.     xo,yo,  // local origin
  518.     x1,y1,  // end points of current line being processed
  519.     x2,y2;
  520.  
  521. // extract local origin
  522.  
  523. xo = poly->lxo;
  524. yo = poly->lyo;
  525.  
  526. // draw polygon
  527.  
  528. for (index=0; index<poly->num_vertices-1; index++)
  529.     {
  530.  
  531.     // extract the line
  532.  
  533.     x1 = (int)poly->vertices[index].x+xo;
  534.     y1 = (int)poly->vertices[index].y+yo;
  535.  
  536.     x2 = (int)poly->vertices[index+1].x+xo;
  537.     y2 = (int)poly->vertices[index+1].y+yo;
  538.  
  539.     // clip line to viewing screen and draw unless line is totally invisible
  540.  
  541.     if (Clip_Line(&x1,&y1,&x2,&y2))
  542.        {
  543.        // line was clipped and now can be drawn
  544.        Bline(x1,y1,x2,y2,poly->b_color);
  545.  
  546.        } // end if draw line
  547.  
  548.     } // end for index
  549.  
  550.     // close polygon?        // close polygon
  551.  
  552.     if (!poly->closed)
  553.        return;
  554.  
  555.     // extract the line
  556.  
  557.     x1 = (int)poly->vertices[index].x+xo;
  558.     y1 = (int)poly->vertices[index].y+yo;
  559.  
  560.     x2 = (int)poly->vertices[0].x+xo;
  561.     y2 = (int)poly->vertices[0].y+yo;
  562.  
  563.     // clip line to viewing screen and draw unless line is totally invisible
  564.  
  565.     if (Clip_Line(&x1,&y1,&x2,&y2))
  566.        {
  567.  
  568.        // line was clipped and now can be drawn
  569.  
  570.        Bline(x1,y1,x2,y2,poly->b_color);
  571.  
  572.        } // end if draw line
  573.  
  574. } // end Draw_Polygon_Clip
  575.  
  576. //////////////////////////////////////////////////////////////////////////////
  577.  
  578. void Bline(int xo, int yo, int x1,int y1, unsigned char color)
  579. {
  580. // this function uses Bresenham's algorithm IBM (1965) to draw a line from
  581. // (xo,yo) - (x1,y1)
  582.  
  583. int dx,             // difference in x's
  584.     dy,             // difference in y's
  585.     x_inc,          // amount in pixel space to move during drawing
  586.     y_inc,          // amount in pixel space to move during drawing
  587.     error=0,        // the discriminant i.e. error i.e. decision variable
  588.     index;          // used for looping
  589.  
  590.  
  591.  
  592. unsigned char far *vb_start = video_buffer; // directly access the video
  593.                                             // buffer for speed
  594.  
  595.  
  596. // SECTION 1 /////////////////////////////////////////////////////////////////
  597.  
  598. // pre-compute first pixel address in video buffer
  599. // use shifts for multiplication
  600.  
  601.  
  602. vb_start = vb_start + ((unsigned int)yo<<6) +
  603.                       ((unsigned int)yo<<8) +
  604.                       (unsigned int)xo;
  605.  
  606. // compute deltas
  607.  
  608. dx = x1-xo;
  609. dy = y1-yo;
  610.  
  611. // SECTION 2 /////////////////////////////////////////////////////////////////
  612.  
  613. // test which direction the line is going in i.e. slope angle
  614.  
  615. if (dx>=0)
  616.    {
  617.    x_inc = 1;
  618.  
  619.    } // end if line is moving right
  620. else
  621.    {
  622.    x_inc = -1;
  623.    dx    = -dx;  // need absolute value
  624.  
  625.    } // end else moving left
  626.  
  627. // SECTION 3 /////////////////////////////////////////////////////////////////
  628.  
  629. // test y component of slope
  630.  
  631. if (dy>=0)
  632.    {
  633.    y_inc = 320; // 320 bytes per line
  634.  
  635.    } // end if line is moving down
  636. else
  637.    {
  638.    y_inc = -320;
  639.    dy    = -dy;  // need absolute value
  640.  
  641.    } // end else moving up
  642.  
  643. // SECTION 4 /////////////////////////////////////////////////////////////////
  644.  
  645. // now based on which delta is greater we can draw the line
  646.  
  647. if (dx>dy)
  648.    {
  649.  
  650.    // draw the line
  651.  
  652.    for (index=0; index<=dx; index++)
  653.        {
  654.        // set the pixel
  655.  
  656.        *vb_start = color;
  657.  
  658.        // adjust the discriminate
  659.  
  660.        error+=dy;
  661.  
  662.        // test if error overflowed
  663.  
  664.        if (error>dx)
  665.           {
  666.  
  667.           error-=dx;
  668.  
  669.           // move to next line
  670.  
  671.           vb_start+=y_inc;
  672.  
  673.           } // end if error overflowed
  674.  
  675.        // move to the next pixel
  676.  
  677.        vb_start+=x_inc;
  678.  
  679.        } // end for
  680.  
  681.    } // end if |slope| <= 1
  682. else
  683.    {
  684.  
  685. // SECTION 5 /////////////////////////////////////////////////////////////////
  686.  
  687.    // draw the line
  688.  
  689.    for (index=0; index<=dy; index++)
  690.        {
  691.        // set the pixel
  692.  
  693.        *vb_start = color;
  694.  
  695.        // adjust the discriminate
  696.  
  697.        error+=dx;
  698.  
  699.        // test if error overflowed
  700.  
  701.        if (error>0)
  702.           {
  703.  
  704.           error-=dy;
  705.  
  706.           // move to next line
  707.  
  708.           vb_start+=x_inc;
  709.  
  710.           } // end if error overflowed
  711.  
  712.        // move to the next pixel
  713.  
  714.        vb_start+=y_inc;
  715.  
  716.        } // end for
  717.  
  718.    } // end else |slope| > 1
  719.  
  720. } // end Bline
  721.  
  722. ///////////////////////////////////////////////////////////////////////////////
  723.  
  724. void Draw_Boundary(int color)
  725. {
  726. // draws in the clipping boundary if user is intersted in seeing it
  727.  
  728. Bline(poly_clip_min_x,poly_clip_min_y,
  729.       poly_clip_max_x,poly_clip_min_y,color);
  730.  
  731.  
  732. Bline(poly_clip_max_x,poly_clip_min_y,
  733.       poly_clip_max_x,poly_clip_max_y,color);
  734.  
  735. Bline(poly_clip_max_x,poly_clip_max_y,
  736.       poly_clip_min_x,poly_clip_max_y,color);
  737.  
  738. Bline(poly_clip_min_x,poly_clip_max_y,
  739.       poly_clip_min_x,poly_clip_min_y,color);
  740.  
  741. } // end Draw_Boundary
  742.  
  743. ///////////////////////////////////////////////////////////////////////////////
  744.  
  745.