[net.micro.amiga] balls

perry@well.UUCP (Perry S. Kivolowitz) (11/27/85)

As promised, though noone  sent  me  a  sound subroutine, here is the
source to my kinetic thingy. This is balls.c to be linked with bres.c
			Perry S. Kivolowitz
    REMEMBER THE JERSEY AMIGA USER'S GROUP MEETING DECEMBER 20TH!
---------------------------------------------------------------------
#include <exec/types.h>
#include <libraries/mathffp.h>
#include <graphics/gfxbase.h>
#include <intuition/intuition.h>
#undef   NULL
#include <stdio.h>
 
/*
**    balls - a simulation of that kinetic thingy with three-d
**            smooth shaded  spheres with diffuse and specular
**            reflections. It'd be  nice if someone could  add
**            sound. A good demonstration  of  using  the  ffp
**            math subroutines.  I plan to add texture mapping
**            to the spheres in the future.
**
**
**    perry s. kivolowitz - ihnp4!ptsfa!well!perry
**
**    not to be distributed for commercial purposes. any
**    distribution must include this notice, please.
**
*/
 
#ifdef   MY_DEBUG
FILE *dfp;
#endif
 
#define  RADIUS   20       /* radius of the balls ve are goink to draw */
#define  DEPTH    5        /* number of pixel planes */
#define  NMAP     32       /* 2 to the DEPTH power   */
#define  AMBIENT  2        /* how much light on the dark side ofthe moon */
#define  NSTEPS   6        /* how many discreet frames in bouncers */
 
#define  SH       200      /* screen height */
#define  SW       320      /* screen width  */
#define  WH       (SH-10)  /* window height */
#define  WW       SW       /* window width  */
#define  MW       (WW / 2) /* middle of window */
 
#define  D        (2 * RADIUS)
 
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
int    MathBase;
int    MathTransBase;
 
int is_cli = 0;
 
struct Window *w;                  /* window structure returned by exec */
struct Screen *s;                  /* screen structure returned by exec */
struct ColorMap *color_map;        /* pointer to c_map returned by exec */
short  displacements[D];           /* place for sphere's scanline dx's  */
short  surface[D];                 /* place for spehre's scanline dz's  */
 
extern int SPAdd() , SPSub() , SPMul() , SPDiv() , SPNeg() ;
extern int SPFix() , SPFlt() , SPCmp() , SPTst() , SPAbs() ;
extern int SPSqrt() , SPFieee() , SPTieee();
extern int SPSin() , SPCos() , SPPow();
 
union kludge {
   float f;
   int   i;
};
 
struct bouncer {
   struct RastPort rp;
   struct BitMap   bm;
   int sx , sy;
} left[NSTEPS] , right[NSTEPS];
 
struct point {
   union kludge x;
   union kludge y;
   union kludge z;
} light;
 
/*
** mask is a bit mask of things that I should close or deallocate
** when the program terminates for  any reason.  after opening or
** allocating some resource set the appropriate bit in mask.
*/
 
unsigned int mask = 0;
 
#define  INTUITION   0x00000001
#define  GRAPHICS    0x00000002
#define  SCREEN      0x00000004
#define  WINDOW      0x00000008
#define  COLORMAP    0x00000010
#define  MATH        0x00000020
#define  MATHTRANS   0x00000040
 
int rastcount = 0;      /* easy way to free rasters at termination */
 
struct NewScreen ns = {    /*****************/
   0 ,                     /* LeftEdge      */
   0 ,                     /* TopEdge       */
   SW ,                    /* Width         */
   SH ,                    /* Height        */
   DEPTH ,                 /* Depth         */
   0 ,                     /* DetailPen     */
   1 ,                     /* BlockPen      */
   0 ,                     /* ViewModes     */
   CUSTOMSCREEN ,          /* Type          */
   NULL ,                  /* *Font         */
   " spheres by p.s.kivolowitz" ,       /* *DefaultTitle */
   NULL ,                  /* *Gadgets      */
   NULL                    /* *CustomBitMap */
};                         /*****************/
 
struct NewWindow nw = {    /*****************/
   0 ,                     /* LeftEdge      */
   10 ,                    /* TopEdge       */
   WW ,                    /* Width         */
   WH ,                    /* Height        */
   -1 ,                    /* DetailPen     */
   -1 ,                    /* BlockPen      */
   CLOSEWINDOW ,           /* IDCMP---Flags */
   WINDOWCLOSE             /*   F           */
   | BACKDROP              /*     l         */
   | BORDERLESS            /*       a       */
   | NOCAREREFRESH         /*         g     */
   | ACTIVATE ,            /*           s   */
   NULL ,                  /* *FirstGadget  */
   NULL ,                  /* *CheckMark    */
   "(still under development)" ,/* *Title        */
   NULL ,                  /* *Screen       */ /* to be filled in */
   NULL ,                  /* *BitMap       */
   0 ,                     /* MinWidth      */
   0 ,                     /* MinHeight     */
   0 ,                     /* MaxWidth      */
   0 ,                     /* MaxHeight     */
   CUSTOMSCREEN            /* Type          */
};                         /*****phew!!!*****/
 
float convert(i)
{
   union kludge k;
 
   k.i = SPTieee(i);
   return(k.f);
}
 
degrad(degrees)
{
   union kludge pi;
 
   pi.f = 355.0 / 113.0;   /* chinese approximation */
   pi.i = SPMul(SPFieee(pi.i) , SPFlt(degrees));
   return(SPDiv(SPFlt(180) , pi.i));
}
 
main(argc , argv)
char *argv[];
{
   int i;
   struct IntuiMessage *message;
   if (argc) is_cli = 1;
 
#ifdef   MY_DEBUG
   if ((dfp = fopen("debug.file" , "w")) == NULL) {
      if (is_cli) printf("can't open debugging file\n");
      exit(1);
   }
   fprintf(dfp,"debugging information\n");
   fflush(dfp);
#endif
 
   if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0)))
   {
      if (is_cli) printf("no graphics library!!!\n");
      close_things();
      exit(1);
   }
   mask |= GRAPHICS;
 
   if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library")
   {
      if (is_cli) printf("no intuition here!!\n");
      close_things();
      exit(1);
   }
   mask |= INTUITION;
 
   if ((MathBase = OpenLibrary("mathffp.library" , 0)) == NULL) {
      if (is_cli) printf("couldn't open mathffp library\n");
      close_things();
      exit(1);
   }
   mask |= MATH;
 
   if ((MathTransBase = OpenLibrary("mathtrans.library" , 0)) == NULL) {
      if (is_cli) printf("couldn't open mathtrans library\n");
      close_things();
      exit(1);
   }
   mask |= MATHTRANS;
 
   allocate_rasters();
 
   if ((s = (struct Screen *) OpenScreen(&ns)) == (struct Screen *) NULL) {
      if (is_cli) printf("could not open the screen!\n");
      close_things();
      exit(2);
   }
   mask |= SCREEN;
   nw.Screen = s;
 
   if((w = (struct Window *)OpenWindow(&nw)) == (struct Window *) NULL) {
      if (is_cli) printf("could not open the window!\n");
      close_things();
      exit(2);
   }
   mask |= WINDOW;
 
   init_color_map();
 
   light.x.f = 0.0;
   light.y.f = light.x.f + 150.0 - light.x.f;
   light.z.f = light.x.f + 25.0 - light.x.f;
 
   light.x.i = SPFieee(light.x.i);  /*                             */
   light.y.i = SPFieee(light.y.i);  /* convert light vector to FFP */
   light.z.i = SPFieee(light.z.i);  /*                             */
 
   bres(RADIUS , displacements);
 
   /*
   ** make the three bottom balls
   */
 
   make_ball(w->RPort , MW - D , WH - RADIUS , -D , 0 , 0);
   make_ball(w->RPort , MW     , WH - RADIUS ,  0 , 0 , 0);
   make_ball(w->RPort , MW + D , WH - RADIUS ,  D , 0 , 0);
 
   make_rotated_ball(&left[0] , -15 , MW - 2 * D , 10 , WH - 10 - RADIUS);
   make_rotated_ball(&right[0] , 15 , MW + 2 * D , 10 , WH - 10 - RADIUS);
   make_rotated_ball(&left[1] , -14 , MW - 2 * D , 10 , WH - 10 - RADIUS);
   make_rotated_ball(&right[1] , 14 , MW + 2 * D , 10 , WH - 10 - RADIUS);
   make_rotated_ball(&left[2] , -12 , MW - 2 * D , 10 , WH - 10 - RADIUS);
   make_rotated_ball(&right[2] , 12 , MW + 2 * D , 10 , WH - 10 - RADIUS);
   make_rotated_ball(&left[3] , -9  , MW - 2 * D , 10 , WH - 10 - RADIUS);
   make_rotated_ball(&right[3],  9  , MW + 2 * D , 10 , WH - 10 - RADIUS);
   make_rotated_ball(&left[4] , -5  , MW - 2 * D , 10 , WH - 10 - RADIUS);
   make_rotated_ball(&right[4],  5  , MW + 2 * D , 10 , WH - 10 - RADIUS);
   make_rotated_ball(&left[5] ,  0  , MW - 2 * D , 10 , WH - 10 - RADIUS);
   make_rotated_ball(&right[5],  0  , MW + 2 * D , 10 , WH - 10 - RADIUS);
 
   ClipBlit(&left[0].rp,0,0,w->RPort,left[0].sx,left[0].sy,D,D,0xC0);
   ClipBlit(&right[NSTEPS-1].rp,0,0,w->RPort,right[NSTEPS-1].sx,right[NSTEPS-1];
 
   message = (struct IntuiMessage *) GetMsg(w->UserPort);
   while (!message || (message->Class != CLOSEWINDOW)) {
      for (i = 1; i < NSTEPS; i++) {
         Delay(2);
         WaitBOVP(&s->ViewPort);
         clear_rect(w->RPort,left[i-1].sx,left[i-1].sy,D,D);
         ClipBlit(&left[i].rp,0,0,w->RPort,left[i].sx,left[i].sy,D,D,0xC0);
      }
      for (i = NSTEPS-2; i >= 0; i--) {
         WaitBOVP(&s->ViewPort);
         clear_rect(w->RPort,right[i+1].sx,right[i+1].sy,D,D);
         ClipBlit(&right[i].rp,0,0,w->RPort,right[i].sx,right[i].sy,D,D,0xC0);
         Delay(2);
      }
      Delay(1);
      for (i = 1; i < NSTEPS; i++) {
         Delay(2);
         WaitBOVP(&s->ViewPort);
         clear_rect(w->RPort,right[i-1].sx,right[i-1].sy,D,D);
         ClipBlit(&right[i].rp,0,0,w->RPort,right[i].sx,right[i].sy,D,D,0xC0);
      }
      for (i = NSTEPS-2; i >= 0; i--) {
         WaitBOVP(&s->ViewPort);
         clear_rect(w->RPort,left[i+1].sx,left[i+1].sy,D,D);
         ClipBlit(&left[i].rp,0,0,w->RPort,left[i].sx,left[i].sy,D,D,0xC0);
         Delay(2);
      }
      Delay(1);
      message = (struct IntuiMessage *) GetMsg(w->UserPort);
   }
 
#ifdef   MY_DEBUG
   fclose(dfp);
#endif
 
   close_things();
   exit(0);
}
 
clear_rect(rp , sx , sy , dx , dy)
struct RastPort *rp;
{
   ClipBlit(rp,sx,sy,rp,sx,sy,dx,dy,0x20);
}
 
make_rotated_ball(b , degrees , cx , cy , length)
struct bouncer *b;
{
   int dx , dy;
 
   dx = SPMul(SPFlt(length) , SPSin(degrad(abs(degrees))));
   dy = SPMul(SPFlt(length) , SPCos(degrad(abs(degrees))));
   b->sx = cx + ((degrees < 0) ? -SPFix(dx) : SPFix(dx));
   b->sy = cy + SPFix(dy);
   make_ball(&b->rp , RADIUS , RADIUS , b->sx - MW , WH - RADIUS - b->sy , 0);
   b->sx -= RADIUS;
   b->sy -= RADIUS;
}
 
close_things()
{
   if (rastcount) deallocate_rasters();
   if (mask & WINDOW)    CloseWindow(w);
   if (mask & SCREEN)    CloseScreen(s);
   if (mask & GRAPHICS)  CloseLibrary(GfxBase);
   (void) OpenWorkBench();
   if (mask & INTUITION) CloseLibrary(IntuitionBase);
}
 
init_color_map()
{
   static short map_values[NMAP] = {
      /* format 0x0RGB */   /* ooooooooh ychhhhhh! fix this later! */
      /* 0  */  0x0430 , 
      /* 1  */  0x0FFF ,
      /* 2  */  0x0F01 ,
      /* 3  */  0x0F11 ,
      /* 4  */  0x0F12 ,
      /* 5  */  0x0F22 ,
      /* 6  */  0x0F23 ,
      /* 7  */  0x0F33 ,
      /* 8  */  0x0F34 ,
      /* 9  */  0x0F44 ,
      /* 10 */  0x0F45 ,
      /* 11 */  0x0F55 ,
      /* 12 */  0x0F56 ,
      /* 13 */  0x0F66 ,
      /* 14 */  0x0F67 ,
      /* 15 */  0x0F77 ,
      /* 16 */  0x0F78 ,
      /* 17 */  0x0F88 ,
      /* 18 */  0x0F89 ,
      /* 19 */  0x0F99 ,
      /* 20 */  0x0F9A ,
      /* 21 */  0x0FAA ,
      /* 22 */  0x0FAB ,
      /* 23 */  0x0FBB ,
      /* 24 */  0x0FBC ,
      /* 25 */  0x0FCC ,
      /* 26 */  0x0FCD ,
      /* 27 */  0x0FDD ,
      /* 28 */  0x0FDE ,
      /* 29 */  0x0FEE ,
      /* 30 */  0x0FEF ,
      /* 31 */  0x0FFF
};
   LoadRGB4(&s->ViewPort , map_values , NMAP);
}
 
normalize(p)
struct point *p;
{
   union kludge length;
 
   length.i = SPSqrt(SPAdd(SPAdd(SPMul(p->x.i,p->x.i) , SPMul(p->y.i,p->y.i)) ,;
   p->x.i = SPDiv(length.i , p->x.i);
   p->y.i = SPDiv(length.i , p->y.i);
   p->z.i = SPDiv(length.i , p->z.i);
}
 
 
make_ball(rp , basex , basey , cx , cy , cz)
struct RastPort *rp;
{
   int I , scanline;
   int twelve , x , y;
   struct point H , l;
   struct point pnt;
   union kludge tmp , rad , d;
 
 
   rad.i = SPDiv(SPFlt(RADIUS) , SPFlt(1));
 
   basex -= RADIUS;
   basey -= RADIUS;
   twelve = SPFlt(12);
   l.x.i = SPSub(SPFlt(cx) , light.x.i);  /* translate light source to */
   l.y.i = SPSub(SPFlt(cy) , light.y.i);  /* make center of sphere the */
   l.z.i = SPSub(SPFlt(cz) , light.z.i);  /* origin relative to light  */
   normalize(&l);
 
   for (scanline = 0; scanline < 2 * RADIUS; scanline++) {
      register int r;
      register int i;
 
      r = displacements[scanline];
      y = scanline + basey;
      pnt.y.i = SPMul(SPFlt(RADIUS - scanline) , rad.i);
      bres(r , surface);
      for (i = 0; i < 2 * r; i++) {
         pnt.x.i = SPMul(SPFlt(-r + i) , rad.i);
         pnt.z.i = SPMul(SPFlt(surface[i]) , rad.i);
         d.i = SPAdd(SPAdd(SPMul(pnt.z.i , l.z.i) , SPMul(pnt.y.i , l.y.i)) , S;
         I = AMBIENT;
         tmp.i = SPTieee(d.i);
         if (tmp.f > 0.0) {
            I += SPFix(SPMul(d.i , SPFlt(NMAP - AMBIENT)));
            H.x.i = l.x.i;
            H.y.i = l.y.i;
            H.z.i = SPAdd(SPFlt(1) , l.z.i);
            normalize(&H);
            /* reusing d */
            d.i = SPAdd(SPAdd(SPMul(H.x.i , pnt.x.i) , SPMul(H.y.i , pnt.y.i)) ;
            d.i = SPPow(twelve , d.i);
            tmp.i = SPTieee(d.i);
            if (tmp.f > 0.0) I += SPFix(SPMul(d.i , twelve));
         }
         x = RADIUS - r + i + basex;
         if (I >= NMAP) I = NMAP - 1;
         SetAPen(rp , I);
         (void) WritePixel(rp , x , y);
      }
   }
}
 
allocate_rasters()
{
   int i , j;
 
   for (i = 0; i < NSTEPS; i++) {
      InitRastPort(&left[i].rp);
      InitRastPort(&right[i].rp);
      InitBitMap(&left[i].bm , DEPTH , D , D);
      InitBitMap(&right[i].bm , DEPTH , D , D);
      for (j = 0; j < DEPTH; j++) {
         left[i].bm.Planes[j] = AllocRaster(D , D);
         if (left[i].bm.Planes[j] == NULL) {
outer:      if (is_cli) printf("cannot allocate raster space\n");
            close_things();
            exit(1);
         }
         rastcount++;
         right[i].bm.Planes[j] = AllocRaster(D , D);
         if (right[i].bm.Planes[j] == NULL) goto outer;
         rastcount++;
      }
      left[i].rp.BitMap = &left[i].bm;
      right[i].rp.BitMap = &right[i].bm;
      SetRast(&left[i].rp , 0);
      SetRast(&right[i].rp , 0);
   }
}
 
deallocate_rasters()
{
   int i , j;
 
   for (i = 0; i < NSTEPS && rastcount >= 0; i++) {
      for (j = 0; j < DEPTH && rastcount >= 0; j++) {
         if (rastcount-- == 0) continue;
         FreeRaster(left[i].bm.Planes[j] , D , D);
         if (rastcount-- == 0) continue;
         FreeRaster(right[i].bm.Planes[j] , D , D);
      }
   }
}

perry@well.UUCP (Perry S. Kivolowitz) (11/27/85)

This is file two of two. To be loaded with balls.c
Thanks to Captain Crunch for getting this off my amiga
and onto a VAX.
	Perry S. Kivolowitz
-----------------------------------------------------
/*
** b r e s . c
**
** perry s. kivolowitz - ihnp4!ptsfa!well!perry
**
** not to be distritbuted for commercial use. any distribution
** must included this notice, please.
**
** generate radial  displacements according to bresenham's circle
** algorithm. suitable for running twice, giving a fast spherical
** surface.
**
*/
 
bres(r , array)
register short *array;
register r;
{
   register x , y , d;
 
   x = 0;
   y = r;
   d = 3 - 2 * r;
   while (x < y) {
      *(array + r - y) = x;
      *(array + r - x) = y;
      *(array + r + y - 1) = x;
      *(array + r + x - 1) = y;
      if (d < 0) d += 4 * x + 6;
      else d += 4 * (x - y--) + 10;
      x++;
   }
   if (x == y) {
      *(array + r - y) = x;
      *(array + r + y - 1) = x;
   }
}

louie@trantor.UMD.EDU (11/29/85)

From: Louis A. Mamakos <louie@trantor.UMD.EDU>

It seems that a few of the longer lines of this program were truncated; thus
the program doesn't compile.  I suppost that this will be one of many messages
to this effect; I don't know a path to well!perry from here.

Louis A. Mamakos  WA3YMH    Internet: louie@TRANTOR.UMD.EDU
  University of Maryland, Computer Science Center - Systems Programming