/*   *** SPIN4.C ***
     ***************


    Will spin ==========>  A triangle in 3 space <===============
             
    !!! New things:
                 1) uses inline assembly routines to multiply 
                    numbers...a little faster than previous versions
                 2) modifies #1 and makes 2 assembly multiplication routines,
                    one for COSINE multiplication and one for SINE mult.
                    (This GREATLY speeds up multiplication, see benchmrk.txt
                     for more details)


    *** uses INTEGER ARITHMETIC for faster speed ***
   
    ** You can set up 3 diff projections  
       project : xy, xz, or yz
       just my slight modification of draw3dline()
       for xz projection do
          x1 = p1.x  y1 = p1.z
          x2 = p2.x  y2 = p2.z     just DROP the y coord to project 
                                   onto the XZ plane!


   


  

   March 28 ,1994  jeff bilger 
   jbilger@cs.tamu.edu

*/


#include <math.h>
#include <linea.h>
#include <osbind.h>
int pts[4][2] = { 
	320, 050,
	120, 150,
	520, 150,
	320, 050
};
lineaport *theport;

long mu_global_s();                     /* prototype, tells our 
    			        				  Assembly language function
						         		  to return a long int  */
long mu_global_c();  /* multiply 32 bit global w/ a precomputed sin or cos value */


#define SCALE 2048L       /* so far 2048 is the upper bounds scale
                              i can get W/O overflow */
#define BITSH 11        /* what to shift (ie DIVIDE) by. this number
                           2^11 = 2048 */


typedef struct {long x,y,z;} point3d;   /* our faithful structure that defines a point in 3 space*/

          
/* these are used to allocate size of arrays */
#define NPTS   25                 /* max allowable points */
#define NLINES 50                
#define NFACES 50                


#define I ( SCALE  )           /* set up a SCALE factor */

point3d point_[NPTS] =         /* define our triangle in 3d */
		{ 
          I,I,I,     3*I,I,I, 2*I,I,-I,  2*I,-I,I/2,
 },
        drawpt1[NPTS],drawpt2[NPTS];     /* for fast draw/erasing look up */



int 
    npts  = 4,         /* linefrom, lineto for drawing lines */                                                                                            
    linefrom[NLINES] = {0,1,2,0,1,2},     /* set up lines to draw */
    lineto[NLINES]   = {1,2,0,3,3,3}, 
    nlines = 6,         /* number of lines */
    x_offset=320,       /* for viewport mapping */
    y_offset=100,
    z_offset=1;

long cos_2=2048;    /* cos of 3 degrees * scale of 2048 */
long sin_2=107;     /* sin of 3 degrees * scale of 2048 */


main()
{
register int i,j;   /* use em for FOR loops */
point3d pointi;     /* declare one instance of our point3d struct */
int color =1;       /* color to draw triangle */
char com;           /* for user input */




puts("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
puts("1-Spin Y  2-Spin X  3-Spin Z  9-Quit\n");


theport = a_init();                   /* line a invokage */    
	theport -> plane0 = 1;
	theport -> plane1 = 0;
	theport -> plane2 = 0;
	theport -> plane3 = 0;


   
for(i=0;i<nlines;i++)  /* set up points-to-connect lookup table*/
{ drawpt1[i] = point_[linefrom[i]];
  drawpt2[i] = point_[lineto[i]];  
}

com = 0x32;                       /* set to spin about x */

while( com != 0x39)
{
if( Bconstat(2) )       /* if keypress */
 com = Bconin(2);       /* get input */


                                  /* The main loop */
 for(i=0;i<npts;i++)
   {
   pointi = point_[i];        /* get current point data. We do this for efficiency, since we will use this value many times within one loop
                                 it's more efficient to compute it's value only once */
   
    if(com == 0x31) {              /* spin y */
               point_[i].x =( mu_global_c(pointi.x)  -
                              mu_global_s(pointi.z))>>BITSH; /* since our points are scaled AND or trig angles, sin&cos values are scaled we must divide by scale once here*/
               point_[i].z =( mu_global_s(pointi.x) +
                              mu_global_c(pointi.z))>>BITSH;

                    }
    if(com == 0x32) {              /* spin x */
                point_[i].y =( mu_global_c(pointi.y)  +
                               mu_global_s(pointi.z))>>BITSH;
                point_[i].z =( -(mu_global_s(pointi.y)) +
                                 mu_global_c(pointi.z))>>BITSH;
                    }
    if(com == 0x33) {              /* spin z */
                point_[i].x =( mu_global_c(pointi.x)  +
                               mu_global_s(pointi.y))>>BITSH;
                point_[i].y =( mu_global_c(pointi.y)  -
                               mu_global_s(pointi.x))>>BITSH;
                    }
  

   }

                              /* draw and erase triangle */
  for(i=0;i<nlines;i++)
   { draw3dline(drawpt1[i],drawpt2[i],0);  /*erase */
     draw3dline(drawpt1[i]=point_[linefrom[i]],drawpt2[i]=point_[lineto[i]],color);
     /* draw it */
  }
   

}/* end of while */



} /* end of main */



/*******************************/

draw3dline(p1,p2,color)
point3d p1,p2;
int color;
{
 int x1,y1,x2,y2;

 /* project onto the xy plane */
 x1 = (p1.x>>BITSH-5) + x_offset;      
 y1 = (p1.y>>BITSH-5) + y_offset;
 x2 = (p2.x>>BITSH-5) + x_offset;
 y2 = (p2.y>>BITSH-5) + y_offset;

theport -> plane0 = color;

a_line(x1,y1,x2,y2); 

}



/***************************************************************/
/* We will now modify the assembly mult. routine to be as efficient
   as possible. We will make 2 mult. routines, one to multiply 
   by a precomputed SINE value, and one to multiply by a precomputed
   COSINE value
   ************************************************************/

/*******************************************************/
/* Multiply 1 16 bit(GLOBAL) SIGNED number b by a precomputed 
   SINE value of 3 degrees (then the sine value was * SCALE where
   scale was 2048 )

  and return the 32 bit result in D0

   *** BIG NOTE:: b MUST be a GLOBAL var!!!!!!!!!!!!!!!!!

   * WARNING * No test is made on the overflow bit (V) to see if 
               the result in c is indeed correct. 

   Send arguments to this prodecure by: c=multiply(b) 
*/

long mu_global_s(b)
register long b;  /* extern variables so b is placed in D7,*/          
{
 asm
    { 
  
      muls   #107,b    /* generates  muls #107,d7 */
      move.l b,D0  /* generates   move.l A7,(A5) */
                    /* Note: You MUST specify the size (.l) cause
                             if you just write 'move b,d0' Laser
                             C will assume move.w as the default */
     
    }

}

/*************************************************
 multiplies a number 'b' by a precomputed COSINE value
 The Cos value is ===> cosine of 2 degrees * SCALE factor
 where scale factor is defined. In our case the precomputed cos value 
 is 2045 */

long mu_global_c(b)
register long b;  /* extern variable so b is placed in D7*/
{
 asm
    { 
  
      muls   #2045,b    /* generates  muls #2045,d7 */
      move.l b,D0  /* generates   move.l A7,(A5) */
                    /* Note: You MUST specify the size (.l) cause
                             if you just write 'move b,d0' Laser
                             C will assume move.w as the default */
     
    }

}



di(a,b)
register long int a,b;
{
 asm
    {
     move.l a,D0
     move.l b,D1
    }
}
