1 /************************************************************************/
2 /* This file contains a 3D replacement for the out_line function called */
3 /* by the decoder. The purpose is to apply various 3D transformations   */
4 /* before displaying points. Called once per line of the input file.    */
5 /*                                                                      */
6 /* Original Author Tim Wegner, with extensive help from Marc Reinig.    */
7 /*    July 1994 - TW broke out several pieces of code and added pragma  */
8 /*                to eliminate compiler warnings. Did a long-overdue    */
9 /*                formatting cleanup.                                   */
10 /************************************************************************/
11 
12 #include <limits.h>
13 
14   /* see Fractint.c for a description of the "include"  hierarchy */
15 #include "port.h"
16 #include "prototyp.h"
17 
18 struct point
19 {
20    int x;
21    int y;
22    int color;
23 };
24 
25 struct f_point
26 {
27    float x;
28    float y;
29    float color;
30 };
31 
32 struct minmax
33 {
34    int minx;
35    int maxx;
36 };
37 
38 /* routines in this module */
39 int line3d(BYTE *, unsigned);
40 int _fastcall targa_color(int, int, int);
41 int targa_validate(char *);
42 static int first_time(int, VECTOR);
43 static int H_R(BYTE *, BYTE *, BYTE *, unsigned long, unsigned long, unsigned long);
44 static int line3dmem(void);
45 static int R_H(BYTE, BYTE, BYTE, unsigned long *, unsigned long *, unsigned long *);
46 static int set_pixel_buff(BYTE *, BYTE far *, unsigned);
47 int startdisk1(char *, FILE *, int);
48 static void set_upr_lwr(void);
49 static int _fastcall end_object(int);
50 static int _fastcall offscreen(struct point);
51 static int _fastcall out_triangle(struct f_point, struct f_point, struct f_point, int, int, int);
52 static int _fastcall RAY_Header(void);
53 static int _fastcall start_object(void);
54 static void corners(MATRIX, int, double *, double *, double *, double *, double *, double *);
55 static void draw_light_box(double *, double *, MATRIX);
56 static void draw_rect(VECTOR, VECTOR, VECTOR, VECTOR, int, int);
57 static void File_Error(char *, int);
58 static void line3d_cleanup(void);
59 static void _fastcall clipcolor(int, int, int);
60 static void _fastcall interpcolor(int, int, int);
61 static void _fastcall putatriangle(struct point, struct point, struct point, int);
62 static void _fastcall putminmax(int, int, int);
63 static void _fastcall triangle_bounds(float pt_t[3][3]);
64 static void _fastcall T_clipcolor(int, int, int);
65 static void _fastcall vdraw_line(double *, double *, int color);
66 static void (_fastcall * fillplot) (int, int, int);
67 static void (_fastcall * normalplot) (int, int, int);
68 
69 /* static variables */
70 static float deltaphi;          /* increment of latitude, longitude */
71 static double rscale;           /* surface roughness factor */
72 static long xcenter, ycenter;   /* circle center */
73 static double sclx, scly, sclz; /* scale factors */
74 static double R;                /* radius values */
75 static double Rfactor;          /* for intermediate calculation */
76 static LMATRIX llm;             /* "" */
77 static LVECTOR lview;           /* for perspective views */
78 static double zcutoff;          /* perspective backside cutoff value */
79 static float twocosdeltaphi;
80 static float cosphi, sinphi;    /* precalculated sin/cos of longitude */
81 static float oldcosphi1, oldsinphi1;
82 static float oldcosphi2, oldsinphi2;
83 static BYTE far *fraction;      /* float version of pixels array */
84 static float min_xyz[3], max_xyz[3];        /* For Raytrace output */
85 static int line_length1;
86 static int T_header_24 = 18;/* Size of current Targa-24 header */
87 static FILE *File_Ptr1 = NULL;
88 static unsigned int IAmbient;
89 static int rand_factor;
90 static int HAZE_MULT;
91 static void File_Error(char *File_Name1, int ERROR);
92 static BYTE T24 = 24;
93 static BYTE T32 = 32;
94 static BYTE upr_lwr[4];
95 static int T_Safe; /* Original Targa Image successfully copied to targa_temp */
96 static VECTOR light_direction;
97 static BYTE Real_Color;  /* Actual color of cur pixel */
98 static int RO, CO, CO_MAX;  /* For use in Acrospin support */
99 static FCODE acro_s1[] =
100    {"Set Layer 1\nSet Color 2\nEndpointList X Y Z Name\n"};
101 static FCODE acro_s2[] = {"LineList From To\n"};
102 static FCODE s3[] = {"{ Created by FRACTINT Ver. "};
103 static FCODE s3a[] = {" }\n\n"};
104 #ifndef XFRACT
105 static char banner[] = "%Fs%#4.2f%Fs";
106 #else
107 static char banner[] = "%s%#4.2f%s";
108 #endif
109 static int localpreviewfactor;
110 static int zcoord = 256;
111 static double aspect;       /* aspect ratio */
112 static int evenoddrow;
113 static float far *sinthetaarray;    /* all sine thetas go here  */
114 static float far *costhetaarray;    /* all cosine thetas go here */
115 static double rXrscale;     /* precalculation factor */
116 static int persp;  /* flag for indicating perspective transformations */
117 static struct point p1, p2, p3;
118 static struct f_point f_bad;/* out of range value */
119 static struct point bad;    /* out of range value */
120 static long num_tris; /* number of triangles output to ray trace file */
121 
122 /* global variables defined here */
123 struct f_point far *f_lastrow;
124 void (_fastcall * standardplot) (int, int, int);
125 MATRIX m; /* transformation matrix */
126 int Ambient;
127 int RANDOMIZE;
128 int haze;
129 int Real_V = 0; /* mrr Actual value of V for fillytpe>4 monochrome images */
130 char light_name[FILE_MAX_PATH] = "fract001";
131 int Targa_Overlay, error;
132 char targa_temp[MAX_NAME] = "fractemp.tga";
133 int P = 250; /* Perspective dist used when viewing light vector */
134 BYTE back_color[3];
135 char ray_name[FILE_MAX_PATH] = "fract001";
136 char preview = 0;
137 char showbox = 0;
138 int previewfactor = 20;
139 int xadjust = 0;
140 int yadjust = 0;
141 int xxadjust;
142 int yyadjust;
143 int xshift;
144 int yshift;
145 int bad_value = -10000; /* set bad values to this */
146 int bad_check = -3000;  /* check values against this to determine if good */
147 struct point far *lastrow; /* this array remembers the previous line */
148 int RAY = 0;        /* Flag to generate Ray trace compatible files in 3d */
149 int BRIEF = 0;      /* 1 = short ray trace files */
150 
151 /* array of min and max x values used in triangle fill */
152 struct minmax far *minmax_x;
153 VECTOR view;                /* position of observer for perspective */
154 VECTOR cross;
155 VECTOR tmpcross;
156 
157 struct point oldlast = { 0, 0, 0 }; /* old pixels */
158 
159 
line3d(BYTE * pixels,unsigned linelen)160 int line3d(BYTE * pixels, unsigned linelen)
161 {
162    int tout;                    /* triangle has been sent to ray trace file */
163    int RND;
164    float f_water = (float)0.0;        /* transformed WATERLINE for ray trace files */
165    double r0;
166    int xcenter0 = 0;
167    int ycenter0 = 0;      /* Unfudged versions */
168    double r;                    /* sphere radius */
169    float costheta, sintheta;    /* precalculated sin/cos of latitude */
170    int next;                    /* used by preview and grid */
171    int col;                     /* current column (original GIF) */
172    struct point cur;            /* current pixels */
173    struct point old;            /* old pixels */
174    struct f_point f_cur;
175    struct f_point f_old;
176    VECTOR v;                    /* double vector */
177    VECTOR v1, v2;
178    VECTOR crossavg;
179    char crossnotinit;           /* flag for crossavg init indication */
180    LVECTOR lv;                  /* long equivalent of v */
181    LVECTOR lv0;                 /* long equivalent of v */
182    int lastdot;
183    long fudge;
184 
185    fudge = 1L << 16;
186 
187 
188    if (transparent[0] || transparent[1])
189       plot = normalplot = T_clipcolor;  /* Use transparent plot function */
190    else                         /* Use the usual FRACTINT plot function with
191                                  * clipping */
192       plot = normalplot = clipcolor;
193 
194    currow = rowcount;           /* use separate variable to allow for
195                                  * pot16bit files */
196    if (pot16bit)
197       currow >>= 1;
198 
199    /************************************************************************/
200    /* This IF clause is executed ONCE per image. All precalculations are   */
201    /* done here, with out any special concern about speed. DANGER -        */
202    /* communication with the rest of the program is generally via static   */
203    /* or global variables.                                                 */
204    /************************************************************************/
205    if (rowcount++ == 0)
206    {
207       int err;
208       if ((err = first_time(linelen, v)) != 0)
209          return (err);
210       if(xdots > OLDMAXPIXELS)
211          return(-1);
212       tout = 0;
213       crossavg[0] = 0;
214       crossavg[1] = 0;
215       crossavg[2] = 0;
216       xcenter0 = (int) (xcenter = xdots / 2 + xshift);
217       ycenter0 = (int) (ycenter = ydots / 2 - yshift);
218    }
219    /* make sure these pixel coordinates are out of range */
220    old = bad;
221    f_old = f_bad;
222 
223    /* copies pixels buffer to float type fraction buffer for fill purposes */
224    if (pot16bit)
225    {
226       if (set_pixel_buff(pixels, fraction, linelen))
227          return (0);
228    }
229    else if (grayflag)           /* convert color numbers to grayscale values */
230       for (col = 0; col < (int) linelen; col++)
231       {
232          int pal, colornum;
233          colornum = pixels[col];
234          /* effectively (30*R + 59*G + 11*B)/100 scaled 0 to 255 */
235          pal = ((int) dacbox[colornum][0] * 77 +
236                 (int) dacbox[colornum][1] * 151 +
237                 (int) dacbox[colornum][2] * 28);
238          pal >>= 6;
239          pixels[col] = (BYTE) pal;
240       }
241    crossnotinit = 1;
242    col = 0;
243 
244    CO = 0;
245 
246    /*************************************************************************/
247    /* This section of code allows the operation of a preview mode when the  */
248    /* preview flag is set. Enabled, it allows the drawing of only the first */
249    /* line of the source image, then every 10th line, until and including   */
250    /* the last line. For the undrawn lines, only necessary calculations are */
251    /* made. As a bonus, in non-sphere mode a box is drawn to help visualize */
252    /* the effects of 3D transformations. Thanks to Marc Reinig for this idea*/
253    /* and code -- BTW, Marc did NOT put the goto in, but WE did, to avoid   */
254    /* copying code here, and to avoid a HUGE "if-then" construct. Besides,  */
255    /* we have ALREADY sinned, so why not sin some more?                     */
256    /*************************************************************************/
257    lastdot = min(xdots - 1, (int) linelen - 1);
258    if (FILLTYPE >= 5)
259       if (haze && Targa_Out)
260       {
261          HAZE_MULT = (int) (haze * (
262                                       (float) ((long) (ydots - 1 - currow) *
263                                                (long) (ydots - 1 - currow)) /
264                         (float) ((long) (ydots - 1) * (long) (ydots - 1))));
265          HAZE_MULT = 100 - HAZE_MULT;
266       }
267 
268    if (previewfactor >= ydots || previewfactor > lastdot)
269       previewfactor = min(ydots - 1, lastdot);
270 
271    localpreviewfactor = ydots / previewfactor;
272 
273    tout = 0;
274    /* Insure last line is drawn in preview and filltypes <0  */
275    if ((RAY || preview || FILLTYPE < 0) && (currow != ydots - 1) &&
276        (currow % localpreviewfactor) && /* Draw mod preview lines */
277        !(!RAY && (FILLTYPE > 4) && (currow == 1)))
278       /* Get init geometry in lightsource modes */
279       goto reallythebottom;     /* skip over most of the line3d calcs */
280    if (dotmode == 11)
281    {
282       static FCODE mapping[] = {"mapping to 3d, reading line "};
283       char s[40];
284 #ifndef XFRACT
285       sprintf(s, "%Fs%d", (char far *)mapping, currow);
286 #else
287       sprintf(s, "%s%d", mapping, currow);
288 #endif
289       dvid_status(1, s);
290    }
291 
292    if (!col && RAY && currow != 0)
293       start_object();
294       /* PROCESS ROW LOOP BEGINS HERE */
295       while (col < (int) linelen)
296       {
297          if ((RAY || preview || FILLTYPE < 0) &&
298              (col != lastdot) &&/* if this is not the last col */
299          /* if not the 1st or mod factor col */
300              (col % (int) (aspect * localpreviewfactor)) &&
301              (!(!RAY && FILLTYPE > 4 && col == 1)))
302             goto loopbottom;
303 
304          f_cur.color = cur.color = Real_Color = pixels[col];
305 
306          if (RAY || preview || FILLTYPE < 0)
307          {
308             next = (int) (col + aspect * localpreviewfactor);
309             if (next == col)
310                next = col + 1;
311          }
312          else
313             next = col + 1;
314          if (next >= lastdot)
315             next = lastdot;
316 
317          if (cur.color > 0 && cur.color < WATERLINE)
318             f_cur.color = cur.color = Real_Color = (BYTE)WATERLINE; /* "lake" */
319          else if (pot16bit)
320             f_cur.color += ((float) fraction[col]) / (float) (1 << 8);
321 
322          if (SPHERE)            /* sphere case */
323          {
324             sintheta = sinthetaarray[col];
325             costheta = costhetaarray[col];
326 
327             if (sinphi < 0 && !(RAY || FILLTYPE < 0))
328             {
329                cur = bad;
330                f_cur = f_bad;
331                goto loopbottom; /* another goto ! */
332             }
333             /************************************************************/
334             /* KEEP THIS FOR DOCS - original formula --                 */
335             /* if(rscale < 0.0)                                         */
336             /* r = 1.0+((double)cur.color/(double)zcoord)*rscale;       */
337             /* else                                                     */
338             /* r = 1.0-rscale+((double)cur.color/(double)zcoord)*rscale;*/
339             /* R = (double)ydots/2;                                     */
340             /* r = r*R;                                                 */
341             /* cur.x = xdots/2 + sclx*r*sintheta*aspect + xup ;         */
342             /* cur.y = ydots/2 + scly*r*costheta*cosphi - yup ;         */
343             /************************************************************/
344 
345             if (rscale < 0.0)
346                r = R + Rfactor * (double) f_cur.color * costheta;
347             else if (rscale > 0.0)
348                r = R - rXrscale + Rfactor * (double) f_cur.color * costheta;
349             else
350                r = R;
351             /* Allow Ray trace to go through so display ok */
352             if (persp || RAY)
353             {  /* mrr how do lv[] and cur and f_cur all relate */
354                /* NOTE: fudge was pre-calculated above in r and R */
355                /* (almost) guarantee negative */
356                lv[2] = (long) (-R - r * costheta * sinphi);     /* z */
357                if ((lv[2] > zcutoff) && !FILLTYPE < 0)
358                {
359                   cur = bad;
360                   f_cur = f_bad;
361                   goto loopbottom;      /* another goto ! */
362                }
363                lv[0] = (long) (xcenter + sintheta * sclx * r);  /* x */
364                lv[1] = (long) (ycenter + costheta * cosphi * scly * r); /* y */
365 
366                if ((FILLTYPE >= 5) || RAY)
367                {     /* calculate illumination normal before persp */
368 
369                   r0 = r / 65536L;
370                   f_cur.x = (float) (xcenter0 + sintheta * sclx * r0);
371                   f_cur.y = (float) (ycenter0 + costheta * cosphi * scly * r0);
372                   f_cur.color = (float) (-r0 * costheta * sinphi);
373                }
374                if (!(usr_floatflag || RAY))
375                {
376                   if (longpersp(lv, lview, 16) == -1)
377                   {
378                      cur = bad;
379                      f_cur = f_bad;
380                      goto loopbottom;   /* another goto ! */
381                   }
382                   cur.x = (int) (((lv[0] + 32768L) >> 16) + xxadjust);
383                   cur.y = (int) (((lv[1] + 32768L) >> 16) + yyadjust);
384                }
385                if (usr_floatflag || overflow || RAY)
386                {
387                   v[0] = lv[0];
388                   v[1] = lv[1];
389                   v[2] = lv[2];
390                   v[0] /= fudge;
391                   v[1] /= fudge;
392                   v[2] /= fudge;
393                   perspective(v);
394                   cur.x = (int) (v[0] + .5 + xxadjust);
395                   cur.y = (int) (v[1] + .5 + yyadjust);
396                }
397             }
398             /* mrr Not sure how this an 3rd if above relate */
399             else if (!(persp && RAY))
400             {
401                /* mrr Why the xx- and yyadjust here and not above? */
402                cur.x = (int) (f_cur.x = (float) (xcenter
403                                  + sintheta * sclx * r + xxadjust));
404                cur.y = (int) (f_cur.y = (float) (ycenter
405                                  + costheta * cosphi * scly * r + yyadjust));
406                if (FILLTYPE >= 5 || RAY)        /* mrr why do we do this for
407                                                  * filltype>5? */
408                   f_cur.color = (float) (-r * costheta * sinphi * sclz);
409                v[0] = v[1] = v[2] = 0;  /* MRR Why do we do this? */
410             }
411          }
412          else
413             /* non-sphere 3D */
414          {
415             if (!usr_floatflag && !RAY)
416             {
417                if (FILLTYPE >= 5)       /* flag to save vector before
418                                          * perspective */
419                   lv0[0] = 1;   /* in longvmultpersp calculation */
420                else
421                   lv0[0] = 0;
422 
423                /* use 32-bit multiply math to snap this out */
424                lv[0] = col;
425                lv[0] = lv[0] << 16;
426                lv[1] = currow;
427                lv[1] = lv[1] << 16;
428                if (filetype || pot16bit)        /* don't truncate fractional
429                                                  * part */
430                   lv[2] = (long) (f_cur.color * 65536.0);
431                else
432                   /* there IS no fractaional part here! */
433                {
434                   lv[2] = (long) f_cur.color;
435                   lv[2] = lv[2] << 16;
436                }
437 
438                if (longvmultpersp(lv, llm, lv0, lv, lview, 16) == -1)
439                {
440                   cur = bad;
441                   f_cur = f_bad;
442                   goto loopbottom;
443                }
444 
445                cur.x = (int) (((lv[0] + 32768L) >> 16) + xxadjust);
446                cur.y = (int) (((lv[1] + 32768L) >> 16) + yyadjust);
447                if (FILLTYPE >= 5 && !overflow)
448                {
449                   f_cur.x = (float) lv0[0];
450                   f_cur.x /= (float)65536.0;
451                   f_cur.y = (float) lv0[1];
452                   f_cur.y /= (float)65536.0;
453                   f_cur.color = (float) lv0[2];
454                   f_cur.color /= (float)65536.0;
455                }
456             }
457 
458             if (usr_floatflag || overflow || RAY)
459                /* do in float if integer math overflowed or doing Ray trace */
460             {
461                /* slow float version for comparison */
462                v[0] = col;
463                v[1] = currow;
464                v[2] = f_cur.color;      /* Actually the z value */
465 
466                mult_vec(v);     /* matrix*vector routine */
467 
468                if (FILLTYPE > 4 || RAY)
469                {
470                   f_cur.x = (float) v[0];
471                   f_cur.y = (float) v[1];
472                   f_cur.color = (float) v[2];
473 
474                   if (RAY == 6)
475                   {
476                      f_cur.x = f_cur.x * ((float)2.0 / xdots) - (float)1.0;
477                      f_cur.y = f_cur.y * ((float)2.0 / ydots) - (float)1.0;
478                      f_cur.color = -f_cur.color * ((float)2.0 / numcolors) - (float)1.0;
479                   }
480                }
481 
482                if (persp && !RAY)
483                   perspective(v);
484                cur.x = (int) (v[0] + xxadjust + .5);
485                cur.y = (int) (v[1] + yyadjust + .5);
486 
487                v[0] = 0;
488                v[1] = 0;
489                v[2] = WATERLINE;
490                mult_vec(v);
491                f_water = (float) v[2];
492             }
493          }
494 
495          if (RANDOMIZE)
496             if (cur.color > WATERLINE)
497             {
498                RND = rand15() >> 8;     /* 7-bit number */
499                RND = RND * RND >> rand_factor;  /* n-bit number */
500 
501                if (rand() & 1)
502                   RND = -RND;   /* Make +/- n-bit number */
503 
504                if ((int) (cur.color) + RND >= colors)
505                   cur.color = colors - 2;
506                else if ((int) (cur.color) + RND <= WATERLINE)
507                   cur.color = WATERLINE + 1;
508                else
509                   cur.color = cur.color + RND;
510                Real_Color = (BYTE)cur.color;
511             }
512 
513          if (RAY)
514          {
515             if (col && currow &&
516                 old.x > bad_check &&
517                 old.x < (xdots - bad_check) &&
518                 lastrow[col].x > bad_check &&
519                 lastrow[col].y > bad_check &&
520                 lastrow[col].x < (xdots - bad_check) &&
521                 lastrow[col].y < (ydots - bad_check))
522             {
523                /* Get rid of all the triangles in the plane at the base of
524                 * the object */
525 
526                if (f_cur.color == f_water &&
527                    f_lastrow[col].color == f_water &&
528                    f_lastrow[next].color == f_water)
529                   goto loopbottom;
530 
531                if (RAY != 6)    /* Output the vertex info */
532                   out_triangle(f_cur, f_old, f_lastrow[col],
533                                cur.color, old.color, lastrow[col].color);
534 
535                tout = 1;
536 
537                draw_line(old.x, old.y, cur.x, cur.y, old.color);
538                draw_line(old.x, old.y, lastrow[col].x,
539                          lastrow[col].y, old.color);
540                draw_line(lastrow[col].x, lastrow[col].y,
541                          cur.x, cur.y, cur.color);
542                num_tris++;
543             }
544 
545             if (col < lastdot && currow &&
546                 lastrow[col].x > bad_check &&
547                 lastrow[col].y > bad_check &&
548                 lastrow[col].x < (xdots - bad_check) &&
549                 lastrow[col].y < (ydots - bad_check) &&
550                 lastrow[next].x > bad_check &&
551                 lastrow[next].y > bad_check &&
552                 lastrow[next].x < (xdots - bad_check) &&
553                 lastrow[next].y < (ydots - bad_check))
554             {
555                /* Get rid of all the triangles in the plane at the base of
556                 * the object */
557 
558                if (f_cur.color == f_water &&
559                    f_lastrow[col].color == f_water &&
560                    f_lastrow[next].color == f_water)
561                   goto loopbottom;
562 
563                if (RAY != 6)    /* Output the vertex info */
564                   out_triangle(f_cur, f_lastrow[col], f_lastrow[next],
565                         cur.color, lastrow[col].color, lastrow[next].color);
566 
567                tout = 1;
568 
569                draw_line(lastrow[col].x, lastrow[col].y, cur.x, cur.y,
570                          cur.color);
571                draw_line(lastrow[next].x, lastrow[next].y, cur.x, cur.y,
572                          cur.color);
573                draw_line(lastrow[next].x, lastrow[next].y, lastrow[col].x,
574                          lastrow[col].y, lastrow[col].color);
575                num_tris++;
576             }
577 
578             if (RAY == 6)       /* Output vertex info for Acrospin */
579             {
580                fprintf(File_Ptr1, "% #4.4f % #4.4f % #4.4f R%dC%d\n",
581                        f_cur.x, f_cur.y, f_cur.color, RO, CO);
582                if (CO > CO_MAX)
583                   CO_MAX = CO;
584                CO++;
585             }
586             goto loopbottom;
587          }
588 
589          switch (FILLTYPE)
590          {
591          case -1:
592             if (col &&
593                 old.x > bad_check &&
594                 old.x < (xdots - bad_check))
595                draw_line(old.x, old.y, cur.x, cur.y, cur.color);
596             if (currow &&
597                 lastrow[col].x > bad_check &&
598                 lastrow[col].y > bad_check &&
599                 lastrow[col].x < (xdots - bad_check) &&
600                 lastrow[col].y < (ydots - bad_check))
601                draw_line(lastrow[col].x, lastrow[col].y, cur.x,
602                          cur.y, cur.color);
603             break;
604 
605          case 0:
606             (*plot) (cur.x, cur.y, cur.color);
607             break;
608 
609          case 1:                /* connect-a-dot */
610             if ((old.x < xdots) && (col) &&
611                 old.x > bad_check &&
612                 old.y > bad_check)      /* Don't draw from old to cur on col
613                                          * 0 */
614                draw_line(old.x, old.y, cur.x, cur.y, cur.color);
615             break;
616 
617          case 2:                /* with interpolation */
618          case 3:                /* no interpolation */
619             /*************************************************************/
620             /* "triangle fill" - consider four points: current point,    */
621             /* previous point same row, point opposite current point in  */
622             /* previous row, point after current point in previous row.  */
623             /* The object is to fill all points inside the two triangles.*/
624             /*                                                           */
625             /* lastrow[col].x/y___ lastrow[next]                         */
626             /* /        1                 /                              */
627             /* /                1         /                              */
628             /* /                       1  /                              */
629             /* oldrow/col ________ trow/col                              */
630             /*************************************************************/
631 
632             if (currow && !col)
633                putatriangle(lastrow[next], lastrow[col], cur, cur.color);
634             if (currow && col)  /* skip first row and first column */
635             {
636                if (col == 1)
637                   putatriangle(lastrow[col], oldlast, old, old.color);
638 
639                if (col < lastdot)
640                   putatriangle(lastrow[next], lastrow[col], cur, cur.color);
641                putatriangle(old, lastrow[col], cur, cur.color);
642             }
643             break;
644 
645          case 4:                /* "solid fill" */
646             if (SPHERE)
647             {
648                if (persp)
649                {
650                   old.x = (int) (xcenter >> 16);
651                   old.y = (int) (ycenter >> 16);
652                }
653                else
654                {
655                   old.x = (int) xcenter;
656                   old.y = (int) ycenter;
657                }
658             }
659             else
660             {
661                lv[0] = col;
662                lv[1] = currow;
663                lv[2] = 0;
664 
665                /* apply fudge bit shift for integer math */
666                lv[0] = lv[0] << 16;
667                lv[1] = lv[1] << 16;
668                /* Since 0, unnecessary lv[2] = lv[2] << 16; */
669 
670                if (longvmultpersp(lv, llm, lv0, lv, lview, 16))
671                {
672                   cur = bad;
673                   f_cur = f_bad;
674                   goto loopbottom;      /* another goto ! */
675                }
676 
677                /* Round and fudge back to original  */
678                old.x = (int) ((lv[0] + 32768L) >> 16);
679                old.y = (int) ((lv[1] + 32768L) >> 16);
680             }
681             if (old.x < 0)
682                old.x = 0;
683             if (old.x >= xdots)
684                old.x = xdots - 1;
685             if (old.y < 0)
686                old.y = 0;
687             if (old.y >= ydots)
688                old.y = ydots - 1;
689             draw_line(old.x, old.y, cur.x, cur.y, cur.color);
690             break;
691 
692          case 5:
693          case 6:
694             /* light-source modulated fill */
695             if (currow && col)  /* skip first row and first column */
696             {
697                if (f_cur.color < bad_check || f_old.color < bad_check ||
698                    f_lastrow[col].color < bad_check)
699                   break;
700 
701                v1[0] = f_cur.x - f_old.x;
702                v1[1] = f_cur.y - f_old.y;
703                v1[2] = f_cur.color - f_old.color;
704 
705                v2[0] = f_lastrow[col].x - f_cur.x;
706                v2[1] = f_lastrow[col].y - f_cur.y;
707                v2[2] = f_lastrow[col].color - f_cur.color;
708 
709                cross_product(v1, v2, cross);
710 
711                /* normalize cross - and check if non-zero */
712                if (normalize_vector(cross))
713                {
714                   if (debugflag)
715                   {
716                      static FCODE msg[] = {"debug, cur.color=bad"};
717                      stopmsg(0, msg);
718                   }
719                   cur.color = (int)(f_cur.color = bad.color);
720                }
721                else
722                {
723                   /* line-wise averaging scheme */
724                   if (LIGHTAVG > 0)
725                   {
726                      if (crossnotinit)
727                      {
728                         /* initialize array of old normal vectors */
729                         crossavg[0] = cross[0];
730                         crossavg[1] = cross[1];
731                         crossavg[2] = cross[2];
732                         crossnotinit = 0;
733                      }
734                      tmpcross[0] = (crossavg[0] * LIGHTAVG + cross[0]) /
735                         (LIGHTAVG + 1);
736                      tmpcross[1] = (crossavg[1] * LIGHTAVG + cross[1]) /
737                         (LIGHTAVG + 1);
738                      tmpcross[2] = (crossavg[2] * LIGHTAVG + cross[2]) /
739                         (LIGHTAVG + 1);
740                      cross[0] = tmpcross[0];
741                      cross[1] = tmpcross[1];
742                      cross[2] = tmpcross[2];
743                      if (normalize_vector(cross))
744                      {
745                         /* this shouldn't happen */
746                         if (debugflag)
747                         {
748                            static FCODE msg[] = {"debug, normal vector err2"};
749                            stopmsg(0, msg);
750                            /* use next instead if you ever need details:
751                             * static char far tmp[] = {"debug, vector err"};
752                             * char msg[200]; #ifndef XFRACT
753                             * sprintf(msg,"%Fs\n%f %f %f\n%f %f %f\n%f %f
754                             * %f", #else sprintf(msg,"%s\n%f %f %f\n%f %f
755                             * %f\n%f %f %f", #endif tmp, f_cur.x, f_cur.y,
756                             * f_cur.color, f_lastrow[col].x,
757                             * f_lastrow[col].y, f_lastrow[col].color,
758                             * f_lastrow[col-1].x,
759                             * f_lastrow[col-1].y,f_lastrow[col-1].color);
760                             * stopmsg(0,msg); */
761                         }
762                         cur.color = (int)(f_cur.color = colors);
763                      }
764                   }
765                   crossavg[0] = tmpcross[0];
766                   crossavg[1] = tmpcross[1];
767                   crossavg[2] = tmpcross[2];
768 
769                   /* dot product of unit vectors is cos of angle between */
770                   /* we will use this value to shade surface */
771 
772                   cur.color = (int) (1 + (colors - 2) *
773                                (1.0 - dot_product(cross, light_direction)));
774                }
775                /* if colors out of range, set them to min or max color index
776                 * but avoid background index. This makes colors "opaque" so
777                 * SOMETHING plots. These conditions shouldn't happen but just
778                 * in case                                        */
779                if (cur.color < 1)       /* prevent transparent colors */
780                   cur.color = 1;/* avoid background */
781                if (cur.color > colors - 1)
782                   cur.color = colors - 1;
783 
784                /* why "col < 2"? So we have sufficient geometry for the fill */
785                /* algorithm, which needs previous point in same row to have  */
786                /* already been calculated (variable old)                 */
787                /* fix ragged left margin in preview */
788                if (col == 1 && currow > 1)
789                   putatriangle(lastrow[next], lastrow[col], cur, cur.color);
790 
791                if (col < 2 || currow < 2)       /* don't have valid colors
792                                                  * yet */
793                   break;
794 
795                if (col < lastdot)
796                   putatriangle(lastrow[next], lastrow[col], cur, cur.color);
797                putatriangle(old, lastrow[col], cur, cur.color);
798 
799                plot = standardplot;
800             }
801             break;
802          }                      /* End of CASE statement for fill type  */
803        loopbottom:
804          if (RAY || (FILLTYPE != 0 && FILLTYPE != 4))
805          {
806             /* for triangle and grid fill purposes */
807             oldlast = lastrow[col];
808             old = lastrow[col] = cur;
809 
810             /* for illumination model purposes */
811             f_old = f_lastrow[col] = f_cur;
812             if (currow && RAY && col >= lastdot)
813                /* if we're at the end of a row, close the object */
814             {
815                end_object(tout);
816                tout = 0;
817                if (ferror(File_Ptr1))
818                {
819                   fclose(File_Ptr1);
820                   remove(light_name);
821                   File_Error(ray_name, 2);
822                   return (-1);
823                }
824             }
825          }
826          col++;
827       }                         /* End of while statement for plotting line  */
828    RO++;
829  reallythebottom:
830 
831    /* stuff that HAS to be done, even in preview mode, goes here */
832    if (SPHERE)
833    {
834       /* incremental sin/cos phi calc */
835       if (currow == 0)
836       {
837          sinphi = oldsinphi2;
838          cosphi = oldcosphi2;
839       }
840       else
841       {
842          sinphi = twocosdeltaphi * oldsinphi2 - oldsinphi1;
843          cosphi = twocosdeltaphi * oldcosphi2 - oldcosphi1;
844          oldsinphi1 = oldsinphi2;
845          oldsinphi2 = sinphi;
846          oldcosphi1 = oldcosphi2;
847          oldcosphi2 = cosphi;
848       }
849    }
850    return (0);                  /* decoder needs to know all is well !!! */
851 }
852 
853 /* vector version of line draw */
vdraw_line(double * v1,double * v2,int color)854 static void _fastcall vdraw_line(double *v1, double *v2, int color)
855 {
856    int x1, y1, x2, y2;
857    x1 = (int) v1[0];
858    y1 = (int) v1[1];
859    x2 = (int) v2[0];
860    y2 = (int) v2[1];
861    draw_line(x1, y1, x2, y2, color);
862 }
863 
corners(MATRIX m,int show,double * pxmin,double * pymin,double * pzmin,double * pxmax,double * pymax,double * pzmax)864 static void corners(MATRIX m, int show, double *pxmin, double *pymin, double *pzmin, double *pxmax, double *pymax, double *pzmax)
865 {
866    int i, j;
867    VECTOR S[2][4];              /* Holds the top an bottom points,
868                                  * S[0][]=bottom */
869 
870    /* define corners of box fractal is in in x,y,z plane "b" stands for
871     * "bottom" - these points are the corners of the screen in the x-y plane.
872     * The "t"'s stand for Top - they are the top of the cube where 255 color
873     * points hit. */
874 
875    *pxmin = *pymin = *pzmin = (int) INT_MAX;
876    *pxmax = *pymax = *pzmax = (int) INT_MIN;
877 
878    for (j = 0; j < 4; ++j)
879       for (i = 0; i < 3; i++)
880          S[0][j][i] = S[1][j][i] = 0;
881 
882    S[0][1][0] = S[0][2][0] = S[1][1][0] = S[1][2][0] = xdots - 1;
883    S[0][2][1] = S[0][3][1] = S[1][2][1] = S[1][3][1] = ydots - 1;
884    S[1][0][2] = S[1][1][2] = S[1][2][2] = S[1][3][2] = zcoord - 1;
885 
886    for (i = 0; i < 4; ++i)
887    {
888       /* transform points */
889       vmult(S[0][i], m, S[0][i]);
890       vmult(S[1][i], m, S[1][i]);
891 
892       /* update minimums and maximums */
893       if (S[0][i][0] <= *pxmin)
894          *pxmin = S[0][i][0];
895       if (S[0][i][0] >= *pxmax)
896          *pxmax = S[0][i][0];
897       if (S[1][i][0] <= *pxmin)
898          *pxmin = S[1][i][0];
899       if (S[1][i][0] >= *pxmax)
900          *pxmax = S[1][i][0];
901       if (S[0][i][1] <= *pymin)
902          *pymin = S[0][i][1];
903       if (S[0][i][1] >= *pymax)
904          *pymax = S[0][i][1];
905       if (S[1][i][1] <= *pymin)
906          *pymin = S[1][i][1];
907       if (S[1][i][1] >= *pymax)
908          *pymax = S[1][i][1];
909       if (S[0][i][2] <= *pzmin)
910          *pzmin = S[0][i][2];
911       if (S[0][i][2] >= *pzmax)
912          *pzmax = S[0][i][2];
913       if (S[1][i][2] <= *pzmin)
914          *pzmin = S[1][i][2];
915       if (S[1][i][2] >= *pzmax)
916          *pzmax = S[1][i][2];
917    }
918 
919    if (show)
920    {
921       if (persp)
922       {
923          for (i = 0; i < 4; i++)
924          {
925             perspective(S[0][i]);
926             perspective(S[1][i]);
927          }
928       }
929 
930       /* Keep the box surrounding the fractal */
931       for (j = 0; j < 2; j++)
932          for (i = 0; i < 4; ++i)
933          {
934             S[j][i][0] += xxadjust;
935             S[j][i][1] += yyadjust;
936          }
937 
938       draw_rect(S[0][0], S[0][1], S[0][2], S[0][3], 2, 1);      /* Bottom */
939 
940       draw_rect(S[0][0], S[1][0], S[0][1], S[1][1], 5, 0);      /* Sides */
941       draw_rect(S[0][2], S[1][2], S[0][3], S[1][3], 6, 0);
942 
943       draw_rect(S[1][0], S[1][1], S[1][2], S[1][3], 8, 1);      /* Top */
944    }
945 }
946 
947 /* This function draws a vector from origin[] to direct[] and a box
948         around it. The vector and box are transformed or not depending on
949         FILLTYPE.
950 */
951 
draw_light_box(double * origin,double * direct,MATRIX light_m)952 static void draw_light_box(double *origin, double *direct, MATRIX light_m)
953 {
954    VECTOR S[2][4];
955    int i, j;
956    double temp;
957 
958    S[1][0][0] = S[0][0][0] = origin[0];
959    S[1][0][1] = S[0][0][1] = origin[1];
960 
961    S[1][0][2] = direct[2];
962 
963    for (i = 0; i < 2; i++)
964    {
965       S[i][1][0] = S[i][0][0];
966       S[i][1][1] = direct[1];
967       S[i][1][2] = S[i][0][2];
968       S[i][2][0] = direct[0];
969       S[i][2][1] = S[i][1][1];
970       S[i][2][2] = S[i][0][2];
971       S[i][3][0] = S[i][2][0];
972       S[i][3][1] = S[i][0][1];
973       S[i][3][2] = S[i][0][2];
974    }
975 
976    /* transform the corners if necessary */
977    if (FILLTYPE == 6)
978       for (i = 0; i < 4; i++)
979       {
980          vmult(S[0][i], light_m, S[0][i]);
981          vmult(S[1][i], light_m, S[1][i]);
982       }
983 
984    /* always use perspective to aid viewing */
985    temp = view[2];              /* save perspective distance for a later
986                                  * restore */
987    view[2] = -P * 300.0 / 100.0;
988 
989    for (i = 0; i < 4; i++)
990    {
991       perspective(S[0][i]);
992       perspective(S[1][i]);
993    }
994    view[2] = temp;              /* Restore perspective distance */
995 
996    /* Adjust for aspect */
997    for (i = 0; i < 4; i++)
998    {
999       S[0][i][0] = S[0][i][0] * aspect;
1000       S[1][i][0] = S[1][i][0] * aspect;
1001    }
1002 
1003    /* draw box connecting transformed points. NOTE order and COLORS */
1004    draw_rect(S[0][0], S[0][1], S[0][2], S[0][3], 2, 1);
1005 
1006    vdraw_line(S[0][0], S[1][2], 8);
1007 
1008    /* sides */
1009    draw_rect(S[0][0], S[1][0], S[0][1], S[1][1], 4, 0);
1010    draw_rect(S[0][2], S[1][2], S[0][3], S[1][3], 5, 0);
1011 
1012    draw_rect(S[1][0], S[1][1], S[1][2], S[1][3], 3, 1);
1013 
1014    /* Draw the "arrow head" */
1015    for (i = -3; i < 4; i++)
1016       for (j = -3; j < 4; j++)
1017          if (abs(i) + abs(j) < 6)
1018             plot((int) (S[1][2][0] + i), (int) (S[1][2][1] + j), 10);
1019 }
1020 
draw_rect(VECTOR V0,VECTOR V1,VECTOR V2,VECTOR V3,int color,int rect)1021 static void draw_rect(VECTOR V0, VECTOR V1, VECTOR V2, VECTOR V3, int color, int rect)
1022 {
1023    VECTOR V[4];
1024    int i;
1025 
1026    /* Since V[2] is not used by vdraw_line don't bother setting it */
1027    for (i = 0; i < 2; i++)
1028    {
1029       V[0][i] = V0[i];
1030       V[1][i] = V1[i];
1031       V[2][i] = V2[i];
1032       V[3][i] = V3[i];
1033    }
1034    if (rect)                    /* Draw a rectangle */
1035    {
1036       for (i = 0; i < 4; i++)
1037          if (fabs(V[i][0] - V[(i + 1) % 4][0]) < -2 * bad_check &&
1038              fabs(V[i][1] - V[(i + 1) % 4][1]) < -2 * bad_check)
1039             vdraw_line(V[i], V[(i + 1) % 4], color);
1040    }
1041    else
1042       /* Draw 2 lines instead */
1043    {
1044       for (i = 0; i < 3; i += 2)
1045          if (fabs(V[i][0] - V[i + 1][0]) < -2 * bad_check &&
1046              fabs(V[i][1] - V[i + 1][1]) < -2 * bad_check)
1047             vdraw_line(V[i], V[i + 1], color);
1048    }
1049    return;
1050 }
1051 
1052 /* replacement for plot - builds a table of min and max x's instead of plot */
1053 /* called by draw_line as part of triangle fill routine */
putminmax(int x,int y,int color)1054 static void _fastcall putminmax(int x, int y, int color)
1055 {
1056    color = 0; /* to supress warning only */
1057    if (y >= 0 && y < ydots)
1058    {
1059       if (x < minmax_x[y].minx)
1060          minmax_x[y].minx = x;
1061       if (x > minmax_x[y].maxx)
1062          minmax_x[y].maxx = x;
1063    }
1064 }
1065 
1066 /*
1067         This routine fills in a triangle. Extreme left and right values for
1068         each row are calculated by calling the line function for the sides.
1069         Then rows are filled in with horizontal lines
1070 */
1071 #define MAXOFFSCREEN  2    /* allow two of three points to be off screen */
1072 
putatriangle(struct point pt1,struct point pt2,struct point pt3,int color)1073 static void _fastcall putatriangle(struct point pt1, struct point pt2, struct point pt3, int color)
1074 {
1075    int miny, maxy;
1076    int x, y, xlim;
1077 
1078    /* Too many points off the screen? */
1079    if ((offscreen(pt1) + offscreen(pt2) + offscreen(pt3)) > MAXOFFSCREEN)
1080       return;
1081 
1082    p1 = pt1;                    /* needed by interpcolor */
1083    p2 = pt2;
1084    p3 = pt3;
1085 
1086    /* fast way if single point or single line */
1087    if (p1.y == p2.y && p1.x == p2.x)
1088    {
1089       plot = fillplot;
1090       if (p1.y == p3.y && p1.x == p3.x)
1091          (*plot) (p1.x, p1.y, color);
1092       else
1093          draw_line(p1.x, p1.y, p3.x, p3.y, color);
1094       plot = normalplot;
1095       return;
1096    }
1097    else if ((p3.y == p1.y && p3.x == p1.x) || (p3.y == p2.y && p3.x == p2.x))
1098    {
1099       plot = fillplot;
1100       draw_line(p1.x, p1.y, p2.x, p2.y, color);
1101       plot = normalplot;
1102       return;
1103    }
1104 
1105    /* find min max y */
1106    miny = maxy = p1.y;
1107    if (p2.y < miny)
1108       miny = p2.y;
1109    else
1110       maxy = p2.y;
1111    if (p3.y < miny)
1112       miny = p3.y;
1113    else if (p3.y > maxy)
1114       maxy = p3.y;
1115 
1116    /* only worried about values on screen */
1117    if (miny < 0)
1118       miny = 0;
1119    if (maxy >= ydots)
1120       maxy = ydots - 1;
1121 
1122    for (y = miny; y <= maxy; y++)
1123    {
1124       minmax_x[y].minx = (int) INT_MAX;
1125       minmax_x[y].maxx = (int) INT_MIN;
1126    }
1127 
1128    /* set plot to "fake" plot function */
1129    plot = putminmax;
1130 
1131    /* build table of extreme x's of triangle */
1132    draw_line(p1.x, p1.y, p2.x, p2.y, 0);
1133    draw_line(p2.x, p2.y, p3.x, p3.y, 0);
1134    draw_line(p3.x, p3.y, p1.x, p1.y, 0);
1135 
1136    for (y = miny; y <= maxy; y++)
1137    {
1138       xlim = minmax_x[y].maxx;
1139       for (x = minmax_x[y].minx; x <= xlim; x++)
1140          (*fillplot) (x, y, color);
1141    }
1142    plot = normalplot;
1143 }
1144 
offscreen(struct point pt)1145 static int _fastcall offscreen(struct point pt)
1146 {
1147    if (pt.x >= 0)
1148       if (pt.x < xdots)
1149          if (pt.y >= 0)
1150             if (pt.y < ydots)
1151                return (0);      /* point is ok */
1152    if (abs(pt.x) > 0 - bad_check || abs(pt.y) > 0 - bad_check)
1153       return (99);              /* point is bad */
1154    return (1);                  /* point is off the screen */
1155 }
1156 
clipcolor(int x,int y,int color)1157 static void _fastcall clipcolor(int x, int y, int color)
1158 {
1159    if (0 <= x && x < xdots &&
1160        0 <= y && y < ydots &&
1161        0 <= color && color < filecolors)
1162    {
1163       standardplot(x, y, color);
1164 
1165       if (Targa_Out)
1166          /* standardplot modifies color in these types */
1167          if (!(glassestype == 1 || glassestype == 2))
1168             targa_color(x, y, color);
1169    }
1170 }
1171 
1172 /*********************************************************************/
1173 /* This function is the same as clipcolor but checks for color being */
1174 /* in transparent range. Intended to be called only if transparency  */
1175 /* has been enabled.                                                 */
1176 /*********************************************************************/
1177 
T_clipcolor(int x,int y,int color)1178 static void _fastcall T_clipcolor(int x, int y, int color)
1179 {
1180    if (0 <= x && x < xdots &&   /* is the point on screen?  */
1181        0 <= y && y < ydots &&   /* Yes?  */
1182        0 <= color && color < colors &&  /* Colors in valid range?  */
1183    /* Lets make sure its not a transparent color  */
1184        (transparent[0] > color || color > transparent[1]))
1185    {
1186       standardplot(x, y, color);/* I guess we can plot then  */
1187       if (Targa_Out)
1188          /* standardplot modifies color in these types */
1189          if (!(glassestype == 1 || glassestype == 2))
1190             targa_color(x, y, color);
1191    }
1192 }
1193 
1194 /************************************************************************/
1195 /* A substitute for plotcolor that interpolates the colors according    */
1196 /* to the x and y values of three points (p1,p2,p3) which are static in */
1197 /* this routine                                                         */
1198 /*                                                                      */
1199 /*      In Light source modes, color is light value, not actual color   */
1200 /*      Real_Color always contains the actual color                     */
1201 /************************************************************************/
1202 
interpcolor(int x,int y,int color)1203 static void _fastcall interpcolor(int x, int y, int color)
1204 {
1205    int D, d1, d2, d3;
1206 
1207    /* this distance formula is not the usual one - but it has the virtue that
1208     * it uses ONLY additions (almost) and it DOES go to zero as the points
1209     * get close. */
1210 
1211    d1 = abs(p1.x - x) + abs(p1.y - y);
1212    d2 = abs(p2.x - x) + abs(p2.y - y);
1213    d3 = abs(p3.x - x) + abs(p3.y - y);
1214 
1215    D = (d1 + d2 + d3) << 1;
1216    if (D)
1217    {  /* calculate a weighted average of colors long casts prevent integer
1218          overflow. This can evaluate to zero */
1219       color = (int) (((long) (d2 + d3) * (long) p1.color +
1220                       (long) (d1 + d3) * (long) p2.color +
1221                       (long) (d1 + d2) * (long) p3.color) / D);
1222    }
1223 
1224    if (0 <= x && x < xdots &&
1225        0 <= y && y < ydots &&
1226        0 <= color && color < colors &&
1227        (transparent[1] == 0 || (int) Real_Color > transparent[1] ||
1228         transparent[0] > (int) Real_Color))
1229    {
1230       if (Targa_Out)
1231          /* standardplot modifies color in these types */
1232          if (!(glassestype == 1 || glassestype == 2))
1233             D = targa_color(x, y, color);
1234 
1235       if (FILLTYPE >= 5) {
1236          if (Real_V && Targa_Out)
1237             color = D;
1238          else
1239          {
1240             color = (1 + (unsigned) color * IAmbient) / 256;
1241             if (color == 0)
1242                color = 1;
1243          }
1244       }
1245       standardplot(x, y, color);
1246    }
1247 }
1248 
1249 /*
1250         In non light source modes, both color and Real_Color contain the
1251         actual pixel color. In light source modes, color contains the
1252         light value, and Real_Color contains the origninal color
1253 
1254         This routine takes a pixel modifies it for lightshading if appropriate
1255         and plots it in a Targa file. Used in plot3d.c
1256 */
1257 
targa_color(int x,int y,int color)1258 int _fastcall targa_color(int x, int y, int color)
1259 {
1260    unsigned long H, S, V;
1261    BYTE RGB[3];
1262 
1263    if (FILLTYPE == 2 || glassestype == 1 || glassestype == 2 || truecolor)
1264       Real_Color = (BYTE)color;       /* So Targa gets interpolated color */
1265 
1266    switch (truemode)
1267    {
1268       case 0:
1269       default:
1270       {
1271          RGB[0] = (BYTE)(dacbox[Real_Color][0] << 2); /* Move color space to */
1272          RGB[1] = (BYTE)(dacbox[Real_Color][1] << 2); /* 256 color primaries */
1273          RGB[2] = (BYTE)(dacbox[Real_Color][2] << 2); /* from 64 colors */
1274          break;
1275       }
1276       case 1:
1277       {
1278          RGB[0] = (BYTE)((realcoloriter >> 16) & 0xff);  /* red   */
1279          RGB[1] = (BYTE)((realcoloriter >> 8 ) & 0xff);  /* green */
1280          RGB[2] = (BYTE)((realcoloriter      ) & 0xff);  /* blue  */
1281          break;
1282       }
1283    }
1284 
1285    /* Now lets convert it to HSV */
1286    R_H(RGB[0], RGB[1], RGB[2], &H, &S, &V);
1287 
1288    /* Modify original S and V components */
1289    if (FILLTYPE > 4 && !(glassestype == 1 || glassestype == 2))
1290       /* Adjust for Ambient */
1291       V = (V * (65535L - (unsigned) (color * IAmbient))) / 65535L;
1292 
1293    if (haze)
1294    {
1295       /* Haze lowers sat of colors */
1296       S = (unsigned long) (S * HAZE_MULT) / 100;
1297       if (V >= 32640)           /* Haze reduces contrast */
1298       {
1299          V = V - 32640;
1300          V = (unsigned long) ((V * HAZE_MULT) / 100);
1301          V = V + 32640;
1302       }
1303       else
1304       {
1305          V = 32640 - V;
1306          V = (unsigned long) ((V * HAZE_MULT) / 100);
1307          V = 32640 - V;
1308       }
1309    }
1310    /* Now lets convert it back to RGB. Original Hue, modified Sat and Val */
1311    H_R(&RGB[0], &RGB[1], &RGB[2], H, S, V);
1312 
1313    if (Real_V)
1314       V = (35 * (int) RGB[0] + 45 * (int) RGB[1] + 20 * (int) RGB[2]) / 100;
1315 
1316    /* Now write the color triple to its transformed location */
1317    /* on the disk. */
1318    targa_writedisk(x + sxoffs, y + syoffs, RGB[0], RGB[1], RGB[2]);
1319 
1320    return ((int) (255 - V));
1321 }
1322 
set_pixel_buff(BYTE * pixels,BYTE far * fraction,unsigned linelen)1323 static int set_pixel_buff(BYTE * pixels, BYTE far * fraction, unsigned linelen)
1324 {
1325    int i;
1326    if ((evenoddrow++ & 1) == 0) /* even rows are color value */
1327    {
1328       for (i = 0; i < (int) linelen; i++)       /* add the fractional part in
1329                                                  * odd row */
1330          fraction[i] = pixels[i];
1331       return (1);
1332    }
1333    else
1334       /* swap */
1335    {
1336       BYTE tmp;
1337       for (i = 0; i < (int) linelen; i++)       /* swap so pixel has color */
1338       {
1339          tmp = pixels[i];
1340          pixels[i] = fraction[i];
1341          fraction[i] = tmp;
1342       }
1343    }
1344    return (0);
1345 }
1346 
1347 /**************************************************************************
1348 
1349   Common routine for printing error messages to the screen for Targa
1350     and other files
1351 
1352 **************************************************************************/
1353 
1354 #ifndef XFRACT
1355 static char s_f[] = "%Fs%Fs";
1356 static char s_fff[] = "%Fs%Fs%Fs";
1357 #else
1358 static char s_f[] = "%s%s";
1359 static char s_fff[] = "%s%s%s";
1360 #endif
1361 static FCODE OOPS[] = {"OOPS, "};
1362 static FCODE E1[] = {"can't handle this type of file.\n"};
1363 static FCODE str1[] = {"couldn't open  < "};
1364 static FCODE str3[] = {"image wrong size\n"};
1365 static FCODE outofdisk[] = {"ran out of disk space. < "};
1366 
File_Error(char * File_Name1,int ERROR)1367 static void File_Error(char *File_Name1, int ERROR)
1368 {
1369    char msgbuf[200];
1370 
1371    error = ERROR;
1372    switch (ERROR)
1373    {
1374    case 1:                      /* Can't Open */
1375 #ifndef XFRACT
1376       sprintf(msgbuf, "%Fs%Fs%s >", (char far *)OOPS, (char far *)str1, File_Name1);
1377 #else
1378       sprintf(msgbuf, "%s%s%s >", OOPS, str1, File_Name1);
1379 #endif
1380       break;
1381    case 2:                      /* Not enough room */
1382 #ifndef XFRACT
1383       sprintf(msgbuf, "%Fs%Fs%s >", (char far *)OOPS, (char far *)outofdisk, File_Name1);
1384 #else
1385       sprintf(msgbuf, "%s%s%s >", OOPS, outofdisk, File_Name1);
1386 #endif
1387       break;
1388    case 3:                      /* Image wrong size */
1389       sprintf(msgbuf, s_f, (char far *)OOPS, (char far *)str3);
1390       break;
1391    case 4:                      /* Wrong file type */
1392       sprintf(msgbuf, s_f, (char far *)OOPS, (char far *)E1);
1393       break;
1394    }
1395    stopmsg(0, msgbuf);
1396    return;
1397 }
1398 
1399 
1400 /************************************************************************/
1401 /*                                                                      */
1402 /*   This function opens a TARGA_24 file for reading and writing. If    */
1403 /*   its a new file, (overlay == 0) it writes a header. If it is to     */
1404 /*   overlay an existing file (overlay == 1) it copies the original     */
1405 /*   header whose lenght and validity was determined in                 */
1406 /*   Targa_validate.                                                    */
1407 /*                                                                      */
1408 /*   It Verifies there is enough disk space, and leaves the file        */
1409 /*   at the start of the display data area.                             */
1410 /*                                                                      */
1411 /*   If this is an overlay, closes source and copies to "targa_temp"    */
1412 /*   If there is an error close the file.                               */
1413 /*                                                                      */
1414 /* **********************************************************************/
1415 
startdisk1(char * File_Name2,FILE * Source,int overlay)1416 int startdisk1(char *File_Name2, FILE * Source, int overlay)
1417 {
1418    int i, j, k, inc;
1419    FILE *fps;
1420 
1421    /* Open File for both reading and writing */
1422    if ((fps = dir_fopen(workdir,File_Name2, "w+b")) == NULL)
1423    {
1424       File_Error(File_Name2, 1);
1425       return (-1);              /* Oops, somethings wrong! */
1426    }
1427 
1428    inc = 1;                     /* Assume we are overlaying a file */
1429 
1430    /* Write the header */
1431    if (overlay)                 /* We are overlaying a file */
1432       for (i = 0; i < T_header_24; i++) /* Copy the header from the Source */
1433          fputc(fgetc(Source), fps);
1434    else
1435    {                            /* Write header for a new file */
1436       /* ID field size = 0, No color map, Targa type 2 file */
1437       for (i = 0; i < 12; i++)
1438       {
1439          if (i == 0 && truecolor != 0)
1440          {
1441             set_upr_lwr();
1442             fputc(4, fps); /* make room to write an extra number */
1443             T_header_24 = 18 + 4;
1444          }
1445          else if (i == 2)
1446             fputc(i, fps);
1447          else
1448             fputc(0, fps);
1449       }
1450       /* Write image size  */
1451       for (i = 0; i < 4; i++)
1452          fputc(upr_lwr[i], fps);
1453       fputc(T24, fps);          /* Targa 24 file */
1454       fputc(T32, fps);          /* Image at upper left */
1455       inc = 3;
1456    }
1457 
1458    if(truecolor) /* write maxit */
1459    {
1460       fputc((BYTE)(maxit       & 0xff), fps);
1461       fputc((BYTE)((maxit>>8 ) & 0xff), fps);
1462       fputc((BYTE)((maxit>>16) & 0xff), fps);
1463       fputc((BYTE)((maxit>>24) & 0xff), fps);
1464    }
1465 
1466    /* Finished with the header, now lets work on the display area  */
1467    for (i = 0; i < ydots; i++)  /* "clear the screen" (write to the disk) */
1468    {
1469       for (j = 0; j < line_length1; j = j + inc)
1470       {
1471          if (overlay)
1472             fputc(fgetc(Source), fps);
1473          else
1474             for (k = 2; k > -1; k--)
1475                fputc(back_color[k], fps);       /* Targa order (B, G, R) */
1476       }
1477       if (ferror(fps))
1478       {
1479          /* Almost certainly not enough disk space  */
1480          fclose(fps);
1481          if(overlay)
1482             fclose(Source);
1483          dir_remove(workdir,File_Name2);
1484          File_Error(File_Name2, 2);
1485          return (-2);
1486       }
1487       if (keypressed())
1488          return (-3);
1489    }
1490 
1491    if (targa_startdisk(fps, T_header_24) != 0)
1492    {
1493       enddisk();
1494       dir_remove(workdir,File_Name2);
1495       return (-4);
1496    }
1497    return (0);
1498 }
1499 
targa_validate(char * File_Name)1500 int targa_validate(char *File_Name)
1501 {
1502    FILE *fp;
1503    int i;
1504 #if 0
1505    int j = 0;
1506 #endif
1507 
1508    /* Attempt to open source file for reading */
1509    if ((fp = dir_fopen(workdir,File_Name, "rb")) == NULL)
1510    {
1511       File_Error(File_Name, 1);
1512       return (-1);              /* Oops, file does not exist */
1513    }
1514 
1515    T_header_24 += fgetc(fp);    /* Check ID field and adjust header size */
1516 
1517    if (fgetc(fp))               /* Make sure this is an unmapped file */
1518    {
1519       File_Error(File_Name, 4);
1520       return (-1);
1521    }
1522 
1523    if (fgetc(fp) != 2)          /* Make sure it is a type 2 file */
1524    {
1525       File_Error(File_Name, 4);
1526       return (-1);
1527    }
1528 
1529    /* Skip color map specification */
1530    for (i = 0; i < 5; i++)
1531       fgetc(fp);
1532 
1533    for (i = 0; i < 4; i++)
1534    {
1535       /* Check image origin */
1536       fgetc(fp);
1537 #if 0
1538       if (j != 0)
1539       {
1540          File_Error(File_Name, 4);
1541          return (-1);
1542       }
1543 #endif
1544    }
1545    /* Check Image specs */
1546    for (i = 0; i < 4; i++)
1547       if (fgetc(fp) != (int) upr_lwr[i])
1548       {
1549          File_Error(File_Name, 3);
1550          return (-1);
1551       }
1552 
1553    if (fgetc(fp) != (int) T24)
1554       error = 4;                /* Is it a targa 24 file? */
1555    if (fgetc(fp) != (int) T32)
1556       error = 4;                /* Is the origin at the upper left? */
1557    if (error == 4)
1558    {
1559       File_Error(File_Name, 4);
1560       return (-1);
1561    }
1562    rewind(fp);
1563 
1564    /* Now that we know its a good file, create a working copy */
1565    if (startdisk1(targa_temp, fp, 1))
1566       return (-1);
1567 
1568    fclose(fp);                  /* Close the source */
1569 
1570    T_Safe = 1;                  /* Original file successfully copied to
1571                                  * targa_temp */
1572    return (0);
1573 }
1574 
R_H(BYTE R,BYTE G,BYTE B,unsigned long * H,unsigned long * S,unsigned long * V)1575 static int R_H(BYTE R, BYTE G, BYTE B, unsigned long *H, unsigned long *S, unsigned long *V)
1576 {
1577    unsigned long R1, G1, B1, DENOM;
1578    BYTE MIN;
1579 
1580    *V = R;
1581    MIN = G;
1582    if (R < G)
1583    {
1584       *V = G;
1585       MIN = R;
1586       if (G < B)
1587          *V = B;
1588       if (B < R)
1589          MIN = B;
1590    }
1591    else
1592    {
1593       if (B < G)
1594          MIN = B;
1595       if (R < B)
1596          *V = B;
1597    }
1598    DENOM = *V - MIN;
1599    if (*V != 0 && DENOM != 0)
1600    {
1601       *S = ((DENOM << 16) / *V) - 1;
1602    }
1603    else
1604       *S = 0;      /* Color is black! and Sat has no meaning */
1605    if (*S == 0)    /* R=G=B => shade of grey and Hue has no meaning */
1606    {
1607       *H = 0;
1608       *V = *V << 8;
1609       return (1);               /* v or s or both are 0 */
1610    }
1611    if (*V == MIN)
1612    {
1613       *H = 0;
1614       *V = *V << 8;
1615       return (0);
1616    }
1617    R1 = (((*V - R) * 60) << 6) / DENOM; /* distance of color from red   */
1618    G1 = (((*V - G) * 60) << 6) / DENOM; /* distance of color from green */
1619    B1 = (((*V - B) * 60) << 6) / DENOM; /* distance of color from blue  */
1620    if (*V == R) {
1621       if (MIN == G)
1622          *H = (300 << 6) + B1;
1623       else
1624          *H = (60 << 6) - G1;
1625    }
1626    if (*V == G) {
1627       if (MIN == B)
1628          *H = (60 << 6) + R1;
1629       else
1630          *H = (180 << 6) - B1;
1631    }
1632    if (*V == B) {
1633       if (MIN == R)
1634          *H = (180 << 6) + G1;
1635       else
1636          *H = (300 << 6) - R1;
1637     }
1638    *V = *V << 8;
1639    return (0);
1640 }
1641 
H_R(BYTE * R,BYTE * G,BYTE * B,unsigned long H,unsigned long S,unsigned long V)1642 static int H_R(BYTE *R, BYTE *G, BYTE *B, unsigned long H, unsigned long S, unsigned long V)
1643 {
1644    unsigned long P1, P2, P3;
1645    int RMD, I;
1646 
1647    if (H >= 23040)
1648       H = H % 23040;            /* Makes h circular  */
1649    I = (int) (H / 3840);
1650    RMD = (int) (H % 3840);      /* RMD = fractional part of H    */
1651 
1652    P1 = ((V * (65535L - S)) / 65280L) >> 8;
1653    P2 = (((V * (65535L - (S * RMD) / 3840)) / 65280L) - 1) >> 8;
1654    P3 = (((V * (65535L - (S * (3840 - RMD)) / 3840)) / 65280L)) >> 8;
1655    V = V >> 8;
1656    switch (I)
1657    {
1658    case 0:
1659       *R = (BYTE) V;
1660       *G = (BYTE) P3;
1661       *B = (BYTE) P1;
1662       break;
1663    case 1:
1664       *R = (BYTE) P2;
1665       *G = (BYTE) V;
1666       *B = (BYTE) P1;
1667       break;
1668    case 2:
1669       *R = (BYTE) P1;
1670       *G = (BYTE) V;
1671       *B = (BYTE) P3;
1672       break;
1673    case 3:
1674       *R = (BYTE) P1;
1675       *G = (BYTE) P2;
1676       *B = (BYTE) V;
1677       break;
1678    case 4:
1679       *R = (BYTE) P3;
1680       *G = (BYTE) P1;
1681       *B = (BYTE) V;
1682       break;
1683    case 5:
1684       *R = (BYTE) V;
1685       *G = (BYTE) P1;
1686       *B = (BYTE) P2;
1687       break;
1688    }
1689    return (0);
1690 }
1691 
1692 
1693 /***************************************************************************/
1694 /*                                                                         */
1695 /* EB & DG fiddled with outputs for Rayshade so they work. with v4.x.      */
1696 /* EB == eli brandt.     ebrandt@jarthur.claremont.edu                     */
1697 /* DG == dan goldwater.  daniel_goldwater@brown.edu & dgold@math.umass.edu */
1698 /*  (NOTE: all the stuff we fiddled with is commented with "EB & DG" )     */
1699 /* general raytracing code info/notes:                                     */
1700 /*                                                                         */
1701 /*  ray == 0 means no raytracer output  ray == 7 is for dxf                */
1702 /*  ray == 1 is for dkb/pov             ray == 4 is for mtv                */
1703 /*  ray == 2 is for vivid               ray == 5 is for rayshade           */
1704 /*  ray == 3 is for raw                 ray == 6 is for acrospin           */
1705 /*                                                                         */
1706 /*  rayshade needs counterclockwise triangles.  raytracers that support    */
1707 /*  the 'heightfield' primitive include rayshade and pov.  anyone want to  */
1708 /*  write code to make heightfields?  they are *MUCH* faster to trace than */
1709 /*  triangles when doing landscapes...                                     */
1710 /*                                                                         */
1711 /*  stuff EB & DG changed:                                                 */
1712 /*  made the rayshade output create a "grid" aggregate object (one of      */
1713 /*  rayshade's primitives), instead  of a global grid.  as a result, the   */
1714 /*  grid can be optimized based on the number of triangles.                */
1715 /*  the z component of the grid can always be 1 since the surface formed   */
1716 /*  by the triangles is flat                                               */
1717 /*  (ie, it doesnt curve over itself).  this is a major optimization.      */
1718 /*  the x and y grid size is also optimized for a 4:3 aspect ratio image,  */
1719 /*  to get the fewest possible traingles in each grid square.              */
1720 /*  also, we fixed the rayshade code so it actually produces output that   */
1721 /*  works with rayshade.                                                   */
1722 /*  (maybe the old code was for a really old version of rayshade?).        */
1723 /*                                                                         */
1724 /***************************************************************************/
1725 
1726 /********************************************************************/
1727 /*                                                                  */
1728 /*  This routine writes a header to a ray tracer data file. It      */
1729 /*  Identifies the version of FRACTINT which created it an the      */
1730 /*  key 3D parameters in effect at the time.                        */
1731 /*                                                                  */
1732 /********************************************************************/
1733 
1734 static FCODE declare[] = {"DECLARE       "};
1735 static FCODE frac_default[] = {"F_Dflt"};
1736 static FCODE s_color[] = {"COLOR  "};
1737 static FCODE dflt[] = {"RED 0.8 GREEN 0.4 BLUE 0.1\n"};
1738 static FCODE d_color[] = {"0.8 0.4 0.1"};
1739 static FCODE r_surf[] = {"0.95 0.05 5 0 0\n"};
1740 static FCODE surf[] = {"surf={diff="};
1741 /* EB & DG: changed "surface T" to "applysurf" and "diff" to "diffuse" */
1742 static FCODE rs_surf[] = {"applysurf diffuse "};
1743 static FCODE end[] = {"END_"};
1744 static FCODE plane[] = {"PLANE"};
1745 static FCODE m1[] = {"-1.0 "};
1746 static FCODE one[] = {" 1.0 "};
1747 static FCODE z[] = {" 0.0 "};
1748 static FCODE bnd_by[] = {" BOUNDED_BY\n"};
1749 static FCODE end_bnd[] = {" END_BOUND\n"};
1750 static FCODE inter[] = {"INTERSECTION\n"};
1751 #ifndef XFRACT
1752 static char fmt[] = "   %Fs <%Fs%Fs%Fs> % #4.3f %Fs%Fs\n";
1753 #else
1754 static char fmt[] = "   %s <%s%s%s> % #4.3f %s%s\n";
1755 #endif
1756 static char dxf_begin[] =
1757 {"  0\nSECTION\n  2\nTABLES\n  0\nTABLE\n  2\nLAYER\n\
1758  70\n     2\n  0\nLAYER\n  2\n0\n 70\n     0\n 62\n     7\n  6\nCONTINUOUS\n\
1759   0\nLAYER\n  2\nFRACTAL\n 70\n    64\n 62\n     1\n  6\nCONTINUOUS\n  0\n\
1760 ENDTAB\n  0\nENDSEC\n  0\nSECTION\n  2\nENTITIES\n"};
1761 static char dxf_3dface[] = {"  0\n3DFACE\n  8\nFRACTAL\n 62\n%3d\n"};
1762 static char dxf_vertex[] = {"%3d\n%g\n"};
1763 static char dxf_end[] = {"  0\nENDSEC\n  0\nEOF\n"};
1764 static FCODE composite[] = {"COMPOSITE"};
1765 static FCODE object[] = {"OBJECT"};
1766 static FCODE triangle[] = {"TRIANGLE "};
1767 static FCODE l_tri[] = {"triangle"};
1768 static FCODE texture[] = {"TEXTURE\n"};
1769 /* static FCODE end_texture[] = {" END_TEXTURE\n"}; */
1770 static FCODE red[] = {"RED"};
1771 static FCODE green[] = {"GREEN"};
1772 static FCODE blue[] = {"BLUE"};
1773 static FCODE frac_texture[] = {"      AMBIENT 0.25 DIFFUSE 0.75"};
1774 static FCODE polygon[] = {"polygon={points=3;"};
1775 static FCODE vertex[] = {" vertex =  "};
1776 static FCODE d_vert[] = {"      <"};
1777 static char f1[] = "% #4.4f ";
1778 /* EB & DG: changed this to much better values */
1779 static FCODE grid[] =
1780 {"screen 640 480\neyep 0 2.1 0.8\nlookp 0 0 -0.95\nlight 1 point -2 1 1.5\n"};
1781 static FCODE grid2[] = {"background .3 0 0\nreport verbose\n"};
1782 
1783 static char s_n[] = "\n";
1784 static char f2[] = "R%dC%d R%dC%d\n";
1785 static FCODE ray_comment1[] =
1786    {"/* make a gridded aggregate. this size grid is fast for landscapes. */\n"};
1787 static FCODE ray_comment2[] =
1788    {"/* make z grid = 1 always for landscapes. */\n\n"};
1789 static FCODE grid3[] = {"grid 33 25 1\n"};
1790 
RAY_Header(void)1791 static int _fastcall RAY_Header(void)
1792 {
1793    /* Open the ray tracing output file */
1794    check_writefile(ray_name, ".ray");
1795    if ((File_Ptr1 = fopen(ray_name, "w")) == NULL)
1796       return (-1);              /* Oops, somethings wrong! */
1797 
1798    if (RAY == 2)
1799       fprintf(File_Ptr1, "//");
1800    if (RAY == 4)
1801       fprintf(File_Ptr1, "#");
1802    if (RAY == 5)
1803       fprintf(File_Ptr1, "/*\n");
1804    if (RAY == 6)
1805       fprintf(File_Ptr1, "--");
1806    if (RAY == 7)
1807       fprintf(File_Ptr1, dxf_begin);
1808 
1809    if (RAY != 7)
1810       fprintf(File_Ptr1, banner, (char far *)s3, release / 100., (char far *)s3a);
1811 
1812    if (RAY == 5)
1813       fprintf(File_Ptr1, "*/\n");
1814 
1815 
1816    /* Set the default color */
1817    if (RAY == 1)
1818    {
1819       fprintf(File_Ptr1, s_f, (char far *)declare, (char far *)frac_default);
1820       fprintf(File_Ptr1, " = ");
1821       fprintf(File_Ptr1, s_f, (char far *)s_color, (char far *)dflt);
1822    }
1823    if (BRIEF)
1824    {
1825       if (RAY == 2)
1826       {
1827          fprintf(File_Ptr1, s_f, (char far *)surf, (char far *)d_color);
1828          fprintf(File_Ptr1, ";}\n");
1829       }
1830       if (RAY == 4)
1831       {
1832          fprintf(File_Ptr1, "f ");
1833          fprintf(File_Ptr1, s_f, (char far *)d_color, (char far *)r_surf);
1834       }
1835       if (RAY == 5)
1836          fprintf(File_Ptr1, s_f, (char far *)rs_surf, (char far *)d_color);
1837    }
1838    if (RAY != 7)
1839       fprintf(File_Ptr1, s_n);
1840 
1841    /* EB & DG: open "grid" opject, a speedy way to do aggregates in rayshade */
1842    if (RAY == 5)
1843       fprintf(File_Ptr1, s_fff, (char far *)ray_comment1, (char far *)ray_comment2, (char far *)grid3);
1844 
1845    if (RAY == 6)
1846 #ifndef XFRACT
1847       fprintf(File_Ptr1, "%Fs", (char far *)acro_s1);
1848 #else
1849       fprintf(File_Ptr1, "%s", acro_s1);
1850 #endif
1851 
1852    return (0);
1853 }
1854 
1855 
1856 /********************************************************************/
1857 /*                                                                  */
1858 /*  This routine describes the triangle to the ray tracer, it       */
1859 /*  sets the color of the triangle to the average of the color      */
1860 /*  of its verticies and sets the light parameters to arbitrary     */
1861 /*  values.                                                         */
1862 /*                                                                  */
1863 /*  Note: numcolors (number of colors in the source                 */
1864 /*  file) is used instead of colors (number of colors avail. with   */
1865 /*  display) so you can generate ray trace files with your LCD      */
1866 /*  or monochrome display                                           */
1867 /*                                                                  */
1868 /********************************************************************/
1869 
out_triangle(struct f_point pt1,struct f_point pt2,struct f_point pt3,int c1,int c2,int c3)1870 static int _fastcall out_triangle(struct f_point pt1, struct f_point pt2, struct f_point pt3, int c1, int c2, int c3)
1871 {
1872    int i, j;
1873    float c[3];
1874    float pt_t[3][3];
1875 
1876    /* Normalize each vertex to screen size and adjust coordinate system */
1877    pt_t[0][0] = 2 * pt1.x / xdots - 1;
1878    pt_t[0][1] = (2 * pt1.y / ydots - 1);
1879    pt_t[0][2] = -2 * pt1.color / numcolors - 1;
1880    pt_t[1][0] = 2 * pt2.x / xdots - 1;
1881    pt_t[1][1] = (2 * pt2.y / ydots - 1);
1882    pt_t[1][2] = -2 * pt2.color / numcolors - 1;
1883    pt_t[2][0] = 2 * pt3.x / xdots - 1;
1884    pt_t[2][1] = (2 * pt3.y / ydots - 1);
1885    pt_t[2][2] = -2 * pt3.color / numcolors - 1;
1886 
1887    /* Color of triangle is average of colors of its verticies */
1888    if (!BRIEF)
1889       for (i = 0; i <= 2; i++)
1890 #ifdef __SVR4
1891          c[i] = (float) ((int)(dacbox[c1][i] + dacbox[c2][i] + dacbox[c3][i])
1892             / (3 * 63));
1893 #else
1894          c[i] = (float) (dacbox[c1][i] + dacbox[c2][i] + dacbox[c3][i])
1895             / (3 * 63);
1896 #endif
1897 
1898    /* get rid of degenerate triangles: any two points equal */
1899    if ((pt_t[0][0] == pt_t[1][0] &&
1900         pt_t[0][1] == pt_t[1][1] &&
1901         pt_t[0][2] == pt_t[1][2]) ||
1902 
1903        (pt_t[0][0] == pt_t[2][0] &&
1904         pt_t[0][1] == pt_t[2][1] &&
1905         pt_t[0][2] == pt_t[2][2]) ||
1906 
1907        (pt_t[2][0] == pt_t[1][0] &&
1908         pt_t[2][1] == pt_t[1][1] &&
1909         pt_t[2][2] == pt_t[1][2]))
1910       return (0);
1911 
1912    /* Describe the triangle */
1913 #ifndef XFRACT
1914    if (RAY == 1)
1915       fprintf(File_Ptr1, " %Fs\n  %Fs", (char far *)object, (char far *)triangle);
1916    if (RAY == 2 && !BRIEF)
1917       fprintf(File_Ptr1, "%Fs", (char far *)surf);
1918 #else
1919    if (RAY == 1)
1920       fprintf(File_Ptr1, " %s\n  %s", object, triangle);
1921    if (RAY == 2 && !BRIEF)
1922       fprintf(File_Ptr1, "%s", surf);
1923 #endif
1924    if (RAY == 4 && !BRIEF)
1925       fprintf(File_Ptr1, "f");
1926    if (RAY == 5 && !BRIEF)
1927 #ifndef XFRACT
1928       fprintf(File_Ptr1, "%Fs", (char far *)rs_surf);
1929 #else
1930       fprintf(File_Ptr1, "%s", rs_surf);
1931 #endif
1932 
1933    if (!BRIEF && RAY != 1 && RAY != 7)
1934       for (i = 0; i <= 2; i++)
1935          fprintf(File_Ptr1, f1, c[i]);
1936 
1937    if (RAY == 2)
1938    {
1939       if (!BRIEF)
1940          fprintf(File_Ptr1, ";}\n");
1941 #ifndef XFRACT
1942       fprintf(File_Ptr1, "%Fs", (char far *)polygon);
1943 #else
1944       fprintf(File_Ptr1, "%s", polygon);
1945 #endif
1946    }
1947    if (RAY == 4)
1948    {
1949       if (!BRIEF)
1950 #ifndef XFRACT
1951          fprintf(File_Ptr1, "%Fs", (char far *)r_surf);
1952 #else
1953          fprintf(File_Ptr1, "%s", r_surf);
1954 #endif
1955       fprintf(File_Ptr1, "p 3");
1956    }
1957    if (RAY == 5)
1958    {
1959       if (!BRIEF)
1960          fprintf(File_Ptr1, s_n);
1961       /* EB & DG: removed "T" after "triangle" */
1962 #ifndef XFRACT
1963       fprintf(File_Ptr1, "%Fs", (char far *)l_tri);
1964 #else
1965       fprintf(File_Ptr1, "%s", l_tri);
1966 #endif
1967    }
1968 
1969    if (RAY == 7)
1970       fprintf(File_Ptr1, dxf_3dface, min(255, max(1, c1)));
1971 
1972    for (i = 0; i <= 2; i++)     /* Describe each  Vertex  */
1973    {
1974       if (RAY != 7)
1975          fprintf(File_Ptr1, s_n);
1976 
1977 #ifndef XFRACT
1978       if (RAY == 1)
1979          fprintf(File_Ptr1, "%Fs", (char far *)d_vert);
1980       if (RAY == 2)
1981          fprintf(File_Ptr1, "%Fs", (char far *)vertex);
1982 #else
1983       if (RAY == 1)
1984          fprintf(File_Ptr1, "%s", d_vert);
1985       if (RAY == 2)
1986          fprintf(File_Ptr1, "%s", vertex);
1987 #endif
1988       if (RAY > 3 && RAY != 7)
1989          fprintf(File_Ptr1, " ");
1990 
1991       for (j = 0; j <= 2; j++)
1992       {
1993          if (RAY == 7)
1994          {
1995             /* write 3dface entity to dxf file */
1996             fprintf(File_Ptr1, dxf_vertex, 10 * (j + 1) + i, pt_t[i][j]);
1997             if (i == 2)         /* 3dface needs 4 vertecies */
1998                fprintf(File_Ptr1, dxf_vertex, 10 * (j + 1) + i + 1,
1999                   pt_t[i][j]);
2000          }
2001          else if (!(RAY == 4 || RAY == 5))
2002             fprintf(File_Ptr1, f1, pt_t[i][j]); /* Right handed */
2003          else
2004             fprintf(File_Ptr1, f1, pt_t[2 - i][j]);     /* Left handed */
2005       }
2006 
2007       if (RAY == 1)
2008          fprintf(File_Ptr1, ">");
2009       if (RAY == 2)
2010          fprintf(File_Ptr1, ";");
2011    }
2012 
2013    if (RAY == 1)
2014    {
2015 #ifndef XFRACT
2016       fprintf(File_Ptr1, " %Fs%Fs\n", (char far *)end, (char far *)triangle);
2017 #else
2018       fprintf(File_Ptr1, " %s%s\n", end, triangle);
2019 #endif
2020       if (!BRIEF)
2021       {
2022 #ifndef XFRACT
2023          fprintf(File_Ptr1, "  %Fs"
2024                  "      %Fs%Fs% #4.4f %Fs% #4.4f %Fs% #4.4f\n"
2025                  "%Fs"
2026                  " %Fs%Fs",
2027 #else
2028          fprintf(File_Ptr1,
2029                  "  %s   %s%s% #4.4f %s% #4.4f %s% #4.4f\n%s %s%s",
2030 #endif
2031                  (char far *)texture,
2032                  (char far *)s_color,
2033                  (char far *)red,   c[0],
2034                  (char far *)green, c[1],
2035                  (char far *)blue,  c[2],
2036                  (char far *)frac_texture,
2037                  (char far *)end,
2038                  (char far *)texture);
2039       }
2040 #ifndef XFRACT
2041       fprintf(File_Ptr1, "  %Fs%Fs  %Fs%Fs",
2042 #else
2043       fprintf(File_Ptr1, "  %s%s  %s%s",
2044 #endif
2045               (char far *)s_color, (char far *)frac_default,
2046               (char far *)end, (char far *)object);
2047       triangle_bounds(pt_t);    /* update bounding info */
2048    }
2049    if (RAY == 2)
2050       fprintf(File_Ptr1, "}");
2051    if (RAY == 3 && !BRIEF)
2052       fprintf(File_Ptr1, s_n);
2053 
2054    if (RAY != 7)
2055       fprintf(File_Ptr1, s_n);
2056 
2057    return (0);
2058 }
2059 
2060 /********************************************************************/
2061 /*                                                                  */
2062 /*  This routine calculates the min and max values of a triangle    */
2063 /*  for use in creating ray tracer data files. The values of min    */
2064 /*  and max x, y, and z are assumed to be global.                   */
2065 /*                                                                  */
2066 /********************************************************************/
2067 
triangle_bounds(float pt_t[3][3])2068 static void _fastcall triangle_bounds(float pt_t[3][3])
2069 {
2070    int i, j;
2071 
2072    for (i = 0; i <= 2; i++)
2073       for (j = 0; j <= 2; j++)
2074       {
2075          if (pt_t[i][j] < min_xyz[j])
2076             min_xyz[j] = pt_t[i][j];
2077          if (pt_t[i][j] > max_xyz[j])
2078             max_xyz[j] = pt_t[i][j];
2079       }
2080    return;
2081 }
2082 
2083 /********************************************************************/
2084 /*                                                                  */
2085 /*  This routine starts a composite object for ray trace data files */
2086 /*                                                                  */
2087 /********************************************************************/
2088 
start_object(void)2089 static int _fastcall start_object(void)
2090 {
2091    if (RAY != 1)
2092       return (0);
2093 
2094    /* Reset the min/max values, for bounding box  */
2095    min_xyz[0] = min_xyz[1] = min_xyz[2] = (float)999999.0;
2096    max_xyz[0] = max_xyz[1] = max_xyz[2] = (float)-999999.0;
2097 
2098 #ifndef XFRACT
2099    fprintf(File_Ptr1, "%Fs\n", (char far *)composite);
2100 #else
2101    fprintf(File_Ptr1, "%s\n", composite);
2102 #endif
2103    return (0);
2104 }
2105 
2106 /********************************************************************/
2107 /*                                                                  */
2108 /*  This routine adds a bounding box for the triangles drawn        */
2109 /*  in the last block and completes the composite object created.   */
2110 /*  It uses the globals min and max x,y and z calculated in         */
2111 /*  z calculated in Triangle_Bounds().                              */
2112 /*                                                                  */
2113 /********************************************************************/
2114 
end_object(int triout)2115 static int _fastcall end_object(int triout)
2116 {
2117    if (RAY == 7)
2118       return (0);
2119    if (RAY == 1)
2120    {
2121       if (triout)
2122       {
2123          /* Make sure the bounding box is slightly larger than the object */
2124          int i;
2125          for (i = 0; i <= 2; i++)
2126          {
2127             if (min_xyz[i] == max_xyz[i])
2128             {
2129                min_xyz[i] -= (float)0.01;
2130                max_xyz[i] += (float)0.01;
2131             }
2132             else
2133             {
2134                min_xyz[i] -= (max_xyz[i] - min_xyz[i]) * (float)0.01;
2135                max_xyz[i] += (max_xyz[i] - min_xyz[i]) * (float)0.01;
2136             }
2137          }
2138 
2139          /* Add the bounding box info */
2140 #ifndef XFRACT
2141          fprintf(File_Ptr1, "%Fs  %Fs", (char far *)bnd_by, (char far *)inter);
2142 #else
2143          fprintf(File_Ptr1, "%s  %s", bnd_by, inter);
2144 #endif
2145          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);
2146          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);
2147          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);
2148          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);
2149          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);
2150          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);
2151 #ifndef XFRACT
2152          fprintf(File_Ptr1, "  %Fs%Fs%Fs", (char far *)end,
2153                 (char far *)inter, (char far *)end_bnd);
2154 #else
2155          fprintf(File_Ptr1, "  %s%s%s", end, inter, end_bnd);
2156 #endif
2157       }
2158 
2159       /* Complete the composite object statement */
2160 #ifndef XFRACT
2161       fprintf(File_Ptr1, "%Fs%Fs\n", (char far *)end, (char far *)composite);
2162 #else
2163       fprintf(File_Ptr1, "%s%s\n", end, composite);
2164 #endif
2165    }
2166 
2167    if (RAY != 6 && RAY != 5)
2168       fprintf(File_Ptr1, s_n);    /* EB & DG: too many newlines */
2169 
2170    return (0);
2171 }
2172 
line3d_cleanup(void)2173 static void line3d_cleanup(void)
2174 {
2175    int i, j;
2176    if (RAY && File_Ptr1)
2177    {                            /* Finish up the ray tracing files */
2178       static FCODE n_ta[] = {"{ No. Of Triangles = "};
2179       if (RAY != 5 && RAY != 7)
2180          fprintf(File_Ptr1, s_n); /* EB & DG: too many newlines */
2181       if (RAY == 2)
2182          fprintf(File_Ptr1, "\n\n//");
2183       if (RAY == 4)
2184          fprintf(File_Ptr1, "\n\n#");
2185 
2186       if (RAY == 5)
2187 #ifndef XFRACT
2188          /* EB & DG: end grid aggregate */
2189          fprintf(File_Ptr1, "end\n\n/*good landscape:*/\n%Fs%Fs\n/*",
2190             (char far *)grid, (char far *)grid2);
2191 #else
2192          /* EB & DG: end grid aggregate */
2193          fprintf(File_Ptr1, "end\n\n/*good landscape:*/\n%s%s\n/*",
2194             grid, grid2);
2195 #endif
2196       if (RAY == 6)
2197       {
2198 #ifndef XFRACT
2199          fprintf(File_Ptr1, "%Fs", (char far *)acro_s2);
2200 #else
2201          fprintf(File_Ptr1, "%s", acro_s2);
2202 #endif
2203          for (i = 0; i < RO; i++)
2204             for (j = 0; j <= CO_MAX; j++)
2205             {
2206                if (j < CO_MAX)
2207                   fprintf(File_Ptr1, f2, i, j, i, j + 1);
2208                if (i < RO - 1)
2209                   fprintf(File_Ptr1, f2, i, j, i + 1, j);
2210                if (i && i < RO && j < CO_MAX)
2211                   fprintf(File_Ptr1, f2, i, j, i - 1, j + 1);
2212             }
2213          fprintf(File_Ptr1, "\n\n--");
2214       }
2215       if (RAY != 7)
2216 #ifndef XFRACT
2217          fprintf(File_Ptr1, "%Fs%ld }*/\n\n", (char far *)n_ta, num_tris);
2218 #else
2219          fprintf(File_Ptr1, "%s%ld }*/\n\n", n_ta, num_tris);
2220 #endif
2221       if (RAY == 7)
2222          fprintf(File_Ptr1, dxf_end);
2223       fclose(File_Ptr1);
2224       File_Ptr1 = NULL;
2225    }
2226    if (Targa_Out)
2227    {                            /* Finish up targa files */
2228       T_header_24 = 18;         /* Reset Targa header size */
2229       enddisk();
2230       if (!debugflag && (!T_Safe || error) && Targa_Overlay)
2231       {
2232          dir_remove(workdir, light_name);
2233          rename(targa_temp, light_name);
2234       }
2235       if (!debugflag && Targa_Overlay)
2236          dir_remove(workdir, targa_temp);
2237    }
2238    usr_floatflag &= 1;          /* strip second bit */
2239    error = T_Safe = 0;
2240 }
2241 
set_upr_lwr(void)2242 static void set_upr_lwr(void)
2243 {
2244    upr_lwr[0] = (BYTE)(xdots & 0xff);
2245    upr_lwr[1] = (BYTE)(xdots >> 8);
2246    upr_lwr[2] = (BYTE)(ydots & 0xff);
2247    upr_lwr[3] = (BYTE)(ydots >> 8);
2248    line_length1 = 3 * xdots;    /* line length @ 3 bytes per pixel  */
2249 }
2250 
first_time(int linelen,VECTOR v)2251 static int first_time(int linelen, VECTOR v)
2252 {
2253    int err;
2254    MATRIX lightm;               /* m w/no trans, keeps obj. on screen */
2255    float twocosdeltatheta;
2256    double xval, yval, zval;     /* rotation values */
2257    /* corners of transformed xdotx by ydots x colors box */
2258    double xmin, ymin, zmin, xmax, ymax, zmax;
2259    int i, j;
2260    double v_length;
2261    VECTOR origin, direct, tmp;
2262    float theta, theta1, theta2; /* current,start,stop latitude */
2263    float phi1, phi2;            /* current start,stop longitude */
2264    float deltatheta;            /* increment of latitude */
2265    outln_cleanup = line3d_cleanup;
2266 
2267    calctime = evenoddrow = 0;
2268    /* mark as in-progress, and enable <tab> timer display */
2269    calc_status = 1;
2270 
2271    IAmbient = (unsigned int) (255 * (float) (100 - Ambient) / 100.0);
2272    if (IAmbient < 1)
2273       IAmbient = 1;
2274 
2275    num_tris = 0;
2276 
2277    /* Open file for RAY trace output and write header */
2278    if (RAY)
2279    {
2280       RAY_Header();
2281       xxadjust = yyadjust = 0;  /* Disable shifting in ray tracing */
2282       xshift = yshift = 0;
2283    }
2284 
2285    CO_MAX = CO = RO = 0;
2286 
2287    set_upr_lwr();
2288    error = 0;
2289 
2290    if (whichimage < 2)
2291       T_Safe = 0; /* Not safe yet to mess with the source image */
2292 
2293    if (Targa_Out && !((glassestype == 1 || glassestype == 2)
2294                  && whichimage == 2))
2295    {
2296       if (Targa_Overlay)
2297       {
2298          /* Make sure target file is a supportable Targa File */
2299          if (targa_validate(light_name))
2300             return (-1);
2301       }
2302       else
2303       {
2304          check_writefile(light_name, ".tga");
2305          if (startdisk1(light_name, NULL, 0))   /* Open new file */
2306             return (-1);
2307       }
2308    }
2309 
2310    rand_factor = 14 - RANDOMIZE;
2311 
2312    zcoord = filecolors;
2313 
2314    if((err=line3dmem()) != 0)
2315       return(err);
2316 
2317 
2318    /* get scale factors */
2319    sclx = XSCALE / 100.0;
2320    scly = YSCALE / 100.0;
2321    if (ROUGH)
2322       sclz = -ROUGH / 100.0;
2323    else
2324       rscale = sclz = -0.0001;  /* if rough=0 make it very flat but plot
2325                                  * something */
2326 
2327    /* aspect ratio calculation - assume screen is 4 x 3 */
2328    aspect = (double) xdots *.75 / (double) ydots;
2329 
2330    if (SPHERE == FALSE)         /* skip this slow stuff in sphere case */
2331    {
2332       /*********************************************************************/
2333       /* What is done here is to create a single matrix, m, which has      */
2334       /* scale, rotation, and shift all combined. This allows us to use    */
2335       /* a single matrix to transform any point. Additionally, we create   */
2336       /* two perspective vectors.                                          */
2337       /*                                                                   */
2338       /* Start with a unit matrix. Add scale and rotation. Then calculate  */
2339       /* the perspective vectors. Finally add enough translation to center */
2340       /* the final image plus whatever shift the user has set.             */
2341       /*********************************************************************/
2342 
2343       /* start with identity */
2344       identity(m);
2345       identity(lightm);
2346 
2347       /* translate so origin is in center of box, so that when we rotate */
2348       /* it, we do so through the center */
2349       trans((double) xdots / (-2.0), (double) ydots / (-2.0),
2350             (double) zcoord / (-2.0), m);
2351       trans((double) xdots / (-2.0), (double) ydots / (-2.0),
2352             (double) zcoord / (-2.0), lightm);
2353 
2354       /* apply scale factors */
2355       scale(sclx, scly, sclz, m);
2356       scale(sclx, scly, sclz, lightm);
2357 
2358       /* rotation values - converting from degrees to radians */
2359       xval = XROT / 57.29577;
2360       yval = YROT / 57.29577;
2361       zval = ZROT / 57.29577;
2362 
2363       if (RAY)
2364       {
2365          xval = yval = zval = 0;
2366       }
2367 
2368       xrot(xval, m);
2369       xrot(xval, lightm);
2370       yrot(yval, m);
2371       yrot(yval, lightm);
2372       zrot(zval, m);
2373       zrot(zval, lightm);
2374 
2375       /* Find values of translation that make all x,y,z negative */
2376       /* m current matrix */
2377       /* 0 means don't show box */
2378       /* returns minimum and maximum values of x,y,z in fractal */
2379       corners(m, 0, &xmin, &ymin, &zmin, &xmax, &ymax, &zmax);
2380    }
2381 
2382    /* perspective 3D vector - lview[2] == 0 means no perspective */
2383 
2384    /* set perspective flag */
2385    persp = 0;
2386    if (ZVIEWER != 0)
2387    {
2388       persp = 1;
2389       if (ZVIEWER < 80)         /* force float */
2390          usr_floatflag |= 2;    /* turn on second bit */
2391    }
2392 
2393    /* set up view vector, and put viewer in center of screen */
2394    lview[0] = xdots >> 1;
2395    lview[1] = ydots >> 1;
2396 
2397    /* z value of user's eye - should be more negative than extreme negative
2398     * part of image */
2399    if (SPHERE)                  /* sphere case */
2400       lview[2] = -(long) ((double) ydots * (double) ZVIEWER / 100.0);
2401    else                         /* non-sphere case */
2402       lview[2] = (long) ((zmin - zmax) * (double) ZVIEWER / 100.0);
2403 
2404    view[0] = lview[0];
2405    view[1] = lview[1];
2406    view[2] = lview[2];
2407    lview[0] = lview[0] << 16;
2408    lview[1] = lview[1] << 16;
2409    lview[2] = lview[2] << 16;
2410 
2411    if (SPHERE == FALSE)         /* sphere skips this */
2412    {
2413       /* translate back exactly amount we translated earlier plus enough to
2414        * center image so maximum values are non-positive */
2415       trans(((double) xdots - xmax - xmin) / 2,
2416             ((double) ydots - ymax - ymin) / 2, -zmax, m);
2417 
2418       /* Keep the box centered and on screen regardless of shifts */
2419       trans(((double) xdots - xmax - xmin) / 2,
2420             ((double) ydots - ymax - ymin) / 2, -zmax, lightm);
2421 
2422       trans((double) (xshift), (double) (-yshift), 0.0, m);
2423 
2424       /* matrix m now contains ALL those transforms composed together !!
2425        * convert m to long integers shifted 16 bits */
2426       for (i = 0; i < 4; i++)
2427          for (j = 0; j < 4; j++)
2428             llm[i][j] = (long) (m[i][j] * 65536.0);
2429 
2430    }
2431    else
2432       /* sphere stuff goes here */
2433    {
2434       /* Sphere is on side - north pole on right. Top is -90 degrees
2435        * latitude; bottom 90 degrees */
2436 
2437       /* Map X to this LATITUDE range */
2438       theta1 = (float) (THETA1 * PI / 180.0);
2439       theta2 = (float) (THETA2 * PI / 180.0);
2440 
2441       /* Map Y to this LONGITUDE range */
2442       phi1 = (float) (PHI1 * PI / 180.0);
2443       phi2 = (float) (PHI2 * PI / 180.0);
2444 
2445       theta = theta1;
2446 
2447       /*********************************************************************/
2448       /* Thanks to Hugh Bray for the following idea: when calculating      */
2449       /* a table of evenly spaced sines or cosines, only a few initial     */
2450       /* values need be calculated, and the remaining values can be        */
2451       /* gotten from a derivative of the sine/cosine angle sum formula     */
2452       /* at the cost of one multiplication and one addition per value!     */
2453       /*                                                                   */
2454       /* This idea is applied once here to get a complete table for        */
2455       /* latitude, and near the bottom of this routine to incrementally    */
2456       /* calculate longitude.                                              */
2457       /*                                                                   */
2458       /* Precalculate 2*cos(deltaangle), sin(start) and sin(start+delta).  */
2459       /* Then apply recursively:                                           */
2460       /* sin(angle+2*delta) = sin(angle+delta) * 2cosdelta - sin(angle)    */
2461       /*                                                                   */
2462       /* Similarly for cosine. Neat!                                       */
2463       /*********************************************************************/
2464 
2465       deltatheta = (float) (theta2 - theta1) / (float) linelen;
2466 
2467       /* initial sin,cos theta */
2468       sinthetaarray[0] = (float) sin((double) theta);
2469       costhetaarray[0] = (float) cos((double) theta);
2470       sinthetaarray[1] = (float) sin((double) (theta + deltatheta));
2471       costhetaarray[1] = (float) cos((double) (theta + deltatheta));
2472 
2473       /* sin,cos delta theta */
2474       twocosdeltatheta = (float) (2.0 * cos((double) deltatheta));
2475 
2476       /* build table of other sin,cos with trig identity */
2477       for (i = 2; i < (int) linelen; i++)
2478       {
2479          sinthetaarray[i] = sinthetaarray[i - 1] * twocosdeltatheta -
2480             sinthetaarray[i - 2];
2481          costhetaarray[i] = costhetaarray[i - 1] * twocosdeltatheta -
2482             costhetaarray[i - 2];
2483       }
2484 
2485       /* now phi - these calculated as we go - get started here */
2486       deltaphi = (float) (phi2 - phi1) / (float) height;
2487 
2488       /* initial sin,cos phi */
2489 
2490       sinphi = oldsinphi1 = (float) sin((double) phi1);
2491       cosphi = oldcosphi1 = (float) cos((double) phi1);
2492       oldsinphi2 = (float) sin((double) (phi1 + deltaphi));
2493       oldcosphi2 = (float) cos((double) (phi1 + deltaphi));
2494 
2495       /* sin,cos delta phi */
2496       twocosdeltaphi = (float) (2.0 * cos((double) deltaphi));
2497 
2498 
2499       /* affects how rough planet terrain is */
2500       if (ROUGH)
2501          rscale = .3 * ROUGH / 100.0;
2502 
2503       /* radius of planet */
2504       R = (double) (ydots) / 2;
2505 
2506       /* precalculate factor */
2507       rXrscale = R * rscale;
2508 
2509       sclz = sclx = scly = RADIUS / 100.0;      /* Need x,y,z for RAY */
2510 
2511       /* adjust x scale factor for aspect */
2512       sclx *= aspect;
2513 
2514       /* precalculation factor used in sphere calc */
2515       Rfactor = rscale * R / (double) zcoord;
2516 
2517       if (persp)                /* precalculate fudge factor */
2518       {
2519          double radius;
2520          double zview;
2521          double angle;
2522 
2523          xcenter = xcenter << 16;
2524          ycenter = ycenter << 16;
2525 
2526          Rfactor *= 65536.0;
2527          R *= 65536.0;
2528 
2529          /* calculate z cutoff factor attempt to prevent out-of-view surfaces
2530           * from being written */
2531          zview = -(long) ((double) ydots * (double) ZVIEWER / 100.0);
2532          radius = (double) (ydots) / 2;
2533          angle = atan(-radius / (zview + radius));
2534          zcutoff = -radius - sin(angle) * radius;
2535          zcutoff *= 1.1;        /* for safety */
2536          zcutoff *= 65536L;
2537       }
2538    }
2539 
2540    /* set fill plot function */
2541    if (FILLTYPE != 3)
2542       fillplot = interpcolor;
2543    else
2544    {
2545       fillplot = clipcolor;
2546 
2547       if (transparent[0] || transparent[1])
2548          /* If transparent colors are set */
2549          fillplot = T_clipcolor;/* Use the transparent plot function  */
2550    }
2551 
2552    /* Both Sphere and Normal 3D */
2553    direct[0] = light_direction[0] = XLIGHT;
2554    direct[1] = light_direction[1] = -YLIGHT;
2555    direct[2] = light_direction[2] = ZLIGHT;
2556 
2557    /* Needed because sclz = -ROUGH/100 and light_direction is transformed in
2558     * FILLTYPE 6 but not in 5. */
2559    if (FILLTYPE == 5)
2560       direct[2] = light_direction[2] = -ZLIGHT;
2561 
2562    if (FILLTYPE == 6)           /* transform light direction */
2563    {
2564       /* Think of light direction  as a vector with tail at (0,0,0) and head
2565        * at (light_direction). We apply the transformation to BOTH head and
2566        * tail and take the difference */
2567 
2568       v[0] = 0.0;
2569       v[1] = 0.0;
2570       v[2] = 0.0;
2571       vmult(v, m, v);
2572       vmult(light_direction, m, light_direction);
2573 
2574       for (i = 0; i < 3; i++)
2575          light_direction[i] -= v[i];
2576    }
2577    normalize_vector(light_direction);
2578 
2579    if (preview && showbox)
2580    {
2581       normalize_vector(direct);
2582 
2583       /* move light vector to be more clear with grey scale maps */
2584       origin[0] = (3 * xdots) / 16;
2585       origin[1] = (3 * ydots) / 4;
2586       if (FILLTYPE == 6)
2587          origin[1] = (11 * ydots) / 16;
2588 
2589       origin[2] = 0.0;
2590 
2591       v_length = min(xdots, ydots) / 2;
2592       if (persp && ZVIEWER <= P)
2593          v_length *= (long) (P + 600) / ((long) (ZVIEWER + 600) * 2);
2594 
2595       /* Set direct[] to point from origin[] in direction of untransformed
2596        * light_direction (direct[]). */
2597       for (i = 0; i < 3; i++)
2598          direct[i] = origin[i] + direct[i] * v_length;
2599 
2600       /* center light box */
2601       for (i = 0; i < 2; i++)
2602       {
2603          tmp[i] = (direct[i] - origin[i]) / 2;
2604          origin[i] -= tmp[i];
2605          direct[i] -= tmp[i];
2606       }
2607 
2608       /* Draw light source vector and box containing it, draw_light_box will
2609        * transform them if necessary. */
2610       draw_light_box(origin, direct, lightm);
2611       /* draw box around original field of view to help visualize effect of
2612        * rotations 1 means show box - xmin etc. do nothing here */
2613       if (!SPHERE)
2614          corners(m, 1, &xmin, &ymin, &zmin, &xmax, &ymax, &zmax);
2615    }
2616 
2617    /* bad has values caught by clipping */
2618    f_bad.x = bad.x = bad_value;
2619    f_bad.y = bad.y = bad_value;
2620    f_bad.color = bad.color = bad_value;
2621    for (i = 0; i < (int) linelen; i++)
2622    {
2623       lastrow[i] = bad;
2624       f_lastrow[i] = f_bad;
2625    }
2626    got_status = 3;
2627    return (0);
2628 } /* end of once-per-image intializations */
2629 
2630 /*
2631    This pragma prevents optimizer failure in MSC/C++ 7.0. Program compiles ok
2632    without pragma, but error message is real ugly, paraphrasing loosely,
2633    something like "optimizer screwed up big time, call Bill Gates collect ...
2634    (Note: commented out pragma because we removed the compiler "/Og" option
2635     in MAKEFRACT.BAT - left these notes as a warning...
2636 */
2637 #ifdef _MSC_VER
2638 #if (_MSC_VER >= 600)
2639 /* #pragma optimize( "g", off ) */
2640 #endif
2641 #endif
2642 
line3dmem(void)2643 static int line3dmem(void)
2644 {
2645    /*********************************************************************/
2646    /*  Memory allocation - assumptions - a 64K segment starting at      */
2647    /*  extraseg has been grabbed. It may have other purposes elsewhere, */
2648    /*  but it is assumed that it is totally free for use here. Our      */
2649    /*  strategy is to assign all the far pointers needed here to various*/
2650    /*  spots in the extra segment, depending on the pixel dimensions of */
2651    /*  the video mode, and check whether we have run out. There is      */
2652    /*  basically one case where the extra segment is not big enough     */
2653    /*  -- SPHERE mode with a fill type that uses putatriangle() (array  */
2654    /*  minmax_x) at the largest legal resolution of MAXPIXELSxMAXPIXELS */
2655    /*  or thereabouts. In that case we use farmemalloc to grab memory   */
2656    /*  for minmax_x. This memory is never freed.                        */
2657    /*********************************************************************/
2658    long check_extra;  /* keep track ofd extraseg array use */
2659 
2660    /* lastrow stores the previous row of the original GIF image for
2661       the purpose of filling in gaps with triangle procedure */
2662    /* first 8k of extraseg now used in decoder TW 3/95 */
2663    lastrow = MK_FP(extraseg, 0);
2664 
2665    check_extra = sizeof(*lastrow) * xdots;
2666    if (SPHERE)
2667    {
2668       sinthetaarray = (float far *) (lastrow + xdots);
2669       check_extra += sizeof(*sinthetaarray) * xdots;
2670       costhetaarray = (float far *) (sinthetaarray + xdots);
2671       check_extra += sizeof(*costhetaarray) * xdots;
2672       f_lastrow = (struct f_point far *) (costhetaarray + xdots);
2673    }
2674    else
2675       f_lastrow = (struct f_point far *) (lastrow + xdots);
2676    check_extra += sizeof(*f_lastrow) * (xdots);
2677    if (pot16bit)
2678    {
2679       fraction = (BYTE far *) (f_lastrow + xdots);
2680       check_extra += sizeof(*fraction) * xdots;
2681    }
2682    minmax_x = (struct minmax *) NULL;
2683 
2684    /* these fill types call putatriangle which uses minmax_x */
2685    if (FILLTYPE == 2 || FILLTYPE == 3 || FILLTYPE == 5 || FILLTYPE == 6)
2686    {
2687       /* end of arrays if we use extra segement */
2688       check_extra += sizeof(struct minmax) * ydots;
2689       if (check_extra > (1L << 16))     /* run out of extra segment? */
2690       {
2691          static FCODE msg[] = {"farmemalloc minmax"};
2692          static struct minmax far *got_mem = NULL;
2693          if(debugflag == 2222)
2694             stopmsg(0,msg);
2695          /* not using extra segment so decrement check_extra */
2696          check_extra -= sizeof(struct minmax) * ydots;
2697          if (got_mem == NULL)
2698             got_mem = (struct minmax far *) (farmemalloc(OLDMAXPIXELS *
2699                                                     sizeof(struct minmax)));
2700          if (got_mem)
2701             minmax_x = got_mem;
2702          else
2703             return (-1);
2704       }
2705       else /* ok to use extra segment */
2706       {
2707          if (pot16bit)
2708             minmax_x = (struct minmax far *) (fraction + xdots);
2709          else
2710             minmax_x = (struct minmax far *) (f_lastrow + xdots);
2711       }
2712    }
2713    if (debugflag == 2222 || check_extra > (1L << 16))
2714    {
2715       char tmpmsg[70];
2716       static FCODE extramsg[] = {" of extra segment"};
2717 #ifndef XFRACT
2718       sprintf(tmpmsg, "used %ld%Fs", check_extra, (char far *)extramsg);
2719 #else
2720       sprintf(tmpmsg, "used %ld%s", check_extra, extramsg);
2721 #endif
2722       stopmsg(4, tmpmsg);
2723    }
2724    return(0);
2725 }
2726 
2727 #ifdef _MSC_VER
2728 #if (_MSC_VER >= 600)
2729 #pragma optimize( "g", on )
2730 #endif
2731 #endif
2732