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";
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[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);
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 */ 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";
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 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 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
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 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);
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 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 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);
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 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 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 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);
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