/*
 * Title:
 *	sincos.c
 *
 * Authors:
 *	Michael P. Schenck
 *
 * Purpose:
 *	This demo shows a three dimensional function over time.  The function being displayed
 *	is sin*cos.  The y-dimension displays the sine wave over time.  For each iteration,
 *	the x-dimension shows a portion of a cosine wave which is multiplied by the sine wave.
 *	Both the sine and cosine frequency (amount of wave or waves visible in the mesh) can
 *	be changed.  Shown below are all the commands.
 *
 *	q	positive rotation about x-axis
 *	w	negitive rotation about x-axis
 *	a	positive rotation about y-axis
 *	s	negitive rotation about y-axis
 *	z	positive rotation about z-axis
 *	x	negitive rotation about z-axis
 *	e	zoom in
 *	r	zoom out
 *	d	increase sine frequency
 *	f	decrease sine frequency
 *	c	increase cosine frequency
 *	v	decrease cosine frequency
 *	space	quit
 *	   
 * 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"

#define	SIZE	10	/* change SIZE to 20, change plane10.bin to plane20.bin and recompile.
			   You will get a larger mesh. */

void cleanexit(void);

UWORD colortable[2] = {0x007,0xFFF};	/* Rgb format (blue and white). */
     
UBYTE error,done,key;
ULONG plane,cube;			/* Primitive IDs. */
struct Action *pnode,*cnode;		/* Pointers to actions blocks in display map. */
struct View *view = NULL;		/* Pointer to view structure. */
MATRIX m;	  			/* Pointers to matrix. */
FLOAT j,x,y,
      xrot=0.0,yrot=0.0,zrot=0.0,
      freq1=0.3,freq2=0.3,
      *vert;
LONG i;

extern struct Model *models[MAXNUMMODELS];	/* we need access to model verticies */  

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 a matrix that will be used for both the mesh and the cube. */ 
	
   if((m = allocatematrix()) == NULL)
        cleanexit();
   
	/* Set up plane (mesh). */

   if((plane = requestmodel("plane10.bin",SINGLELINK)) == NOMODEL)
   	 cleanexit();
   if((pnode = createrootaction(m,plane)) == NULL)
   	cleanexit(); 	
   
   	/* Set up cube for outline.  These models are all 'unit' models. */
   
   if((cube = requestmodel("cube.bin",SINGLELINK)) == NOMODEL)
   	 cleanexit();
   if((cnode = createrootaction(m,cube)) == 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 = 1.58;		/* Standard spherical coords of camera relative to that pos. */
   view->theta = 0.0;		/* Thus, looking right down the x-axis toward neg direction. */
   view->ro = 15.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. */
   
   configureview(view);

   	/* Setup initial transformation.  Remember, we are using one matrix for both objects! */ 

   setsrttrans(4.0,4.0,4.0,0.0,0.0,0.0,0.0,0.0,0.0,m);
 
 	/* Get a pointer to the vertices of the plane model. */
 
   vert = models[plane]->verticies;
   
   	/* Loop until done is true. */
   
   done = FALSE;
   
   while(!done) {
	
	/* Tell system that a matrix has changed so that it will recompute the portion
	   of the display map below that point.  This is done for both objects. */

	pnode->changed = TRUE;	
	cnode->changed = TRUE;
	
	/* Shift rows of z coords down (verticies are homogeneous, so there are four values). */
	
	for(i=((SIZE+1)*SIZE-1);i>=0;i--) 
		*(vert+(i+SIZE+1)*4+2) = *(vert+i*4+2);
		
	/* Calculate new row. */
		
	j += freq1;	
	y = sin(j);
	x = 0.0;	
	for(i=0;i<(SIZE+1);i++) {
		*(vert+i*4+2) = y*cos(x);
		x += freq2; 	
	}
	
	key = getinput(NOWAIT);	/* No wait will allow us to continue. */
	
	/* Check for input. */
	
	switch(key) {
		case 'q' :	xrot += 0.1;	
				setsrttrans(4.0,4.0,4.0,xrot,yrot,zrot,0.0,0.0,0.0,m);
				break;
		case 'w' :	xrot -= 0.1;
				setsrttrans(4.0,4.0,4.0,xrot,yrot,zrot,0.0,0.0,0.0,m);
				break;
		case 'a' :	yrot += 0.1;
				setsrttrans(4.0,4.0,4.0,xrot,yrot,zrot,0.0,0.0,0.0,m);
				break;
		case 's' :	yrot -= 0.1;
				setsrttrans(4.0,4.0,4.0,xrot,yrot,zrot,0.0,0.0,0.0,m);
				break;	
		case 'z' :	zrot += 0.1;
				setsrttrans(4.0,4.0,4.0,xrot,yrot,zrot,0.0,0.0,0.0,m);
				break;
		case 'x' :	zrot -= 0.1;
				setsrttrans(4.0,4.0,4.0,xrot,yrot,zrot,0.0,0.0,0.0,m);
				break;
		case 'e' :	view->ro -= 0.25;
				configureview(view);
				break;
		case 'r' :	view->ro += 0.25;
				configureview(view);
				break;
		case 'd' :	freq1 += 0.01;
				break;
		case 'f' :	freq1 -= 0.01;
				break;
		case 'c' :	freq2 += 0.01;
				break;
		case 'v' :	freq2 -= 0.01;
				break;
		case ' ' :	done = TRUE;
	}

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

        displaygraphics();	
   }
   cleanexit();
}

void cleanexit()
{  
   	/* Free the matrix. */
	
   freematrix(m);
	
	/* Release the view structure. */
	
   if(view)
      releaseview(view);
   
   	/* Shutdown */
	
   closegraphics();
   
   exit(0);
}   
   
   
