home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / windows / winsrc.zip / LINE3D.C < prev    next >
Text File  |  1990-12-10  |  57KB  |  1,979 lines

  1. /* This file contains a 3D replacement for the out_line function called
  2.    by the decoder. The purpose is to apply various 3D transformations before
  3.    displaying points. Called once per line of the input file.
  4.  
  5.    This module is linked as an overlay, use ENTER_OVLY and EXIT_OVLY.
  6.  
  7.    Original Author Tim Wegner, with extensive help from Marc Reinig.
  8. */
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <limits.h>
  13. #include <dos.h>
  14. #include "fractint.h"
  15.  
  16. /* routines in this module    */
  17.  
  18. void line3d_overlay(void);
  19. int  line3d();
  20.  
  21. static void vdraw_line(double *,double *,int);
  22. static int  putminmax();
  23. static int  clipcolor(int,int,int);
  24. /* static int  clipcolor2(int,int,int); */
  25. static int  interpcolor(int,int,int);
  26. static int  T_clipcolor(int,int,int);
  27. static int  T_interpcolor(int,int,int);
  28. static void corners(),draw_light_box(),showfpoint();
  29. static int  putatriangle(),offscreen(),H_R(),R_H();
  30. static int  Open_T_24(),startdisk1(),set_pixel_buff();
  31.  
  32. static    int line_length1;
  33. static    int T_header_24 = 18; /* Size of current Targa-24 header */
  34. extern    unsigned char dacbox[256][3];
  35. static    FILE *File_Ptr1 = NULL;
  36. int Ambient;
  37. static unsigned int IAmbient;
  38. int RANDOMIZE;
  39. static int rand_factor;
  40. int haze;
  41. static int HAZE_MULT;
  42. int full_color;
  43. char light_name[80];
  44. extern    char overwrite;     /* overwrite flag on/off */
  45. unsigned char back_color[3];
  46. static unsigned char Real_Color;
  47. extern int dotmode; /* video access method, 11 if really disk video */
  48. extern int calc_status;
  49. extern long calctime;
  50.  
  51. static int (*fillplot)();
  52. static int (*normalplot)();
  53. int (*standardplot)();
  54.  
  55. char preview = 0;
  56. char showbox = 0;
  57. static int localpreviewfactor;
  58. int previewfactor = 20;
  59. int xadjust = 0;
  60. int yadjust = 0;
  61. int xxadjust;
  62. int yyadjust;
  63. int xshift;
  64. int yshift;
  65. extern int overflow;
  66. extern int filetype;
  67. extern char floatflag;
  68. extern int (*plot)();
  69. extern int xdots, ydots, colors, sxoffs, syoffs;
  70. extern int debugflag;
  71. extern void draw_line (int X1, int Y1, int X2, int Y2, int color);
  72. extern int extraseg;
  73. extern unsigned height;
  74. extern int rowcount;        /* in general.asm */
  75. extern int init3d[];            /* 3D arguments (FRACTINT.C) */
  76. extern long far *lx0;
  77. extern int transparent[2];        /* transparency min/max */
  78. extern int pot16bit;
  79. extern int filecolors;
  80.  
  81. static int zcoord = 256;
  82. static double aspect;           /* aspect ratio */
  83. static int evenoddrow;
  84.  
  85. static float far *sinthetaarray;    /* all sine   thetas go here  */
  86. static float far *costhetaarray;    /* all cosine thetas go here */
  87.  
  88. static double rXrscale;        /* precalculation factor */
  89.  
  90. static int persp;    /* flag for indicating perspective transformations */
  91. int bad_value = -10000; /* set bad values to this */
  92. int bad_check = -1000;    /* check values against this to determine if good */
  93.  
  94. /* this array remembers the previous line */
  95. struct point
  96. {
  97.    int x;
  98.    int y;
  99.    int color;
  100. } far *lastrow;
  101.  
  102. static struct point p1,p2,p3;
  103.  
  104. struct f_point
  105. {
  106.    float x;
  107.    float y;
  108.    float color;
  109. } far *f_lastrow;
  110.  
  111. /* array of min and max x values used in triangle fill */
  112. struct minmax
  113. {
  114.     int minx;
  115.     int maxx;
  116. } far *minmax_x;
  117.  
  118. VECTOR view;    /* position of observer for perspective */
  119. VECTOR cross;
  120. VECTOR tmpcross;
  121.  
  122. void line3d_overlay() { }    /* for restore_active_ovly */
  123.  
  124. int line3d(unsigned char pixels[], unsigned linelen)
  125. {
  126.  
  127. static FILE *out1;
  128. static int numsaves1=0;
  129. char File_Name[12];
  130. int RND;
  131. char openfile[80], lightfiletype[10];
  132.  
  133.    /* these values come from FRACTINT.C */
  134.  
  135.    /* These variables must preserve their values across calls */
  136.    static float   deltaphi;  /* increment of latitude, longitude */
  137.    static float phi;
  138.    static double rscale;          /* surface roughness factor */
  139.    static long xcenter,ycenter;       /* circle center */
  140.    static double sclx,scly,sclz;      /* scale factors */
  141.    static double R;              /* radius values */
  142.    static double Rfactor;          /* for intermediate calculation */
  143.    static MATRIX m;              /* transformation matrix */
  144.    static MATRIX lightm;          /* m w/no trans, keeps obj. on screen */
  145.  
  146.  
  147.    static LMATRIX lm;              /* "" */
  148.    static LVECTOR lview;              /* for perspective views */
  149.    static double zcutoff;          /* perspective backside cutoff value */
  150.    static float twocosdeltaphi;
  151.    static float cosphi,sinphi;            /* precalculated sin/cos of longitude */
  152.    static float oldcosphi1,oldsinphi1;
  153.    static float oldcosphi2,oldsinphi2;
  154.    double r;                  /* sphere radius */
  155.    double xval,yval,zval;          /* rotation values */
  156.    float costheta,sintheta;         /* precalculated sin/cos of latitude */
  157.    float twocosdeltatheta;
  158.  
  159.    int col;                  /* current column (original GIF) */
  160.    struct point cur;              /* current pixels */
  161.    struct point old;              /* old pixels */
  162.    struct point oldlast;          /* old pixels */
  163.  
  164.    static struct point bad;          /* out of range value */
  165.  
  166.    struct f_point f_cur;
  167.    struct f_point f_old;
  168.    static struct f_point f_bad;       /* out of range value */
  169.  
  170.    static float far *fpixels;          /* float persion of pixels array */
  171.  
  172.    VECTOR v;                  /* double vector */
  173.    VECTOR v1,v2;
  174.    VECTOR crossavg;
  175.    char crossnotinit;              /* flag for crossavg init indication */
  176.  
  177.    static VECTOR light_direction;
  178.    double v_length;
  179.    VECTOR origin, direct;
  180.    LVECTOR lv;                      /* long equivalent of v */
  181.    LVECTOR lv0;                   /* long equivalent of v */
  182.    int color;                  /* current decoded color */
  183.    /* corners of transformed xdotx by ydots x colors box */
  184.    double xmin, ymin, zmin, xmax, ymax, zmax;
  185.    int i,j;
  186.    int lastdot;
  187.    int rownum;
  188.  
  189.    ENTER_OVLY(OVLY_LINE3D);
  190.  
  191.    if(transparent[0] || transparent[1])
  192.       plot = normalplot = T_clipcolor;    /*  Use the transparent plot function */
  193.    else /* if(colors >= 16) */
  194.       plot = normalplot = clipcolor;    /* the usual FRACTINT plot function with clipping */
  195. /* else
  196.       plot = normalplot = clipcolor2; */
  197.  
  198.    rownum = rowcount;
  199.    if (pot16bit)
  200.       rownum >>= 1;
  201.  
  202.    /*
  203.       This IF clause is executed ONCE per image. All precalculations are
  204.       done here, with out any special concern about speed. DANGER -
  205.       communication with the rest of the program is generally via static
  206.       or global variables.
  207.    */
  208.    if(rowcount++ == 0)
  209.    {
  210.  
  211.  
  212.       long check_extra;
  213.       float theta,theta1,theta2;    /* current,start,stop latitude */
  214.       float phi1,phi2;            /* current start,stop longitude */
  215.       float   deltatheta;        /* increment of latitude */
  216.       /* plot_setup();*/
  217.       /* lastrow stores the previous row of the original GIF image for
  218.      the purpose of filling in gaps with triangle procedure */
  219.  
  220.     calctime = evenoddrow = 0;
  221.     calc_status = 1; /* mark as in-progress, and enable <tab> timer display */
  222.     if (dotmode == 11)
  223.        dvid_status(1,"...mapping to 3d...");
  224.  
  225. /* MRR */
  226.     IAmbient = (unsigned int) (255 * (float)(100 - Ambient) / 100.0);
  227.     if (IAmbient < 1)    IAmbient = 1;
  228.  
  229.     if (full_color && FILLTYPE >= 5)
  230.     {
  231.     restart:
  232.  
  233.     strcpy(openfile,light_name);              /*  Work with copy  */
  234.     strcpy(lightfiletype,".tga");          /*  Assume ext. is ".tga"  */
  235.     for (i = 0; i < strlen(openfile); i++)    /*  See if they supplied  */
  236.         if (openfile[i] == '.')                     /*  an extension  */
  237.         {                            /*  Yes!  */
  238.         strcpy(lightfiletype,&openfile[i]);      /*  Capture it  */
  239.         openfile[i] = 0;    /*    Del. the ext. from the filename   */
  240.         }
  241.     if ((++numsaves1 > 1))            /*    Already saved this file?  */
  242.     {   /*    Yes!  */
  243.         updatesavename(openfile);           /*  Make new filename  */
  244.         strncpy(light_name, openfile, strlen(openfile));
  245.     }
  246.     strcat(openfile,lightfiletype);     /*  Add .xxx to filename  */
  247.                            /*  Does file name exist?  */
  248.     if ((overwrite==0) && (out1=fopen(openfile,"r")) != NULL)
  249.     {   /*    Oops!  */
  250.         fclose(out1);
  251.         goto restart;
  252.     }
  253.     fclose(out1);
  254.     strcpy (light_name,openfile);
  255.     startdisk1(light_name);
  256.     }
  257. /* MRR end */
  258.  
  259.     rand_factor = 14 - RANDOMIZE;
  260.  
  261.  /* if(colors<16)
  262.        zcoord = 256;
  263.     else
  264.        zcoord = colors; */
  265.     zcoord = filecolors;
  266.  
  267.     crossavg[0] = 0;
  268.     crossavg[1] = 0;
  269.     crossavg[2] = 0;
  270.  
  271.       /*********************************************************************
  272.        Memory allocation - assumptions - a 64K segment starting at extraseg
  273.        has been grabbed. It may have other purposes elsewhere, but it is
  274.        assumed that it is totally free for use here. Our strategy is to
  275.        assign all the far pointers needed here to various spots in the extra
  276.        segment, depending on the pixel dimensions of the video mode, and
  277.        check whether we have run out. There is basically one case where the
  278.        extra segment is not big enough - SPHERE mode with a fill type that
  279.        uses putatriangle() (array minmax_x) at the largest legal resolution
  280.        of 2048x2048 or thereabouts. In that case we use farmemalloc to grab
  281.        memory for minmax_x. This memory is never freed.
  282.       *******************************************************************/
  283.  
  284.       if(extraseg)
  285.       {
  286. #ifdef __TURBOC__
  287.      lastrow = MK_FP(extraseg,0);
  288. #else
  289.      FP_SEG(lastrow)=extraseg;
  290.      FP_OFF(lastrow)=0;
  291. #endif
  292.       }else {
  293.      EXIT_OVLY;
  294.      return(-1);
  295.      }
  296.  
  297.       check_extra = sizeof(*lastrow)*xdots;
  298.       if(SPHERE)
  299.       {
  300.      sinthetaarray = (float far *)(lastrow+xdots);
  301.      check_extra += sizeof(*sinthetaarray)*xdots;
  302.  
  303.      costhetaarray = (float far *)(sinthetaarray+xdots);
  304.      check_extra += sizeof(*costhetaarray)*xdots;
  305.  
  306.      f_lastrow = (struct f_point far *)(costhetaarray+xdots);
  307.       }
  308.       else
  309.      f_lastrow = (struct f_point far *)(lastrow+xdots);
  310.       check_extra += sizeof(*f_lastrow)*(xdots);
  311.  
  312.       fpixels = (float far *)(f_lastrow+xdots);
  313.       check_extra += sizeof(*fpixels)*xdots;
  314.  
  315.       minmax_x = (struct minmax *)NULL;
  316.  
  317.       /* these fill types call putatriangle which uses minmax_x */
  318.       if( FILLTYPE == 2 || FILLTYPE == 3 || FILLTYPE == 5 || FILLTYPE == 6)
  319.       {
  320.      /* end of arrays if we use extra segement */
  321.      check_extra += sizeof(struct minmax)*ydots;
  322.      if(check_extra > 1L<<16) /* run out of extra segment? */
  323.      {
  324.         static struct minmax far *got_mem = NULL;
  325.         /* not using extra segment so decrement check_extra */
  326.         check_extra -= sizeof(struct minmax)*ydots;
  327.         if(got_mem == NULL)
  328.            got_mem = (struct minmax far *)(farmemalloc(2048L*sizeof(struct minmax)));
  329.         if(got_mem)
  330.            minmax_x = got_mem;
  331.         else
  332.         {
  333.            EXIT_OVLY;
  334.            return(-1);
  335.         }
  336.      }
  337.      else /* ok to use extra segment */
  338.         minmax_x = (struct minmax far *)(fpixels+xdots);
  339.       }
  340.       if(debugflag == 2222 || check_extra > 1L<<16)
  341.      {
  342.      char tmpmsg[70];
  343.      sprintf(tmpmsg,"used %ld of extra segment",check_extra);
  344.      stopmsg(4,tmpmsg);
  345.      }
  346.       /* get scale factors */
  347.       sclx =   XSCALE/100.0;
  348.       scly =   YSCALE/100.0;
  349.       sclz = - ROUGH/100.0;
  350.  
  351.       /* aspect ratio calculation - assume screen is 4 x 3 */
  352.       aspect = (double)xdots*.75/(double)ydots;
  353.  
  354.       if(SPHERE==FALSE)  /* skip this slow stuff in sphere case */
  355.       {
  356.      /*
  357.         What is done here is to create a single matrix, m, which has
  358.         scale, rotation, and shift all combined. This allows us to use
  359.         a single matrix to transform any point. Additionally, we create
  360.         two perspective vectors.
  361.  
  362.         Start with a unit matrix. Add scale and rotation. Then calculate
  363.         the perspective vectors. Finally add enough translation to center
  364.         the final image plus whatever shift the user has set.
  365.      */
  366.  
  367.      /* start with identity */
  368.      identity (m);
  369.      identity (lightm);
  370.  
  371.      /* translate so origin is in center of box, so that when we rotate
  372.         it, we do so through the center */
  373.      trans ( (double)xdots/(-2.0),(double)ydots/(-2.0),
  374.          (double)zcoord/(-2.0),m);
  375.      trans ( (double)xdots/(-2.0),(double)ydots/(-2.0),
  376.          (double)zcoord/(-2.0),lightm);
  377.  
  378.      /* apply scale factors */
  379.      scale(sclx,scly,sclz,m);
  380.      scale(sclx,scly,sclz,lightm);
  381.  
  382.      /* rotation values - converting from degrees to radians */
  383.      xval = XROT / 57.29577;
  384.      yval = YROT / 57.29577;
  385.      zval = ZROT / 57.29577;
  386.  
  387.      xrot (xval,m);     xrot (xval,lightm);
  388.      yrot (yval,m);     yrot (yval,lightm);
  389.      zrot (zval,m);     zrot (zval,lightm);
  390.  
  391.  
  392.      /* Find values of translation that make all x,y,z negative */
  393.      /* m current matrix */
  394.      /* 0 means don't show box */
  395.      /* returns minimum and maximum values of x,y,z in fractal */
  396.      corners(m,0,&xmin,&ymin,&zmin,&xmax,&ymax,&zmax);
  397.       }
  398.  
  399.       /* perspective 3D vector - lview[2] == 0 means no perspective */
  400.  
  401.       /* set perspective flag */
  402.       persp = 0;
  403.       if (ZVIEWER != 0)
  404.       {
  405.      persp = 1;
  406.      if(ZVIEWER < 80) /* force float */
  407.          floatflag |= 2; /* turn on second bit */
  408.       }
  409.  
  410.       /* set up view vector, and put viewer in center of screen */
  411.       lview[0] = xdots >> 1;
  412.       lview[1] = ydots >> 1;
  413.  
  414.       /* z value of user's eye - should be more negative than extreme
  415.      negative part of image */
  416.       if(SPHERE) /* sphere case */
  417.      lview[2] = -(long)((double)ydots*(double)ZVIEWER/100.0);
  418.       else        /* non-sphere case */
  419.      lview[2] = (long)((zmin-zmax)*(double)ZVIEWER/100.0);
  420.  
  421.       view[0] = lview[0];  view[1] = lview[1]; view[2] = lview[2];
  422.       lview[0] = lview[0] << 16;
  423.       lview[1] = lview[1] << 16;
  424.       lview[2] = lview[2] << 16;
  425.  
  426.       if(SPHERE==FALSE) /* sphere skips this */
  427.       {
  428.      /* translate back exactly amount we translated earlier plus enough
  429.         to center image so maximum values are non-positive */
  430.      trans(((double)xdots-xmax-xmin)/2,((double)ydots-ymax-ymin)/2,-zmax,m);
  431.  
  432.     /* Keep the box centered and on screen regardless of shifts */
  433.      trans(((double)xdots-xmax-xmin)/2,((double)ydots-ymax-ymin)/2,
  434.         -zmax,lightm);
  435.  
  436.      trans((double)(xshift),(double)(-yshift),0.0,m);
  437.  
  438.      /* matrix m now contains ALL those transforms composed together !!!! */
  439.      /* convert m to long integers shifted 16 bits */
  440.      for (i = 0; i < 4; i++)
  441.      for (j = 0; j < 4; j++)
  442.             lm[i][j] = m[i][j] * 65536.0;
  443.  
  444.       }
  445.       else /* sphere stuff goes here */
  446.       {
  447.      float z;
  448.      /* Sphere is on side - north pole on right. Top is -90 degrees
  449.         latitude; bottom 90 degrees */
  450.  
  451.      /* Map X to this LATITUDE range */
  452.      theta1 = THETA1*PI/180.0;
  453.      theta2 = THETA2*PI/180.0;
  454.  
  455.      /* Map Y to this LONGITUDE range */
  456.      phi1    = PHI1*PI/180.0;
  457.      phi2    = PHI2*PI/180.0;
  458.  
  459.      theta = theta1;
  460.      phi   = phi1;
  461.  
  462.      /*
  463.         Thanks to Hugh Bray for the following idea: when calculating
  464.         a table of evenly spaced sines or cosines, only a few initial
  465.         values need be calculated, and the remaining values can be
  466.         gotten from a derivative of the sine/cosine angle sum formula
  467.         at the cost of one multiplication and one addition per value!
  468.  
  469.         This idea is applied once here to get a complete table for
  470.         latitude, and near the bottom of this routine to incrementally
  471.         calculate longitude.
  472.  
  473.         Precalculate 2*cos(deltaangle), sin(start) and sin(start+delta).
  474.         Then apply recursively:
  475.           sin(angle+2*delta) = sin(angle+delta) * 2cosdelta - sin(angle)
  476.  
  477.         Similarly for cosine. Neat!
  478.       */
  479.  
  480.      deltatheta = (float)(theta2 - theta1)/(float)linelen;
  481.  
  482.      /* initial sin,cos theta */
  483.      sinthetaarray[0] = sin((double)theta);
  484.      costhetaarray[0] = cos((double)theta);
  485.      sinthetaarray[1] = sin((double)(theta + deltatheta));
  486.      costhetaarray[1] = cos((double)(theta + deltatheta));
  487.  
  488.      /* sin,cos delta theta */
  489.      twocosdeltatheta = 2.0*cos((double)deltatheta);
  490.  
  491.      /* build table of other sin,cos with trig identity */
  492.      for(i=2;i<linelen;i++)
  493.      {
  494.         sinthetaarray[i] = sinthetaarray[i-1]*twocosdeltatheta-
  495.                    sinthetaarray[i-2];
  496.         costhetaarray[i] = costhetaarray[i-1]*twocosdeltatheta-
  497.                    costhetaarray[i-2];
  498.      }
  499.  
  500.      /* now phi - these calculated as we go - get started here */
  501.      deltaphi   = (float)(phi2   - phi1  )/(float)height;
  502.  
  503.      /* initial sin,cos phi */
  504.  
  505.      sinphi = oldsinphi1 = sin((double)phi1);
  506.      cosphi = oldcosphi1 = cos((double)phi1);
  507.      oldsinphi2 = sin((double)(phi1+deltaphi));
  508.      oldcosphi2 = cos((double)(phi1+deltaphi));
  509.  
  510.      /* sin,cos delta phi */
  511.      twocosdeltaphi = 2*cos((double)deltaphi);
  512.  
  513.      xcenter = xdots/2 + xshift;
  514.      ycenter = ydots/2 - yshift;
  515.  
  516.      /* affects how rough planet terrain is */
  517.      rscale= .3*ROUGH/100.0;
  518.  
  519.      /* radius of planet */
  520.      R = (double)(ydots)/2;
  521.  
  522.      /* precalculate factor */
  523.      rXrscale = R*rscale;
  524.  
  525.      sclx = scly = RADIUS/100.0;
  526.  
  527.      /* adjust x scale factor for aspect */
  528.      sclx *= aspect;
  529.  
  530.      /* precalculation factor used in sphere calc */
  531.      Rfactor = rscale*R/(double)zcoord;
  532.  
  533.      if(persp) /* precalculate fudge factor */
  534.      {
  535.         double radius;
  536.         double zview;
  537.         double angle;
  538.  
  539.         xcenter     = xcenter << 16;
  540.         ycenter     = ycenter << 16;
  541.  
  542.         Rfactor *= 65536.0;
  543.         R        *= 65536.0;
  544.  
  545.         /* calculate z cutoff factor */
  546.         /* attempt to prevent out-of-view surfaces from being written */
  547.         zview = -(long)((double)ydots*(double)ZVIEWER/100.0);
  548.         radius = (double)(ydots)/2;
  549.         angle = atan(-radius/(zview+radius));
  550.         zcutoff = -radius - sin(angle)*radius;
  551.         zcutoff *= 1.1; /* for safety */
  552.         zcutoff *= 65536;
  553.      }
  554.       }
  555.       /* set fill plot function */
  556.       if(FILLTYPE != 3)
  557.       {
  558.      fillplot = interpcolor;
  559.      if(transparent[0] || transparent[1]) /*  If transparent colors are set */
  560.         fillplot = T_interpcolor;  /*  Use the transparent plot function  */
  561.       }
  562.       else
  563.       {
  564.      fillplot = clipcolor;
  565.  
  566.      if(transparent[0] || transparent[1]) /*  If transparent colors are set */
  567.         fillplot = T_clipcolor;  /*  Use the transparent plot function  */
  568.       }
  569.  
  570.  
  571.       /* Both Sphere and Normal 3D */
  572.       direct[0] = light_direction[0] = XLIGHT;
  573.       direct[1] = light_direction[1] = -YLIGHT;
  574.       direct[2] = light_direction[2] = ZLIGHT;
  575.  
  576.     /* Needed because sclz = -ROUGH/100 and light_direction is transformed
  577.        in FILLTYPE 6 but not in 5.
  578.     */
  579.       if (FILLTYPE == 5 && !SPHERE)
  580.      direct[2] = light_direction[2] = -ZLIGHT;
  581.       else {
  582.  
  583.       /*
  584.     Needed to keep light_source in SPHERE consistent with planar
  585.     but don't know exactly why this is needed, but it is. I hate that!
  586.       */
  587.        if (SPHERE)
  588.        {
  589.         light_direction[0] = -XLIGHT;
  590.         direct[2] = -ZLIGHT;
  591.     }
  592.     }
  593.  
  594.       if(FILLTYPE==6) /* transform light direction */
  595.       {
  596.      /* Think of light direction  as a vector with tail at (0,0,0) and
  597.         head at (light_direction). We apply the transformation to
  598.         BOTH head and tail and take the difference */
  599.  
  600.      v[0] = 0.0;
  601.      v[1] = 0.0;
  602.      v[2] = 0.0;
  603.      vmult(v,m,v);
  604.      vmult(light_direction,m,light_direction);
  605.      light_direction[0] -= v[0];
  606.      light_direction[1] -= v[1];
  607.      light_direction[2] -= v[2];
  608.       }
  609.       normalize_vector(light_direction);
  610.  
  611.     if(preview && FILLTYPE >= 5 && showbox)
  612.     {
  613.         normalize_vector(direct);
  614.  
  615.         /* Set origin[] to be the center of the untransformed xy plane at z=0 */
  616.         /* and torigin[] to be the same */
  617.         origin[0] = (double)(xdots)/2.0;
  618.         origin[1] = (double)(ydots)/2.0;
  619.         origin[2] = 0.0;
  620.  
  621.         /*    Set length of light direction vector to be convienient for viewing */
  622.         v_length = min ((xdots/2.0), min ((ydots/2.0), (float)(zcoord)));
  623.  
  624.         /* Set direct[] to point from origin[] in direction of untransformed
  625.         light_direction (direct[]). */
  626.  
  627.         direct[0] = origin[0] + direct[0] * v_length;
  628.         direct[1] = origin[1] + direct[1] * v_length;
  629.         direct[2] = origin[2] + direct[2] * v_length;
  630.  
  631.         /* Draw light source vector and box containing it, draw_light_box
  632.         will transform them if necessary. */
  633.         draw_light_box (origin,direct,lightm);
  634.         /* draw box around original field of view to help visualize effect of rotations */
  635.         /* 1 means show box - xmin etc. do nothing here */
  636.         corners(m,1,&xmin,&ymin,&zmin,&xmax,&ymax,&zmax);
  637.     }
  638.  
  639.       /* bad has values caught by clipping */
  640.       f_bad.x      = bad.x     = bad_value;
  641.       f_bad.y      = bad.y     = bad_value;
  642.       f_bad.color = bad.color = bad_value;
  643.       for(i=0;i<linelen;i++)
  644.       {
  645.      lastrow[i]   = bad;
  646.      f_lastrow[i] = f_bad;
  647.       }
  648.    } /* end of once-per-image intializations */
  649.    crossnotinit = 1;
  650.    col = 0;
  651.  
  652.    /* make sure these pixel coordinates are out of range */
  653.    old     = bad;
  654.    f_old = f_bad;
  655.  
  656.    /* copies pixels buffer to float type fpixels buffer for fill purposes */
  657.    if (set_pixel_buff(pixels,fpixels,linelen))
  658.    {
  659.       EXIT_OVLY;
  660.       return(0);
  661.    }
  662.  
  663.    /*
  664.    This section of code allows the operation of a preview mode when the
  665.    preview flag is set. Enabled, it allows the drawing of only the first
  666.    line of the source image, then every 10th line, until and including the
  667.    last line. For the undrawn lines, only necessary calculations are
  668.    made. As a bonus, in non-sphere mode a box is drawn to help visualize
  669.    the effects of 3D transformations. Thanks to Marc Reinig for this idea
  670.    and code -- BTW, Marc did NOT put the goto in, but WE did, to avoid
  671.    copying code here, and to avoid a HUGE "if-then" construct. Besides,
  672.    we have ALREADY sinned, so why not sin some more? */
  673.  
  674.    localpreviewfactor = ydots/previewfactor;
  675.  
  676.    /* Insure last line is drawn in preview and filltype -1  */
  677.    if ((preview || FILLTYPE == -1) && (rownum != ydots-1))
  678.       if (rownum % localpreviewfactor)
  679.      if ( !(((FILLTYPE == 5) || (FILLTYPE == 6)) && (rownum == 1)))
  680.         goto reallythebottom; /* skip over most of the line3d calcs */
  681.    lastdot = min(xdots-1, linelen-1);
  682.  
  683.    /* PROCESS ROW LOOP BEGINS HERE */
  684.    while(col < linelen)
  685.    {
  686.  
  687.     if (FILLTYPE >= 5)
  688.     if (haze != 0 && full_color)
  689.     {
  690. /* MRR */
  691.         HAZE_MULT = haze * (
  692.         (float)((long)(ydots - 1 - rownum) *
  693.         (long)(ydots - 1 - rownum)) /
  694.         (float)((long)(ydots - 1) * (long)(ydots - 1)));
  695.         HAZE_MULT = 100 - HAZE_MULT;
  696.     }
  697. /* MRR end */
  698.  
  699.       if (FILLTYPE == -1)
  700.       {
  701.      if (col != lastdot) /* if this is not the last col */
  702.         if (col % localpreviewfactor) /* if not the 1st or mod factor col*/
  703.            goto loopbottom;
  704.       }
  705.  
  706.       cur.color   = pixels[col];
  707.       f_cur.color = fpixels[col];
  708.       if (cur.color > 0 && cur.color < WATERLINE)
  709.       f_cur.color = cur.color = WATERLINE;    /* "lake" */
  710.  
  711.       if(SPHERE) /* sphere case */
  712.       {
  713.      sintheta = sinthetaarray[col];
  714.      costheta = costhetaarray[col];
  715.  
  716.      /* if naked use of goto's offend you don't read next two lines! */
  717.      if(sinphi < 0)
  718.      {
  719.         cur   = bad;
  720.         f_cur = f_bad;
  721.         goto loopbottom;   /* another goto ! */
  722.      }
  723.  
  724.      /* KEEP THIS FOR DOCS - original formula --
  725.      if(rscale < 0.0)
  726.         r = 1.0+((double)cur.color/(double)zcoord)*rscale;
  727.      else
  728.         r = 1.0-rscale+((double)cur.color/(double)zcoord)*rscale;
  729.      R = (double)ydots/2;
  730.      r = r*R;
  731.      cur.x = xdots/2 + sclx*r*sintheta*aspect + xup ;
  732.      cur.y = ydots/2 + scly*r*costheta*cosphi - yup ;
  733.      */
  734.  
  735.      if(rscale < 0.0)
  736.         r = R + Rfactor*(double)f_cur.color*costheta;
  737.      else if(rscale > 0.0)
  738.         r = R -rXrscale + Rfactor*(double)f_cur.color*costheta;
  739.      else
  740.         r = R;
  741.      if(persp)
  742.      {
  743.         /* NOTE: fudge was pre-calculated above in r and R */
  744.         lv[2] = -R - r*costheta*sinphi; /* (almost) guarantee negative */
  745.         if(lv[2] > zcutoff)
  746.         {
  747.            cur = bad;
  748.            f_cur = f_bad;
  749.            goto loopbottom;   /* another goto ! */
  750.         }
  751.         lv[0] = xcenter + sintheta*sclx*r;        /* x */
  752.         lv[1] = ycenter + costheta*cosphi*scly*r;    /* y */
  753.  
  754.         if(FILLTYPE >= 5) /* calculate illumination normal before persp */
  755.         {
  756.            double r0;
  757.            int xcenter0,ycenter0;
  758.  
  759.            r0    = r/65536;
  760.            xcenter0 =  xcenter >> 16;
  761.            ycenter0 =  xcenter >> 16;
  762.  
  763.            f_cur.x       = xcenter0 + sintheta*sclx*r0;
  764.            f_cur.y       = ycenter0 + costheta*cosphi*scly*r0;
  765.            f_cur.color = -r0*costheta*sinphi;
  766.         }
  767.         if(!floatflag)
  768.         {
  769.            if(longpersp(lv,lview,16) == -1)
  770.            {
  771.           cur = bad;
  772.           f_cur = f_bad;
  773.           goto loopbottom;   /* another goto ! */
  774.            }
  775.            cur.x = ((lv[0]+32768L) >> 16) + xxadjust;
  776.            cur.y = ((lv[1]+32768L) >> 16) + yyadjust;
  777.         }
  778.         if(floatflag||overflow)
  779.         {
  780.            VECTOR v;
  781.            long fudge;
  782.            fudge = 1L<<16;
  783.            v[0] = lv[0];
  784.            v[1] = lv[1];
  785.            v[2] = lv[2];
  786.            v[0] /= fudge;
  787.            v[1] /= fudge;
  788.            v[2] /= fudge;
  789.            perspective(v);
  790.            cur.x = v[0]+.5 + xxadjust;
  791.            cur.y = v[1]+.5 + yyadjust;
  792.         }
  793.      }
  794.      else
  795.      {
  796.         cur.x = f_cur.x = xcenter + sintheta*sclx*r + xxadjust;
  797.         cur.y = f_cur.y = ycenter + costheta*cosphi*scly*r + yyadjust;
  798.         if(FILLTYPE >= 5)
  799.         f_cur.color = -r*costheta*sinphi;
  800.      }
  801.       }
  802.       else /* non-sphere 3D */
  803.       {
  804.      if(!floatflag)
  805.      {
  806.          if(FILLTYPE >= 5) /* flag to save vector before perspective */
  807.         lv0[0] = 1;    /* in longvmultpersp calculation */
  808.          else
  809.         lv0[0] = 0;
  810.  
  811.          /* use 32-bit multiply math to snap this out */
  812.          lv[0] = col;    lv[0] = lv[0] << 16;
  813.          lv[1] = rownum; lv[1] = lv[1] << 16;
  814.          if(filetype || pot16bit) /* don't truncate fractional part */
  815.          lv[2] = f_cur.color*65536.0;
  816.          else      /* there IS no fractaional part here! */
  817.          {
  818.         lv[2] = f_cur.color;
  819.         lv[2] = lv[2] << 16;
  820.          }
  821.  
  822.          if(longvmultpersp(lv,lm,lv0,lv,lview,16) == -1)
  823.          {
  824.         cur   = bad;
  825.         f_cur = f_bad;
  826.         goto loopbottom;
  827.          }
  828.  
  829.          cur.x = ((lv[0]+32768L) >> 16) + xxadjust;
  830.          cur.y = ((lv[1]+32768L) >> 16) + yyadjust;
  831.          if(FILLTYPE >= 5)
  832.          {
  833.         f_cur.x      = lv0[0];
  834.         f_cur.x     /= 65536.0;
  835.         f_cur.y      = lv0[1];
  836.         f_cur.y     /= 65536.0;
  837.         f_cur.color  = lv0[2];
  838.         f_cur.color /= 65536.0;
  839.          }
  840.      }
  841.      if(floatflag||overflow) /* do in float if integer math overflowed */
  842.      {
  843.         /* slow float version for comparison */
  844.         v[0] = col;
  845.         v[1] = rownum;
  846.         v[2] = f_cur.color;
  847.         vmult(v,m,v);
  848.         f_cur.x   = v[0];
  849.         f_cur.y   = v[1];
  850.         f_cur.color = v[2];
  851.         if(persp)
  852.            perspective(v);
  853.         cur.x = v[0] + xxadjust + .5;
  854.         cur.y = v[1] + yyadjust + .5;
  855.      }
  856.       }
  857. if (RANDOMIZE)
  858. if (cur.color > WATERLINE)
  859. {
  860.     RND = rand() >> 8;     /* 7-bit number */
  861.     RND = RND * RND >> rand_factor;  /* n-bit number */
  862.     if (rand() & 1) RND = -RND; /* Make +/- n-bit number */
  863.     if ((int)(cur.color) + RND >= colors) cur.color = colors-2;
  864.     else
  865.     if ((int)(cur.color) + RND <= WATERLINE) cur.color = WATERLINE + 1;
  866.     else
  867.         pixels[col] = cur.color = cur.color + RND;
  868. }
  869.  
  870.       switch(FILLTYPE)
  871.       {
  872.       case -1:
  873.     if (col &&
  874.         old.x > bad_check &&
  875.         old.x < (xdots - bad_check))
  876.         draw_line (old.x, old.y, cur.x, cur.y, cur.color);
  877.     if (rownum &&
  878.         lastrow[col].x > bad_check &&
  879.         lastrow[col].y > bad_check &&
  880.         lastrow[col].x < (xdots - bad_check) &&
  881.         lastrow[col].y < (ydots - bad_check))
  882.         draw_line (lastrow[col].x,lastrow[col].y,cur.x, cur.y,cur.color);
  883.     break;
  884.  
  885.        case 0:
  886.      (*plot)(cur.x,cur.y,cur.color);
  887.      break;
  888.  
  889.        case 1:           /* connect-a-dot */
  890.      if ((old.x < xdots) && (col) &&
  891.         old.x > bad_check &&
  892.         old.y > bad_check) /* Don't draw from old to cur on col 0 */
  893.         draw_line(old.x,old.y,cur.x,cur.y,cur.color);
  894.      old.x = cur.x;
  895.      old.y = cur.y;
  896.      break;
  897.  
  898.       case 2: /* with interpolation */
  899.       case 3: /* no interpolation */
  900.      /*
  901.         "triangle fill" - consider four points: current point,
  902.         previous point same row, point opposite current point in
  903.         previous row, point after current point in previous row.
  904.         The object is to fill all points inside the two triangles.
  905.  
  906.                lastrow[col].x/y___ lastrow[col+1]
  907.                /   1          /
  908.              /     1        /
  909.                /       1      /
  910.         oldrow/col _____ trow/col    /
  911.      */
  912.      if(rownum && col)    /* skip first row and first column */
  913.      {
  914.         if(col == 1)
  915.            putatriangle(lastrow[col],oldlast,old,old.color);
  916.  
  917.         if(col < lastdot)
  918.            putatriangle(lastrow[col+1],lastrow[col],cur,cur.color);
  919.         putatriangle(old,        lastrow[col],cur,cur.color);
  920.  
  921.         /* make sure corner colors not overwritten */
  922.         (*plot)(cur.x,cur.y,cur.color);
  923.         (*plot)(old.x,old.y,old.color);
  924.         (*plot)(lastrow[col  ].x,lastrow[col  ].y,lastrow[col  ].color);
  925.         if(col < lastdot)
  926.            (*plot)(lastrow[col+1].x,lastrow[col+1].y,lastrow[col+1].color);
  927.  
  928.      }
  929.      break;
  930.  
  931.       case 4: /* "solid fill" */
  932.      if (SPHERE)
  933.      {
  934.         if (persp)
  935.         {
  936.           old.x = xcenter>>16;
  937.           old.y = ycenter>>16;
  938.         } else
  939.         {
  940.           old.x = xcenter;
  941.           old.y = ycenter;
  942.         }
  943.      }
  944.      else
  945.      {
  946.         lv[0] = col;  lv[1] = rownum;  lv[2] = 0;
  947.  
  948.         /* apply fudge bit shift for integer math */
  949.         lv[0] = lv[0] << 16;  lv[1] = lv[1] << 16;
  950.         /* Since 0, unnecessary lv[2] = lv[2] << 16;*/
  951.  
  952.         if(longvmultpersp(lv,lm,lv0,lv,lview,16))
  953.         {
  954.            cur   = bad;
  955.            f_cur = f_bad;
  956.            goto loopbottom;   /* another goto ! */
  957.         }
  958.  
  959.         /*    Round and fudge back to original  */
  960.         old.x = (lv[0]+32768L) >> 16;
  961.         old.y = (lv[1]+32768L) >> 16;
  962.      }
  963.      if (old.x < 0)
  964.         old.x = 0;
  965.      if (old.x >= xdots)
  966.         old.x = xdots-1;
  967.      if (old.y < 0)
  968.         old.y = 0;
  969.      if (old.y >= ydots)
  970.         old.y = ydots-1;
  971.      draw_line(old.x,old.y,cur.x,cur.y,cur.color);
  972.      break;
  973.  
  974.       case 5:
  975.       case 6:
  976.      /* light-source modulated fill */
  977.      if(rownum && col)    /* skip first row and first column */
  978.      {
  979.         if(f_cur.color < bad_check || f_old.color < bad_check ||
  980.         f_lastrow[col].color < bad_check)
  981.            break;
  982.         if(FILLTYPE==5)
  983.         {
  984.            v1[0] = 1;
  985.            v1[1] = 0;
  986.            v1[2] = f_cur.color - f_old.color;
  987.  
  988.            v2[0] = 0;
  989.            v2[1] = 1;
  990.            v2[2] = f_lastrow[col].color - f_cur.color;
  991.         }
  992.         else if(FILLTYPE==6)
  993.         {
  994.            if(f_lastrow[col].color < bad_check)
  995.           break;
  996.            v1[0] = f_cur.x       - f_old.x;
  997.            v1[1] = f_cur.y       - f_old.y;
  998.            v1[2] = f_cur.color - f_old.color;
  999.  
  1000.            v2[0] = f_lastrow[col].x     - f_cur.x;
  1001.            v2[1] = f_lastrow[col].y     - f_cur.y;
  1002.            v2[2] = f_lastrow[col].color - f_cur.color;
  1003.         }
  1004.  
  1005.         cross_product (v1, v2, cross);
  1006.  
  1007.         /* normalize cross - and check if non-zero */
  1008.         if(normalize_vector(cross))
  1009.         {
  1010.            if(debugflag)
  1011.           printf("cur.color = bad.color!\n");
  1012.            cur.color = f_cur.color = bad.color;
  1013.         }
  1014.         else
  1015.         {
  1016.            /* line-wise averaging scheme */
  1017.            if(LIGHTAVG>0)
  1018.            {
  1019.           if(crossnotinit)
  1020.           {
  1021.              /* initialize array of old normal vectors */
  1022.              crossavg[0] = cross[0];
  1023.              crossavg[1] = cross[1];
  1024.              crossavg[2] = cross[2];
  1025.              crossnotinit = 0;
  1026.           }
  1027.           tmpcross[0] = (crossavg[0]*LIGHTAVG+cross[0])/(LIGHTAVG+1);
  1028.           tmpcross[1] = (crossavg[1]*LIGHTAVG+cross[1])/(LIGHTAVG+1);
  1029.           tmpcross[2] = (crossavg[2]*LIGHTAVG+cross[2])/(LIGHTAVG+1);
  1030.  
  1031.           cross[0] = tmpcross[0];
  1032.           cross[1] = tmpcross[1];
  1033.           cross[2] = tmpcross[2];
  1034.           if(normalize_vector(cross))
  1035.           {
  1036.              /* this shouldn't happen */
  1037.              if(debugflag)
  1038.              {
  1039.              printf("normal vector error #2\r");
  1040.              showfpoint(f_cur);
  1041.              showfpoint(f_lastrow[col]);
  1042.              showfpoint(f_lastrow[col-1]);
  1043.              getakey();
  1044.              }
  1045.              cur.color = f_cur.color = colors;
  1046.           }
  1047.           crossavg[0] = tmpcross[0];
  1048.           crossavg[1] = tmpcross[1];
  1049.           crossavg[2] = tmpcross[2];
  1050.            }
  1051.  
  1052.        /* dot product of unit vectors is cos of angle between */
  1053.            /* we will use this value to shade surface */
  1054.  
  1055.        cur.color = 1+(colors-2)*(1.0-dot_product(cross,light_direction));
  1056.         }
  1057.         /* if colors out of range, set them to min or max color index
  1058.            but avoid background index. This makes colors "opaque" so
  1059.        SOMETHING plots. These conditions shouldn't happen but just
  1060.        in case
  1061.     */
  1062.     if(cur.color < 1)       /* prevent transparent colors */
  1063.         cur.color = 1;        /* avoid background */
  1064.     if(cur.color > colors-1)
  1065.         cur.color = colors-1;
  1066.  
  1067.         /* why "col < 2"? So we have sufficient geometry for the fill
  1068.            algorithm, which needs previous point in same row to have
  1069.            already been calculated (variable old) */
  1070.         if(col < 2 || rownum < 2) /* don't have valid colors yet */
  1071.            break;
  1072.  
  1073.         Real_Color = pixels[col];
  1074.  
  1075.         if(col < lastdot)
  1076.            putatriangle(lastrow[col+1],lastrow[col],cur,cur.color);
  1077.         putatriangle(old,lastrow[col],cur,cur.color);
  1078.  
  1079.         /* make sure corner colors not overwritten */
  1080.  
  1081.         plot=standardplot;
  1082.      }
  1083.          break;
  1084.       }  /*  End of CASE statement for fill type  */
  1085.  
  1086.       loopbottom:
  1087.  
  1088.       if (FILLTYPE == -1 || (FILLTYPE >= 2 && FILLTYPE != 4))
  1089.       {
  1090.     /* for triangle and grid fill purposes */
  1091.     oldlast = lastrow[col];
  1092.     old = lastrow[col] = cur;
  1093.  
  1094.     if(FILLTYPE >= 5)
  1095.     {
  1096.        /* for illumination model purposes */
  1097.        f_old = f_lastrow[col] = f_cur;
  1098.     }
  1099.       }
  1100.       col++;
  1101.    }  /*  End of while statement for plotting line  */
  1102.  
  1103. reallythebottom:
  1104.  
  1105.    if(rownum >= ydots)
  1106.    {
  1107.  
  1108.       if (full_color && FILLTYPE >= 5)
  1109.      enddisk(); /* We done! */
  1110.  
  1111.       if(preview && !SPHERE && showbox)
  1112.       {
  1113.      /* draw box to help visualize effect of rotations */
  1114.      /* 1 means show box - xmin etc. do nothing here */
  1115.      corners(m,1,&xmin,&ymin,&zmin,&xmax,&ymax,&zmax);
  1116.       }
  1117.  
  1118.       /* reset floatflag */
  1119.       floatflag &= 1; /* strip second bit */
  1120.    }
  1121.    /* stuff that HAS to be done, even in preview mode, goes here */
  1122.    if(SPHERE)
  1123.    {
  1124.       /* incremental sin/cos phi calc */
  1125.       if(rownum == 0)
  1126.       {
  1127.      sinphi = oldsinphi2;
  1128.      cosphi = oldcosphi2;
  1129.       }else
  1130.       {
  1131.      sinphi = twocosdeltaphi*oldsinphi2 - oldsinphi1;
  1132.      cosphi = twocosdeltaphi*oldcosphi2 - oldcosphi1;
  1133.      oldsinphi1 = oldsinphi2;
  1134.      oldsinphi2 = sinphi;
  1135.          oldcosphi1 = oldcosphi2;
  1136.      oldcosphi2 = cosphi;
  1137.       }
  1138.    }
  1139.    EXIT_OVLY;
  1140.    return(0); /* decoder needs to know all is well !!! */
  1141. }
  1142.  
  1143. /* vector version of line draw */
  1144. static void vdraw_line(v1,v2,color)
  1145. double *v1,*v2;
  1146. int color;
  1147. {
  1148.    int x1,y1,x2,y2;
  1149.    x1 = (int)v1[0];
  1150.    y1 = (int)v1[1];
  1151.    x2 = (int)v2[0];
  1152.    y2 = (int)v2[1];
  1153.    draw_line(x1,y1,x2,y2,color);
  1154. }
  1155.  
  1156. /*
  1157.    This bizarre function has two purposes. The main purpose is to determine
  1158.    the extreme values of a transformed box containing a fractal for
  1159.    centering purposes. As a side effect it can also plot the transformed
  1160.    box as an aid in setting reasonable rotation parameters
  1161. */
  1162. static void corners(m,show,pxmin,pymin,pzmin,pxmax,pymax,pzmax)
  1163. MATRIX m;
  1164. int show; /* turns on box-showing feature */
  1165. double *pxmin,*pymin,*pzmin,*pxmax,*pymax,*pzmax;
  1166. {
  1167.    extern int xdots,ydots,zcoord;
  1168.    VECTOR b1,b2,b3,b4,t1,t2,t3,t4;
  1169.  
  1170.    *pxmin = *pymin = *pzmin = INT_MAX;
  1171.    *pxmax = *pymax = *pzmax = INT_MIN;
  1172.  
  1173.    /* define corners of box fractal is in in x,y,z plane */
  1174.    /* "b" stands for "bottom" - these points are the corners of the screen
  1175.        in the x-y plane. The "t"'s stand for Top - they are the top of
  1176.        the cube where 255 color points hit. */
  1177.    b1[0] = 0;
  1178.    b1[1] = 0;
  1179.    b1[2] = 0;
  1180.  
  1181.    b2[0] = xdots-1;
  1182.    b2[1] = 0;
  1183.    b2[2] = 0;
  1184.  
  1185.    b3[0] = xdots-1;
  1186.    b3[1] = ydots-1;
  1187.    b3[2] = 0;
  1188.  
  1189.    b4[0] = 0;
  1190.    b4[1] = ydots-1;
  1191.    b4[2] = 0;
  1192.  
  1193.    t1[0] = 0;
  1194.    t1[1] = 0;
  1195.    t1[2] = zcoord-1;
  1196.  
  1197.    t2[0] = xdots-1;
  1198.    t2[1] = 0;
  1199.    t2[2] = zcoord-1;
  1200.  
  1201.    t3[0] = xdots-1;
  1202.    t3[1] = ydots-1;
  1203.    t3[2] = zcoord-1;
  1204.  
  1205.    t4[0] = 0;
  1206.    t4[1] = ydots-1;
  1207.    t4[2] = zcoord-1;
  1208.  
  1209.    /* transform points */
  1210.    vmult(b1,m,b1);
  1211.    vmult(b2,m,b2);
  1212.    vmult(b3,m,b3);
  1213.    vmult(b4,m,b4);
  1214.  
  1215.    vmult(t1,m,t1);
  1216.    vmult(t2,m,t2);
  1217.    vmult(t3,m,t3);
  1218.    vmult(t4,m,t4);
  1219.  
  1220.    /* find minimum x */
  1221.    if(b1[0] <= *pxmin) *pxmin = b1[0];
  1222.    if(b2[0] <= *pxmin) *pxmin = b2[0];
  1223.    if(b3[0] <= *pxmin) *pxmin = b3[0];
  1224.    if(b4[0] <= *pxmin) *pxmin = b4[0];
  1225.  
  1226.    if(t1[0] <= *pxmin) *pxmin = t1[0];
  1227.    if(t2[0] <= *pxmin) *pxmin = t2[0];
  1228.    if(t3[0] <= *pxmin) *pxmin = t3[0];
  1229.    if(t4[0] <= *pxmin) *pxmin = t4[0];
  1230.  
  1231.    /* find minimum y */
  1232.    if(b1[1] <= *pymin) *pymin = b1[1];
  1233.    if(b2[1] <= *pymin) *pymin = b2[1];
  1234.    if(b3[1] <= *pymin) *pymin = b3[1];
  1235.    if(b4[1] <= *pymin) *pymin = b4[1];
  1236.  
  1237.    if(t1[1] <= *pymin) *pymin = t1[1];
  1238.    if(t2[1] <= *pymin) *pymin = t2[1];
  1239.    if(t3[1] <= *pymin) *pymin = t3[1];
  1240.    if(t4[1] <= *pymin) *pymin = t4[1];
  1241.  
  1242.    /* find minimum z */
  1243.    if(b1[2] <= *pzmin) *pzmin = b1[2];
  1244.    if(b2[2] <= *pzmin) *pzmin = b2[2];
  1245.    if(b3[2] <= *pzmin) *pzmin = b3[2];
  1246.    if(b4[2] <= *pzmin) *pzmin = b4[2];
  1247.  
  1248.    if(t1[2] <= *pzmin) *pzmin = t1[2];
  1249.    if(t2[2] <= *pzmin) *pzmin = t2[2];
  1250.    if(t3[2] <= *pzmin) *pzmin = t3[2];
  1251.    if(t4[2] <= *pzmin) *pzmin = t4[2];
  1252.  
  1253.    /* find maximum x */
  1254.    if(b1[0] >= *pxmax) *pxmax = b1[0];
  1255.    if(b2[0] >= *pxmax) *pxmax = b2[0];
  1256.    if(b3[0] >= *pxmax) *pxmax = b3[0];
  1257.    if(b4[0] >= *pxmax) *pxmax = b4[0];
  1258.  
  1259.    if(t1[0] >= *pxmax) *pxmax = t1[0];
  1260.    if(t2[0] >= *pxmax) *pxmax = t2[0];
  1261.    if(t3[0] >= *pxmax) *pxmax = t3[0];
  1262.    if(t4[0] >= *pxmax) *pxmax = t4[0];
  1263.  
  1264.    /* find maximum y */
  1265.    if(b1[1] >= *pymax) *pymax = b1[1];
  1266.    if(b2[1] >= *pymax) *pymax = b2[1];
  1267.    if(b3[1] >= *pymax) *pymax = b3[1];
  1268.    if(b4[1] >= *pymax) *pymax = b4[1];
  1269.  
  1270.    if(t1[1] >= *pymax) *pymax = t1[1];
  1271.    if(t2[1] >= *pymax) *pymax = t2[1];
  1272.    if(t3[1] >= *pymax) *pymax = t3[1];
  1273.    if(t4[1] >= *pymax) *pymax = t4[1];
  1274.  
  1275.    /* find maximum z */
  1276.    if(b1[2] >= *pzmax) *pzmax = b1[2];
  1277.    if(b2[2] >= *pzmax) *pzmax = b2[2];
  1278.    if(b3[2] >= *pzmax) *pzmax = b3[2];
  1279.    if(b4[2] >= *pzmax) *pzmax = b4[2];
  1280.  
  1281.    if(t1[2] >= *pzmax) *pzmax = t1[2];
  1282.    if(t2[2] >= *pzmax) *pzmax = t2[2];
  1283.    if(t3[2] >= *pzmax) *pzmax = t3[2];
  1284.    if(t4[2] >= *pzmax) *pzmax = t4[2];
  1285.  
  1286.    if(show)
  1287.    {
  1288.       if(persp)
  1289.       {
  1290.      /* bottom */
  1291.      perspective(b1);
  1292.      perspective(b2);
  1293.      perspective(b3);
  1294.      perspective(b4);
  1295.  
  1296.      perspective(t1);
  1297.      perspective(t2);
  1298.      perspective(t3);
  1299.      perspective(t4);
  1300.       }
  1301.       /* draw box connecting transformed points. NOTE COLORS */
  1302.  
  1303.       /* Keep the box surrounding the fractal */
  1304.       b1[0] = b1[0] + xxadjust;        t1[0] = t1[0] + xxadjust;
  1305.       b2[0] = b2[0] + xxadjust;        t2[0] = t2[0] + xxadjust;
  1306.       b3[0] = b3[0] + xxadjust;        t3[0] = t3[0] + xxadjust;
  1307.       b4[0] = b4[0] + xxadjust;        t4[0] = t4[0] + xxadjust;
  1308.  
  1309.       b1[1] = b1[1] + yyadjust;        t1[1] = t1[1] + yyadjust;
  1310.       b2[1] = b2[1] + yyadjust;        t2[1] = t2[1] + yyadjust;
  1311.       b3[1] = b3[1] + yyadjust;        t3[1] = t3[1] + yyadjust;
  1312.       b4[1] = b4[1] + yyadjust;        t4[1] = t4[1] + yyadjust;
  1313.  
  1314.  
  1315.       /* bottom */
  1316.       vdraw_line (b1,b2,2);
  1317.       vdraw_line (b2,b3,2);
  1318.       vdraw_line (b3,b4,2);
  1319.       vdraw_line (b4,b1,2);
  1320.  
  1321.       /* top */
  1322.       vdraw_line (t1,t2,3);
  1323.       vdraw_line (t2,t3,3);
  1324.       vdraw_line (t3,t4,3);
  1325.       vdraw_line (t4,t1,3);
  1326.  
  1327.       /* sides */
  1328.       vdraw_line (b1,t1,4); /* these pixels written first - want in BACK */
  1329.       vdraw_line (b2,t2,5);
  1330.       vdraw_line (b3,t3,6); /* these pixels written last - want in FRONT */
  1331.       vdraw_line (b4,t4,7);
  1332.    }
  1333. }
  1334.  
  1335. /* This function draws a vector from origin[] to direct[] and a box
  1336.    around it. The vector and box are transformed or not depending on
  1337.    FILLTYPE.
  1338.  
  1339.    Will consolidate this and corners if the feature is used. Also, will
  1340.    be adding hidded line capability to this and/or corners.
  1341. */
  1342.  
  1343. static void draw_light_box(origin,direct,m)
  1344.     double *origin, *direct;
  1345.     MATRIX m;
  1346.  
  1347. {
  1348.     VECTOR b1,b2,b3,b4,t1,t2,t3,t4;
  1349.     int i;
  1350.     double temp;
  1351.     /* Initialize the arrays */
  1352.     for (i=0;i<=2;i++)
  1353.     t1[i] = b1[i] = origin[i];
  1354.  
  1355.     /*     "x"                 "y"                         "z"    */
  1356.     b2[0] = b1[0];    b2[1] = direct[1];        b2[2] = b1[2];
  1357.     b3[0] = direct[0];    b3[1] = b2[1];            b3[2] = b1[2];
  1358.     b4[0] = b3[0];    b4[1] = b1[1];            b4[2] = b1[2];
  1359.  
  1360.                             t1[2] = direct[2];
  1361.     t2[0] = t1[0];    t2[1] = direct[1];        t2[2] = t1[2];
  1362.     t3[0] = direct[0];    t3[1] = t2[1];            t3[2] = t1[2];
  1363.     t4[0] = t3[0];    t4[1] = t1[1];            t4[2] = t1[2];
  1364.  
  1365.     /* transform the corners if necessary */
  1366.     if (FILLTYPE == 6)
  1367.     {
  1368.     /* Transform the coordinates */
  1369.      /* bottom */         /* top */
  1370.     vmult(b1,m,b1);        vmult(t1,m,t1);
  1371.     vmult(b2,m,b2);        vmult(t2,m,t2);
  1372.     vmult(b3,m,b3);        vmult(t3,m,t3);
  1373.     vmult(b4,m,b4);        vmult(t4,m,t4);
  1374.     }
  1375.  
  1376.     if(persp) /* Adjust for perspective if set */
  1377.     {
  1378.     perspective(b1);    perspective(t1);
  1379.     perspective(b2);    perspective(t2);
  1380.     perspective(b3);    perspective(t3);
  1381.     perspective(b4);    perspective(t4);
  1382.     }
  1383.  
  1384.     /* Adjust for aspect and shift back to origin (b1[]) */
  1385.     temp = b1[0] * aspect;
  1386.     temp = temp - b1[0];
  1387.  
  1388.     b1[0] = b1[0] * aspect - temp;  t1[0] = t1[0] * aspect - temp;
  1389.     b2[0] = b2[0] * aspect - temp;  t2[0] = t2[0] * aspect - temp;
  1390.     b3[0] = b3[0] * aspect - temp;  t3[0] = t3[0] * aspect - temp;
  1391.     b4[0] = b4[0] * aspect - temp;  t4[0] = t4[0] * aspect - temp;
  1392.  
  1393.     /* draw box connecting transformed points. NOTE COLORS */
  1394.     /* bottom */        /* top */
  1395.     vdraw_line (b1,b2,2);    vdraw_line (t1,t2,3);
  1396.     vdraw_line (b2,b3,2);    vdraw_line (t2,t3,3);
  1397.     vdraw_line (b3,b4,2);    vdraw_line (t3,t4,3);
  1398.     vdraw_line (b4,b1,2);    vdraw_line (t4,t1,3);
  1399.  
  1400.     /* sides */
  1401.     vdraw_line (b1,t1,4); /* these pixels written first - want in BACK */
  1402.     vdraw_line (b2,t2,5);
  1403.     vdraw_line (b3,t3,6); /* these pixels written last - want in FRONT */
  1404.     vdraw_line (b4,t4,7);
  1405.  
  1406.     /* draw light source vector */
  1407.     vdraw_line (b1,t3,8);
  1408. }
  1409.  
  1410. /* replacement for plot - builds a table of min and max x's instead of plot */
  1411. /* called by draw_line as part of triangle fill routine */
  1412. static int putminmax(int x,int y,int color)
  1413. {
  1414.     if(y < 0 || y >= ydots) return(-1);
  1415.     if(x < minmax_x[y].minx) minmax_x[y].minx = x;
  1416.     if(x > minmax_x[y].maxx) minmax_x[y].maxx = x;
  1417.     return(0);
  1418. }
  1419.  
  1420.  
  1421.  
  1422. /*
  1423.    This routine fills in a triangle. Extreme left and right values for
  1424.    each row are calculated by calling the line function for the sides.
  1425.    Then rows are filled in with horizontal lines
  1426. */
  1427. #define MAXOFFSCREEN  2 /* allow two of three points to be off screen */
  1428. static int putatriangle(pt1,pt2,pt3,color)
  1429. struct point pt1,pt2,pt3;
  1430. int color;
  1431. {
  1432.    extern struct point p1,p2,p3;
  1433.    int miny,maxy,minx,maxx;
  1434.    int y;
  1435.  
  1436.    p1 = pt1;
  1437.    p2 = pt2;
  1438.    p3 = pt3;
  1439.  
  1440.    /* are these all good points? */
  1441.    if(-abs(p1.x) <= bad_check) return(-1);
  1442.    if(-abs(p1.y) <= bad_check) return(-1);
  1443.    if(-abs(p2.x) <= bad_check) return(-1);
  1444.    if(-abs(p2.y) <= bad_check) return(-1);
  1445.    if(-abs(p3.x) <= bad_check) return(-1);
  1446.    if(-abs(p3.y) <= bad_check) return(-1);
  1447.  
  1448.    /* Too many points off the screen? */
  1449.    if(offscreen(&p1) + offscreen(&p2) + offscreen(&p3) > MAXOFFSCREEN)
  1450.       return(-1);
  1451.  
  1452.    /* bail out if points are equal */
  1453.    if (pt1.x == pt2.x)
  1454.       if (pt2.x == pt3.x)
  1455.      if (pt1.y == pt2.y)
  1456.         if (pt2.y == pt3.y)
  1457.         {
  1458.         plot(p3.x, p3.y, color);
  1459.         return(-1);
  1460.         }
  1461.  
  1462.    /* find min max y */
  1463.    miny = INT_MAX;
  1464.    maxy = INT_MIN;
  1465.    if(p1.y < miny) miny = p1.y;
  1466.    if(p2.y < miny) miny = p2.y;
  1467.    if(p3.y < miny) miny = p3.y;
  1468.  
  1469.    if(p1.y > maxy) maxy = p1.y;
  1470.    if(p2.y > maxy) maxy = p2.y;
  1471.    if(p3.y > maxy) maxy = p3.y;
  1472.  
  1473.    if(maxy < 0 || miny >= ydots) /* bail out if totally off screen */
  1474.       return(-1);
  1475.  
  1476.    if(maxy - miny <= 1)
  1477.    {
  1478.       /* find min max x */
  1479.       minx = INT_MAX;
  1480.       maxx = INT_MIN;
  1481.       if(p1.x < minx) minx = p1.x;
  1482.       if(p2.x < minx) minx = p2.x;
  1483.       if(p3.x < minx) minx = p3.x;
  1484.  
  1485.       if(p1.x > maxx) maxx = p1.x;
  1486.       if(p2.x > maxx) maxx = p2.x;
  1487.       if(p3.x > maxx) maxx = p3.x;
  1488.  
  1489.       if(maxx < 0 || minx >= xdots) /* bail out if totally off screen */
  1490.      return(-1);
  1491.    }
  1492.  
  1493.    /* only worried about values on screen */
  1494.    miny = max(0,miny);
  1495.    maxy = min(ydots-1,maxy);
  1496.  
  1497.    for(y=miny;y<=maxy;y++)
  1498.    {
  1499.       minmax_x[y].minx = INT_MAX;
  1500.       minmax_x[y].maxx = INT_MIN;
  1501.    }
  1502.  
  1503.    /* set plot to "fake" plot function */
  1504.    plot = putminmax;
  1505.  
  1506.    /* build table of extreme x's of triangle */
  1507.    draw_line(p1.x,p1.y,p2.x,p2.y,0);
  1508.    draw_line(p2.x,p2.y,p3.x,p3.y,0);
  1509.    draw_line(p3.x,p3.y,p1.x,p1.y,0);
  1510.  
  1511.    plot = fillplot;
  1512.    for(y=miny;y<=maxy;y++)
  1513.       draw_line(minmax_x[y].minx,y,minmax_x[y].maxx,y,color);
  1514.    plot = normalplot;
  1515.  
  1516.    return(0); /* zero means ok */
  1517. }
  1518.  
  1519.  
  1520. static int offscreen(struct point *pt)
  1521. {
  1522.    if(pt->x >= 0)
  1523.       if(pt->x < xdots)
  1524.     if(pt->y >= 0)
  1525.       if(pt->y < ydots)
  1526.          return(0); /* point is ok */
  1527.    return(1); /* point is off the screen */
  1528. }
  1529.  
  1530. static int clipcolor(int x,int y,int color)
  1531. {
  1532.    if(0 <= x    && x < xdots   &&
  1533.       0 <= y    && y < ydots   &&
  1534.       0 <= color && color < filecolors)
  1535.    {
  1536.       standardplot(x,y,color);
  1537.       return(0);
  1538.    }
  1539.    else
  1540.       return(-1);
  1541. }
  1542.  
  1543. /*
  1544. static int clipcolor2(int x,int y,int color)
  1545. {
  1546.    if(0 <= x    && x < xdots   &&
  1547.       0 <= y    && y < ydots   &&
  1548.       0 <= color)
  1549.    {
  1550.       standardplot(x,y,color&1);
  1551.       return(0);
  1552.    }
  1553.    else
  1554.       return(-1);
  1555. }
  1556. */
  1557.  
  1558. static int T_clipcolor(int x,int y,int color)
  1559. /*    This function is the same as clipcolor but checks for color being
  1560.     in transparent range. Intended to be called only if transparency
  1561.     has been enabled.
  1562. */
  1563.  
  1564.  
  1565. {
  1566.    if(0 <= x    && x < xdots         && /*  is the point on screen?  */
  1567.       0 <= y    && y < ydots         && /*  Yes?  */
  1568.       0 <= color && color < colors   && /*  Colors in valid range?  */
  1569.       /*  Lets make sure its not a transparent color  */
  1570.       (transparent[0] > color || color > transparent[1]))
  1571.    {
  1572.       standardplot(x,y,color); /* I guess we can plot then  */
  1573.       return(0);  /*  Done  */
  1574.    }
  1575.    else
  1576.       return(-1);  /*  Sorry, can't plot that  */
  1577. }
  1578.  
  1579. /* A substitute for plotcolor that interpolates the colors according
  1580.    to the x and y values of three points (p1,p2,p3) which are static in
  1581.    this routine */
  1582.  
  1583. static int interpcolor(int x,int y,int color)
  1584. {
  1585. unsigned char R1, G, B;
  1586. unsigned long H, S, V;
  1587. unsigned char RGB[3];
  1588. int D,d1,d2,d3;
  1589.  
  1590.     /* this distance formula is not the usual one - but it has the virtue
  1591.        that it uses ONLY additions (almost) and it DOES go to zero as the
  1592.        points get close. */
  1593.  
  1594.     d1 = abs(p1.x-x)+abs(p1.y-y);
  1595.     d2 = abs(p2.x-x)+abs(p2.y-y);
  1596.     d3 = abs(p3.x-x)+abs(p3.y-y);
  1597.  
  1598.     D = (d1 + d2 + d3) << 1;
  1599.     if(D)
  1600.     {    /* calculate a weighted average of colors -
  1601.         long casts prevent integer overflow */
  1602.     color = ((long)(d2+d3)*(long)p1.color +
  1603.         (long)(d1+d3)*(long)p2.color +
  1604.         (long)(d1+d2)*(long)p3.color) / D;
  1605.     }
  1606.  
  1607.     if(0 <= x     && x < xdots    &&
  1608.        0 <= y     && y < ydots    &&
  1609.        0 < color && color < colors)
  1610.  
  1611.     {
  1612.     if (full_color)
  1613.     {
  1614.         /*    Get the color triplet for the original untransformed pixel */
  1615.         RGB[0]  =  dacbox [Real_Color] [0];
  1616.         RGB[1]  =  dacbox [Real_Color] [1];
  1617.         RGB[2]  =  dacbox [Real_Color] [2];
  1618.  
  1619.     /* Now lets convert it to hsv */
  1620.         R_H(RGB[0], RGB[1], RGB[2], &H, &S, &V);
  1621.  
  1622.     /* Modify S and V components */
  1623. /* MRR */
  1624.     V = (65280 - color * IAmbient);
  1625.     if (haze)
  1626.         {
  1627.         S = (unsigned long)(S * HAZE_MULT) / 100;
  1628.         if (V >= 32640)
  1629.         {
  1630.         V = V - 32640;
  1631.         V = (unsigned long)((V * HAZE_MULT) / 100);
  1632.         V = V + 32640;
  1633.         }
  1634.         else
  1635.         {
  1636.         V = 32640 - V;
  1637.         V = (unsigned long)((V * HAZE_MULT) / 100);
  1638.         V = 32640 - V;
  1639.         }
  1640.     }
  1641.         /*    Now lets convert it back to RGB  */
  1642.         H_R(&RGB[0], &RGB[1], &RGB[2], H, S, V);
  1643. /* MRR end */
  1644.  
  1645.         /* Now write the color triple to its transformed location
  1646.         on the disk. */
  1647.         targa_writedisk (x+sxoffs, y+syoffs, RGB[0], RGB[1], RGB[2]);
  1648.     }
  1649.  
  1650.     if (FILLTYPE >= 5)      color = 1 + (color * IAmbient) / 256;
  1651.  
  1652.     standardplot(x,y,color);
  1653.     return(0);
  1654.    }
  1655.    else
  1656.     return(-1);
  1657.  
  1658. }
  1659.  
  1660. static int T_interpcolor(int x,int y,int color)
  1661.  
  1662. /* A substitute for interpcolor that interpolates the colors according
  1663.    to the x and y values of three points (p1,p2,p3) which are static in
  1664.    this routine AND additionally checks for transparent colors    */
  1665.  
  1666. {
  1667.    int d1,d2,d3;
  1668.  
  1669.    /* this distance formula is not the usual one - put it has the virtue
  1670.       that it uses ONLY additions (almost) and it DOES go to zero as the
  1671.       points get close. */
  1672.  
  1673.    d1 = abs(p1.x-x)+abs(p1.y-y);
  1674.    d2 = abs(p2.x-x)+abs(p2.y-y);
  1675.    d3 = abs(p3.x-x)+abs(p3.y-y);
  1676.  
  1677.    /* calculate a weighted average of colors -
  1678.       long casts prevent integer overflow */
  1679.    color = ((long)(d2+d3)*(long)p1.color +
  1680.         (long)(d1+d3)*(long)p2.color +
  1681.         (long)(d1+d2)*(long)p3.color) /(d2+d3+d1+d3+d1+d2);
  1682.  
  1683. /*  Checking for on-screen x,y might be moved to top of routine if
  1684.     it would speed things significantly for values of perspective <100    */
  1685.  
  1686.    if(0 <= x    && x < xdots         && /*  is the point on screen?  */
  1687.       0 <= y    && y < ydots         && /*  Yes?  */
  1688.       0 <= color && color < colors   && /*  Colors in valid range?  */
  1689.       /*  Lets make sure its not a transparent color  */
  1690.       (transparent[0] > color || color > transparent[1]))
  1691.    {
  1692.       standardplot(x,y,color); /* I guess we can plot then  */
  1693.       return(0);  /*  Done  */
  1694.    }
  1695.    else
  1696.       return(-1);  /*  Sorry, can't plot that  */
  1697. }
  1698.  
  1699. static int set_pixel_buff(unsigned char *pixels,float far *fpixels,unsigned linelen)
  1700. {
  1701.    unsigned int *intbuf;
  1702.    int i;
  1703.    if (filetype) /* obsolete (last generated in v14) .tga potfile */
  1704.    {
  1705.       intbuf = (unsigned int *)pixels;
  1706.       for(i=0;i<linelen;i++)
  1707.      pixels[i] = fpixels[i] = ((float)intbuf[i])/(1<<8);
  1708.    }
  1709.    else if (pot16bit) /* gif type, but 16 bits per pixel on alt rows */
  1710.    {
  1711.       if ((evenoddrow++ & 1) == 0) /* even rows are color value */
  1712.       {
  1713.      for(i=0;i<linelen;i++)
  1714.         *(fpixels+i) = *(pixels+i);
  1715.      return(1);
  1716.       }
  1717.       for(i=0;i<linelen;i++) /* add the fractional part in odd row */
  1718.      pixels[i] = *(fpixels+i) += ((float)*(pixels+i))/(1<<8);
  1719.    }
  1720.    else /* normal gif type file */
  1721.    {
  1722.       for(i=0;i<linelen;i++)
  1723.      *(fpixels+i) = *(pixels+i);
  1724.    }
  1725.    return(0);
  1726. }
  1727.  
  1728.  
  1729. static void showfpoint(struct f_point pt)
  1730. {
  1731.    printf("%f %f %f\n",pt.x,pt.y,pt.color);
  1732. }
  1733.  
  1734. /* cross product  - useful because cross is perpendicular to v and w */
  1735. /**** PB commented this out - it is unused
  1736. static int chk_cross_product (int col, int row,VECTOR v, VECTOR w, VECTOR cross, VECTOR crossavg)
  1737. {
  1738.    static start = 1;
  1739.    static FILE *fp;
  1740.  
  1741.    if(start)
  1742.    {
  1743.       fp = fopen("blob","w");
  1744.       start = 0;
  1745.    }
  1746.  
  1747.    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",
  1748.     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]);
  1749.    return(0);
  1750. }
  1751. ****/
  1752.  
  1753.  
  1754. static int startdisk1 (File_Name1)
  1755. char *File_Name1;
  1756.  
  1757. /**********************************************************************
  1758.  
  1759.       This function opens a TARGA_24 file for writing, writes the
  1760.       header, and verifies there is enough disk space for the file.
  1761.  
  1762.  
  1763. **********************************************************************/
  1764.  
  1765. {
  1766. int status;
  1767. char msgbuf[300];
  1768.  
  1769. if ( (status = Open_T_24 (File_Name1)) == 0 )
  1770.     return(0);
  1771.  
  1772. if (status == -1)
  1773. {
  1774.     sprintf(msgbuf,"OOPS - Couldn't Open  < %s >",File_Name1);
  1775.     stopmsg(0,msgbuf);
  1776.     return(-1);
  1777. }
  1778.  
  1779. if (status == -2)
  1780. {
  1781.     sprintf(msgbuf,"\
  1782. OOPS - Ran out of disk space.\n\
  1783. You will need a min of\n\
  1784.   < %ld bytes >\n\
  1785. of disk space to create\n\
  1786.   < %s >\n\
  1787. I will continue with screen only.",
  1788.         (3L*(long)xdots*(long)ydots)+18L, File_Name1);
  1789.     stopmsg(0,msgbuf);
  1790.     return(-1);
  1791.     }
  1792.  
  1793. /* error -3, from targa_startdisk, message already issued */
  1794. return(-1);
  1795.  
  1796. }
  1797.  
  1798.  
  1799.  
  1800. static int Open_T_24(File_Name2)
  1801. char *File_Name2;
  1802.  
  1803. /**********************************************************
  1804.  
  1805.  Open Targa 24 uncompressed file write header, verify
  1806.  there is enough disk space, and leave the file pointer
  1807.  at the start of the display data area.
  1808.  
  1809.  If there is an error close the file.
  1810.  
  1811.        return (0)   successfull
  1812.        return (-1)  Open failure
  1813.        return (-2)  Out of disk space
  1814.        return (-3)  Error in targa_startdisk (probably out of memory)
  1815.  
  1816.  **********************************************************/
  1817.  
  1818. {
  1819. int i,j;
  1820. extern xdots;
  1821. extern ydots;
  1822.  
  1823. /* Open File for both reading and writing */
  1824. if ((File_Ptr1=fopen(File_Name2,"w+b"))==NULL)
  1825.     return(-1); /* Oops, somethings wrong! */
  1826.  
  1827. else
  1828.     /* File opened successfully, now write TARGA header */
  1829.     for (i = 0; i < 12; i++)
  1830.     {
  1831.     if (i == 2)
  1832.         putc(i,File_Ptr1);
  1833.     else
  1834.         putc(0,File_Ptr1);
  1835.     }
  1836.  
  1837. /*  Write image size  */
  1838. putc((unsigned char)(xdots &  0xff),File_Ptr1);
  1839. putc((unsigned char)(xdots >> 8),   File_Ptr1);
  1840. putc((unsigned char)(ydots &  0xff),File_Ptr1);
  1841. putc((unsigned char)(ydots >> 8),   File_Ptr1);
  1842.  
  1843. /*  Write  TARGA 24 ID    */
  1844. putc(24,File_Ptr1);
  1845. putc(32,File_Ptr1);
  1846.  
  1847. /*  Finished with the header, now lets work on the display area  */
  1848.  
  1849. line_length1 = 3 * xdots;    /*  length of a line @ 3 bytes per pixel  */
  1850. for (i = 0; i < ydots; i++)    /* "clear the screen" (write to the disk) */
  1851.     for (j = 0; j < line_length1; j=j+3)    /*    clear the line to some color  */
  1852.     {
  1853.     putc(back_color[2], File_Ptr1);     /* Targa order (B, G, R) */
  1854.     putc(back_color[1], File_Ptr1);
  1855.     putc(back_color[0], File_Ptr1);
  1856.     }
  1857.     if (ferror (File_Ptr1))
  1858.     {
  1859.     /*  Almost certainly not enough disk space  */
  1860.     fclose (File_Ptr1);
  1861.     remove (light_name);
  1862.     return(-2);
  1863.     }
  1864.  
  1865. if (targa_startdisk(File_Ptr1, T_header_24) != 0)
  1866. {
  1867.     enddisk();
  1868.     remove (light_name);
  1869.     return(-3);
  1870. }
  1871.  
  1872. return(0);
  1873. }
  1874.  
  1875.  
  1876.  
  1877. static int R_H (R, G, B, H, S, V)
  1878. unsigned char R,G,B;
  1879. unsigned long *H, *S, *V;
  1880.  
  1881. /***********************************************************************
  1882.  
  1883.  
  1884.  
  1885. ***********************************************************************/
  1886.  
  1887. {
  1888. unsigned long    H1, R1, G1, B1, DENOM;
  1889. unsigned char MIN;
  1890.  
  1891.     *V = R;
  1892.     MIN = G;
  1893.     if (R < G)
  1894.     {
  1895.        *V = G;
  1896.     MIN = R;
  1897.     if (G < B)          *V = B;
  1898.     if (B < R)          MIN = B;
  1899.     }
  1900.     else
  1901.     {
  1902.     if (B < G)          MIN = B;
  1903.     if (R < B)          *V = B;
  1904.     }
  1905.     DENOM = *V - MIN;
  1906.     if (*V != 0 && DENOM !=0)
  1907.     {
  1908.     *S = ((DENOM << 16) / *V) - 1;
  1909.     if (*S < 0)        *S = 0;
  1910.     }
  1911.     else     *S = 0;/* Color is black! and Sat has no meaning */
  1912.     if(*S == 0) /*  R=G=B => shade of grey and Hue has no meaning */
  1913.     {
  1914.     *H = 0;
  1915.     *V = *V << 8;
  1916.     return(1);  /* v or s or both are 0 */
  1917.     }
  1918. if (*V == MIN)
  1919. {
  1920.     *H = 0;
  1921.     *V = *V << 8;
  1922.     return(0);
  1923. }
  1924.     R1 = (((*V - R) * 60) << 6) / DENOM;    /* distance of color from red   */
  1925.     G1 = (((*V - G) * 60) << 6) / DENOM;    /* distance of color from green */
  1926.     B1 = (((*V - B) * 60) << 6) / DENOM;    /* distance of color from blue  */
  1927.     if(*V == R)
  1928.     if (MIN == G)        *H = (300 << 6) + B1;
  1929.     else            *H = (60 << 6) - G1;
  1930.     if(*V == G)
  1931.     if (MIN == B)        *H = (60 << 6) + R1;
  1932.     else            *H = (180 << 6) - B1;
  1933.     if(*V == B)
  1934.     if(MIN == R)        *H = (180 << 6) + G1;
  1935.     else            *H = (300 << 6) - R1;
  1936.  
  1937.     *V = *V << 8;
  1938.     return(0);
  1939. }
  1940.  
  1941.  
  1942.  
  1943. static int H_R (R, G, B, H, S, V)
  1944. unsigned char *R, *G, *B;
  1945. unsigned long  H, S, V;
  1946.  
  1947. /********************************************************************
  1948.  
  1949.  
  1950.  
  1951.  
  1952. ********************************************************************/
  1953.  
  1954. {
  1955. unsigned long     P1, P2, P3;
  1956. int    RMD, I;
  1957.  
  1958.     if(H >= 23040)     H = H % 23040; /*  Makes h circular  */
  1959.     I = H / 3840;
  1960.     RMD = H % 3840;            /*  RMD = fractional part of H    */
  1961.  
  1962.     P1 = ((V * (65535 - S)) / 65280) >> 8;
  1963.     P2 = (((V * (65535 - (S * RMD) / 3840)) / 65280) - 1) >> 8;
  1964.     P3 = (((V * (65535 - (S * (3840 - RMD)) / 3840)) / 65280)) >> 8;
  1965.     V = V >> 8;
  1966.     switch (I)
  1967.     {
  1968.     case 0:     *R = V;    *G = P3;    *B = P1;    break;
  1969.     case 1:     *R = P2;    *G = V;     *B = P1;    break;
  1970.     case 2:     *R = P1;    *G = V;     *B = P3;    break;
  1971.     case 3:     *R = P1;    *G = P2;    *B = V;    break;
  1972.     case 4:     *R = P3;    *G = P1;    *B = V;    break;
  1973.     case 5:     *R = V ;    *G = P1;    *B = P2;    break;
  1974.     }
  1975.     return(0);
  1976. }
  1977.  
  1978.  
  1979.