/* main.c * ***************************************************************** * * * basic ray tracing: * * spheres and a floor (reflection, refraction and diffuse) * * programmer: friedrich knauss * * 7-4-86 to 7-21-86 * * ported to st: allen king 5/87, added: * * limited color * * low rez display first * * .25 to 16 rays per pixel * * object definitions in file * * multiple-frame movies * * bouncing and gravity * * * *****************************************************************/ #include #include #include #include #include "rtd.h" #define dprintf if (debug) printf /* these definitions describe a window in the x-y plane that the whole thing is viewd through. */ int XMIN, YMIN, XMAX, YMAX; float xmin, ymax; /* floating pt versions */ wOnewSize(x,y, w,h) int x,y, w,h; { XMIN = x; YMIN = y; XMAX = x+w+2; YMAX = y+h+2; } /* Nomenclature notes: * 1. P stands for "the number of 's PER * 2. r stands for rays * 3. p stands for pixels * 4. s stands for either side of the screen * 5. the suffix "Max" denotes the max number compiled into the program * * Note: these are linear (not area) conversions. A value of 2 rPp (rays PER * pixel) is applied in both x and y directions to get an area (and more * true to life) conversion of 4 (square) rays through each (square) pixel. */ float rPp; /* rays PER pixel (on a (linear) side)*/ # define rPpMax 4 /* maximum rays PER pixel (ditto) */ int pPs; /* pixels PER side (of screen) */ int rPs; /* rays PER side (of screen) */ int rPsMax; /* Max rays PER side (of screen) */ #define INC 1 #define INCY (1.25/rPpMax) #define INCX (1.0/rPpMax) int colorInd; /* color index (1->b/w, 2->2tones, 3->3tones)*/ #define colors(r,g,b) 1000*(2*(r)+1)/16, 1000*(2*(g)+1)/16, 1000*(2*(b)+1)/16, int oldClut[16][3], trClut[][3] = { #include "colors.h" 0}; struct { int (*pal)[][3]; int Navg; } cConfig[] = {{trClut, 16}, {trClut+16, 32}, {trClut+32, 43}}; FILE *fp, *fopen(); char getline(); char outname[6] = "pearl"; int wHandle; int pxy_array[4]; #define Nball 15 struct ball bl[Nball]; int level, nob; struct vector vp; float gravity = 0.0, attraction = 0.0; int step, Step = 1000, bounce = 1;; int fr=0, frames=1; int debug =0; struct sphere ls; main () { static float xco, yco, yup; struct ray rr; int h, i, j, k; int c, cr, cg, cb; int x0, y0, x1, y1, dx, dy, dmax, xMax, yMax; double red, green, blue; /* was int */ long ctr, BavgN; float tmp; char str[200], *buf; int Navg, *avg, *Bavg; rPp = 1.0;/* defaults: */ colorInd = 1; /* graf_mouse(M_OFF, 0L);/**/ printf("\033E"); do { printf(" RAYMOVI.PRG\n\n"); printf("Enter scene descriptor\nfilename: "); if (getline(str, sizeof(str)) == '\003') exit(0); printf("\nreading file %s\n", str); } while(scene_inz(str) == 0); printf("\033E"); wHandle = w_open(0, "raymovi", 0); /* open window (typeless, menueless) */ w_lClut(cConfig[colorInd-1].pal, oldClut); v_hide_c(wHandle); xmin = XMIN; ymax = YMAX; dx = XMAX-XMIN; dy = YMAX-YMIN; if (rPp > 1.0001) { BavgN = (long)dx * dy * colorInd; Bavg = Malloc(BavgN * sizeof(int)); if (Bavg == 0) { long l1; printf("limited to 1 ray/pixel due to insufficient RAM\n"); if (rPp > 1.0) rPp = 1.0; for (l1=0; l1<200000; l1++); } for (tmp = 1.0; rPp >= 1.0001; tmp *= 2.0, rPp /= 2.0); } else for (tmp = 1.0; rPp < .5001; tmp /= 2.0, rPp *= 2.0); rPp = tmp; dmax = (dx>dy)? dx: dy; for (i=dmax-1, pPs=1; i>0 ; i>>=1, pPs<<=1); for (i=rPp*pPs-0.5, rPs=1; i>0 ; i>>=1, rPs<<=1); rPsMax = rPpMax * pPs; xMax = ((long)rPsMax*dx)/pPs; yMax = ((long)rPsMax*dy)/pPs; for (; fr<=frames; fr++) { int len, len1, p34, x, y, Elen, Ey; redraw: if (Bavg) for (avg = Bavg, ctr=0; ctr= rPsMax/rPs; len /=2) { p34 = 3; if (len>=rPpMax) { len1 = len/rPpMax - 1; Elen = 0; }else { len1 = 0; Elen = rPpMax -1; Navg *= 4; } for (y=0; y 3*(cg+cb)) { c = cr/Navg % 6; /* red */ if (c) c += 5; /* red */ else c = 1; } else if (4*cb > 3*(cr+cg)) { c = cb/Navg % 6; /* blue */ if (c) c += 10; /* red */ else c = 1; } else c = (cg/Navg+1) % 6; /* white */ break; } dprintf("%d,%d,%d -> %d\n", cr, cg, cb, c); vsf_color(wHandle, c); /*draw colored box*/ v_bar(wHandle, pxy_array); } if ((ctr&15)== 0 && kbd() == -1) goto redraw; } sprintf(str, "%s%03d: RAYMOVI.PRG rpp=%05.3f", outname, fr, (float)ctr/((long)dx*dy)); di_header(1, str); } } sprintf(str, "%s%03d.pi1", outname, fr); f_write(str, colorInd-1); movie(&bl, nob, step, Step, gravity, bounce, attraction); write_ckpt("checkpt"); } exit: w_lClut(oldClut, (long)0); w_close(); } kbd() { char key, fname[20]; int found_first = 0, fr1, rval=0; if (Cconis() == 0) return(0); key = Cconin(); while (1) { sprintf(fname, "%s%03d.pi1", outname, fr); switch(key) { case ('?'): case ('\0'): /* help */ printf("\033E\n\n RayMovi\n\ \nw - write \"%s\" from screen,\ \nr - read \"%s\" to screen,\ \np - play movie \"%sXXX.pi1\ \ne - exit\n\n", fname, fname, outname); key = Cconin(); printf("\033E"); rval = -1; break; case ('D'): debug = 1-debug; return (rval); case ('w'): f_write(fname, colorInd-1); return (rval); case ('r'): case ('p'): fr1 = 1; while (key == 'p' || key == 'r') { sprintf(fname,"%s%03d.pi1", outname, fr1++); if (f_read(fname, (long)0) <0) { if (found_first) { fr1 = 1; found_first = 0; } } else found_first = 1; if (Cconis() != 0 || key == 'r' && found_first) key = Cconin(); } rval = -1; break; case ('e'): case('\003'): w_lClut(oldClut, (long)0); w_close(); exit(0); default: return(rval); } } } scene_inz(inz_file) char *inz_file; { int h, i, j, k; char str[200], *buf; if ((fp=fopen(inz_file, "r"))==0) { printf("can't open file '%s'\n", inz_file); return(0); } j=0, h=0; while (1) { int linenum; buf = str; for (k=0; (i = getc(fp)) != '\n' && i != EOF && ++k= Nball) panic("**** ERROR: too many balls (%d >= %d)", j,Nball); if (7 !=sscanf(buf+1," %f,%f,%f,%f,%f,%f,%f", &bl[j].s.cent.x, &bl[j].v.x, &bl[j].s.cent.y, &bl[j].v.y,&bl[j].s.cent.z, &bl[j].v.z, &bl[j].s.rad)) goto errors; j++; break; case ('o'): /* optical ball properties */ if (h >= Nball) panic("**** ERROR: Too many balls (%d >= %d)", h,Nball); if(8 !=sscanf(buf+1," %f,%f,%f,%f,%f,%f,%f,%f", &bl[h].ior, &bl[h].rfr, &bl[h].rfl, &bl[h].dif, &bl[h].amb, &bl[h].red, &bl[h].green, &bl[h].blue)) goto errors; bl[h].ior *= bl[h].ior; h++; break; case ('v'): /* define viewpoint */ if (3 != sscanf(buf+1, " %f,%f,%f", &vp.x, &vp.y, &vp.z)) goto errors; break; case ('l'): /* define light source (rad = how fuzzy shadows are) */ if (4 != sscanf(buf+1, " %f,%f,%f,%f", &ls.cent.x, &ls.cent.y, &ls.cent.z, &ls.rad)) goto errors; break; case ('r'): /* define number of rays per pixel and color scheme */ if (2 != sscanf(buf+1, " %f, %d", &rPp, &colorInd)) goto errors; colorInd = colorInd<1? 1: colorInd>=3? 3: colorInd; rPp = sqrt(rPp>16.0? 16.0: rPp); break; case ('g'): /* gravity, etc */ if (3 != sscanf(buf+1, " %f, %f, %d", &gravity, &attraction, &bounce)) goto errors; gravity /= Step * 10; break; case ('f'): /* define the filename */ while(*(++buf) == ' '); /* skip leading spaces */ for (i=0; i<5 && *buf!=','; i++) outname[i] = *buf++; outname[i] = 0; if (2 != sscanf(buf+1, "%d,%d", &fr, &frames)) goto errors; break; case ('\t'): /* comment */ case (' '): case ('\0'): break; default: errors: printf("**** ERROR in line %d:\n%s\n", linenum, buf); } } fclose(fp); if (h != j) panic("Number of 'o' lines (%ld) mismatches\n number of 'p' lines (%ld)\n", (long)h, (long)j); nob = j; return(1); } write_ckpt(name) char *name; { int i; if ((fp = fopen(name, "w")) != 0) { fprintf(fp, "f %s, %d, %d\n", outname, fr+1, frames); for (i=0; i 0;) { c = i = Cconin(); if (c == '\n' || c == '\r' || c == ' ') return (c); else if (c == '\003' || c == '\214') /* ^c or Undo */ return ('\003'); else if (c == '\b') { if (k < sizeofstr) { *--buf = 0; k++; }else printf(" "); } else { *buf++ = c; *buf = '\0'; k--; } } } panic(s,l1,l2) char *s; long l1,l2; { printf("\n"); printf(s,l1,l2); printf("\npress any key to continue"); Cconin(); if (wHandle) { w_lClut(oldClut, (long)0); w_close(); } exit(1); atoi(); }