home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************/
- /* This file contains a 3D replacement for the out_line function called */
- /* by the decoder. The purpose is to apply various 3D transformations */
- /* before displaying points. Called once per line of the input file. */
- /* */
- /* Original Author Tim Wegner, with extensive help from Marc Reinig. */
- /* July 1994 - TW broke out several pieces of code and added pragma */
- /* to eliminate compiler warnings. Did a long-overdue */
- /* formatting cleanup. */
- /************************************************************************/
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <limits.h>
- #ifndef XFRACT
- #include <dos.h>
- #endif
- #include "fractint.h"
- #include "prototyp.h"
-
- struct point
- {
- int x;
- int y;
- int color;
- };
-
- struct f_point
- {
- float x;
- float y;
- float color;
- };
-
- struct minmax
- {
- int minx;
- int maxx;
- };
-
- /* routines in this module */
- int line3d(BYTE *, unsigned);
- int _fastcall targa_color(int, int, int);
- int targa_validate(char *);
- static int first_time(int, VECTOR);
- static int H_R(BYTE *, BYTE *, BYTE *, unsigned long, unsigned long, unsigned long);
- static int line3dmem(void);
- static int R_H(BYTE, BYTE, BYTE, unsigned long *, unsigned long *, unsigned long *);
- static int set_pixel_buff(BYTE *, BYTE far *, unsigned);
- static int startdisk1(char *, FILE *, int);
- static int _fastcall end_object(int);
- static int _fastcall offscreen(struct point);
- static int _fastcall out_triangle(struct f_point, struct f_point, struct f_point, int, int, int);
- static int _fastcall RAY_Header(void);
- static int _fastcall start_object(void);
- static void corners(MATRIX, int, double *, double *, double *, double *, double *, double *);
- static void draw_light_box(double *, double *, MATRIX);
- static void draw_rect(VECTOR, VECTOR, VECTOR, VECTOR, int, int);
- static void File_Error(char *, int);
- static void line3d_cleanup(void);
- static void _fastcall clipcolor(int, int, int);
- static void _fastcall interpcolor(int, int, int);
- static void _fastcall putatriangle(struct point, struct point, struct point, int);
- static void _fastcall putminmax(int, int, int);
- static void _fastcall triangle_bounds(float pt_t[3][3]);
- static void _fastcall T_clipcolor(int, int, int);
- static void _fastcall vdraw_line(double *, double *, int color);
- static void (_fastcall * fillplot) (int, int, int);
- static void (_fastcall * normalplot) (int, int, int);
-
- /* static variables */
- static float deltaphi; /* increment of latitude, longitude */
- static double rscale; /* surface roughness factor */
- static long xcenter, ycenter; /* circle center */
- static double sclx, scly, sclz; /* scale factors */
- static double R; /* radius values */
- static double Rfactor; /* for intermediate calculation */
- static LMATRIX llm; /* "" */
- static LVECTOR lview; /* for perspective views */
- static double zcutoff; /* perspective backside cutoff value */
- static float twocosdeltaphi;
- static float cosphi, sinphi; /* precalculated sin/cos of longitude */
- static float oldcosphi1, oldsinphi1;
- static float oldcosphi2, oldsinphi2;
- static BYTE far *fraction; /* float version of pixels array */
- static float min_xyz[3], max_xyz[3]; /* For Raytrace output */
- static int line_length1;
- static int T_header_24 = 18;/* Size of current Targa-24 header */
- static FILE *File_Ptr1 = NULL;
- static unsigned int IAmbient;
- static int rand_factor;
- static int HAZE_MULT;
- static void File_Error(char *File_Name1, int ERROR);
- static BYTE T24 = 24;
- static BYTE T32 = 32;
- static BYTE upr_lwr[4];
- static int T_Safe; /* Original Targa Image successfully copied to targa_temp */
- static void draw_rect(VECTOR, VECTOR, VECTOR, VECTOR, int, int);
- static VECTOR light_direction;
- static BYTE Real_Color; /* Actual color of cur pixel */
- static int RO, CO, CO_MAX; /* For use in Acrospin support */
- static FCODE acro_s1[] =
- {"Set Layer 1\nSet Color 2\nEndpointList X Y Z Name\n"};
- static FCODE acro_s2[] = {"LineList From To\n"};
- static FCODE s3[] = {"{ Created by FRACTINT Ver. "};
- static FCODE s3a[] = {" }\n\n"};
- #ifndef XFRACT
- static char banner[] = "%Fs%#4.2f%Fs";
- #else
- static char banner[] = "%s%#4.2f%s";
- #endif
- static int localpreviewfactor;
- static int zcoord = 256;
- static double aspect; /* aspect ratio */
- static int evenoddrow;
- static float far *sinthetaarray; /* all sine thetas go here */
- static float far *costhetaarray; /* all cosine thetas go here */
- static double rXrscale; /* precalculation factor */
- static int persp; /* flag for indicating perspective transformations */
- static struct point p1, p2, p3;
- static struct f_point f_bad;/* out of range value */
- static struct point bad; /* out of range value */
- static long num_tris; /* number of triangles output to ray trace file */
-
- /* global variables defined here */
- struct f_point far *f_lastrow;
- void (_fastcall * standardplot) (int, int, int);
- MATRIX m; /* transformation matrix */
- void (*mult_vec) (VECTOR) = mult_vec_c;
- int Ambient;
- int RANDOMIZE;
- int haze;
- int Real_V = 0; /* mrr Actual value of V for fillytpe>4 monochrome images */
- char light_name[80] = "fract001";
- int Targa_Overlay, error;
- char targa_temp[14] = "fractemp.tga";
- int P = 250; /* Perspective dist used when viewing light vector */
- BYTE back_color[3];
- char ray_name[80] = "fract001";
- char preview = 0;
- char showbox = 0;
- int previewfactor = 20;
- int xadjust = 0;
- int yadjust = 0;
- int xxadjust;
- int yyadjust;
- int xshift;
- int yshift;
- int bad_value = -10000; /* set bad values to this */
- int bad_check = -3000; /* check values against this to determine if good */
- struct point far *lastrow; /* this array remembers the previous line */
- int RAY = 0; /* Flag to generate Ray trace compatible files in 3d */
- int BRIEF = 0; /* 1 = short ray trace files */
-
- /* array of min and max x values used in triangle fill */
- struct minmax far *minmax_x;
- VECTOR view; /* position of observer for perspective */
- VECTOR cross;
- VECTOR tmpcross;
-
- struct point oldlast = { 0, 0, 0 }; /* old pixels */
-
-
- int line3d(BYTE * pixels, unsigned linelen)
- {
- int tout; /* triangle has been sent to ray trace file */
- int RND;
- float f_water = (float)0.0; /* transformed WATERLINE for ray trace files */
- double r0;
- int xcenter0 = 0;
- int ycenter0 = 0; /* Unfudged versions */
- double r; /* sphere radius */
- float costheta, sintheta; /* precalculated sin/cos of latitude */
- int next; /* used by preview and grid */
- int col; /* current column (original GIF) */
- struct point cur; /* current pixels */
- struct point old; /* old pixels */
- struct f_point f_cur;
- struct f_point f_old;
- VECTOR v; /* double vector */
- VECTOR v1, v2;
- VECTOR crossavg;
- char crossnotinit; /* flag for crossavg init indication */
- LVECTOR lv; /* long equivalent of v */
- LVECTOR lv0; /* long equivalent of v */
- int lastdot;
- long fudge;
-
- fudge = 1L << 16;
-
-
- if (transparent[0] || transparent[1])
- plot = normalplot = T_clipcolor; /* Use transparent plot function */
- else /* Use the usual FRACTINT plot function with
- * clipping */
- plot = normalplot = clipcolor;
-
- currow = rowcount; /* use separate variable to allow for
- * pot16bit files */
- if (pot16bit)
- currow >>= 1;
-
- /************************************************************************/
- /* This IF clause is executed ONCE per image. All precalculations are */
- /* done here, with out any special concern about speed. DANGER - */
- /* communication with the rest of the program is generally via static */
- /* or global variables. */
- /************************************************************************/
- if (rowcount++ == 0)
- {
- int err;
- if ((err = first_time(linelen, v)) != 0)
- return (err);
- tout = 0;
- crossavg[0] = 0;
- crossavg[1] = 0;
- crossavg[2] = 0;
- xcenter0 = (int) (xcenter = xdots / 2 + xshift);
- ycenter0 = (int) (ycenter = ydots / 2 - yshift);
-
- }
- /* make sure these pixel coordinates are out of range */
- old = bad;
- f_old = f_bad;
-
- /* copies pixels buffer to float type fraction buffer for fill purposes */
- if (pot16bit)
- {
- if (set_pixel_buff(pixels, fraction, linelen))
- return (0);
- }
- else if (grayflag) /* convert color numbers to grayscale values */
- for (col = 0; col < (int) linelen; col++)
- {
- int pal, colornum;
- colornum = pixels[col];
- /* effectively (30*R + 59*G + 11*B)/100 scaled 0 to 255 */
- pal = ((int) dacbox[colornum][0] * 77 +
- (int) dacbox[colornum][1] * 151 +
- (int) dacbox[colornum][2] * 28);
- pal >>= 6;
- pixels[col] = (BYTE) pal;
- }
- crossnotinit = 1;
- col = 0;
-
- CO = 0;
-
- /*************************************************************************/
- /* This section of code allows the operation of a preview mode when the */
- /* preview flag is set. Enabled, it allows the drawing of only the first */
- /* line of the source image, then every 10th line, until and including */
- /* the last line. For the undrawn lines, only necessary calculations are */
- /* made. As a bonus, in non-sphere mode a box is drawn to help visualize */
- /* the effects of 3D transformations. Thanks to Marc Reinig for this idea*/
- /* and code -- BTW, Marc did NOT put the goto in, but WE did, to avoid */
- /* copying code here, and to avoid a HUGE "if-then" construct. Besides, */
- /* we have ALREADY sinned, so why not sin some more? */
- /*************************************************************************/
- lastdot = min(xdots - 1, (int) linelen - 1);
- if (FILLTYPE >= 5)
- if (haze && Targa_Out)
- {
- HAZE_MULT = (int) (haze * (
- (float) ((long) (ydots - 1 - currow) *
- (long) (ydots - 1 - currow)) /
- (float) ((long) (ydots - 1) * (long) (ydots - 1))));
- HAZE_MULT = 100 - HAZE_MULT;
- }
-
- if (previewfactor >= ydots || previewfactor > lastdot)
- previewfactor = min(ydots - 1, lastdot);
-
- localpreviewfactor = ydots / previewfactor;
-
- tout = 0;
- /* Insure last line is drawn in preview and filltypes <0 */
- if ((RAY || preview || FILLTYPE < 0) && (currow != ydots - 1) &&
- (currow % localpreviewfactor) && /* Draw mod preview lines */
- !(!RAY && (FILLTYPE > 4) && (currow == 1)))
- /* Get init geometry in lightsource modes */
- goto reallythebottom; /* skip over most of the line3d calcs */
- if (dotmode == 11)
- {
- static FCODE mapping[] = {"mapping to 3d, reading line "};
- char s[40];
- #ifndef XFRACT
- sprintf(s, "%Fs%d", (char far *)mapping, currow);
- #else
- sprintf(s, "%s%d", mapping, currow);
- #endif
- dvid_status(1, s);
- }
-
- if (!col && RAY && currow != 0)
- start_object();
- /* PROCESS ROW LOOP BEGINS HERE */
- while (col < (int) linelen)
- {
- if ((RAY || preview || FILLTYPE < 0) &&
- (col != lastdot) &&/* if this is not the last col */
- /* if not the 1st or mod factor col */
- (col % (int) (aspect * localpreviewfactor)) &&
- (!(!RAY && FILLTYPE > 4 && col == 1)))
- goto loopbottom;
-
- f_cur.color = cur.color = Real_Color = pixels[col];
-
- if (RAY || preview || FILLTYPE < 0)
- {
- next = (int) (col + aspect * localpreviewfactor);
- if (next == col)
- next = col + 1;
- }
- else
- next = col + 1;
- if (next >= lastdot)
- next = lastdot;
-
- if (cur.color > 0 && cur.color < WATERLINE)
- f_cur.color = cur.color = Real_Color = (BYTE)WATERLINE; /* "lake" */
- else if (pot16bit)
- f_cur.color += ((float) fraction[col]) / (float) (1 << 8);
-
- if (SPHERE) /* sphere case */
- {
- sintheta = sinthetaarray[col];
- costheta = costhetaarray[col];
-
- if (sinphi < 0 && !(RAY || FILLTYPE < 0))
- {
- cur = bad;
- f_cur = f_bad;
- goto loopbottom; /* another goto ! */
- }
- /************************************************************/
- /* KEEP THIS FOR DOCS - original formula -- */
- /* if(rscale < 0.0) */
- /* r = 1.0+((double)cur.color/(double)zcoord)*rscale; */
- /* else */
- /* r = 1.0-rscale+((double)cur.color/(double)zcoord)*rscale;*/
- /* R = (double)ydots/2; */
- /* r = r*R; */
- /* cur.x = xdots/2 + sclx*r*sintheta*aspect + xup ; */
- /* cur.y = ydots/2 + scly*r*costheta*cosphi - yup ; */
- /************************************************************/
-
- if (rscale < 0.0)
- r = R + Rfactor * (double) f_cur.color * costheta;
- else if (rscale > 0.0)
- r = R - rXrscale + Rfactor * (double) f_cur.color * costheta;
- else
- r = R;
- /* Allow Ray trace to go through so display ok */
- if (persp || RAY)
- { /* mrr how do lv[] and cur and f_cur all relate */
- /* NOTE: fudge was pre-calculated above in r and R */
- /* (almost) guarantee negative */
- lv[2] = (long) (-R - r * costheta * sinphi); /* z */
- if ((lv[2] > zcutoff) && !FILLTYPE < 0)
- {
- cur = bad;
- f_cur = f_bad;
- goto loopbottom; /* another goto ! */
- }
- lv[0] = (long) (xcenter + sintheta * sclx * r); /* x */
- lv[1] = (long) (ycenter + costheta * cosphi * scly * r); /* y */
-
- if ((FILLTYPE >= 5) || RAY)
- { /* calculate illumination normal before persp */
-
- r0 = r / 65536L;
- f_cur.x = (float) (xcenter0 + sintheta * sclx * r0);
- f_cur.y = (float) (ycenter0 + costheta * cosphi * scly * r0);
- f_cur.color = (float) (-r0 * costheta * sinphi);
- }
- if (!(usr_floatflag || RAY))
- {
- if (longpersp(lv, lview, 16) == -1)
- {
- cur = bad;
- f_cur = f_bad;
- goto loopbottom; /* another goto ! */
- }
- cur.x = (int) (((lv[0] + 32768L) >> 16) + xxadjust);
- cur.y = (int) (((lv[1] + 32768L) >> 16) + yyadjust);
- }
- if (usr_floatflag || overflow || RAY)
- {
- v[0] = lv[0];
- v[1] = lv[1];
- v[2] = lv[2];
- v[0] /= fudge;
- v[1] /= fudge;
- v[2] /= fudge;
- perspective(v);
- cur.x = (int) (v[0] + .5 + xxadjust);
- cur.y = (int) (v[1] + .5 + yyadjust);
- }
- }
- /* mrr Not sure how this an 3rd if above relate */
- else if (!(persp && RAY))
- {
- /* mrr Why the xx- and yyadjust here and not above? */
- cur.x = (int) (f_cur.x = (float) (xcenter
- + sintheta * sclx * r + xxadjust));
- cur.y = (int) (f_cur.y = (float) (ycenter
- + costheta * cosphi * scly * r + yyadjust));
- if (FILLTYPE >= 5 || RAY) /* mrr why do we do this for
- * filltype>5? */
- f_cur.color = (float) (-r * costheta * sinphi * sclz);
- v[0] = v[1] = v[2] = 0; /* MRR Why do we do this? */
- }
- }
- else
- /* non-sphere 3D */
- {
- if (!usr_floatflag && !RAY)
- {
- if (FILLTYPE >= 5) /* flag to save vector before
- * perspective */
- lv0[0] = 1; /* in longvmultpersp calculation */
- else
- lv0[0] = 0;
-
- /* use 32-bit multiply math to snap this out */
- lv[0] = col;
- lv[0] = lv[0] << 16;
- lv[1] = currow;
- lv[1] = lv[1] << 16;
- if (filetype || pot16bit) /* don't truncate fractional
- * part */
- lv[2] = (long) (f_cur.color * 65536.0);
- else
- /* there IS no fractaional part here! */
- {
- lv[2] = (long) f_cur.color;
- lv[2] = lv[2] << 16;
- }
-
- if (longvmultpersp(lv, llm, lv0, lv, lview, 16) == -1)
- {
- cur = bad;
- f_cur = f_bad;
- goto loopbottom;
- }
-
- cur.x = (int) (((lv[0] + 32768L) >> 16) + xxadjust);
- cur.y = (int) (((lv[1] + 32768L) >> 16) + yyadjust);
- if (FILLTYPE >= 5 && !overflow)
- {
- f_cur.x = (float) lv0[0];
- f_cur.x /= (float)65536.0;
- f_cur.y = (float) lv0[1];
- f_cur.y /= (float)65536.0;
- f_cur.color = (float) lv0[2];
- f_cur.color /= (float)65536.0;
- }
- }
-
- if (usr_floatflag || overflow || RAY)
- /* do in float if integer math overflowed or doing Ray trace */
- {
- /* slow float version for comparison */
- v[0] = col;
- v[1] = currow;
- v[2] = f_cur.color; /* Actually the z value */
-
- mult_vec(v); /* matrix*vector routine */
-
- if (FILLTYPE > 4 || RAY)
- {
- f_cur.x = (float) v[0];
- f_cur.y = (float) v[1];
- f_cur.color = (float) v[2];
-
- if (RAY == 6)
- {
- f_cur.x = f_cur.x * ((float)2.0 / xdots) - (float)1.0;
- f_cur.y = f_cur.y * ((float)2.0 / ydots) - (float)1.0;
- f_cur.color = -f_cur.color * ((float)2.0 / numcolors) - (float)1.0;
- }
- }
-
- if (persp && !RAY)
- perspective(v);
- cur.x = (int) (v[0] + xxadjust + .5);
- cur.y = (int) (v[1] + yyadjust + .5);
-
- v[0] = 0;
- v[1] = 0;
- v[2] = WATERLINE;
- mult_vec(v);
- f_water = (float) v[2];
- }
- }
-
- if (RANDOMIZE)
- if (cur.color > WATERLINE)
- {
- RND = rand15() >> 8; /* 7-bit number */
- RND = RND * RND >> rand_factor; /* n-bit number */
-
- if (rand() & 1)
- RND = -RND; /* Make +/- n-bit number */
-
- if ((int) (cur.color) + RND >= colors)
- cur.color = colors - 2;
- else if ((int) (cur.color) + RND <= WATERLINE)
- cur.color = WATERLINE + 1;
- else
- cur.color = cur.color + RND;
- Real_Color = (BYTE)cur.color;
- }
-
- if (RAY)
- {
- if (col && currow &&
- old.x > bad_check &&
- old.x < (xdots - bad_check) &&
- lastrow[col].x > bad_check &&
- lastrow[col].y > bad_check &&
- lastrow[col].x < (xdots - bad_check) &&
- lastrow[col].y < (ydots - bad_check))
- {
- /* Get rid of all the triangles in the plane at the base of
- * the object */
-
- if (f_cur.color == f_water &&
- f_lastrow[col].color == f_water &&
- f_lastrow[next].color == f_water)
- goto loopbottom;
-
- if (RAY != 6) /* Output the vertex info */
- out_triangle(f_cur, f_old, f_lastrow[col],
- cur.color, old.color, lastrow[col].color);
-
- tout = 1;
-
- draw_line(old.x, old.y, cur.x, cur.y, old.color);
- draw_line(old.x, old.y, lastrow[col].x,
- lastrow[col].y, old.color);
- draw_line(lastrow[col].x, lastrow[col].y,
- cur.x, cur.y, cur.color);
- num_tris++;
- }
-
- if (col < lastdot && currow &&
- lastrow[col].x > bad_check &&
- lastrow[col].y > bad_check &&
- lastrow[col].x < (xdots - bad_check) &&
- lastrow[col].y < (ydots - bad_check) &&
- lastrow[next].x > bad_check &&
- lastrow[next].y > bad_check &&
- lastrow[next].x < (xdots - bad_check) &&
- lastrow[next].y < (ydots - bad_check))
- {
- /* Get rid of all the triangles in the plane at the base of
- * the object */
-
- if (f_cur.color == f_water &&
- f_lastrow[col].color == f_water &&
- f_lastrow[next].color == f_water)
- goto loopbottom;
-
- if (RAY != 6) /* Output the vertex info */
- out_triangle(f_cur, f_lastrow[col], f_lastrow[next],
- cur.color, lastrow[col].color, lastrow[next].color);
-
- tout = 1;
-
- draw_line(lastrow[col].x, lastrow[col].y, cur.x, cur.y,
- cur.color);
- draw_line(lastrow[next].x, lastrow[next].y, cur.x, cur.y,
- cur.color);
- draw_line(lastrow[next].x, lastrow[next].y, lastrow[col].x,
- lastrow[col].y, lastrow[col].color);
- num_tris++;
- }
-
- if (RAY == 6) /* Output vertex info for Acrospin */
- {
- fprintf(File_Ptr1, "% #4.4f % #4.4f % #4.4f R%dC%d\n",
- f_cur.x, f_cur.y, f_cur.color, RO, CO);
- if (CO > CO_MAX)
- CO_MAX = CO;
- CO++;
- }
- goto loopbottom;
- }
-
- switch (FILLTYPE)
- {
- case -1:
- if (col &&
- old.x > bad_check &&
- old.x < (xdots - bad_check))
- draw_line(old.x, old.y, cur.x, cur.y, cur.color);
- if (currow &&
- lastrow[col].x > bad_check &&
- lastrow[col].y > bad_check &&
- lastrow[col].x < (xdots - bad_check) &&
- lastrow[col].y < (ydots - bad_check))
- draw_line(lastrow[col].x, lastrow[col].y, cur.x,
- cur.y, cur.color);
- break;
-
- case 0:
- (*plot) (cur.x, cur.y, cur.color);
- break;
-
- case 1: /* connect-a-dot */
- if ((old.x < xdots) && (col) &&
- old.x > bad_check &&
- old.y > bad_check) /* Don't draw from old to cur on col
- * 0 */
- draw_line(old.x, old.y, cur.x, cur.y, cur.color);
- break;
-
- case 2: /* with interpolation */
- case 3: /* no interpolation */
- /*************************************************************/
- /* "triangle fill" - consider four points: current point, */
- /* previous point same row, point opposite current point in */
- /* previous row, point after current point in previous row. */
- /* The object is to fill all points inside the two triangles.*/
- /* */
- /* lastrow[col].x/y___ lastrow[next] */
- /* / 1 / */
- /* / 1 / */
- /* / 1 / */
- /* oldrow/col ________ trow/col */
- /*************************************************************/
-
- if (currow && !col)
- putatriangle(lastrow[next], lastrow[col], cur, cur.color);
- if (currow && col) /* skip first row and first column */
- {
- if (col == 1)
- putatriangle(lastrow[col], oldlast, old, old.color);
-
- if (col < lastdot)
- putatriangle(lastrow[next], lastrow[col], cur, cur.color);
- putatriangle(old, lastrow[col], cur, cur.color);
- }
- break;
-
- case 4: /* "solid fill" */
- if (SPHERE)
- {
- if (persp)
- {
- old.x = (int) (xcenter >> 16);
- old.y = (int) (ycenter >> 16);
- }
- else
- {
- old.x = (int) xcenter;
- old.y = (int) ycenter;
- }
- }
- else
- {
- lv[0] = col;
- lv[1] = currow;
- lv[2] = 0;
-
- /* apply fudge bit shift for integer math */
- lv[0] = lv[0] << 16;
- lv[1] = lv[1] << 16;
- /* Since 0, unnecessary lv[2] = lv[2] << 16; */
-
- if (longvmultpersp(lv, llm, lv0, lv, lview, 16))
- {
- cur = bad;
- f_cur = f_bad;
- goto loopbottom; /* another goto ! */
- }
-
- /* Round and fudge back to original */
- old.x = (int) ((lv[0] + 32768L) >> 16);
- old.y = (int) ((lv[1] + 32768L) >> 16);
- }
- if (old.x < 0)
- old.x = 0;
- if (old.x >= xdots)
- old.x = xdots - 1;
- if (old.y < 0)
- old.y = 0;
- if (old.y >= ydots)
- old.y = ydots - 1;
- draw_line(old.x, old.y, cur.x, cur.y, cur.color);
- break;
-
- case 5:
- case 6:
- /* light-source modulated fill */
- if (currow && col) /* skip first row and first column */
- {
- if (f_cur.color < bad_check || f_old.color < bad_check ||
- f_lastrow[col].color < bad_check)
- break;
-
- v1[0] = f_cur.x - f_old.x;
- v1[1] = f_cur.y - f_old.y;
- v1[2] = f_cur.color - f_old.color;
-
- v2[0] = f_lastrow[col].x - f_cur.x;
- v2[1] = f_lastrow[col].y - f_cur.y;
- v2[2] = f_lastrow[col].color - f_cur.color;
-
- cross_product(v1, v2, cross);
-
- /* normalize cross - and check if non-zero */
- if (normalize_vector(cross))
- {
- if (debugflag)
- {
- static FCODE msg[] = {"debug, cur.color=bad"};
- stopmsg(0, msg);
- }
- cur.color = (int)(f_cur.color = bad.color);
- }
- else
- {
- /* line-wise averaging scheme */
- if (LIGHTAVG > 0)
- {
- if (crossnotinit)
- {
- /* initialize array of old normal vectors */
- crossavg[0] = cross[0];
- crossavg[1] = cross[1];
- crossavg[2] = cross[2];
- crossnotinit = 0;
- }
- tmpcross[0] = (crossavg[0] * LIGHTAVG + cross[0]) /
- (LIGHTAVG + 1);
- tmpcross[1] = (crossavg[1] * LIGHTAVG + cross[1]) /
- (LIGHTAVG + 1);
- tmpcross[2] = (crossavg[2] * LIGHTAVG + cross[2]) /
- (LIGHTAVG + 1);
- cross[0] = tmpcross[0];
- cross[1] = tmpcross[1];
- cross[2] = tmpcross[2];
- if (normalize_vector(cross))
- {
- /* this shouldn't happen */
- if (debugflag)
- {
- static FCODE msg[] = {"debug, normal vector err2"};
- stopmsg(0, msg);
- /* use next instead if you ever need details:
- * static char far tmp[] = {"debug, vector err"};
- * char msg[200]; #ifndef XFRACT
- * sprintf(msg,"%Fs\n%f %f %f\n%f %f %f\n%f %f
- * %f", #else sprintf(msg,"%s\n%f %f %f\n%f %f
- * %f\n%f %f %f", #endif tmp, f_cur.x, f_cur.y,
- * f_cur.color, f_lastrow[col].x,
- * f_lastrow[col].y, f_lastrow[col].color,
- * f_lastrow[col-1].x,
- * f_lastrow[col-1].y,f_lastrow[col-1].color);
- * stopmsg(0,msg); */
- }
- cur.color = (int)(f_cur.color = colors);
- }
- }
- crossavg[0] = tmpcross[0];
- crossavg[1] = tmpcross[1];
- crossavg[2] = tmpcross[2];
-
- /* dot product of unit vectors is cos of angle between */
- /* we will use this value to shade surface */
-
- cur.color = (int) (1 + (colors - 2) *
- (1.0 - dot_product(cross, light_direction)));
- }
- /* if colors out of range, set them to min or max color index
- * but avoid background index. This makes colors "opaque" so
- * SOMETHING plots. These conditions shouldn't happen but just
- * in case */
- if (cur.color < 1) /* prevent transparent colors */
- cur.color = 1;/* avoid background */
- if (cur.color > colors - 1)
- cur.color = colors - 1;
-
- /* why "col < 2"? So we have sufficient geometry for the fill */
- /* algorithm, which needs previous point in same row to have */
- /* already been calculated (variable old) */
- /* fix ragged left margin in preview */
- if (col == 1 && currow > 1)
- putatriangle(lastrow[next], lastrow[col], cur, cur.color);
-
- if (col < 2 || currow < 2) /* don't have valid colors
- * yet */
- break;
-
- if (col < lastdot)
- putatriangle(lastrow[next], lastrow[col], cur, cur.color);
- putatriangle(old, lastrow[col], cur, cur.color);
-
- plot = standardplot;
- }
- break;
- } /* End of CASE statement for fill type */
- loopbottom:
- if (RAY || (FILLTYPE != 0 && FILLTYPE != 4))
- {
- /* for triangle and grid fill purposes */
- oldlast = lastrow[col];
- old = lastrow[col] = cur;
-
- /* for illumination model purposes */
- f_old = f_lastrow[col] = f_cur;
- if (currow && RAY && col >= lastdot)
- /* if we're at the end of a row, close the object */
- {
- end_object(tout);
- tout = 0;
- if (ferror(File_Ptr1))
- {
- fclose(File_Ptr1);
- remove(light_name);
- File_Error(ray_name, 2);
- return (-1);
- }
- }
- }
- col++;
- } /* End of while statement for plotting line */
- RO++;
- reallythebottom:
-
- /* stuff that HAS to be done, even in preview mode, goes here */
- if (SPHERE)
- {
- /* incremental sin/cos phi calc */
- if (currow == 0)
- {
- sinphi = oldsinphi2;
- cosphi = oldcosphi2;
- }
- else
- {
- sinphi = twocosdeltaphi * oldsinphi2 - oldsinphi1;
- cosphi = twocosdeltaphi * oldcosphi2 - oldcosphi1;
- oldsinphi1 = oldsinphi2;
- oldsinphi2 = sinphi;
- oldcosphi1 = oldcosphi2;
- oldcosphi2 = cosphi;
- }
- }
- return (0); /* decoder needs to know all is well !!! */
- }
-
- /* vector version of line draw */
- static void _fastcall vdraw_line(double *v1, double *v2, int color)
- {
- int x1, y1, x2, y2;
- x1 = (int) v1[0];
- y1 = (int) v1[1];
- x2 = (int) v2[0];
- y2 = (int) v2[1];
- draw_line(x1, y1, x2, y2, color);
- }
-
- static void corners(MATRIX m, int show, double *pxmin, double *pymin, double *pzmin, double *pxmax, double *pymax, double *pzmax)
- {
- int i, j;
- VECTOR S[2][4]; /* Holds the top an bottom points,
- * S[0][]=bottom */
-
- /* define corners of box fractal is in in x,y,z plane "b" stands for
- * "bottom" - these points are the corners of the screen in the x-y plane.
- * The "t"'s stand for Top - they are the top of the cube where 255 color
- * points hit. */
-
- *pxmin = *pymin = *pzmin = (int) INT_MAX;
- *pxmax = *pymax = *pzmax = (int) INT_MIN;
-
- for (j = 0; j < 4; ++j)
- for (i = 0; i < 3; i++)
- S[0][j][i] = S[1][j][i] = 0;
-
- S[0][1][0] = S[0][2][0] = S[1][1][0] = S[1][2][0] = xdots - 1;
- S[0][2][1] = S[0][3][1] = S[1][2][1] = S[1][3][1] = ydots - 1;
- S[1][0][2] = S[1][1][2] = S[1][2][2] = S[1][3][2] = zcoord - 1;
-
- for (i = 0; i < 4; ++i)
- {
- /* transform points */
- vmult(S[0][i], m, S[0][i]);
- vmult(S[1][i], m, S[1][i]);
-
- /* update minimums and maximums */
- if (S[0][i][0] <= *pxmin)
- *pxmin = S[0][i][0];
- if (S[0][i][0] >= *pxmax)
- *pxmax = S[0][i][0];
- if (S[1][i][0] <= *pxmin)
- *pxmin = S[1][i][0];
- if (S[1][i][0] >= *pxmax)
- *pxmax = S[1][i][0];
- if (S[0][i][1] <= *pymin)
- *pymin = S[0][i][1];
- if (S[0][i][1] >= *pymax)
- *pymax = S[0][i][1];
- if (S[1][i][1] <= *pymin)
- *pymin = S[1][i][1];
- if (S[1][i][1] >= *pymax)
- *pymax = S[1][i][1];
- if (S[0][i][2] <= *pzmin)
- *pzmin = S[0][i][2];
- if (S[0][i][2] >= *pzmax)
- *pzmax = S[0][i][2];
- if (S[1][i][2] <= *pzmin)
- *pzmin = S[1][i][2];
- if (S[1][i][2] >= *pzmax)
- *pzmax = S[1][i][2];
- }
-
- if (show)
- {
- if (persp)
- {
- for (i = 0; i < 4; i++)
- {
- perspective(S[0][i]);
- perspective(S[1][i]);
- }
- }
-
- /* Keep the box surrounding the fractal */
- for (j = 0; j < 2; j++)
- for (i = 0; i < 4; ++i)
- {
- S[j][i][0] += xxadjust;
- S[j][i][1] += yyadjust;
- }
-
- draw_rect(S[0][0], S[0][1], S[0][2], S[0][3], 2, 1); /* Bottom */
-
- draw_rect(S[0][0], S[1][0], S[0][1], S[1][1], 5, 0); /* Sides */
- draw_rect(S[0][2], S[1][2], S[0][3], S[1][3], 6, 0);
-
- draw_rect(S[1][0], S[1][1], S[1][2], S[1][3], 8, 1); /* Top */
- }
- }
-
- /* This function draws a vector from origin[] to direct[] and a box
- around it. The vector and box are transformed or not depending on
- FILLTYPE.
- */
-
- static void draw_light_box(double *origin, double *direct, MATRIX light_m)
- {
- VECTOR S[2][4];
- int i, j;
- double temp;
-
- S[1][0][0] = S[0][0][0] = origin[0];
- S[1][0][1] = S[0][0][1] = origin[1];
-
- S[1][0][2] = direct[2];
-
- for (i = 0; i < 2; i++)
- {
- S[i][1][0] = S[i][0][0];
- S[i][1][1] = direct[1];
- S[i][1][2] = S[i][0][2];
- S[i][2][0] = direct[0];
- S[i][2][1] = S[i][1][1];
- S[i][2][2] = S[i][0][2];
- S[i][3][0] = S[i][2][0];
- S[i][3][1] = S[i][0][1];
- S[i][3][2] = S[i][0][2];
- }
-
- /* transform the corners if necessary */
- if (FILLTYPE == 6)
- for (i = 0; i < 4; i++)
- {
- vmult(S[0][i], light_m, S[0][i]);
- vmult(S[1][i], light_m, S[1][i]);
- }
-
- /* always use perspective to aid viewing */
- temp = view[2]; /* save perspective distance for a later
- * restore */
- view[2] = -P * 300.0 / 100.0;
-
- for (i = 0; i < 4; i++)
- {
- perspective(S[0][i]);
- perspective(S[1][i]);
- }
- view[2] = temp; /* Restore perspective distance */
-
- /* Adjust for aspect */
- for (i = 0; i < 4; i++)
- {
- S[0][i][0] = S[0][i][0] * aspect;
- S[1][i][0] = S[1][i][0] * aspect;
- }
-
- /* draw box connecting transformed points. NOTE order and COLORS */
- draw_rect(S[0][0], S[0][1], S[0][2], S[0][3], 2, 1);
-
- vdraw_line(S[0][0], S[1][2], 8);
-
- /* sides */
- draw_rect(S[0][0], S[1][0], S[0][1], S[1][1], 4, 0);
- draw_rect(S[0][2], S[1][2], S[0][3], S[1][3], 5, 0);
-
- draw_rect(S[1][0], S[1][1], S[1][2], S[1][3], 3, 1);
-
- /* Draw the "arrow head" */
- for (i = -3; i < 4; i++)
- for (j = -3; j < 4; j++)
- if (abs(i) + abs(j) < 6)
- plot((int) (S[1][2][0] + i), (int) (S[1][2][1] + j), 10);
- }
-
- static void draw_rect(VECTOR V0, VECTOR V1, VECTOR V2, VECTOR V3, int color, int rect)
- {
- VECTOR V[4];
- int i;
-
- /* Since V[2] is not used by vdraw_line don't bother setting it */
- for (i = 0; i < 2; i++)
- {
- V[0][i] = V0[i];
- V[1][i] = V1[i];
- V[2][i] = V2[i];
- V[3][i] = V3[i];
- }
- if (rect) /* Draw a rectangle */
- {
- for (i = 0; i < 4; i++)
- if (fabs(V[i][0] - V[(i + 1) % 4][0]) < -2 * bad_check &&
- fabs(V[i][1] - V[(i + 1) % 4][1]) < -2 * bad_check)
- vdraw_line(V[i], V[(i + 1) % 4], color);
- }
- else
- /* Draw 2 lines instead */
- {
- for (i = 0; i < 3; i += 2)
- if (fabs(V[i][0] - V[i + 1][0]) < -2 * bad_check &&
- fabs(V[i][1] - V[i + 1][1]) < -2 * bad_check)
- vdraw_line(V[i], V[i + 1], color);
- }
- return;
- }
-
- /* replacement for plot - builds a table of min and max x's instead of plot */
- /* called by draw_line as part of triangle fill routine */
- static void _fastcall putminmax(int x, int y, int color)
- {
- color = 0; /* to supress warning only */
- if (y >= 0 && y < ydots)
- {
- if (x < minmax_x[y].minx)
- minmax_x[y].minx = x;
- if (x > minmax_x[y].maxx)
- minmax_x[y].maxx = x;
- }
- }
-
- /*
- This routine fills in a triangle. Extreme left and right values for
- each row are calculated by calling the line function for the sides.
- Then rows are filled in with horizontal lines
- */
- #define MAXOFFSCREEN 2 /* allow two of three points to be off screen */
-
- static void _fastcall putatriangle(struct point pt1, struct point pt2, struct point pt3, int color)
- {
- int miny, maxy;
- int x, y, xlim;
-
- /* Too many points off the screen? */
- if (offscreen(pt1) + offscreen(pt2) + offscreen(pt3) > MAXOFFSCREEN)
- return;
-
- p1 = pt1; /* needed by interpcolor */
- p2 = pt2;
- p3 = pt3;
-
- /* fast way if single point or single line */
- if (p1.y == p2.y && p1.x == p2.x)
- {
- plot = fillplot;
- if (p1.y == p3.y && p1.x == p3.x)
- (*plot) (p1.x, p1.y, color);
- else
- draw_line(p1.x, p1.y, p3.x, p3.y, color);
- plot = normalplot;
- return;
- }
- else if ((p3.y == p1.y && p3.x == p1.x) || (p3.y == p2.y && p3.x == p2.x))
- {
- plot = fillplot;
- draw_line(p1.x, p1.y, p2.x, p2.y, color);
- plot = normalplot;
- return;
- }
-
- /* find min max y */
- miny = maxy = p1.y;
- if (p2.y < miny)
- miny = p2.y;
- else
- maxy = p2.y;
- if (p3.y < miny)
- miny = p3.y;
- else if (p3.y > maxy)
- maxy = p3.y;
-
- /* only worried about values on screen */
- if (miny < 0)
- miny = 0;
- if (maxy >= ydots)
- maxy = ydots - 1;
-
- for (y = miny; y <= maxy; y++)
- {
- minmax_x[y].minx = (int) INT_MAX;
- minmax_x[y].maxx = (int) INT_MIN;
- }
-
- /* set plot to "fake" plot function */
- plot = putminmax;
-
- /* build table of extreme x's of triangle */
- draw_line(p1.x, p1.y, p2.x, p2.y, 0);
- draw_line(p2.x, p2.y, p3.x, p3.y, 0);
- draw_line(p3.x, p3.y, p1.x, p1.y, 0);
-
- for (y = miny; y <= maxy; y++)
- {
- xlim = minmax_x[y].maxx;
- for (x = minmax_x[y].minx; x <= xlim; x++)
- (*fillplot) (x, y, color);
- }
- plot = normalplot;
- }
-
- static int _fastcall offscreen(struct point pt)
- {
- if (pt.x >= 0)
- if (pt.x < xdots)
- if (pt.y >= 0)
- if (pt.y < ydots)
- return (0); /* point is ok */
- if (abs(pt.x) > 0 - bad_check || abs(pt.y) > 0 - bad_check)
- return (99); /* point is bad */
- return (1); /* point is off the screen */
- }
-
- static void _fastcall clipcolor(int x, int y, int color)
- {
- if (0 <= x && x < xdots &&
- 0 <= y && y < ydots &&
- 0 <= color && color < filecolors)
- {
- standardplot(x, y, color);
-
- if (Targa_Out)
- /* standardplot modifies color in these types */
- if (!(glassestype == 1 || glassestype == 2))
- targa_color(x, y, color);
- }
- }
-
- /*********************************************************************/
- /* This function is the same as clipcolor but checks for color being */
- /* in transparent range. Intended to be called only if transparency */
- /* has been enabled. */
- /*********************************************************************/
-
- static void _fastcall T_clipcolor(int x, int y, int color)
- {
- if (0 <= x && x < xdots && /* is the point on screen? */
- 0 <= y && y < ydots && /* Yes? */
- 0 <= color && color < colors && /* Colors in valid range? */
- /* Lets make sure its not a transparent color */
- (transparent[0] > color || color > transparent[1]))
- {
- standardplot(x, y, color);/* I guess we can plot then */
- if (Targa_Out)
- /* standardplot modifies color in these types */
- if (!(glassestype == 1 || glassestype == 2))
- targa_color(x, y, color);
- }
- }
-
- /************************************************************************/
- /* A substitute for plotcolor that interpolates the colors according */
- /* to the x and y values of three points (p1,p2,p3) which are static in */
- /* this routine */
- /* */
- /* In Light source modes, color is light value, not actual color */
- /* Real_Color always contains the actual color */
- /************************************************************************/
-
- static void _fastcall interpcolor(int x, int y, int color)
- {
- int D, d1, d2, d3;
-
- /* this distance formula is not the usual one - but it has the virtue that
- * it uses ONLY additions (almost) and it DOES go to zero as the points
- * get close. */
-
- d1 = abs(p1.x - x) + abs(p1.y - y);
- d2 = abs(p2.x - x) + abs(p2.y - y);
- d3 = abs(p3.x - x) + abs(p3.y - y);
-
- D = (d1 + d2 + d3) << 1;
- if (D)
- { /* calculate a weighted average of colors long casts prevent integer
- overflow. This can evaluate to zero */
- color = (int) (((long) (d2 + d3) * (long) p1.color +
- (long) (d1 + d3) * (long) p2.color +
- (long) (d1 + d2) * (long) p3.color) / D);
- }
-
- if (0 <= x && x < xdots &&
- 0 <= y && y < ydots &&
- 0 <= color && color < colors &&
- (transparent[1] == 0 || (int) Real_Color > transparent[1] ||
- transparent[0] > (int) Real_Color))
- {
- if (Targa_Out)
- /* standardplot modifies color in these types */
- if (!(glassestype == 1 || glassestype == 2))
- D = targa_color(x, y, color);
-
- if (FILLTYPE >= 5)
- if (Real_V && Targa_Out)
- color = D;
- else
- {
- color = (1 + (unsigned) color * IAmbient) / 256;
- if (color == 0)
- color = 1;
- }
- standardplot(x, y, color);
- }
- }
-
- /*
- In non light source modes, both color and Real_Color contain the
- actual pixel color. In light source modes, color contains the
- light value, and Real_Color contains the origninal color
-
- This routine takes a pixel modifies it for lightshading if appropriate
- and plots it in a Targa file. Used in plot3d.c
- */
-
- int _fastcall targa_color(int x, int y, int color)
- {
- unsigned long H, S, V;
- BYTE RGB[3];
-
- if (FILLTYPE == 2 || glassestype == 1 || glassestype == 2)
- Real_Color = (BYTE)color; /* So Targa gets interpolated color */
-
- RGB[0] = (BYTE)(dacbox[Real_Color][0] << 2); /* Move color space to */
- RGB[1] = (BYTE)(dacbox[Real_Color][1] << 2); /* 256 color primaries */
- RGB[2] = (BYTE)(dacbox[Real_Color][2] << 2); /* from 64 colors */
-
- /* Now lets convert it to HSV */
- R_H(RGB[0], RGB[1], RGB[2], &H, &S, &V);
-
- /* Modify original S and V components */
- if (FILLTYPE > 4 && !(glassestype == 1 || glassestype == 2))
- /* Adjust for Ambient */
- V = (V * (65535L - (unsigned) (color * IAmbient))) / 65535L;
-
- if (haze)
- {
- /* Haze lowers sat of colors */
- S = (unsigned long) (S * HAZE_MULT) / 100;
- if (V >= 32640) /* Haze reduces contrast */
- {
- V = V - 32640;
- V = (unsigned long) ((V * HAZE_MULT) / 100);
- V = V + 32640;
- }
- else
- {
- V = 32640 - V;
- V = (unsigned long) ((V * HAZE_MULT) / 100);
- V = 32640 - V;
- }
- }
- /* Now lets convert it back to RGB. Original Hue, modified Sat and Val */
- H_R(&RGB[0], &RGB[1], &RGB[2], H, S, V);
-
- if (Real_V)
- V = (35 * (int) RGB[0] + 45 * (int) RGB[1] + 20 * (int) RGB[2]) / 100;
-
- /* Now write the color triple to its transformed location */
- /* on the disk. */
- targa_writedisk(x + sxoffs, y + syoffs, RGB[0], RGB[1], RGB[2]);
-
- return ((int) (255 - V));
- }
-
- static int set_pixel_buff(BYTE * pixels, BYTE far * fraction, unsigned linelen)
- {
- int i;
- if ((evenoddrow++ & 1) == 0) /* even rows are color value */
- {
- for (i = 0; i < (int) linelen; i++) /* add the fractional part in
- * odd row */
- fraction[i] = pixels[i];
- return (1);
- }
- else
- /* swap */
- {
- BYTE tmp;
- for (i = 0; i < (int) linelen; i++) /* swap so pixel has color */
- {
- tmp = pixels[i];
- pixels[i] = fraction[i];
- fraction[i] = tmp;
- }
- }
- return (0);
- }
-
- /**************************************************************************
-
- Common routine for printing error messages to the screen for Targa
- and other files
-
- **************************************************************************/
-
- #ifndef XFRACT
- static char s_f[] = "%Fs%Fs";
- static char s_fff[] = "%Fs%Fs%Fs";
- #else
- static char s_f[] = "%s%s";
- static char s_fff[] = "%s%s%s";
- #endif
- static FCODE OOPS[] = {"OOPS, "};
- static FCODE E1[] = {"can't handle this type of file.\n"};
- static FCODE str1[] = {"couldn't open < "};
- static FCODE str3[] = {"image wrong size\n"};
- static FCODE outofdisk[] = {"ran out of disk space. < "};
-
- static void File_Error(char *File_Name1, int ERROR)
- {
- char msgbuf[200];
-
- error = ERROR;
- switch (ERROR)
- {
- case 1: /* Can't Open */
- #ifndef XFRACT
- sprintf(msgbuf, "%Fs%Fs%s >", (char far *)OOPS, (char far *)str1, File_Name1);
- #else
- sprintf(msgbuf, "%s%s%s >", OOPS, str1, File_Name1);
- #endif
- break;
- case 2: /* Not enough room */
- #ifndef XFRACT
- sprintf(msgbuf, "%Fs%Fs%s >", (char far *)OOPS, (char far *)outofdisk, File_Name1);
- #else
- sprintf(msgbuf, "%s%s%s >", OOPS, outofdisk, File_Name1);
- #endif
- break;
- case 3: /* Image wrong size */
- sprintf(msgbuf, s_f, (char far *)OOPS, (char far *)str3);
- break;
- case 4: /* Wrong file type */
- sprintf(msgbuf, s_f, (char far *)OOPS, (char far *)E1);
- break;
- }
- stopmsg(0, msgbuf);
- return;
- }
-
-
- /************************************************************************/
- /* */
- /* This function opens a TARGA_24 file for reading and writing. If */
- /* its a new file, (overlay == 0) it writes a header. If it is to */
- /* overlay an existing file (overlay == 1) it copies the original */
- /* header whose lenght and validity was determined in */
- /* Targa_validate. */
- /* */
- /* It Verifies there is enough disk space, and leaves the file */
- /* at the start of the display data area. */
- /* */
- /* If this is an overlay, closes source and copies to "targa_temp" */
- /* If there is an error close the file. */
- /* */
- /* **********************************************************************/
-
-
- static int startdisk1(char *File_Name2, FILE * Source, int overlay)
- {
- int i, j, k, inc;
- FILE *fps;
-
- /* Open File for both reading and writing */
- if ((fps = dir_fopen(workdir,File_Name2, "w+b")) == NULL)
- {
- File_Error(File_Name2, 1);
- return (-1); /* Oops, somethings wrong! */
- }
-
- inc = 1; /* Assume we are overlaying a file */
-
- /* Write the header */
- if (overlay) /* We are overlaying a file */
- for (i = 0; i < T_header_24; i++) /* Copy the header from the Source */
- fputc(fgetc(Source), fps);
- else
- { /* Write header for a new file */
- /* ID field size = 0, No color map, Targa type 2 file */
- for (i = 0; i < 12; i++)
- {
- if (i == 2)
- fputc(i, fps);
- else
- fputc(0, fps);
- }
- /* Write image size */
- for (i = 0; i < 4; i++)
- fputc(upr_lwr[i], fps);
- fputc(T24, fps); /* Targa 24 file */
- fputc(T32, fps); /* Image at upper left */
- inc = 3;
- }
-
- /* Finished with the header, now lets work on the display area */
- for (i = 0; i < ydots; i++) /* "clear the screen" (write to the disk) */
- {
- for (j = 0; j < line_length1; j = j + inc)
- {
- if (overlay)
- fputc(fgetc(Source), fps);
- else
- for (k = 2; k > -1; k--)
- fputc(back_color[k], fps); /* Targa order (B, G, R) */
- }
- if (ferror(fps))
- {
- /* Almost certainly not enough disk space */
- fclose(fps);
- fclose(Source);
- dir_remove(tempdir,File_Name2);
- File_Error(File_Name2, 2);
- return (-2);
- }
- if (keypressed())
- return (-3);
- }
-
- if (targa_startdisk(fps, T_header_24) != 0)
- {
- enddisk();
- dir_remove(tempdir,File_Name2);
- return (-4);
- }
- return (0);
- }
-
- int targa_validate(char *File_Name)
- {
- FILE *fp;
- int i;
- #if 0
- int j = 0;
- #endif
-
- /* Attempt to open source file for reading */
- if ((fp = fopen(File_Name, "rb")) == NULL)
- {
- File_Error(File_Name, 1);
- return (-1); /* Oops, file does not exist */
- }
-
- T_header_24 += fgetc(fp); /* Check ID field and adjust header size */
-
- if (fgetc(fp)) /* Make sure this is an unmapped file */
- {
- File_Error(File_Name, 4);
- return (-1);
- }
-
- if (fgetc(fp) != 2) /* Make sure it is a type 2 file */
- {
- File_Error(File_Name, 4);
- return (-1);
- }
-
- /* Skip color map specification */
- for (i = 0; i < 5; i++)
- fgetc(fp);
-
- for (i = 0; i < 4; i++)
- {
- /* Check image origin */
- fgetc(fp);
- #if 0
- if (j != 0)
- {
- File_Error(File_Name, 4);
- return (-1);
- }
- #endif
- }
- /* Check Image specs */
- for (i = 0; i < 4; i++)
- if (fgetc(fp) != (int) upr_lwr[i])
- {
- File_Error(File_Name, 3);
- return (-1);
- }
-
- if (fgetc(fp) != (int) T24)
- error = 4; /* Is it a targa 24 file? */
- if (fgetc(fp) != (int) T32)
- error = 4; /* Is the origin at the upper left? */
- if (error == 4)
- {
- File_Error(File_Name, 4);
- return (-1);
- }
- rewind(fp);
-
- /* Now that we know its a good file, create a working copy */
- if (startdisk1(targa_temp, fp, 1))
- return (-1);
-
- fclose(fp); /* Close the source */
-
- T_Safe = 1; /* Original file successfully copied to
- * targa_temp */
- return (0);
- }
-
- static int R_H(BYTE R, BYTE G, BYTE B, unsigned long *H, unsigned long *S, unsigned long *V)
- {
- unsigned long R1, G1, B1, DENOM;
- BYTE MIN;
-
- *V = R;
- MIN = G;
- if (R < G)
- {
- *V = G;
- MIN = R;
- if (G < B)
- *V = B;
- if (B < R)
- MIN = B;
- }
- else
- {
- if (B < G)
- MIN = B;
- if (R < B)
- *V = B;
- }
- DENOM = *V - MIN;
- if (*V != 0 && DENOM != 0)
- {
- *S = ((DENOM << 16) / *V) - 1;
- }
- else
- *S = 0; /* Color is black! and Sat has no meaning */
- if (*S == 0) /* R=G=B => shade of grey and Hue has no meaning */
- {
- *H = 0;
- *V = *V << 8;
- return (1); /* v or s or both are 0 */
- }
- if (*V == MIN)
- {
- *H = 0;
- *V = *V << 8;
- return (0);
- }
- R1 = (((*V - R) * 60) << 6) / DENOM; /* distance of color from red */
- G1 = (((*V - G) * 60) << 6) / DENOM; /* distance of color from green */
- B1 = (((*V - B) * 60) << 6) / DENOM; /* distance of color from blue */
- if (*V == R)
- if (MIN == G)
- *H = (300 << 6) + B1;
- else
- *H = (60 << 6) - G1;
- if (*V == G)
- if (MIN == B)
- *H = (60 << 6) + R1;
- else
- *H = (180 << 6) - B1;
- if (*V == B)
- if (MIN == R)
- *H = (180 << 6) + G1;
- else
- *H = (300 << 6) - R1;
-
- *V = *V << 8;
- return (0);
- }
-
- static int H_R(BYTE *R, BYTE *G, BYTE *B, unsigned long H, unsigned long S, unsigned long V)
- {
- unsigned long P1, P2, P3;
- int RMD, I;
-
- if (H >= 23040)
- H = H % 23040; /* Makes h circular */
- I = (int) (H / 3840);
- RMD = (int) (H % 3840); /* RMD = fractional part of H */
-
- P1 = ((V * (65535L - S)) / 65280L) >> 8;
- P2 = (((V * (65535L - (S * RMD) / 3840)) / 65280L) - 1) >> 8;
- P3 = (((V * (65535L - (S * (3840 - RMD)) / 3840)) / 65280L)) >> 8;
- V = V >> 8;
- switch (I)
- {
- case 0:
- *R = (BYTE) V;
- *G = (BYTE) P3;
- *B = (BYTE) P1;
- break;
- case 1:
- *R = (BYTE) P2;
- *G = (BYTE) V;
- *B = (BYTE) P1;
- break;
- case 2:
- *R = (BYTE) P1;
- *G = (BYTE) V;
- *B = (BYTE) P3;
- break;
- case 3:
- *R = (BYTE) P1;
- *G = (BYTE) P2;
- *B = (BYTE) V;
- break;
- case 4:
- *R = (BYTE) P3;
- *G = (BYTE) P1;
- *B = (BYTE) V;
- break;
- case 5:
- *R = (BYTE) V;
- *G = (BYTE) P1;
- *B = (BYTE) P2;
- break;
- }
- return (0);
- }
-
-
- /***************************************************************************/
- /* */
- /* EB & DG fiddled with outputs for Rayshade so they work. with v4.x. */
- /* EB == eli brandt. ebrandt@jarthur.claremont.edu */
- /* DG == dan goldwater. daniel_goldwater@brown.edu & dgold@math.umass.edu */
- /* (NOTE: all the stuff we fiddled with is commented with "EB & DG" ) */
- /* general raytracing code info/notes: */
- /* */
- /* ray == 0 means no raytracer output ray == 7 is for dxf */
- /* ray == 1 is for dkb/pov ray == 4 is for mtv */
- /* ray == 2 is for vivid ray == 5 is for rayshade */
- /* ray == 3 is for raw ray == 6 is for acrospin */
- /* */
- /* rayshade needs counterclockwise triangles. raytracers that support */
- /* the 'heightfield' primitive include rayshade and pov. anyone want to */
- /* write code to make heightfields? they are *MUCH* faster to trace than */
- /* triangles when doing landscapes... */
- /* */
- /* stuff EB & DG changed: */
- /* made the rayshade output create a "grid" aggregate object (one of */
- /* rayshade's primitives), instead of a global grid. as a result, the */
- /* grid can be optimized based on the number of triangles. */
- /* the z component of the grid can always be 1 since the surface formed */
- /* by the triangles is flat */
- /* (ie, it doesnt curve over itself). this is a major optimization. */
- /* the x and y grid size is also optimized for a 4:3 aspect ratio image, */
- /* to get the fewest possible traingles in each grid square. */
- /* also, we fixed the rayshade code so it actually produces output that */
- /* works with rayshade. */
- /* (maybe the old code was for a really old version of rayshade?). */
- /* */
- /***************************************************************************/
-
- /********************************************************************/
- /* */
- /* This routine writes a header to a ray tracer data file. It */
- /* Identifies the version of FRACTINT which created it an the */
- /* key 3D parameters in effect at the time. */
- /* */
- /********************************************************************/
-
- static FCODE declare[] = {"DECLARE "};
- static FCODE frac_default[] = {"F_Dflt"};
- static FCODE s_color[] = {"COLOR "};
- static FCODE dflt[] = {"RED 0.8 GREEN 0.4 BLUE 0.1\n"};
- static FCODE d_color[] = {"0.8 0.4 0.1"};
- static FCODE r_surf[] = {"0.95 0.05 5 0 0\n"};
- static FCODE surf[] = {"surf={diff="};
- /* EB & DG: changed "surface T" to "applysurf" and "diff" to "diffuse" */
- static FCODE rs_surf[] = {"applysurf diffuse "};
- static FCODE end[] = {"END_"};
- static FCODE plane[] = {"PLANE"};
- static FCODE m1[] = {"-1.0 "};
- static FCODE one[] = {" 1.0 "};
- static FCODE z[] = {" 0.0 "};
- static FCODE bnd_by[] = {" BOUNDED_BY\n"};
- static FCODE end_bnd[] = {" END_BOUND\n"};
- static FCODE inter[] = {"INTERSECTION\n"};
- #ifndef XFRACT
- static char fmt[] = " %Fs <%Fs%Fs%Fs> % #4.3f %Fs%Fs\n";
- #else
- static char fmt[] = " %s <%s%s%s> % #4.3f %s%s\n";
- #endif
- static char dxf_begin[] =
- {" 0\nSECTION\n 2\nTABLES\n 0\nTABLE\n 2\nLAYER\n\
- 70\n 2\n 0\nLAYER\n 2\n0\n 70\n 0\n 62\n 7\n 6\nCONTINUOUS\n\
- 0\nLAYER\n 2\nFRACTAL\n 70\n 64\n 62\n 1\n 6\nCONTINUOUS\n 0\n\
- ENDTAB\n 0\nENDSEC\n 0\nSECTION\n 2\nENTITIES\n"};
- static char dxf_3dface[] = {" 0\n3DFACE\n 8\nFRACTAL\n 62\n%3d\n"};
- static char dxf_vertex[] = {"%3d\n%g\n"};
- static char dxf_end[] = {" 0\nENDSEC\n 0\nEOF\n"};
- static FCODE composite[] = {"COMPOSITE"};
- static FCODE object[] = {"OBJECT"};
- static FCODE triangle[] = {"TRIANGLE "};
- static FCODE l_tri[] = {"triangle"};
- static FCODE texture[] = {"TEXTURE\n"};
- /* static FCODE end_texture[] = {" END_TEXTURE\n"}; */
- static FCODE red[] = {"RED"};
- static FCODE green[] = {"GREEN"};
- static FCODE blue[] = {"BLUE"};
- static FCODE frac_texture[] = {" AMBIENT 0.25 DIFFUSE 0.75"};
- static FCODE polygon[] = {"polygon={points=3;"};
- static FCODE vertex[] = {" vertex = "};
- static FCODE d_vert[] = {" <"};
- static char f1[] = "% #4.4f ";
- /* EB & DG: changed this to much better values */
- static FCODE grid[] =
- {"screen 640 480\neyep 0 2.1 0.8\nlookp 0 0 -0.95\nlight 1 point -2 1 1.5\n"};
- static FCODE grid2[] = {"background .3 0 0\nreport verbose\n"};
-
- static char s_n[] = "\n";
- static char f2[] = "R%dC%d R%dC%d\n";
- static FCODE ray_comment1[] =
- {"/* make a gridded aggregate. this size grid is fast for landscapes. */\n"};
- static FCODE ray_comment2[] =
- {"/* make z grid = 1 always for landscapes. */\n\n"};
- static FCODE grid3[] = {"grid 33 25 1\n"};
-
- static int _fastcall RAY_Header(void)
- {
- /* Open the ray tracing output file */
- check_writefile(ray_name, ".ray");
- if ((File_Ptr1 = fopen(ray_name, "w")) == NULL)
- return (-1); /* Oops, somethings wrong! */
-
- if (RAY == 2)
- fprintf(File_Ptr1, "//");
- if (RAY == 4)
- fprintf(File_Ptr1, "#");
- if (RAY == 5)
- fprintf(File_Ptr1, "/*\n");
- if (RAY == 6)
- fprintf(File_Ptr1, "--");
- if (RAY == 7)
- fprintf(File_Ptr1, dxf_begin);
-
- if (RAY != 7)
- fprintf(File_Ptr1, banner, (char far *)s3, release / 100., (char far *)s3a);
-
- if (RAY == 5)
- fprintf(File_Ptr1, "*/\n");
-
-
- /* Set the default color */
- if (RAY == 1)
- {
- fprintf(File_Ptr1, s_f, (char far *)declare, (char far *)frac_default);
- fprintf(File_Ptr1, " = ");
- fprintf(File_Ptr1, s_f, (char far *)s_color, (char far *)dflt);
- }
- if (BRIEF)
- {
- if (RAY == 2)
- {
- fprintf(File_Ptr1, s_f, (char far *)surf, (char far *)d_color);
- fprintf(File_Ptr1, ";}\n");
- }
- if (RAY == 4)
- {
- fprintf(File_Ptr1, "f ");
- fprintf(File_Ptr1, s_f, (char far *)d_color, (char far *)r_surf);
- }
- if (RAY == 5)
- fprintf(File_Ptr1, s_f, (char far *)rs_surf, (char far *)d_color);
- }
- if (RAY != 7)
- fprintf(File_Ptr1, s_n);
-
- /* EB & DG: open "grid" opject, a speedy way to do aggregates in rayshade */
- if (RAY == 5)
- fprintf(File_Ptr1, s_fff, (char far *)ray_comment1, (char far *)ray_comment2, (char far *)grid3);
-
- if (RAY == 6)
- #ifndef XFRACT
- fprintf(File_Ptr1, "%Fs", (char far *)acro_s1);
- #else
- fprintf(File_Ptr1, "%s", acro_s1);
- #endif
-
- return (0);
- }
-
-
- /********************************************************************/
- /* */
- /* This routine describes the triangle to the ray tracer, it */
- /* sets the color of the triangle to the average of the color */
- /* of its verticies and sets the light parameters to arbitrary */
- /* values. */
- /* */
- /* Note: numcolors (number of colors in the source */
- /* file) is used instead of colors (number of colors avail. with */
- /* display) so you can generate ray trace files with your LCD */
- /* or monochrome display */
- /* */
- /********************************************************************/
-
- static int _fastcall out_triangle(struct f_point pt1, struct f_point pt2, struct f_point pt3, int c1, int c2, int c3)
- {
- int i, j;
- float c[3];
- float pt_t[3][3];
-
- /* Normalize each vertex to screen size and adjust coordinate system */
- pt_t[0][0] = 2 * pt1.x / xdots - 1;
- pt_t[0][1] = (2 * pt1.y / ydots - 1);
- pt_t[0][2] = -2 * pt1.color / numcolors - 1;
- pt_t[1][0] = 2 * pt2.x / xdots - 1;
- pt_t[1][1] = (2 * pt2.y / ydots - 1);
- pt_t[1][2] = -2 * pt2.color / numcolors - 1;
- pt_t[2][0] = 2 * pt3.x / xdots - 1;
- pt_t[2][1] = (2 * pt3.y / ydots - 1);
- pt_t[2][2] = -2 * pt3.color / numcolors - 1;
-
- /* Color of triangle is average of colors of its verticies */
- if (!BRIEF)
- for (i = 0; i <= 2; i++)
- c[i] = (float) (dacbox[c1][i] + dacbox[c2][i] + dacbox[c3][i])
- / (3 * 63);
-
- /* get rid of degenerate triangles: any two points equal */
- if ((pt_t[0][0] == pt_t[1][0] &&
- pt_t[0][1] == pt_t[1][1] &&
- pt_t[0][2] == pt_t[1][2]) ||
-
- (pt_t[0][0] == pt_t[2][0] &&
- pt_t[0][1] == pt_t[2][1] &&
- pt_t[0][2] == pt_t[2][2]) ||
-
- (pt_t[2][0] == pt_t[1][0] &&
- pt_t[2][1] == pt_t[1][1] &&
- pt_t[2][2] == pt_t[1][2]))
- return (0);
-
- /* Describe the triangle */
- #ifndef XFRACT
- if (RAY == 1)
- fprintf(File_Ptr1, " %Fs\n %Fs", (char far *)object, (char far *)triangle);
- if (RAY == 2 && !BRIEF)
- fprintf(File_Ptr1, "%Fs", (char far *)surf);
- #else
- if (RAY == 1)
- fprintf(File_Ptr1, " %s\n %s", object, triangle);
- if (RAY == 2 && !BRIEF)
- fprintf(File_Ptr1, "%s", surf);
- #endif
- if (RAY == 4 && !BRIEF)
- fprintf(File_Ptr1, "f");
- if (RAY == 5 && !BRIEF)
- #ifndef XFRACT
- fprintf(File_Ptr1, "%Fs", (char far *)rs_surf);
- #else
- fprintf(File_Ptr1, "%s", rs_surf);
- #endif
-
- if (!BRIEF && RAY != 1 && RAY != 7)
- for (i = 0; i <= 2; i++)
- fprintf(File_Ptr1, f1, c[i]);
-
- if (RAY == 2)
- {
- if (!BRIEF)
- fprintf(File_Ptr1, ";}\n");
- #ifndef XFRACT
- fprintf(File_Ptr1, "%Fs", (char far *)polygon);
- #else
- fprintf(File_Ptr1, "%s", polygon);
- #endif
- }
- if (RAY == 4)
- {
- if (!BRIEF)
- #ifndef XFRACT
- fprintf(File_Ptr1, "%Fs", (char far *)r_surf);
- #else
- fprintf(File_Ptr1, "%s", r_surf);
- #endif
- fprintf(File_Ptr1, "p 3");
- }
- if (RAY == 5)
- {
- if (!BRIEF)
- fprintf(File_Ptr1, s_n);
- /* EB & DG: removed "T" after "triangle" */
- #ifndef XFRACT
- fprintf(File_Ptr1, "%Fs", (char far *)l_tri);
- #else
- fprintf(File_Ptr1, "%s", l_tri);
- #endif
- }
-
- if (RAY == 7)
- fprintf(File_Ptr1, dxf_3dface, min(255, max(1, c1)));
-
- for (i = 0; i <= 2; i++) /* Describe each Vertex */
- {
- if (RAY != 7)
- fprintf(File_Ptr1, s_n);
-
- #ifndef XFRACT
- if (RAY == 1)
- fprintf(File_Ptr1, "%Fs", (char far *)d_vert);
- if (RAY == 2)
- fprintf(File_Ptr1, "%Fs", (char far *)vertex);
- #else
- if (RAY == 1)
- fprintf(File_Ptr1, "%s", d_vert);
- if (RAY == 2)
- fprintf(File_Ptr1, "%s", vertex);
- #endif
- if (RAY > 3 && RAY != 7)
- fprintf(File_Ptr1, " ");
-
- for (j = 0; j <= 2; j++)
- {
- if (RAY == 7)
- {
- /* write 3dface entity to dxf file */
- fprintf(File_Ptr1, dxf_vertex, 10 * (j + 1) + i, pt_t[i][j]);
- if (i == 2) /* 3dface needs 4 vertecies */
- fprintf(File_Ptr1, dxf_vertex, 10 * (j + 1) + i + 1,
- pt_t[i][j]);
- }
- else if (!(RAY == 4 || RAY == 5))
- fprintf(File_Ptr1, f1, pt_t[i][j]); /* Right handed */
- else
- fprintf(File_Ptr1, f1, pt_t[2 - i][j]); /* Left handed */
- }
-
- if (RAY == 1)
- fprintf(File_Ptr1, ">");
- if (RAY == 2)
- fprintf(File_Ptr1, ";");
- }
-
- if (RAY == 1)
- {
- #ifndef XFRACT
- fprintf(File_Ptr1, " %Fs%Fs\n", (char far *)end, (char far *)triangle);
- #else
- fprintf(File_Ptr1, " %s%s\n", end, triangle);
- #endif
- if (!BRIEF)
- {
- #ifndef XFRACT
- fprintf(File_Ptr1, " %Fs"
- " %Fs%Fs% #4.4f %Fs% #4.4f %Fs% #4.4f\n"
- "%Fs"
- " %Fs%Fs",
- #else
- fprintf(File_Ptr1,
- " %s %s%s% #4.4f %s% #4.4f %s% #4.4f\n%s %s%s",
- #endif
- (char far *)texture,
- (char far *)s_color,
- (char far *)red, c[0],
- (char far *)green, c[1],
- (char far *)blue, c[2],
- (char far *)frac_texture,
- (char far *)end,
- (char far *)texture);
- }
- #ifndef XFRACT
- fprintf(File_Ptr1, " %Fs%Fs %Fs%Fs",
- #else
- fprintf(File_Ptr1, " %s%s %s%s",
- #endif
- (char far *)s_color, (char far *)frac_default,
- (char far *)end, (char far *)object);
- triangle_bounds(pt_t); /* update bounding info */
- }
- if (RAY == 2)
- fprintf(File_Ptr1, "}");
- if (RAY == 3 && !BRIEF)
- fprintf(File_Ptr1, s_n);
-
- if (RAY != 7)
- fprintf(File_Ptr1, s_n);
-
- return (0);
- }
-
- /********************************************************************/
- /* */
- /* This routine calculates the min and max values of a triangle */
- /* for use in creating ray tracer data files. The values of min */
- /* and max x, y, and z are assumed to be global. */
- /* */
- /********************************************************************/
-
- static void _fastcall triangle_bounds(float pt_t[3][3])
- {
- int i, j;
-
- for (i = 0; i <= 2; i++)
- for (j = 0; j <= 2; j++)
- {
- if (pt_t[i][j] < min_xyz[j])
- min_xyz[j] = pt_t[i][j];
- if (pt_t[i][j] > max_xyz[j])
- max_xyz[j] = pt_t[i][j];
- }
- return;
- }
-
- /********************************************************************/
- /* */
- /* This routine starts a composite object for ray trace data files */
- /* */
- /********************************************************************/
-
- static int _fastcall start_object(void)
- {
- if (RAY != 1)
- return (0);
-
- /* Reset the min/max values, for bounding box */
- min_xyz[0] = min_xyz[1] = min_xyz[2] = (float)999999.0;
- max_xyz[0] = max_xyz[1] = max_xyz[2] = (float)-999999.0;
-
- #ifndef XFRACT
- fprintf(File_Ptr1, "%Fs\n", (char far *)composite);
- #else
- fprintf(File_Ptr1, "%s\n", composite);
- #endif
- return (0);
- }
-
- /********************************************************************/
- /* */
- /* This routine adds a bounding box for the triangles drawn */
- /* in the last block and completes the composite object created. */
- /* It uses the globals min and max x,y and z calculated in */
- /* z calculated in Triangle_Bounds(). */
- /* */
- /********************************************************************/
-
- static int _fastcall end_object(int triout)
- {
- if (RAY == 7)
- return (0);
- if (RAY == 1)
- {
- if (triout)
- {
- /* Make sure the bounding box is slightly larger than the object */
- int i;
- for (i = 0; i <= 2; i++)
- {
- if (min_xyz[i] == max_xyz[i])
- {
- min_xyz[i] -= (float)0.01;
- max_xyz[i] += (float)0.01;
- }
- else
- {
- min_xyz[i] -= (max_xyz[i] - min_xyz[i]) * (float)0.01;
- max_xyz[i] += (max_xyz[i] - min_xyz[i]) * (float)0.01;
- }
- }
-
- /* Add the bounding box info */
- #ifndef XFRACT
- fprintf(File_Ptr1, "%Fs %Fs", (char far *)bnd_by, (char far *)inter);
- #else
- fprintf(File_Ptr1, "%s %s", bnd_by, inter);
- #endif
- fprintf(File_Ptr1, fmt, (char far *)plane, (char far *)m1, (char far *)z, (char far *)z, -min_xyz[0], (char far *)end, (char far *)plane);
- fprintf(File_Ptr1, fmt, (char far *)plane, (char far *)one, (char far *)z, (char far *)z, max_xyz[0], (char far *)end, (char far *)plane);
- fprintf(File_Ptr1, fmt, (char far *)plane, (char far *)z, (char far *)m1, (char far *)z, -min_xyz[1], (char far *)end, (char far *)plane);
- fprintf(File_Ptr1, fmt, (char far *)plane, (char far *)z, (char far *)one, (char far *)z, max_xyz[1], (char far *)end, (char far *)plane);
- fprintf(File_Ptr1, fmt, (char far *)plane, (char far *)z, (char far *)z, (char far *)m1, -min_xyz[2], (char far *)end, (char far *)plane);
- fprintf(File_Ptr1, fmt, (char far *)plane, (char far *)z, (char far *)z, (char far *)one, max_xyz[2], (char far *)end, (char far *)plane);
- #ifndef XFRACT
- fprintf(File_Ptr1, " %Fs%Fs%Fs", (char far *)end,
- (char far *)inter, (char far *)end_bnd);
- #else
- fprintf(File_Ptr1, " %s%s%s", end, inter, end_bnd);
- #endif
- }
-
- /* Complete the composite object statement */
- #ifndef XFRACT
- fprintf(File_Ptr1, "%Fs%Fs\n", (char far *)end, (char far *)composite);
- #else
- fprintf(File_Ptr1, "%s%s\n", end, composite);
- #endif
- }
-
- if (RAY != 6 && RAY != 5)
- fprintf(File_Ptr1, s_n); /* EB & DG: too many newlines */
-
- return (0);
- }
-
- static void line3d_cleanup(void)
- {
- int i, j;
- if (RAY && File_Ptr1)
- { /* Finish up the ray tracing files */
- static FCODE n_ta[] = {"{ No. Of Triangles = "};
- if (RAY != 5 && RAY != 7)
- fprintf(File_Ptr1, s_n); /* EB & DG: too many newlines */
- if (RAY == 2)
- fprintf(File_Ptr1, "\n\n//");
- if (RAY == 4)
- fprintf(File_Ptr1, "\n\n#");
-
- if (RAY == 5)
- #ifndef XFRACT
- /* EB & DG: end grid aggregate */
- fprintf(File_Ptr1, "end\n\n/*good landscape:*/\n%Fs%Fs\n/*",
- (char far *)grid, (char far *)grid2);
- #else
- /* EB & DG: end grid aggregate */
- fprintf(File_Ptr1, "end\n\n/*good landscape:*/\n%s%s\n/*",
- grid, grid2);
- #endif
- if (RAY == 6)
- {
- #ifndef XFRACT
- fprintf(File_Ptr1, "%Fs", (char far *)acro_s2);
- #else
- fprintf(File_Ptr1, "%s", acro_s2);
- #endif
- for (i = 0; i < RO; i++)
- for (j = 0; j <= CO_MAX; j++)
- {
- if (j < CO_MAX)
- fprintf(File_Ptr1, f2, i, j, i, j + 1);
- if (i < RO - 1)
- fprintf(File_Ptr1, f2, i, j, i + 1, j);
- if (i && i < RO && j < CO_MAX)
- fprintf(File_Ptr1, f2, i, j, i - 1, j + 1);
- }
- fprintf(File_Ptr1, "\n\n--");
- }
- if (RAY != 7)
- #ifndef XFRACT
- fprintf(File_Ptr1, "%Fs%ld }*/\n\n", (char far *)n_ta, num_tris);
- #else
- fprintf(File_Ptr1, "%s%ld }*/\n\n", n_ta, num_tris);
- #endif
- if (RAY == 7)
- fprintf(File_Ptr1, dxf_end);
- fclose(File_Ptr1);
- File_Ptr1 = NULL;
- }
- if (Targa_Out)
- { /* Finish up targa files */
- T_header_24 = 18; /* Reset Targa header size */
- enddisk();
- if (!debugflag && T_Safe && !error && Targa_Overlay)
- {
- remove(light_name);
- rename(targa_temp, light_name);
- }
- if (!debugflag && Targa_Overlay)
- remove(targa_temp);
- }
- usr_floatflag &= 1; /* strip second bit */
- error = T_Safe = 0;
- }
-
- static int first_time(int linelen, VECTOR v)
- {
- int err;
- MATRIX lightm; /* m w/no trans, keeps obj. on screen */
- float twocosdeltatheta;
- double xval, yval, zval; /* rotation values */
- /* corners of transformed xdotx by ydots x colors box */
- double xmin, ymin, zmin, xmax, ymax, zmax;
- int i, j;
- double v_length;
- VECTOR origin, direct, tmp;
- float theta, theta1, theta2; /* current,start,stop latitude */
- float phi1, phi2; /* current start,stop longitude */
- float deltatheta; /* increment of latitude */
- outln_cleanup = line3d_cleanup;
-
- calctime = evenoddrow = 0;
- /* mark as in-progress, and enable <tab> timer display */
- calc_status = 1;
-
- IAmbient = (unsigned int) (255 * (float) (100 - Ambient) / 100.0);
- if (IAmbient < 1)
- IAmbient = 1;
-
- num_tris = 0;
-
- /* Open file for RAY trace output and write header */
- if (RAY)
- {
- RAY_Header();
- xxadjust = yyadjust = 0; /* Disable shifting in ray tracing */
- xshift = yshift = 0;
- }
-
- CO_MAX = CO = RO = 0;
-
- upr_lwr[0] = (BYTE)(xdots & 0xff);
- upr_lwr[1] = (BYTE)(xdots >> 8);
- upr_lwr[2] = (BYTE)(ydots & 0xff);
- upr_lwr[3] = (BYTE)(ydots >> 8);
- line_length1 = 3 * xdots; /* line length @ 3 bytes per pixel */
- error = 0;
-
- if (whichimage < 2)
- T_Safe = 0; /* Not safe yet to mess with the source image */
-
- if (Targa_Out && !((glassestype == 1 || glassestype == 2)
- && whichimage == 2))
- {
- if (Targa_Overlay)
- {
- /* Make sure target file is a supportable Targa File */
- if (targa_validate(light_name))
- return (-1);
- }
- else
- {
- check_writefile(light_name, ".tga");
- if (startdisk1(light_name, NULL, 0)) /* Open new file */
- return (-1);
- }
- }
-
- rand_factor = 14 - RANDOMIZE;
-
- zcoord = filecolors;
-
- if((err=line3dmem()) != 0)
- return(err);
-
-
- /* get scale factors */
- sclx = XSCALE / 100.0;
- scly = YSCALE / 100.0;
- if (ROUGH)
- sclz = -ROUGH / 100.0;
- else
- rscale = sclz = -0.0001; /* if rough=0 make it very flat but plot
- * something */
-
- /* aspect ratio calculation - assume screen is 4 x 3 */
- aspect = (double) xdots *.75 / (double) ydots;
-
- if (SPHERE == FALSE) /* skip this slow stuff in sphere case */
- {
- /*********************************************************************/
- /* What is done here is to create a single matrix, m, which has */
- /* scale, rotation, and shift all combined. This allows us to use */
- /* a single matrix to transform any point. Additionally, we create */
- /* two perspective vectors. */
- /* */
- /* Start with a unit matrix. Add scale and rotation. Then calculate */
- /* the perspective vectors. Finally add enough translation to center */
- /* the final image plus whatever shift the user has set. */
- /*********************************************************************/
-
- /* start with identity */
- identity(m);
- identity(lightm);
-
- /* translate so origin is in center of box, so that when we rotate */
- /* it, we do so through the center */
- trans((double) xdots / (-2.0), (double) ydots / (-2.0),
- (double) zcoord / (-2.0), m);
- trans((double) xdots / (-2.0), (double) ydots / (-2.0),
- (double) zcoord / (-2.0), lightm);
-
- /* apply scale factors */
- scale(sclx, scly, sclz, m);
- scale(sclx, scly, sclz, lightm);
-
- /* rotation values - converting from degrees to radians */
- xval = XROT / 57.29577;
- yval = YROT / 57.29577;
- zval = ZROT / 57.29577;
-
- if (RAY)
- {
- xval = yval = zval = 0;
- }
-
- xrot(xval, m);
- xrot(xval, lightm);
- yrot(yval, m);
- yrot(yval, lightm);
- zrot(zval, m);
- zrot(zval, lightm);
-
- /* Find values of translation that make all x,y,z negative */
- /* m current matrix */
- /* 0 means don't show box */
- /* returns minimum and maximum values of x,y,z in fractal */
- corners(m, 0, &xmin, &ymin, &zmin, &xmax, &ymax, &zmax);
- }
-
- /* perspective 3D vector - lview[2] == 0 means no perspective */
-
- /* set perspective flag */
- persp = 0;
- if (ZVIEWER != 0)
- {
- persp = 1;
- if (ZVIEWER < 80) /* force float */
- usr_floatflag |= 2; /* turn on second bit */
- }
-
- /* set up view vector, and put viewer in center of screen */
- lview[0] = xdots >> 1;
- lview[1] = ydots >> 1;
-
- /* z value of user's eye - should be more negative than extreme negative
- * part of image */
- if (SPHERE) /* sphere case */
- lview[2] = -(long) ((double) ydots * (double) ZVIEWER / 100.0);
- else /* non-sphere case */
- lview[2] = (long) ((zmin - zmax) * (double) ZVIEWER / 100.0);
-
- view[0] = lview[0];
- view[1] = lview[1];
- view[2] = lview[2];
- lview[0] = lview[0] << 16;
- lview[1] = lview[1] << 16;
- lview[2] = lview[2] << 16;
-
- if (SPHERE == FALSE) /* sphere skips this */
- {
- /* translate back exactly amount we translated earlier plus enough to
- * center image so maximum values are non-positive */
- trans(((double) xdots - xmax - xmin) / 2,
- ((double) ydots - ymax - ymin) / 2, -zmax, m);
-
- /* Keep the box centered and on screen regardless of shifts */
- trans(((double) xdots - xmax - xmin) / 2,
- ((double) ydots - ymax - ymin) / 2, -zmax, lightm);
-
- trans((double) (xshift), (double) (-yshift), 0.0, m);
-
- /* matrix m now contains ALL those transforms composed together !!
- * convert m to long integers shifted 16 bits */
- for (i = 0; i < 4; i++)
- for (j = 0; j < 4; j++)
- llm[i][j] = (long) (m[i][j] * 65536.0);
-
- }
- else
- /* sphere stuff goes here */
- {
- /* Sphere is on side - north pole on right. Top is -90 degrees
- * latitude; bottom 90 degrees */
-
- /* Map X to this LATITUDE range */
- theta1 = (float) (THETA1 * PI / 180.0);
- theta2 = (float) (THETA2 * PI / 180.0);
-
- /* Map Y to this LONGITUDE range */
- phi1 = (float) (PHI1 * PI / 180.0);
- phi2 = (float) (PHI2 * PI / 180.0);
-
- theta = theta1;
-
- /*********************************************************************/
- /* Thanks to Hugh Bray for the following idea: when calculating */
- /* a table of evenly spaced sines or cosines, only a few initial */
- /* values need be calculated, and the remaining values can be */
- /* gotten from a derivative of the sine/cosine angle sum formula */
- /* at the cost of one multiplication and one addition per value! */
- /* */
- /* This idea is applied once here to get a complete table for */
- /* latitude, and near the bottom of this routine to incrementally */
- /* calculate longitude. */
- /* */
- /* Precalculate 2*cos(deltaangle), sin(start) and sin(start+delta). */
- /* Then apply recursively: */
- /* sin(angle+2*delta) = sin(angle+delta) * 2cosdelta - sin(angle) */
- /* */
- /* Similarly for cosine. Neat! */
- /*********************************************************************/
-
- deltatheta = (float) (theta2 - theta1) / (float) linelen;
-
- /* initial sin,cos theta */
- sinthetaarray[0] = (float) sin((double) theta);
- costhetaarray[0] = (float) cos((double) theta);
- sinthetaarray[1] = (float) sin((double) (theta + deltatheta));
- costhetaarray[1] = (float) cos((double) (theta + deltatheta));
-
- /* sin,cos delta theta */
- twocosdeltatheta = (float) (2.0 * cos((double) deltatheta));
-
- /* build table of other sin,cos with trig identity */
- for (i = 2; i < (int) linelen; i++)
- {
- sinthetaarray[i] = sinthetaarray[i - 1] * twocosdeltatheta -
- sinthetaarray[i - 2];
- costhetaarray[i] = costhetaarray[i - 1] * twocosdeltatheta -
- costhetaarray[i - 2];
- }
-
- /* now phi - these calculated as we go - get started here */
- deltaphi = (float) (phi2 - phi1) / (float) height;
-
- /* initial sin,cos phi */
-
- sinphi = oldsinphi1 = (float) sin((double) phi1);
- cosphi = oldcosphi1 = (float) cos((double) phi1);
- oldsinphi2 = (float) sin((double) (phi1 + deltaphi));
- oldcosphi2 = (float) cos((double) (phi1 + deltaphi));
-
- /* sin,cos delta phi */
- twocosdeltaphi = (float) (2.0 * cos((double) deltaphi));
-
-
- /* affects how rough planet terrain is */
- if (ROUGH)
- rscale = .3 * ROUGH / 100.0;
-
- /* radius of planet */
- R = (double) (ydots) / 2;
-
- /* precalculate factor */
- rXrscale = R * rscale;
-
- sclz = sclx = scly = RADIUS / 100.0; /* Need x,y,z for RAY */
-
- /* adjust x scale factor for aspect */
- sclx *= aspect;
-
- /* precalculation factor used in sphere calc */
- Rfactor = rscale * R / (double) zcoord;
-
- if (persp) /* precalculate fudge factor */
- {
- double radius;
- double zview;
- double angle;
-
- xcenter = xcenter << 16;
- ycenter = ycenter << 16;
-
- Rfactor *= 65536.0;
- R *= 65536.0;
-
- /* calculate z cutoff factor attempt to prevent out-of-view surfaces
- * from being written */
- zview = -(long) ((double) ydots * (double) ZVIEWER / 100.0);
- radius = (double) (ydots) / 2;
- angle = atan(-radius / (zview + radius));
- zcutoff = -radius - sin(angle) * radius;
- zcutoff *= 1.1; /* for safety */
- zcutoff *= 65536L;
- }
- }
-
- /* set fill plot function */
- if (FILLTYPE != 3)
- fillplot = interpcolor;
- else
- {
- fillplot = clipcolor;
-
- if (transparent[0] || transparent[1])
- /* If transparent colors are set */
- fillplot = T_clipcolor;/* Use the transparent plot function */
- }
-
- /* Both Sphere and Normal 3D */
- direct[0] = light_direction[0] = XLIGHT;
- direct[1] = light_direction[1] = -YLIGHT;
- direct[2] = light_direction[2] = ZLIGHT;
-
- /* Needed because sclz = -ROUGH/100 and light_direction is transformed in
- * FILLTYPE 6 but not in 5. */
- if (FILLTYPE == 5)
- direct[2] = light_direction[2] = -ZLIGHT;
-
- if (FILLTYPE == 6) /* transform light direction */
- {
- /* Think of light direction as a vector with tail at (0,0,0) and head
- * at (light_direction). We apply the transformation to BOTH head and
- * tail and take the difference */
-
- v[0] = 0.0;
- v[1] = 0.0;
- v[2] = 0.0;
- vmult(v, m, v);
- vmult(light_direction, m, light_direction);
-
- for (i = 0; i < 3; i++)
- light_direction[i] -= v[i];
- }
- normalize_vector(light_direction);
-
- if (preview && showbox)
- {
- normalize_vector(direct);
-
- /* move light vector to be more clear with grey scale maps */
- origin[0] = (3 * xdots) / 16;
- origin[1] = (3 * ydots) / 4;
- if (FILLTYPE == 6)
- origin[1] = (11 * ydots) / 16;
-
- origin[2] = 0.0;
-
- v_length = min(xdots, ydots) / 2;
- if (persp && ZVIEWER <= P)
- v_length *= (long) (P + 600) / ((long) (ZVIEWER + 600) * 2);
-
- /* Set direct[] to point from origin[] in direction of untransformed
- * light_direction (direct[]). */
- for (i = 0; i < 3; i++)
- direct[i] = origin[i] + direct[i] * v_length;
-
- /* center light box */
- for (i = 0; i < 2; i++)
- {
- tmp[i] = (direct[i] - origin[i]) / 2;
- origin[i] -= tmp[i];
- direct[i] -= tmp[i];
- }
-
- /* Draw light source vector and box containing it, draw_light_box will
- * transform them if necessary. */
- draw_light_box(origin, direct, lightm);
- /* draw box around original field of view to help visualize effect of
- * rotations 1 means show box - xmin etc. do nothing here */
- if (!SPHERE)
- corners(m, 1, &xmin, &ymin, &zmin, &xmax, &ymax, &zmax);
- }
-
- /* bad has values caught by clipping */
- f_bad.x = bad.x = bad_value;
- f_bad.y = bad.y = bad_value;
- f_bad.color = bad.color = bad_value;
- for (i = 0; i < (int) linelen; i++)
- {
- lastrow[i] = bad;
- f_lastrow[i] = f_bad;
- }
- got_status = 3;
- if (iit > 0)
- {
- load_mat(m); /* load matrix into iit registers */
- mult_vec = mult_vec_iit;
- }
- else
- mult_vec = mult_vec_c;
- return (0);
- } /* end of once-per-image intializations */
-
- /*
- This pragma prevents optimizer failure in MSC/C++ 7.0. Program compiles ok
- without pragma, but error message is real ugly, paraphrasing loosely,
- something like "optimizer screwed up big time, call Bill Gates collect ...
- (Note: commented out pragma because we removed the compiler "/Og" option
- in MAKEFRACT.BAT - left these notes as a warning...
- */
- #ifdef _MSC_VER
- #if (_MSC_VER >= 600)
- /* #pragma optimize( "g", off ) */
- #endif
- #endif
-
- static int line3dmem(void)
- {
- /*********************************************************************/
- /* Memory allocation - assumptions - a 64K segment starting at */
- /* extraseg has been grabbed. It may have other purposes elsewhere, */
- /* but it is assumed that it is totally free for use here. Our */
- /* strategy is to assign all the far pointers needed here to various*/
- /* spots in the extra segment, depending on the pixel dimensions of */
- /* the video mode, and check whether we have run out. There is */
- /* basically one case where the extra segment is not big enough */
- /* -- SPHERE mode with a fill type that uses putatriangle() (array */
- /* minmax_x) at the largest legal resolution of MAXPIXELSxMAXPIXELS */
- /* or thereabouts. In that case we use farmemalloc to grab memory */
- /* for minmax_x. This memory is never freed. */
- /*********************************************************************/
- long check_extra; /* keep track ofd extraseg array use */
-
- /* lastrow stores the previous row of the original GIF image for
- the purpose of filling in gaps with triangle procedure */
- /* first 8k of extraseg now used in decoder TW 3/95 */
- lastrow = MK_FP(extraseg, 0);
-
- check_extra = sizeof(*lastrow) * xdots;
- if (SPHERE)
- {
- sinthetaarray = (float far *) (lastrow + xdots);
- check_extra += sizeof(*sinthetaarray) * xdots;
- costhetaarray = (float far *) (sinthetaarray + xdots);
- check_extra += sizeof(*costhetaarray) * xdots;
- f_lastrow = (struct f_point far *) (costhetaarray + xdots);
- }
- else
- f_lastrow = (struct f_point far *) (lastrow + xdots);
- check_extra += sizeof(*f_lastrow) * (xdots);
- if (pot16bit)
- {
- fraction = (BYTE far *) (f_lastrow + xdots);
- check_extra += sizeof(*fraction) * xdots;
- }
- minmax_x = (struct minmax *) NULL;
-
- /* these fill types call putatriangle which uses minmax_x */
- if (FILLTYPE == 2 || FILLTYPE == 3 || FILLTYPE == 5 || FILLTYPE == 6)
- {
- /* end of arrays if we use extra segement */
- check_extra += sizeof(struct minmax) * ydots;
- if (check_extra > (1L << 16)) /* run out of extra segment? */
- {
- static FCODE msg[] = {"farmemalloc minmax"};
- static struct minmax far *got_mem = NULL;
- if(debugflag == 2222)
- stopmsg(0,msg);
- /* not using extra segment so decrement check_extra */
- check_extra -= sizeof(struct minmax) * ydots;
- if (got_mem == NULL)
- got_mem = (struct minmax far *) (farmemalloc(MAXPIXELS *
- sizeof(struct minmax)));
- if (got_mem)
- minmax_x = got_mem;
- else
- return (-1);
- }
- else /* ok to use extra segment */
- {
- if (pot16bit)
- minmax_x = (struct minmax far *) (fraction + xdots);
- else
- minmax_x = (struct minmax far *) (f_lastrow + xdots);
- }
- }
- if (debugflag == 2222 || check_extra > (1L << 16))
- {
- char tmpmsg[70];
- static FCODE extramsg[] = {" of extra segment"};
- #ifndef XFRACT
- sprintf(tmpmsg, "used %ld%Fs", check_extra, (char far *)extramsg);
- #else
- sprintf(tmpmsg, "used %ld%s", check_extra, extramsg);
- #endif
- stopmsg(4, tmpmsg);
- }
- return(0);
- }
-
- #ifdef _MSC_VER
- #if (_MSC_VER >= 600)
- #pragma optimize( "g", on )
- #endif
- #endif
-
-