/* animballs.c -- code to handle actual rotating images */ #include #include #include #include #include "globals.h" #include #include #include int woffset = WOFFSET; #define SETANDBOUND(ii,ff) {ii = 0.5 + ff * 15; \ if (ii > 15) ii = 15; \ else if (ii < 0) ii = 0;} float ka, kd, ks, lx, ly, lz, n, r; /* coloring parameters */ long int ix,iy,iz, jx,jy,jz, kx,ky,kz; static char title[81]; int bgcolor = 0; int scx = WIDTH / 2, scy = SMHEIGHT / 2; int xstart = -1; ystart = -1; #define ISIZE 14 #define FTOI(x) ((long int) (x * (1 << ISIZE))) #define MULT(x,y) ((x * y) >> ISIZE) #define LSIZE 10 #define MAKEL(x) ((long int) x * (1 << LSIZE)) struct Ball { long int x,y,z; float r,g,b,rad; long int xp,yp,zp; int y1,y2,intr,size; int dup; }; int nball; struct Ball **ballptr; struct Ball *balls; int maxsize = 0; int maskw = 0, maskh = 1; int maxextent = 0; long int intsin[360]; long int intcos[360]; void readballs(name) char *name; { int i, j, extent; int c; float x,y,z,rad,r,g,b; FILE *fp, *fopen(); int ir,ig,ib; if ((fp = fopen(name,"r")) == NULL) { fprintf(stderr,"Can't open balls file - '%s'",name); panic(""); } strcpy(title,"Drag Mouse to Rotate"); if ((c = getc(fp)) != '"') ungetc(c,fp); else { i = 0; c = getc(fp); while ((c != '"') && (c != EOF)) { if (i < 80) title[i++] = c; c = getc(fp); } if (c == EOF) panic("Error - title lacks final \""); title[i] = 0; } if ((c = fscanf(fp,"%f %f %f",&r,&g,&b)) != 3) { fprintf(stderr,"Error reading background color %d",c+1); panic(""); } else { SETANDBOUND(ir,r); SETANDBOUND(ig,g); SETANDBOUND(ib,b); bgcolor = match(ir,ig,ib); } if (fscanf(fp,"%d",&nball) != 1) panic("Error - Can't read number of balls"); balls = (struct Ball *) malloc(sizeof(struct Ball)*nball); if (balls == 0) panic("Not enough memory for balls"); ballptr = (struct Ball **) malloc(sizeof(long int)*nball); if (ballptr == 0) panic("Not enough memory for ballptr"); for (i = 0; i < nball; i++) { if ((c=fscanf(fp,"%f %f %f %f %f %f %f",&x,&y,&z,&rad,&r,&g,&b))!=7) {fprintf(stderr, "Error in reading item %d in ball description %d", c+1,i+1); panic(""); } balls[i].x = MAKEL(x); balls[i].y = MAKEL(y); balls[i].z = MAKEL(z); balls[i].rad = rad; balls[i].r = r; balls[i].g = g; balls[i].b = b; balls[i].intr = rad + 0.5; balls[i].size = 2 * balls[i].intr + 1; extent = 0.9 + sqrt(x*x + y*y +z*z) + balls[i].intr; if (extent > maxextent) maxextent = extent; if (balls[i].size > maxsize) maxsize = balls[i].size; balls[i].dup = -1; for (j = 0; j < i; j++) /* check for duplicate entries */ if ((balls[j].rad == rad) && (balls[j].r == r) && (balls[j].g == g) && (balls[j].b == b)) { balls[i].dup = j; break; } if (balls[i].dup != -1) { balls[i].y1 = balls[balls[i].dup].y1; balls[i].y2 = balls[balls[i].dup].y2; } else { balls[i].y1 = maskh; maskh += balls[i].size; if (!bw) { balls[i].y2 = maskh; maskh += balls[i].size; } else balls[i].y2 = 0; } } maskw = ((maxsize + 15) & ~15) + 16; fclose(fp); checkextent(); } void checkextent() { int largest,i; long int scale; double fscale; largest = scy - 10; if (scx < largest) largest = scx; if (maxextent > largest) { fprintf(stderr,"Warning, balls are too far apart, I will re-scale.\n"); Delay(250); fscale = (((double) largest) / ((double) maxextent)); scale = FTOI(fscale); maxsize = 0; maskw = 0; maskh = 1; for (i=0; i < nball; i++) { balls[i].x = MULT(balls[i].x,scale); balls[i].y = MULT(balls[i].y,scale); balls[i].z = MULT(balls[i].z,scale); balls[i].rad *= fscale; balls[i].intr = balls[i].rad + 0.5; balls[i].size = 2 * balls[i].intr + 1; if (balls[i].size > maxsize) maxsize = balls[i].size; if (balls[i].dup != -1 ) { balls[i].y1 = balls[balls[i].dup].y1; balls[i].y2 = balls[balls[i].dup].y2; } else { balls[i].y1 = maskh; maskh += balls[i].size; if (!bw) { balls[i].y2 = maskh; maskh += balls[i].size; } else balls[i].y2 = 0; } } maskw = ((maxsize + 15) & ~15) + 16; } } void initsin() { int i; float r,s; for (i=0; i < 360; i++) { r = i * (3.14159/180.0); s = sin(r); intsin[i] = FTOI(s); s = cos(r); intcos[i] = FTOI(s); } } void isin(x,c,s) int x; /* x is degrees */ long int *c,*s; { while (x >= 360) x -=360; while (x < 0) x += 360; *c = intcos[x]; *s = intsin[x]; } void initrender() { float m; initsin(); ka = .2; kd = .5; ks = .65; lx = ly = lz = 1; m = sqrt(lx*lx + ly*ly + lz*lz); lx /= m; ly /= m; lz /= m; n = 10; r = 9.5; ix = FTOI(1); iy = iz = 0; jy = FTOI(1); jx = jz = 0; kz = FTOI(1); kx = ky = 0; } void render() { int i; int x, y; int cont, MouseMoved; struct IntuiMessage *message; ULONG class; USHORT code,qual; for (i = 0; i < nball; i++) renderball(i); SetWindowTitles(mywindow,title,((char *)(-1))); mylinecopy(sbitmap,0,10,WOFFSET); showballs(); cont = 1; while(cont) { Wait(1 << (mywindow->UserPort->mp_SigBit)); MouseMoved = FALSE; while(message = (struct IntuiMessage *) GetMsg(mywindow->UserPort)) { class = message->Class; code = message->Code; x = message->MouseX; y = message->MouseY; qual = message->Qualifier; ReplyMsg((struct Message *)message); if (class == MOUSEMOVE) MouseMoved = TRUE; else if (class == CLOSEWINDOW) { cont = 0; break; } else if (class == MOUSEBUTTONS) mbutton(code,x,y); } if (MouseMoved && cont) mmove(x,y,qual); } } void showballs() { int i,j,sx,sy; struct Ball *ball; long int x,y; for (i = 0; i < nball; i++) { ball = ballptr[i] = &(balls[i]); ball->xp = ((ball->x)*ix + (ball->y)*jx + (ball->z)*kx) >> ISIZE; ball->yp = ((ball->x)*iy + (ball->y)*jy + (ball->z)*ky) >> ISIZE; ball->zp = ((ball->x)*iz + (ball->y)*jz + (ball->z)*kz) >> ISIZE; } for (i = nball-1; i > 0; i--) for (j = 0; j < i; j++) { if (ballptr[i]->zp < ballptr[j]->zp) { ball = ballptr[i]; ballptr[i]=ballptr[j]; ballptr[j]=ball; } } myblankc(sbitmap,10+woffset,190+woffset,bgcolor); if (!bw) myblankc(&tbitmap,0,SMHEIGHT-1,bgcolor); for (i = 0; i < nball; i++) { ball = ballptr[i]; x = (ball->xp + (1 << (LSIZE - 1))) >> LSIZE; y = (ball->yp + (1 << (LSIZE - 1))) >> LSIZE; sx = scx + x - ball->intr; sy = scy - y - ball->intr; BltBitMask(&ibitmap,0,ball->y1, sbitmap,sx,sy+woffset, &mbitmap,0,ball->y1,0, ball->size,ball->size); if (!bw) { BltBitMask(&ibitmap,0,ball->y2, &tbitmap,sx,sy, &mbitmap,0,ball->y1,0, ball->size,ball->size); BltBitMask(&tbitmap,sx+ball->intr+1,sy, sbitmap,sx+ball->intr+1,sy+woffset, &mbitmap,ball->intr,ball->y2,0, ball->intr+1,ball->size); } } flip(); } void scrollx(d) int d; { long int c,s; long int t; isin(-d,&c,&s); t = (c * ix - s * iz) >> ISIZE; iz = (s * ix + c * iz) >> ISIZE; ix = t; t = (c * jx - s * jz) >> ISIZE; jz = (s * jx + c * jz) >> ISIZE; jx = t; t = (c * kx - s * kz) >> ISIZE; kz = (s * kx + c * kz) >> ISIZE; kx = t; } void scrolly(d) int d; { long int c,s; long int t; isin(d,&c,&s); t = (c * iy - s * iz) >> ISIZE; iz = (s * iy + c * iz) >> ISIZE; iy = t; t = (c * jy - s * jz) >> ISIZE; jz = (s * jy + c * jz) >> ISIZE; jy = t; t = (c * ky - s * kz) >> ISIZE; kz = (s * ky + c * kz) >> ISIZE; ky = t; } void scrollz(d) int d; { long int c,s; long int t; isin(d,&c,&s); t = (c * iy - s * ix) >> ISIZE; ix = (s * iy + c * ix) >> ISIZE; iy = t; t = (c * jy - s * jx) >> ISIZE; jx = (s * jy + c * jx) >> ISIZE; jy = t; t = (c * ky - s * kx) >> ISIZE; kx = (s * ky + c * kx) >> ISIZE; ky = t; } void mbutton(code,x,y) int code, x, y; { if (code == SELECTDOWN) { xstart = x; ystart = y; } else if (code == SELECTUP) { xstart = ystart = -1; } } void mmove(x,y,qual) int x,y; USHORT qual; { register int shift; if (qual & 0x30) shift = 2; /* L-ALT, R-ALT */ else if (qual & 0x07) shift = 0; /* SHIFT */ else shift = 1; if (xstart != -1) { if (qual & 0x08) /* CNTL */ scrollz((x - xstart)<RasInfo->RyOffset = WOFFSET; } else { vp->RasInfo->RyOffset = 0; } ScrollVPort(vp); Enable(); Permit(); if (woffset) { woffset = 0; } else { woffset = WOFFSET; } } void renderball(j) int j; { struct Ball *ball; int intr, size, y1, y2; int x, y, xp, yp, ired, igreen, iblue; int start; float nx, ny, nz, rz, id, is; ball = balls+j; if (ball->dup != -1) return; y1 = ball->y1; y2 = ball->y2; intr = ball->intr; size = ball->size; /* special mask is offset -1 in x */ for (y = 0; y < size; y++) { start = 0; for (x = 0; x < size; x++) { xp = x - intr; yp = intr - y; nz = (ball->rad * ball->rad) - (xp * xp) - (yp * yp); if (nz >= 0.0) { mywritepixel1(&mbitmap,x,y+y1); nx = xp / ball->rad; ny = yp / ball->rad; nz = sqrt(nz) / ball->rad; id = lx*nx + ly*ny + lz*nz; /* diffuse intensity */ rz = (nz + nz) * id - lz; if (rz < 0) rz = 0; is = ks * pow(rz,n); id = ka + kd * id; SETANDBOUND(ired, (id * ball->r + is)); SETANDBOUND(igreen,(id * ball->g + is)); SETANDBOUND(iblue, (id * ball->b + is)); setcolor(x,y+y1,y+y2,ired,iblue,igreen,!start); if (start == 0) start = 1; } else if (start == 1) { dolast(); if (!bw) mywritepixel1(&mbitmap,x-1,y+y2); start = 2; } } if (start == 1) { dolast(); if (!bw) mywritepixel1(&mbitmap,x-1,y+y2); } } }