home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / graf / fract3.zip / LINE3D.C < prev    next >
Text File  |  1989-12-17  |  46KB  |  1,389 lines

  1.  
  2. /* This file contains a 3D replacement for the out_line function called
  3.    by the decoder. The purpose is to apply various 3D transformations before 
  4.    displaying points. Called once line of the original GIF file. 
  5.    
  6.    Original Author Tim Wegner, with much help from the usual crew of speed
  7.    demons.
  8. */
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <math.h>
  13. #include <limits.h>
  14. #include <dos.h>
  15. #include "fractint.h"
  16.  
  17. int clipcolor(int,int,int);   
  18. int interpcolor(int,int,int);
  19. int T_clipcolor(int,int,int);   
  20. int T_interpcolor(int,int,int);
  21. int (*fillplot)();   
  22. int (*normalplot)();   
  23.  
  24. char preview = 0;
  25. extern char floatflag;
  26. extern int (*plot)();   
  27. extern int xdots, ydots, colors;
  28. extern int debugflag;
  29. extern void draw_line (int X1, int Y1, int X2, int Y2, int color);
  30. extern int extraseg;
  31. extern unsigned height;
  32. extern int rowcount; /* in general.asm */
  33. extern int init3d[];            /* 3D arguments (FRACTINT.C) */
  34. extern FILE *fp_pot;            /* potential file pointer */
  35. extern int strlocn[];
  36. extern int transparent[2];        /* transparency min/max */
  37.  
  38. static float far *sinthetaarray;    /* all sines thetas go here  */
  39. static float far *costhetaarray;    /* all cosine thetas go here */
  40.  
  41. static double rXrscale;            /* precalculation factor */
  42.  
  43. static int persp;       /* flag for indicating perspective transformations */
  44. int bad_value = -10000;
  45. /* this array remembers the previous line */
  46. struct point
  47. {
  48.    int x;
  49.    int y;
  50.    int color;
  51. } far *lastrow;
  52. static struct point p1,p2,p3;
  53. struct f_point
  54. {
  55.    float x;
  56.    float y;
  57.    float color;
  58. } far *f_lastrow;
  59.  
  60. /* array of min and max x values used in triangle fill */
  61. struct minmax 
  62. {
  63.     int minx;
  64.     int maxx;
  65. } *minmax_x;
  66.      
  67. VECTOR view;    /* position of observer for perspective */
  68. VECTOR cross;
  69. VECTOR tmpcross;
  70. line3d(unsigned char pixels[], unsigned linelen)
  71. {
  72.  
  73.    /* these values come from FRACTINT.C */
  74.  
  75.    /* These variables must preserve their values across calls */
  76.    static double aspect;              /* aspect ration */
  77.    static float   deltaphi;  /* increment of latitude, longitude */
  78.    static float phi;
  79.    static double rscale;              /* surface roughness factor */
  80.    static long xcenter,ycenter;       /* circle center */
  81.    static double sclx,scly,sclz;      /* scale factors */
  82.    static double R;                   /* radius values */
  83.    static double Rfactor;             /* for intermediate calculation */
  84.    static MATRIX m;                   /* transformation matrix */
  85.    static LMATRIX lm;                 /* "" */
  86.    static LVECTOR lview;              /* for perspective views */
  87.    static double zcutoff;             /* perspective backside cutoff value */  
  88.    static float twocosdeltaphi;
  89.    static float cosphi,sinphi;              /* precalculated sin/cos of longitude */
  90.    static float oldcosphi1,oldsinphi1;
  91.    static float oldcosphi2,oldsinphi2;
  92.    double r;                          /* sphere radius */
  93.    double xval,yval,zval;             /* rotation values */
  94.    float costheta,sintheta;          /* precalculated sin/cos of latitude */
  95.    float twocosdeltatheta;
  96.    
  97.    struct point cur;                  /* current pixels */
  98.    struct point old;                  /* old pixels */
  99.    struct point oldlast;              /* old pixels */
  100.  
  101.    static struct point bad;           /* out of range value */
  102.  
  103.    struct f_point f_cur;
  104.    struct f_point f_old;
  105.    static struct f_point f_bad;       /* out of range value */
  106.  
  107.    static float far *fpixels;         /* float persion of pixels array */
  108.     
  109.    VECTOR v;                          /* double vector */
  110.    VECTOR v1,v2;
  111.    VECTOR crossavg;
  112.    char crossnotinit;                 /* flag for crossavg init indication */
  113.    
  114.    static VECTOR light_direction;
  115.    
  116.    LVECTOR lv;                          /* long equivalent of v */
  117.    LVECTOR lv0;                          /* long equivalent of v */
  118.    int color;                         /* current decoded color */
  119.    int col;                           /* current column (original GIF) */ 
  120.    /* corners of transformed xdotx by ydots x colors box */ 
  121.    double xmin, ymin, zmin, xmax, ymax, zmax; 
  122.    int i,j;
  123.    if(transparent[0] || transparent[1])
  124.       plot = normalplot = T_clipcolor;  /*  Use the transparent plot function */
  125.    else
  126.       plot = normalplot = clipcolor;    /* the usual FRACTINT plot function with clipping */
  127.  
  128.    /* 
  129.       This IF clause is executed ONCE per image. All precalculations are 
  130.       done here, with out any special concern about speed. DANGER - 
  131.       communication with the rest of the program is generally via static
  132.       or global variables.
  133.    */   
  134.    if(rowcount == 0)
  135.    {
  136.       long check_extra;       
  137.       float theta,theta1,theta2;      /* current,start,stop latitude */
  138.       float phi1,phi2;                /* current start,stop longitude */
  139.       float   deltatheta;          /* increment of latitude */
  140.  
  141.       /* lastrow stores the previous row of the original GIF image for
  142.          the purpose of filling in gaps with triangle procedure */
  143.  
  144.       crossavg[0] = 0;
  145.       crossavg[1] = 0;
  146.       crossavg[2] = 0;
  147.       minmax_x = (struct minmax *)strlocn;
  148.  
  149.       if(extraseg)
  150.       {
  151. #ifdef __TURBOC__
  152.          lastrow = MK_FP(extraseg,0);
  153. #else         
  154.          FP_SEG(lastrow)=extraseg;
  155.          FP_OFF(lastrow)=0;
  156. #endif      
  157.       }else
  158.          return(-1);
  159.  
  160.       /* stick this array a safe distance from end */
  161.       /* this array used in triangle-fill */
  162.       check_extra = sizeof(*lastrow)*(MAXPIXELS);
  163.  
  164.       /* now stuff the sine and cosine arrays still farther out */
  165.       sinthetaarray = (float far *)(lastrow+MAXPIXELS);
  166.       check_extra = check_extra + sizeof(float)*MAXPIXELS;
  167.  
  168.       costhetaarray = (float far *)(sinthetaarray+MAXPIXELS);
  169.       check_extra = check_extra + sizeof(float)*MAXPIXELS;
  170.  
  171.       f_lastrow = (struct f_point far *)(costhetaarray+MAXPIXELS);
  172.       check_extra = check_extra + sizeof(*f_lastrow)*(MAXPIXELS);
  173.  
  174.       fpixels = (float far *)(f_lastrow+MAXPIXELS);
  175.       check_extra = check_extra + sizeof(float)*MAXPIXELS;
  176.  
  177.       /* get scale factors */
  178.       sclx =   XSCALE/100.0;
  179.       scly =   YSCALE/100.0;
  180.       sclz = - ROUGH/100.0;
  181.  
  182.       if(SPHERE==FALSE)  /* skip this slow stuff in sphere case */
  183.       {
  184.          /* 
  185.             What is done here is to create a single matrix, m, which has 
  186.             scale, rotation, and shift all combined. This allows us to use 
  187.             a single matrix to transform any point. Additionally, we create 
  188.             two perspective vectors.
  189.             
  190.             Start with a unit matrix. Add scale and rotation. Then calculate 
  191.             the perspective vectors. Finally add enough translation to center 
  192.             the final image plus whatever shift the user has set.
  193.          */
  194.          
  195.          /* start with identity */
  196.          identity (m);
  197.  
  198.          /* translate so origin is in center of box, so that when we rotate 
  199.             it, we do so through the center */
  200.          trans ( (double)xdots/(-2.0),(double)ydots/(-2.0),
  201.                  (double)colors/(-2.0),m);
  202.      
  203.          /* apply scale factors */
  204.          scale(sclx,scly,sclz,m);  
  205.  
  206.          /* rotation values - converting from degrees to radians */
  207.          xval = XROT / 57.29577;
  208.          yval = YROT / 57.29577;  
  209.          zval = ZROT / 57.29577;
  210.          xrot (xval,m);
  211.          yrot (yval,m);
  212.          zrot (zval,m);
  213.          
  214.  
  215.          /* Find values of translation that make all x,y,z negative */
  216.          /* m current matrix */
  217.          /* 0 means don't show box */
  218.          /* returns minimum and maximum values of x,y,z in fractal */
  219.          corners(m,0,&xmin,&ymin,&zmin,&xmax,&ymax,&zmax);
  220.       }   
  221.  
  222.       /* perspective 3D vector - lview[2] == 0 means no perspective */
  223.  
  224.       /* set perspective flag */
  225.       persp = 0;
  226.       if (ZVIEWER != 0)
  227.       {
  228.          persp = 1;
  229.          if(ZVIEWER < 80) /* force float */
  230.              floatflag |= 2; /* turn on second bit */
  231.       }   
  232.  
  233.       /* set up view vector, and put viewer in center of screen */
  234.       lview[0] = xdots >> 1;  
  235.       lview[1] = ydots >> 1;
  236.       
  237.       /* z value of user's eye - should be more negative than extreme 
  238.          negative part of image */
  239.       if(SPHERE) /* sphere case */
  240.          lview[2] = -(long)((double)ydots*(double)ZVIEWER/100.0);
  241.       else          /* non-sphere case */
  242.          lview[2] = (long)((zmin-zmax)*(double)ZVIEWER/100.0);
  243.  
  244.       view[0] = lview[0];  view[1] = lview[1]; view[2] = lview[2];
  245.       lview[0] = lview[0] << 16;
  246.       lview[1] = lview[1] << 16;
  247.       lview[2] = lview[2] << 16; 
  248.  
  249.       if(SPHERE==FALSE) /* sphere skips this */
  250.       {
  251.          /* translate back exactly amount we translated earlier plus enough 
  252.             to center image so maximum values are non-positive */
  253.          trans(((double)xdots-xmax-xmin)/2,((double)ydots-ymax-ymin)/2,-zmax,m);
  254.          trans((double)XSHIFT,(double)(-YSHIFT),0.0,m);
  255.          /* matrix m now contains ALL those transforms composed together !!!! */
  256.          /* convert m to long integers shifted 16 bits */
  257.          for (i = 0; i < 4; i++)
  258.          for (j = 0; j < 4; j++)
  259.             lm[i][j] = m[i][j] * 65536.0;
  260.          /* this shows box before plotting fractal - very handy - should let
  261.          user do this */
  262.       }
  263.       else /* sphere stuff goes here */
  264.       {
  265.          float z;
  266.          double blob;    
  267.          /* Sphere is on side - north pole on right. Top is -90 degrees
  268.             latitude; bottom 90 degrees */
  269.       
  270.          /* Map X to this LATITUDE range */
  271.          theta1 = THETA1*PI/180.0;
  272.          theta2 = THETA2*PI/180.0;
  273.  
  274.          /* Map Y to this LONGITUDE range */
  275.          phi1   = PHI1*PI/180.0;
  276.          phi2   = PHI2*PI/180.0;
  277.  
  278.          theta = theta1;
  279.          phi   = phi1;
  280.          
  281.          /*
  282.             Thanks to Hugh Bray for the following idea: when calculating
  283.             a table of evenly spaced sines or cosines, only a few initial
  284.             values need be calculated, and the remaining values can be 
  285.             gotten from a derivative of the sine/cosine angle sum formula
  286.             at the cost of one multiplication and one addition per value!
  287.  
  288.             This idea is applied once here to get a complete table for 
  289.             latitude, and near the bottom of this routine to incrementally
  290.             calculate longitude.
  291.             
  292.             Precalculate 2*cos(deltaangle), sin(start) and sin(start+delta).
  293.             Then apply recursively:
  294.               sin(angle+2*delta) = sin(angle+delta) * 2cosdelta - sin(angle)
  295.  
  296.             Similarly for cosine. Neat!
  297.           */
  298.  
  299.          deltatheta = (float)(theta2 - theta1)/(float)linelen;         
  300.  
  301.          /* initial sin,cos theta */
  302.          sinthetaarray[0] = sin((double)theta);
  303.          costhetaarray[0] = cos((double)theta);
  304.          sinthetaarray[1] = sin((double)(theta + deltatheta));
  305.          costhetaarray[1] = cos((double)(theta + deltatheta));
  306.       
  307.          /* sin,cos delta theta */
  308.          twocosdeltatheta = 2.0*cos((double)deltatheta);
  309.  
  310.          /* build table of other sin,cos with trig identity */
  311.          for(i=2;i<linelen;i++)
  312.          {
  313.             sinthetaarray[i] = sinthetaarray[i-1]*twocosdeltatheta-
  314.                                sinthetaarray[i-2];
  315.             costhetaarray[i] = costhetaarray[i-1]*twocosdeltatheta-
  316.                                costhetaarray[i-2];
  317.          }         
  318.  
  319.          /* now phi - these calculated as we go - get started here */
  320.          deltaphi   = (float)(phi2   - phi1  )/(float)height;
  321.  
  322.          /* initial sin,cos phi */
  323.  
  324.          sinphi = oldsinphi1 = sin((double)phi1);
  325.          cosphi = oldcosphi1 = cos((double)phi1);
  326.          oldsinphi2 = sin((double)(phi1+deltaphi));
  327.          oldcosphi2 = cos((double)(phi1+deltaphi));
  328.       
  329.          /* sin,cos delta phi */
  330.          twocosdeltaphi = 2*cos((double)deltaphi);
  331.  
  332.          xcenter = xdots/2 + XSHIFT;
  333.          ycenter = ydots/2 - YSHIFT;
  334.  
  335.          /* affects how rough planet terrain is */
  336.          rscale= .3*ROUGH/100.0;
  337.  
  338.          /* radius of planet */
  339.          R = (double)(ydots)/2;
  340.  
  341.          /* precalculate factor */
  342.          rXrscale = R*rscale;
  343.          
  344.          /* aspect ratio calculation - assume screen is 4 x 3 */
  345.          aspect = (double)xdots*.75/(double)ydots; 
  346.          sclx = scly = RADIUS/100.0;
  347.  
  348.          /* adjust x scale factor for aspect */
  349.          sclx *= aspect;
  350.          
  351.          /* precalculation factor used in sphere calc */
  352.          Rfactor = rscale*R/(double)colors;
  353.          
  354.          if(persp) /* precalculate fudge factor */
  355.          {
  356.             double radius;
  357.             double zview;
  358.             double angle;
  359.  
  360.             xcenter      = xcenter << 16;
  361.             ycenter      = ycenter << 16;
  362.  
  363.             Rfactor *= 65536.0;
  364.             R       *= 65536.0;
  365.            
  366.             /* calculate z cutoff factor */
  367.             /* attempt to prevent out-of-view surfaces from being written */
  368.             zview = -(long)((double)ydots*(double)ZVIEWER/100.0);
  369.             radius = (double)(ydots)/2;
  370.             angle = atan(-radius/(zview+radius));
  371.             zcutoff = -radius - sin(angle)*radius;
  372.             zcutoff *= 1.1; /* for safety */
  373.             zcutoff *= 65536;
  374.          }
  375.       }
  376.       /* set fill plot function */
  377.       if(FILLTYPE != 3)
  378.       {
  379.          fillplot = interpcolor;
  380.  
  381.          if(transparent[0] || transparent[1]) /*  If transparent colors are set */
  382.             plot = T_interpcolor;  /*  Use the transparent plot function  */
  383.       }
  384.       else
  385.       {
  386.          fillplot = clipcolor;
  387.  
  388.          if(transparent[0] || transparent[1]) /*  If transparent colors are set */
  389.             fillplot = T_clipcolor;  /*  Use the transparent plot function  */
  390.       }
  391.  
  392.       /* Both Sphere and Normal 3D */
  393.       light_direction[0] = XLIGHT;
  394.       light_direction[1] = YLIGHT;
  395.       light_direction[2] = ZLIGHT;
  396.       
  397.       if(FILLTYPE==6 && !SPHERE) /* transform light direction */
  398.       {
  399.          /* Think of light direction  as a vector with tail at (0,0,0) and
  400.             head at (light_direction). We apply the transformation to
  401.             BOTH head and tail and take the difference */
  402.  
  403.          v[0] = 0.0;
  404.          v[1] = 0.0;
  405.          v[2] = 0.0;
  406.          vmult(v,m,v);
  407.          vmult(light_direction,m,light_direction);
  408.          light_direction[0] -= v[0]; 
  409.          light_direction[1] -= v[1]; 
  410.          light_direction[2] -= v[2]; 
  411.       }
  412.       normalize_vector(light_direction);
  413.       
  414.       /* bad has values caught by clipping */
  415.       f_bad.x     = bad.x     = bad_value;
  416.       f_bad.y     = bad.y     = bad_value;
  417.       f_bad.color = bad.color = bad_value;
  418.       for(i=0;i<linelen;i++)
  419.       {
  420.          lastrow[i]   = bad;
  421.          f_lastrow[i] = f_bad;
  422.       }
  423.       if(fp_pot)
  424.          fclose(fp_pot);
  425.       fp_pot=fopen("tmppot","rb");
  426.    } /* end of once-per-image intializations */ 
  427.    
  428.    crossnotinit = 1;
  429.    col = 0;
  430.  
  431.    /* make sure these pixel coordinates are out of range */
  432.    old   = bad;
  433.    f_old = f_bad;
  434.  
  435.    /* copies pixels buffer to float type fpixels buffer for fill purposes */
  436.    set_pixel_buff(pixels,fpixels,linelen);
  437.  
  438.    /*
  439.    This section of code allows the operation of a preview mode when the
  440.    preview flag is set. Enabled, it allows the drawing of only the first 
  441.    line of the source image, then every 10th line, until and including the 
  442.    last line. For the undrawn lines, only necessary calculations are 
  443.    made. As a bonus, in non-sphere mode a box is drawn to help visualize
  444.    the effects of 3D transformations. Thanks to Marc Reinig for this idea
  445.    and code -- BTW, Marc did NOT put the goto in, but WE did, to avoid
  446.    copying code here, and to avoid a HUGE "if-then" construct. Besides,
  447.    we have ALREADY sinned, so why not sin some more? */
  448.  
  449.    /* Enter Preview mode, insure last line is drawn  */   
  450.    if (preview && (rowcount != ydots-1)) 
  451.       if ((rowcount - 10 * (rowcount/10)) != 0) /* insure FIRST line drawn */
  452.          goto reallythebottom; /* skip over most of the line3d calcs */
  453.  
  454.    /* PROCESS ROW LOOP BEGINS HERE */
  455.    while(col < linelen)
  456.    {
  457.       /* printf("row %d col %d\r",rowcount,col); */
  458.       cur.color   = pixels[col];
  459.       f_cur.color = fpixels[col];
  460.       if (cur.color > 0 && cur.color < WATERLINE) 
  461.           f_cur.color = cur.color = WATERLINE;    /* "lake" */
  462.  
  463.       if(SPHERE) /* sphere case */
  464.       {
  465.          sintheta = sinthetaarray[col];
  466.          costheta = costhetaarray[col];
  467.          
  468.          /* if naked use of goto's offend you don't read next two lines! */
  469.          if(sinphi < 0) 
  470.          {
  471.             cur   = bad;
  472.             f_cur = f_bad;
  473.             goto loopbottom;   /* another goto ! */
  474.          }
  475.          
  476.          /* KEEP THIS FOR DOCS - original formula --
  477.          if(rscale < 0.0)
  478.             r = 1.0+((double)cur.color/(double)colors)*rscale;
  479.          else
  480.             r = 1.0-rscale+((double)cur.color/(double)colors)*rscale;
  481.          R = (double)ydots/2;
  482.          r = r*R;
  483.          cur.x = xdots/2 + sclx*r*sintheta*aspect + xup ;
  484.          cur.y = ydots/2 + scly*r*costheta*cosphi - yup ;
  485.          */
  486.  
  487.          if(rscale < 0.0)
  488.             r = R + Rfactor*(double)f_cur.color;
  489.          else if(rscale > 0.0)
  490.             r = R -rXrscale + Rfactor*(double)f_cur.color;
  491.          else
  492.             r = R;
  493.          if(persp)
  494.          {
  495.             /* NOTE: fudge was pre-calculated above in r and R */
  496.             lv[2] = -R - r*costheta*sinphi; /* (almost) guarantee negative */
  497.             if(lv[2] > zcutoff)
  498.             {
  499.                cur = bad;
  500.                f_cur = f_bad;
  501.                goto loopbottom;   /* another goto ! */
  502.             }
  503.             lv[0] = xcenter + sintheta*sclx*r;          /* x */
  504.             lv[1] = ycenter + costheta*cosphi*scly*r;   /* y */
  505.             
  506.             if(FILLTYPE >= 5) /* calculate illumination normal before persp */
  507.             {
  508.                double r0;
  509.                int xcenter0,ycenter0;
  510.             
  511.                r0       = r/65536;
  512.                xcenter0 =  xcenter >> 16;
  513.                ycenter0 =  xcenter >> 16;
  514.                 
  515.                f_cur.x     = xcenter0 + sintheta*sclx*r0;
  516.                f_cur.y     = ycenter0 + costheta*cosphi*scly*r0;
  517.                f_cur.color = -r0*costheta*sinphi;
  518.             }
  519.             if(floatflag)
  520.             {
  521.                VECTOR v;
  522.                long fudge;
  523.                fudge = 1L<<16;
  524.                v[0] = lv[0];
  525.                v[1] = lv[1];
  526.                v[2] = lv[2];
  527.                v[0] /= fudge;
  528.                v[1] /= fudge;
  529.                v[2] /= fudge;
  530.                perspective(v);
  531.                cur.x = v[0]+.5;
  532.                cur.y = v[1]+.5;
  533.             }
  534.             else
  535.             {               
  536.                longpersp(lv,lview,16);
  537.                cur.x = (lv[0]+32768L) >> 16;
  538.                cur.y = (lv[1]+32768L) >> 16;
  539.             }
  540.          }
  541.          else
  542.          {
  543.             cur.x = f_cur.x = xcenter + sintheta*sclx*r;
  544.             cur.y = f_cur.y = ycenter + costheta*cosphi*scly*r;
  545.             if(FILLTYPE >= 5)
  546.                 f_cur.color = -r*costheta*sinphi;
  547.          }
  548.       }
  549.       else /* non-sphere 3D */
  550.       {
  551.          if(floatflag)
  552.          {
  553.             /* slow float version for comparison */
  554.             v[0] = col;
  555.             v[1] = rowcount;
  556.             v[2] = f_cur.color;
  557.             vmult(v,m,v);
  558.             f_cur.x   = v[0];
  559.             f_cur.y   = v[1];
  560.             f_cur.color = v[2];
  561.             if(persp)
  562.                perspective(v);
  563.             cur.x = v[0];
  564.             cur.y = v[1];
  565.          }
  566.          else
  567.          {
  568.              if(FILLTYPE >= 5) /* flag to save vector before perspective */
  569.                 lv0[0] = 1;    /* in longvmultpersp calculation */
  570.              else
  571.                 lv0[0] = 0;
  572.              
  573.              /* use 32-bit multiply math to snap this out */
  574.              lv[0] = col;  lv[1] = rowcount;  lv[2] = f_cur.color*65536.0;
  575.              lv[0] = lv[0] << 16;  lv[1] = lv[1] << 16; /*lv[2] = lv[2] << 16;*/
  576.  
  577.              longvmultpersp(lv,lm,lv0,lv,lview,16);
  578.  
  579.              cur.x = (lv[0]+32768L) >> 16;
  580.              cur.y = (lv[1]+32768L) >> 16;
  581.     
  582.              if(FILLTYPE >= 5)
  583.              {
  584.                 f_cur.x      = lv0[0];
  585.                 f_cur.x     /= 65536.0;
  586.                 f_cur.y      = lv0[1];
  587.                 f_cur.y     /= 65536.0;
  588.                 f_cur.color  = lv0[2];
  589.                 f_cur.color /= 65536.0;
  590.              }
  591.          }
  592.       }
  593.       
  594.       switch(FILLTYPE)
  595.       {
  596.       case 0:   
  597.          (*plot)(cur.x,cur.y,cur.color);
  598.          break;
  599.       case 1:             /* connect-a-dot */
  600.          if ((old.x < xdots) && (col))
  601.             draw_line(old.x,old.y,cur.x,cur.y,cur.color); 
  602.          old.x = cur.x;
  603.          old.y = cur.y;
  604.          break;
  605.       case 2: /* with interpolation */
  606.       case 3: /* no interpolation */
  607.          /* 
  608.             "triangle fill" - consider four points: current point,
  609.             previous point same row, point opposite current point in
  610.             previous row, point after current point in previous row. 
  611.             The object is to fill all points inside the two triangles.
  612.               
  613.                            lastrow[col].x/y___ lastrow[col+1]
  614.                            /   1              /
  615.                          /     1            /
  616.                        /       1          /
  617.             oldrow/col _____ trow/col   /
  618.          */   
  619.          if(rowcount && col)    /* skip first row and first column */
  620.          {
  621.             if(col == 1)
  622.                putatriangle(lastrow[col],oldlast,old,old.color);
  623.               
  624.             if(col < xdots-1)
  625.                putatriangle(lastrow[col+1],lastrow[col],cur,cur.color);
  626.             putatriangle(old,           lastrow[col],cur,cur.color);
  627.  
  628.             /* make sure corner colors not overwritten */
  629.             (*plot)(cur.x,cur.y,cur.color);
  630.             (*plot)(old.x,old.y,old.color);
  631.             (*plot)(lastrow[col  ].x,lastrow[col  ].y,lastrow[col  ].color);
  632.             if(col < xdots-1)
  633.                (*plot)(lastrow[col+1].x,lastrow[col+1].y,lastrow[col+1].color);
  634.  
  635.          }
  636.          break;
  637.       case 4: /* "solid fill" */ 
  638.          if (SPHERE) 
  639.          {
  640.             if (persp) 
  641.             {
  642.                   old.x = xcenter>>16;
  643.                   old.y = ycenter>>16;
  644.             } else 
  645.             {
  646.                   old.x = xcenter;
  647.                   old.y = ycenter;
  648.             }
  649.          } 
  650.          else 
  651.          {
  652.             lv[0] = col;  lv[1] = rowcount;  lv[2] = 0;
  653.  
  654.             /* apply fudge bit shift for integer math */             
  655.             lv[0] = lv[0] << 16;  lv[1] = lv[1] << 16;
  656.             /* Since 0, unnecessary lv[2] = lv[2] << 16;*/
  657.  
  658.             longvmultpersp(lv,lm,lv0,lv,lview,16);
  659.  
  660.           /*  Round and fudge back to original  */
  661.             old.x = (lv[0]+32768L) >> 16;
  662.             old.y = (lv[1]+32768L) >> 16;
  663.          }
  664.          if (old.x < 0) 
  665.             old.x = 0;
  666.          if (old.x >= xdots) 
  667.             old.x = xdots-1;
  668.          if (old.y < 0) 
  669.             old.y = 0;
  670.          if (old.y >= ydots) 
  671.             old.y = ydots-1;
  672.          draw_line(old.x,old.y,cur.x,cur.y,cur.color);
  673.          break;
  674.       case 5:
  675.       case 6: 
  676.          /* light-source modulated fill */
  677.          if(rowcount && col)    /* skip first row and first column */
  678.          {  
  679.             if(f_cur.color <= f_bad.color || f_old.color <= f_bad.color ||
  680.             f_lastrow[col].color <= f_bad.color)
  681.                break;
  682.             if(FILLTYPE==5)
  683.             {
  684.                v1[0] = 1;
  685.                v1[1] = 0;
  686.                v1[2] = f_cur.color - f_old.color;
  687.     
  688.                v2[0] = 0;
  689.                v2[1] = 1;
  690.                v2[2] = f_lastrow[col].color - f_cur.color;
  691.             }
  692.             else if(FILLTYPE==6)
  693.             {
  694.                if(f_lastrow[col].color == f_bad.color)
  695.                   break;
  696.                v1[0] = f_cur.x     - f_old.x;    
  697.                v1[1] = f_cur.y     - f_old.y;    
  698.                v1[2] = f_cur.color - f_old.color;
  699.     
  700.                v2[0] = f_lastrow[col].x     - f_cur.x;
  701.                v2[1] = f_lastrow[col].y     - f_cur.y;
  702.                v2[2] = f_lastrow[col].color - f_cur.color;
  703.             } 
  704.             
  705.             cross_product (v1, v2, cross);
  706.                 
  707.             /* normalize cross - and check if non-zero */
  708.             if(normalize_vector(cross)) 
  709.                cur.color = f_cur.color = bad.color;
  710.             else
  711.             {
  712.                /* line-wise averaging scheme */
  713.                if(LIGHTAVG>0)
  714.                {
  715.                   if(crossnotinit)
  716.                   {
  717.                      /* initialize array of old normal vectors */
  718.                      crossavg[0] = cross[0];
  719.                      crossavg[1] = cross[1];
  720.                      crossavg[2] = cross[2];
  721.                      crossnotinit = 0;
  722.                   }
  723.                   tmpcross[0] = (crossavg[0]*LIGHTAVG+cross[0])/(LIGHTAVG+1);
  724.                   tmpcross[1] = (crossavg[1]*LIGHTAVG+cross[1])/(LIGHTAVG+1);
  725.                   tmpcross[2] = (crossavg[2]*LIGHTAVG+cross[2])/(LIGHTAVG+1);
  726.                      
  727.                   cross[0] = tmpcross[0];
  728.                   cross[1] = tmpcross[1];
  729.                   cross[2] = tmpcross[2];
  730.                   if(normalize_vector(cross)) 
  731.                   {
  732.                      /* this shouldn't happen */
  733.                      if(debugflag > 0)
  734.                      {
  735.                      printf("normal vector error #2\r");
  736.                      showfpoint(f_cur);
  737.                      showfpoint(f_lastrow[col]);
  738.                      showfpoint(f_lastrow[col-1]);
  739.                      getch();
  740.                      }
  741.                      cur.color = f_cur.color = colors;
  742.                   }
  743.                   crossavg[0] = tmpcross[0];
  744.                   crossavg[1] = tmpcross[1];
  745.                   crossavg[2] = tmpcross[2];
  746.                } 
  747.                /* dot product of unit vectors is cos of angle between */
  748.                /* we will use this value to shade surface */
  749.                cur.color = 1+(colors-2)*(1.0-dot_product(cross,light_direction));
  750.             }
  751.             /* if colors out of range, set them to min or max color index
  752.                but avoid background index. This makes colors "opaque" so
  753.                SOMETHING plots */             
  754.             if(cur.color < 0)                  /* prevent transparent colors */
  755.                cur.color = 1;                  /* avoid background */
  756.             if(cur.color >= colors)
  757.                cur.color = colors-1;
  758.  
  759.             /* why "col < 2"? So we have sufficient geometry for the fill
  760.                algorithm, which needs previous point in same row to have
  761.                already been calculated (variable old) */   
  762.             if(col < 2 || rowcount < 2) /* don't have valid colors yet */
  763.                break;
  764.             if(col < xdots-1)
  765.                putatriangle(lastrow[col+1],lastrow[col],cur,cur.color);
  766.             putatriangle(old,lastrow[col],cur,cur.color);
  767.  
  768.             /* make sure corner colors not overwritten */
  769.             (*plot)(cur.x,cur.y,cur.color);
  770.             (*plot)(old.x,old.y,old.color);
  771.             (*plot)(lastrow[col  ].x,lastrow[col  ].y,lastrow[col  ].color);
  772.             if(col < xdots-1)
  773.                (*plot)(lastrow[col+1].x,lastrow[col+1].y,lastrow[col+1].color);
  774.          }
  775.          break;
  776.       }  /*  End of CASE statement for fill type  */
  777.  
  778.       loopbottom:
  779.       if (FILLTYPE >= 2 && FILLTYPE != 4)
  780.       {
  781.         /* for triangle fill purposes */
  782.         oldlast = lastrow[col];
  783.         old = lastrow[col] = cur;
  784.         
  785.         if(FILLTYPE >= 5)
  786.         {        
  787.            /* for illumination model purposes */
  788.            f_old = f_lastrow[col] = f_cur;
  789.         }
  790.       }
  791.       col++;
  792.    }  /*  End of while statement for plotting line  */
  793.  
  794.     /*  Done with the row (line). Now, increment rowcount and see if
  795.             you are  done with image  */
  796.    reallythebottom:
  797.    if(++rowcount >= ydots)
  798.    {
  799.       /* end of image mopup stuff */
  800.       /* done - make sure pot file is closed */
  801.       if(fp_pot)
  802.       {
  803.          fclose(fp_pot);
  804.          fp_pot = NULL;
  805.       }
  806.       if(preview && !SPHERE)
  807.       {
  808.          /* draw box to help visualize effect of rotations */
  809.          /* 1 means show box - xmin etc. do nothing here */
  810.          corners(m,1,&xmin,&ymin,&zmin,&xmax,&ymax,&zmax);
  811.       }
  812.       
  813.       /* reset floatflag */
  814.       floatflag &= 1; /* strip second bit */
  815.    }
  816.    /* stuff that HAS to be done, even in preview mode, goes here */
  817.    if(SPHERE)
  818.    {
  819.       /* incremental sin/cos phi calc */
  820.       if(rowcount == 1)
  821.       {
  822.          sinphi = oldsinphi2;
  823.          cosphi = oldcosphi2;
  824.       }else
  825.       {
  826.          sinphi = twocosdeltaphi*oldsinphi2 - oldsinphi1;
  827.          cosphi = twocosdeltaphi*oldcosphi2 - oldcosphi1;
  828.          oldsinphi1 = oldsinphi2;
  829.          oldsinphi2 = sinphi;
  830.          oldcosphi1 = oldcosphi2;
  831.          oldcosphi2 = cosphi;
  832.       }
  833.    }     
  834.    return(0); /* decoder needs to know all is well !!! */
  835. }
  836.  
  837. /* Bresenham's algorithm for drawing line */
  838. void draw_line (int X1, int Y1, int X2, int Y2, int color)
  839. {                                 /* uses Bresenham algorithm to draw a line */
  840.   int dX, dY;                                           /* vector components */
  841.   int row, col,
  842.       final,                                   /* final row or column number */
  843.       G,                               /* used to test for new row or column */
  844.       inc1,                 /* G increment when row or column doesn't change */
  845.       inc2;                        /* G increment when row or column changes */
  846.   char pos_slope;
  847.   extern int xdots,ydots;
  848.   extern int (*plot)();    
  849.  
  850.   dX = X2 - X1;                                    /* find vector components */
  851.   dY = Y2 - Y1;
  852.   pos_slope = (dX > 0);                                /* is slope positive? */
  853.   if (dY < 0)
  854.     pos_slope = !pos_slope;
  855.   if (abs (dX) > abs (dY))                              /* shallow line case */
  856.   {
  857.     if (dX > 0)                     /* determine start point and last column */
  858.     {
  859.       col = X1;
  860.       row = Y1;
  861.       final = X2;
  862.     }
  863.     else
  864.     {
  865.       col = X2;
  866.       row = Y2;
  867.       final = X1;
  868.     }
  869.     inc1 = 2 * abs (dY);               /* determine increments and initial G */
  870.     G = inc1 - abs (dX);
  871.     inc2 = 2 * (abs (dY) - abs (dX));
  872.     if (pos_slope)
  873.       while (col <= final)      /* step through columns checking for new row */
  874.       {
  875.         (*plot) (col, row, color);
  876.         col++;
  877.         if (G >= 0)                              /* it's time to change rows */
  878.         {
  879.           row++;             /* positive slope so increment through the rows */
  880.           G += inc2;
  881.         }
  882.         else                                         /* stay at the same row */
  883.           G += inc1;
  884.       }
  885.     else
  886.       while (col <= final)      /* step through columns checking for new row */
  887.       {
  888.         (*plot) (col, row, color);
  889.         col++;
  890.         if (G > 0)                               /* it's time to change rows */
  891.         {
  892.           row--;             /* negative slope so decrement through the rows */
  893.           G += inc2;
  894.         }
  895.         else                                         /* stay at the same row */
  896.           G += inc1;
  897.       }
  898.   }  /* if |dX| > |dY| */
  899.   else                                                    /* steep line case */
  900.   {
  901.     if (dY > 0)                        /* determine start point and last row */
  902.     {
  903.       col = X1;
  904.       row = Y1;
  905.       final = Y2;
  906.     }
  907.     else
  908.     {
  909.       col = X2;
  910.       row = Y2;
  911.       final = Y1;
  912.     }
  913.     inc1 = 2 * abs (dX);               /* determine increments and initial G */
  914.     G = inc1 - abs (dY);
  915.     inc2 = 2 * (abs (dX) - abs (dY));
  916.     if (pos_slope)
  917.       while (row <= final)      /* step through rows checking for new column */
  918.       {
  919.         (*plot) (col, row, color);
  920.         row++;
  921.         if (G >= 0)                           /* it's time to change columns */
  922.         {
  923.           col++;          /* positive slope so increment through the columns */
  924.           G += inc2;
  925.         }
  926.         else                                      /* stay at the same column */
  927.           G += inc1;
  928.       }
  929.     else
  930.       while (row <= final)      /* step through rows checking for new column */
  931.       {
  932.         (*plot) (col, row, color);
  933.         row++;
  934.         if (G > 0)                            /* it's time to change columns */
  935.         {
  936.           col--;          /* negative slope so decrement through the columns */
  937.           G += inc2;
  938.         }
  939.         else                                      /* stay at the same column */
  940.           G += inc1;
  941.       }
  942.   }
  943. }  /* draw_line */
  944.  
  945.  
  946. /* vector version of line draw */
  947. void vdraw_line(v1,v2,color)
  948. double *v1,*v2;
  949. int color;
  950. {
  951.    int x1,y1,x2,y2;
  952.    x1 = (int)v1[0];
  953.    y1 = (int)v1[1];
  954.    x2 = (int)v2[0];
  955.    y2 = (int)v2[1];
  956.    draw_line(x1,y1,x2,y2,color);
  957. }
  958.  
  959. /* 
  960.    This bizarre function has two purposes. The main purpose is to determine
  961.    the extreme values of a transformed box containing a fractal for
  962.    centering purposes. As a side effect it can also plot the transformed
  963.    box as an aid in setting reasonable rotation parameters 
  964. */
  965. corners(m,show,pxmin,pymin,pzmin,pxmax,pymax,pzmax)
  966. MATRIX m;
  967. int show; /* turns on box-showing feature */
  968. double *pxmin,*pymin,*pzmin,*pxmax,*pymax,*pzmax;
  969. {
  970.    extern int xdots,ydots,colors;
  971.    VECTOR b1,b2,b3,b4,t1,t2,t3,t4;
  972.    
  973.    *pxmin = *pymin = *pzmin = INT_MAX;
  974.    *pxmax = *pymax = *pzmax = INT_MIN;
  975.  
  976.    /* define corners of box fractal is in in x,y,z plane */
  977.    /* "b" stands for "bottom" - these points are the corners of the screen
  978.        in the x-y plane. The "t"'s stand for Top - they are the top of
  979.        the cube where 255 color points hit. */   
  980.    b1[0] = 0;
  981.    b1[1] = 0;
  982.    b1[2] = 0;
  983.  
  984.    b2[0] = xdots-1;
  985.    b2[1] = 0;
  986.    b2[2] = 0;
  987.  
  988.    b3[0] = xdots-1;
  989.    b3[1] = ydots-1;
  990.    b3[2] = 0;
  991.  
  992.    b4[0] = 0;
  993.    b4[1] = ydots-1;
  994.    b4[2] = 0;
  995.  
  996.    t1[0] = 0;
  997.    t1[1] = 0;
  998.    t1[2] = colors-1;
  999.  
  1000.    t2[0] = xdots-1;
  1001.    t2[1] = 0;
  1002.    t2[2] = colors-1;
  1003.  
  1004.    t3[0] = xdots-1;
  1005.    t3[1] = ydots-1;
  1006.    t3[2] = colors-1;
  1007.  
  1008.    t4[0] = 0;
  1009.    t4[1] = ydots-1;
  1010.    t4[2] = colors-1;
  1011.  
  1012.    /* transform points */
  1013.    vmult(b1,m,b1);   
  1014.    vmult(b2,m,b2);   
  1015.    vmult(b3,m,b3);   
  1016.    vmult(b4,m,b4);   
  1017.                       
  1018.    vmult(t1,m,t1);   
  1019.    vmult(t2,m,t2);   
  1020.    vmult(t3,m,t3);   
  1021.    vmult(t4,m,t4);
  1022.    
  1023.    /* find minimum x */
  1024.    if(b1[0] <= *pxmin) *pxmin = b1[0];
  1025.    if(b2[0] <= *pxmin) *pxmin = b2[0];
  1026.    if(b3[0] <= *pxmin) *pxmin = b3[0];
  1027.    if(b4[0] <= *pxmin) *pxmin = b4[0];
  1028.  
  1029.    if(t1[0] <= *pxmin) *pxmin = t1[0];
  1030.    if(t2[0] <= *pxmin) *pxmin = t2[0];
  1031.    if(t3[0] <= *pxmin) *pxmin = t3[0];
  1032.    if(t4[0] <= *pxmin) *pxmin = t4[0];
  1033.  
  1034.    /* find minimum y */
  1035.    if(b1[1] <= *pymin) *pymin = b1[1];
  1036.    if(b2[1] <= *pymin) *pymin = b2[1];
  1037.    if(b3[1] <= *pymin) *pymin = b3[1];
  1038.    if(b4[1] <= *pymin) *pymin = b4[1];
  1039.  
  1040.    if(t1[1] <= *pymin) *pymin = t1[1];
  1041.    if(t2[1] <= *pymin) *pymin = t2[1];
  1042.    if(t3[1] <= *pymin) *pymin = t3[1];
  1043.    if(t4[1] <= *pymin) *pymin = t4[1];
  1044.  
  1045.    /* find minimum z */
  1046.    if(b1[2] <= *pzmin) *pzmin = b1[2];
  1047.    if(b2[2] <= *pzmin) *pzmin = b2[2];
  1048.    if(b3[2] <= *pzmin) *pzmin = b3[2];
  1049.    if(b4[2] <= *pzmin) *pzmin = b4[2];
  1050.  
  1051.    if(t1[2] <= *pzmin) *pzmin = t1[2];
  1052.    if(t2[2] <= *pzmin) *pzmin = t2[2];
  1053.    if(t3[2] <= *pzmin) *pzmin = t3[2];
  1054.    if(t4[2] <= *pzmin) *pzmin = t4[2];
  1055.  
  1056.    /* find maximum x */
  1057.    if(b1[0] >= *pxmax) *pxmax = b1[0];
  1058.    if(b2[0] >= *pxmax) *pxmax = b2[0];
  1059.    if(b3[0] >= *pxmax) *pxmax = b3[0];
  1060.    if(b4[0] >= *pxmax) *pxmax = b4[0];
  1061.  
  1062.    if(t1[0] >= *pxmax) *pxmax = t1[0];
  1063.    if(t2[0] >= *pxmax) *pxmax = t2[0];
  1064.    if(t3[0] >= *pxmax) *pxmax = t3[0];
  1065.    if(t4[0] >= *pxmax) *pxmax = t4[0];
  1066.  
  1067.    /* find maximum y */
  1068.    if(b1[1] >= *pymax) *pymax = b1[1];
  1069.    if(b2[1] >= *pymax) *pymax = b2[1];
  1070.    if(b3[1] >= *pymax) *pymax = b3[1];
  1071.    if(b4[1] >= *pymax) *pymax = b4[1];
  1072.  
  1073.    if(t1[1] >= *pymax) *pymax = t1[1];
  1074.    if(t2[1] >= *pymax) *pymax = t2[1];
  1075.    if(t3[1] >= *pymax) *pymax = t3[1];
  1076.    if(t4[1] >= *pymax) *pymax = t4[1];
  1077.  
  1078.    /* find maximum z */
  1079.    if(b1[2] >= *pzmax) *pzmax = b1[2];
  1080.    if(b2[2] >= *pzmax) *pzmax = b2[2];
  1081.    if(b3[2] >= *pzmax) *pzmax = b3[2];
  1082.    if(b4[2] >= *pzmax) *pzmax = b4[2];
  1083.  
  1084.    if(t1[2] >= *pzmax) *pzmax = t1[2];
  1085.    if(t2[2] >= *pzmax) *pzmax = t2[2];
  1086.    if(t3[2] >= *pzmax) *pzmax = t3[2];
  1087.    if(t4[2] >= *pzmax) *pzmax = t4[2];
  1088.  
  1089.    if(show)
  1090.    {
  1091.       if(persp)
  1092.       {
  1093.          /* bottom */
  1094.          perspective(b1); 
  1095.          perspective(b2); 
  1096.          perspective(b3); 
  1097.          perspective(b4); 
  1098.                           
  1099.          perspective(t1); 
  1100.          perspective(t2); 
  1101.          perspective(t3); 
  1102.          perspective(t4);
  1103.       } 
  1104.       /* draw box connecting transformed points. NOTE COLORS */   
  1105.    
  1106.       /* bottom */
  1107.       vdraw_line (b1,b2,2);
  1108.       vdraw_line (b2,b3,2);
  1109.       vdraw_line (b3,b4,2);
  1110.       vdraw_line (b4,b1,2);
  1111.       
  1112.       /* top */
  1113.       vdraw_line (t1,t2,3);
  1114.       vdraw_line (t2,t3,3);
  1115.       vdraw_line (t3,t4,3);
  1116.       vdraw_line (t4,t1,3);
  1117.       
  1118.       /* sides */
  1119.       vdraw_line (b1,t1,4); /* these pixels written first - want in BACK */
  1120.       vdraw_line (b2,t2,5);
  1121.       vdraw_line (b3,t3,6); /* these pixels written last - want in FRONT */
  1122.       vdraw_line (b4,t4,7);
  1123.    }
  1124. }
  1125.  
  1126. /* replacement for plot - builds a table of min and max x's instead of plot */
  1127. /* called by draw_line as part of triangle fill routine */
  1128. int putminmax(int x,int y,int color)
  1129. {
  1130.     if(y < 0 || y >= ydots) return(-1); 
  1131.     if(x < minmax_x[y].minx) minmax_x[y].minx = x;
  1132.     if(x > minmax_x[y].maxx) minmax_x[y].maxx = x;
  1133.     return(0);
  1134. }
  1135.  
  1136. /* 
  1137.    This routine fills in a triangle. Extreme left and right values for
  1138.    each row are calculated by calling the line function for the sides.
  1139.    Then rows are filled in with horizontal lines 
  1140. */
  1141. #define MAXOFFSCREEN  2 /* allow two of three points to be off screen */
  1142. putatriangle(pt1,pt2,pt3,color)
  1143. struct point pt1,pt2,pt3;
  1144. int color;
  1145. {
  1146.    extern struct point p1,p2,p3;
  1147.    int miny,maxy,minx,maxx;
  1148.    int y;
  1149.  
  1150.    p1 = pt1;
  1151.    p2 = pt2;
  1152.    p3 = pt3;
  1153.  
  1154.    /* are these all good points? */
  1155.    if(-abs(p1.x) <= bad_value) return(-1);   
  1156.    if(-abs(p1.y) <= bad_value) return(-1);   
  1157.    if(-abs(p2.x) <= bad_value) return(-1);   
  1158.    if(-abs(p2.y) <= bad_value) return(-1);   
  1159.    if(-abs(p3.x) <= bad_value) return(-1);   
  1160.    if(-abs(p3.y) <= bad_value) return(-1);   
  1161.  
  1162.    /* Too many points off the screen? */
  1163.    if(offscreen(&p1) + offscreen(&p2) + offscreen(&p3) > MAXOFFSCREEN)
  1164.       return(-1);
  1165.       
  1166.    /* bail out if points are equal */
  1167.    if (pt1.x == pt2.x)
  1168.       if (pt2.x == pt3.x)
  1169.          if (pt1.y == pt2.y)
  1170.             if (pt2.y == pt3.y)
  1171.                 return(-1);
  1172.  
  1173.  
  1174.     
  1175.    /* find min max y */
  1176.    miny = INT_MAX;
  1177.    maxy = INT_MIN;
  1178.    if(p1.y < miny) miny = p1.y;
  1179.    if(p2.y < miny) miny = p2.y;
  1180.    if(p3.y < miny) miny = p3.y;
  1181.    
  1182.    if(p1.y > maxy) maxy = p1.y;
  1183.    if(p2.y > maxy) maxy = p2.y;
  1184.    if(p3.y > maxy) maxy = p3.y;
  1185.  
  1186.    if(maxy < 0 || miny >= ydots) /* bail out if totally off screen */
  1187.       return(-1);   
  1188.  
  1189.    if(maxy - miny <= 1)
  1190.    {
  1191.       /* find min max x */
  1192.       minx = INT_MAX;
  1193.       maxx = INT_MIN;
  1194.       if(p1.x < minx) minx = p1.x;
  1195.       if(p2.x < minx) minx = p2.x;
  1196.       if(p3.x < minx) minx = p3.x;
  1197.       
  1198.       if(p1.x > maxx) maxx = p1.x;
  1199.       if(p2.x > maxx) maxx = p2.x;
  1200.       if(p3.x > maxx) maxx = p3.x;
  1201.       if(maxx - minx <= 1) /* bail out if too close together */
  1202.          return(-1);
  1203.       if(maxx < 0 || minx >= xdots) /* bail out if totally off screen */
  1204.          return(-1);   
  1205.    }
  1206.    
  1207.    /* only worried about values on screen */
  1208.    miny = max(0,miny);
  1209.    maxy = min(ydots-1,maxy);
  1210.    
  1211.    for(y=miny;y<=maxy;y++)
  1212.    {
  1213.       minmax_x[y].minx = INT_MAX;
  1214.       minmax_x[y].maxx = INT_MIN;
  1215.    }      
  1216.  
  1217.    /* set plot to "fake" plot function */
  1218.    plot = putminmax;
  1219.  
  1220.    /* build table of extreme x's of triangle */
  1221.    draw_line(p1.x,p1.y,p2.x,p2.y,0);
  1222.    draw_line(p2.x,p2.y,p3.x,p3.y,0);
  1223.    draw_line(p3.x,p3.y,p1.x,p1.y,0);
  1224.  
  1225.    plot = fillplot;
  1226.    for(y=miny;y<=maxy;y++)
  1227.       draw_line(minmax_x[y].minx,y,minmax_x[y].maxx,y,color);
  1228.    plot = normalplot;
  1229.  
  1230.    return(0); /* zero means ok */
  1231. }
  1232.  
  1233. offscreen(struct point *pt)
  1234. {
  1235.    if(pt->x >= 0)
  1236.       if(pt->x < xdots)
  1237.         if(pt->y >= 0)
  1238.           if(pt->y < ydots)
  1239.              return(0); /* point is ok */
  1240.    return(1); /* point is off the screen */          
  1241. }
  1242.  
  1243. clipcolor(x,y,color)
  1244. {
  1245.    if(0 <= x    && x < xdots   && 
  1246.       0 <= y    && y < ydots   && 
  1247.       0 <= color && color < colors)
  1248.    {   
  1249.       putcolor(x,y,color);
  1250.       return(0);
  1251.    } 
  1252.    else   
  1253.       return(-1);
  1254. }
  1255.  
  1256. T_clipcolor(x,y,color)
  1257. /*    This function is the same as clipcolor but checks for color being
  1258.     in transparent range. Intended to be called only if transparency
  1259.     has been enabled. - MRR
  1260. */
  1261.  
  1262. {
  1263.    if(0 <= x    && x < xdots         && /*  is the point on screen?  */ 
  1264.       0 <= y    && y < ydots         && /*  Yes?  */
  1265.       0 <= color && color < colors   && /*  Colors in valid range?  */
  1266.       /*  Lets make sure its not a transparent color  */
  1267.       (transparent[0] > color || color > transparent[1]))
  1268.    {   
  1269.       putcolor(x,y,color); /* I guess we can plot then  */
  1270.       return(0);  /*  Done  */
  1271.    } 
  1272.    else   
  1273.       return(-1);  /*  Sorry, can't plot that  */
  1274. }
  1275.  
  1276. /* A substitute for plotcolor that interpolates the colors according
  1277.    to the x and y values of three points (p1,p2,p3) which are static in
  1278.    this routine */
  1279.  
  1280. int interpcolor(x,y,color)
  1281. {
  1282.    int d1,d2,d3;
  1283.  
  1284.    /* this distance formula is not the usual one - put it has the virtue
  1285.       that it uses ONLY additions (almost) and it DOES go to zero as the
  1286.       points get close. */
  1287.  
  1288.    d1 = abs(p1.x-x)+abs(p1.y-y);
  1289.    d2 = abs(p2.x-x)+abs(p2.y-y);
  1290.    d3 = abs(p3.x-x)+abs(p3.y-y);
  1291.       
  1292.    /* calculate a weighted average of colors */   
  1293.    color = ((d2+d3)*p1.color + (d1+d3)*p2.color + (d1+d2)*p3.color)
  1294.              /(d2+d3+d1+d3+d1+d2);
  1295.    if(0 <= x    && x < xdots   && 
  1296.       0 <= y    && y < ydots   && 
  1297.       0 <= color && color < colors)
  1298.    {
  1299.       putcolor(x,y,color);
  1300.       return(0);
  1301.    } 
  1302.    else   
  1303.       return(-1);
  1304. }
  1305.  
  1306. int T_interpcolor(x,y,color)
  1307.  
  1308. /* A substitute for interpcolor that interpolates the colors according
  1309.    to the x and y values of three points (p1,p2,p3) which are static in
  1310.    this routine AND additionally checks for transparent colors - MRR  */
  1311.  
  1312. {
  1313.    int d1,d2,d3;
  1314.  
  1315.    /* this distance formula is not the usual one - put it has the virtue
  1316.       that it uses ONLY additions (almost) and it DOES go to zero as the
  1317.       points get close. */
  1318.  
  1319.    d1 = abs(p1.x-x)+abs(p1.y-y);
  1320.    d2 = abs(p2.x-x)+abs(p2.y-y);
  1321.    d3 = abs(p3.x-x)+abs(p3.y-y);
  1322.       
  1323.    /* calculate a weighted average of colors */   
  1324.    color = ((d2+d3)*p1.color + (d1+d3)*p2.color + (d1+d2)*p3.color)
  1325.              /(d2+d3+d1+d3+d1+d2);
  1326.  
  1327. /*  Checking for on-screen x,y might be moved to top of routine if
  1328.     it would speed things significantly for values of perspective <100  */
  1329.  
  1330.    if(0 <= x    && x < xdots         && /*  is the point on screen?  */ 
  1331.       0 <= y    && y < ydots         && /*  Yes?  */
  1332.       0 <= color && color < colors   && /*  Colors in valid range?  */
  1333.       /*  Lets make sure its not a transparent color  */
  1334.       (transparent[0] > color || color > transparent[1]))
  1335.    {   
  1336.       putcolor(x,y,color); /* I guess we can plot then  */
  1337.       return(0);  /*  Done  */
  1338.    } 
  1339.    else   
  1340.       return(-1);  /*  Sorry, can't plot that  */
  1341. }
  1342.  
  1343. int set_pixel_buff(unsigned char *pixels,float far *fpixels,unsigned linelen)
  1344. {
  1345.    unsigned int *intbuf;
  1346.    int i;
  1347.    extern int filetype;
  1348.    switch(filetype)
  1349.    {
  1350.    case 2:       /* TARGA type 10 (RGB 16 bit) */
  1351.    case 1:       /* TIW 16 bit */
  1352.       intbuf = (unsigned int *)pixels;
  1353.       for(i=0;i<linelen;i++)
  1354.          pixels[i] = fpixels[i] = ((float)intbuf[i])/(1<<8);
  1355.       break;
  1356.    case 0:       /* GIF 8 bit */
  1357.       for(i=0;i<linelen;i++)
  1358.          *(fpixels+i) = *(pixels+i);
  1359.       break;
  1360.    default:
  1361.       return(-1);
  1362.       break; 
  1363.    }
  1364.    return(0);
  1365. }
  1366.  
  1367.  
  1368. showfpoint(struct f_point pt)
  1369. {
  1370.    printf("%f %f %f\n",pt.x,pt.y,pt.color);
  1371. }
  1372.  
  1373. /* cross product  - useful because cross is perpendicular to v and w */
  1374. int chk_cross_product (int col, int row,VECTOR v, VECTOR w, VECTOR cross, VECTOR crossavg)
  1375. {
  1376.    static start = 1;
  1377.    static FILE *fp;
  1378.  
  1379.    if(start)
  1380.    {
  1381.       fp = fopen("blob","w");
  1382.       start = 0;
  1383.    }
  1384.  
  1385.    fprintf(fp,"row %+4d col %+4d v1 %+8.3e %+8.3e %+8.3e v2 %+8.3e %+8.3e %+8.3e cross %+8.3e %+8.3e %+8.3e crossavg %+8.3e %+8.3e %+8.3e \n",
  1386.         row,col,v[0],v[1],v[2],w[0],w[1],w[2],cross[0],cross[1],cross[2],crossavg[0],crossavg[1],crossavg[2]);
  1387.    return(0);
  1388. }
  1389.