/*
 * Title:
 *	anim.c
 *
 * Authors:
 *	Michael P. Schenck
 *
 * Purpose:
 *	This demo is a simple animation with 18 objects composed of 261 verticies (217 polys)
 *      which is run for 1000 frames.  It spins the viewpoint around a scene that has a 100
 *   	polygon plane and a ring of 12 cubes rotating above a ground plane and surrounded
 *	by 4 pyramids.  On an A4000/040, this demo completes in 50 sec (avg of 20fps).
 *	It is interesting to note that running 020 code (no fpu pipelining optimizations) on
 *	an 040 produces an avg 12fps.  This just goes to show you how fast the 040 can work
 *	with floating point math!  What the compiler actually does is sequence these instructions
 *	to execute in parallel with other CPU instructions. 
 *	   
 * Copyright Info:
 *	Copyright (C) 1993, 1994 -- by Michael P. Schenck, 
 *	(mps4466@ultb.isc.rit.edu)
 *	
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published
 *	by the Free Software Foundation; either version 2 of the License,
 *	or (at your option) any later version.
 *
 *	This software is distributed in the hope that it will be useful, but
 *	WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *	GNU General Public License for more details.
 *
 *      For a copy of the GNU General Public License
 *	write to the Free Software Foundation, 675 Mass Ave,
 *	Cambridge, MA  02139, USA.
 *
 */

#include <stdlib.h>
#include "include/graphicsubsystem.h"

void cleanexit(void);

UWORD colortable[2] = {0x007,0xFFF};	/* Rgb format (blue and white). */
     
UBYTE i,error,done,type = SUBOBJECT;	
ULONG prim[19]; 			/* Primitive IDs. */
struct Action *node[19];		/* Pointers to actions blocks in display map. */
struct View *view = NULL;		/* Pointer to view structure. */
MATRIX m[19];	  			/* Pointers to matricies. */
FLOAT j,k;
    
main ()
{
	/* Open a 640x400 screen with background blue and lines white and specify
	   a model library path. */

   if((error = opengraphics(640,400,colortable,"ModelLibrary/")) != SUCCESS)
   	return(error);
	
	/* Allocate all the matricies we need. */ 
	
   for(i=0;i<19;i++) {
      if((m[i] = allocatematrix()) == NULL)
         cleanexit();
   }
   
	/* Here we are setting it to an "identity" transformation ... nothing yet. */
	
   setsrttrans(1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,m[0]);
   
   	/* Create root action for ring of cubes, no model here. */
   
   if((node[0] = createrootaction(m[0],NOMODEL)) == NULL)
   	cleanexit(); 	

	/* Get twelve cubes (uses same model...MULTILINK and set up transformation 
	   matrix for each. */

   for(i=1;i<13;i++) {
      if((prim[i] = requestmodel("cube.bin",MULTILINK)) == NOMODEL)
   	 cleanexit();
	 	 
	/* Use i to create ring by setting translation in x to 10.0 units and rotation in z to
	   an angle based on i. */
	 
      setstrtrans(1.0,1.0,1.0,10.0,0.0,0.0,0.0,0.0,(0.5235*(double)i),m[i]);
   	
	/* Insert action after node specified (i-1) and set the transformation.
	   NOTE: The first cube set is set as a subobject, then each cube after
	   that is on the same level in the display traversal with the subobject. */ 
	
      if((node[i] = createaction(node[i-1],m[i],SET,prim[i],type)) == NULL) 
   	 cleanexit();
      type = CUROBJECT;	/* Switch to curlevel. */
   }

	/* Set up rotating plane. */

   if((prim[13] = requestmodel("plane10.bin",SINGLELINK)) == NOMODEL)
   	 cleanexit();
   setsrttrans(1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,m[13]);
   if((node[13] = createrootaction(m[13],prim[13])) == NULL)
   	cleanexit(); 	
   
   	/* Setup small ground plane.. will not move. */
   
   if((prim[14] = requestmodel("plane5.bin",MULTILINK)) == NOMODEL)
   	 cleanexit();
   setsrttrans(100.0,100.0,100.0,0.0,0.0,0.0,0.0,0.0,-50.0,m[14]);
   if((node[14] = createrootaction(m[14],prim[14])) == NULL)
   	cleanexit(); 	
	
	/* Set up four surrounding pyramids... will not move and all using same model. */
	
   if((prim[15] = requestmodel("pyramid.bin",MULTILINK)) == NOMODEL)
   	 cleanexit();
   setsrttrans(25.0,25.0,75.0,0.0,0.0,0.0,300.0,0.0,25.0,m[15]);
   if((node[15] = createrootaction(m[15],prim[15])) == NULL)
   	cleanexit(); 	
   
   if((prim[16] = requestmodel("pyramid.bin",MULTILINK)) == NOMODEL)
   	 cleanexit();
   setsrttrans(25.0,25.0,75.0,0.0,0.0,0.0,-300.0,0.0,25.0,m[16]);
   if((node[16] = createrootaction(m[16],prim[16])) == NULL)
   	cleanexit(); 	
   
   if((prim[17] = requestmodel("pyramid.bin",MULTILINK)) == NOMODEL)
   	 cleanexit();
   setsrttrans(25.0,25.0,75.0,0.0,0.0,0.0,0.0,300.0,25.0,m[17]);
   if((node[17] = createrootaction(m[17],prim[17])) == NULL)
   	cleanexit(); 	
   
   if((prim[18] = requestmodel("pyramid.bin",MULTILINK)) == NOMODEL)
   	 cleanexit();
   setsrttrans(25.0,25.0,75.0,0.0,0.0,0.0,0.0,-300.0,25.0,m[18]);
   if((node[18] = createrootaction(m[18],prim[18])) == NULL)
   	cleanexit(); 	
   
   	/* Allocate and initialize a view structure. */
   
   view = allocateview();
   view->x = 0.0;		/* X,Y,Z position looking at. */
   view->y = 0.0;	
   view->z = 0.0;
   view->phi = 0.0;		/* Standard spherical coords of camera relative to that pos. */
   view->theta = 2.0;
   view->ro = 300.0;		/* Magnitude of vector depicted by above two values. */
   view->d = 1.0;		/* Position of front clipping plane. */
   view->f = 1000.0;		/* Position of far clipping plane. */
   
   				/* The near and far clipping plane can be based on ro. Try
				   setting them to 150 and 450 respectively and rerun.
				   You will see how they effect the display. */
   
   	/* Start animation loop.  Always moving the viewpoint and rotating plane and cubes. */
   
   k=0;
   for(j=0.0;j<500.0;j+=0.5) {
	  
	if(j>275) {			
	   view->ro += 1.5;
	   view->phi += 0.010;
	}
	else
	   view->ro -= 0.5;
	if(k>=10)
	   view->theta -= 0.05;
 	if((k>=15)&&(view->phi < 1.4))
	   view->phi += 0.01; 

	/* Configuring view computes viewing transformation matrix. */

	configureview(view);

	k += 0.2;	/* Spin some more. */
	
	/* Update cube ring transformation. */
	
	setsrttrans(4.0,4.0,4.0,k+1,k,k+1,-50.0,0.0,0.0,m[0]);
	
	/* Tell system that a matrix has changed so that it will recompute the portion
	   of the display map below that point (update entire circle of cubes...we only
	   changed the root transformation to rotate all of them). */

	node[0]->changed = TRUE;	
	
	/* Update plane rotation. */
	
	setsrttrans(40.0,40.0,40.0,k,k+1,k,50.0,0.0,0.0,m[13]);
	
	/* Change flag here too. */
	
	node[13]->changed = TRUE;

	/* See if a key has been pressed, if so exit. */

	if(getinput(NOWAIT))	/* No wait will allow us to continue. */
	   cleanexit();

	/* Update the screen with all the new changes. */

        displaygraphics();
	
	/* Loop around until done or key is pressed. */	
   }
   cleanexit();
}

void cleanexit()
{  
   	/* Free the matricies. */
	
   for(i=0;i<19;i++)
   	if(m[i])
	   freematrix(m[i]);
	
	/* Release the view structure. */
	
   if(view)
      releaseview(view);
   
   	/* Shutdown */
	
   closegraphics();
   
   exit(0);
}   
   
   
