File: common\line3d.c
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";
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[14] = "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
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);
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 */
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
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
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
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 */
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
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
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
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
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
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
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
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";
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
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);
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);
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
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
1500 int targa_validate(char *File_Name)
1501 {
1502 FILE *fp;
1503 int i;
1504 #if 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
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
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
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
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);
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
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
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);
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);
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);
1945 #endif
1946 }
1947 if (RAY == 4)
1948 {
1949 if (!BRIEF)
1950 #ifndef XFRACT
1951 fprintf(File_Ptr1, "%Fs", (char far *)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);
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);
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);
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",
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",
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
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
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);
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
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);
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);
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);
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
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);
2195 #endif
2196 if (RAY == 6)
2197 {
2198 #ifndef XFRACT
2199 fprintf(File_Ptr1, "%Fs", (char far *)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);
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
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
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
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);
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