/*
   CMSC 427 - Term Project Candidate
   ---------------------------------

   Beth Weinstein - bweinste@wam.umd.edu
   Ben Stewart - stewartb@wam.umd.edu
   Nawfel Tricha - Topaz@endorproductions.com

   Minimal OpenGL project using Microsoft Visual C++.
   This project is a premilinary candidate for the term 
   project required by CMSC 427.

   ABSTRACT:
      In this project, we will develop several fast 
      rendering and collision routines which would 
      require C/C++ speed and accuracy and then 
      implement a VisualJ++ interface.

   MODULE:
      Utilities module declaration header.
*/

#include <windows.h>
#include <stdio.h>
#include <gl/gl.h>

#ifndef UTILS_H
#define UTILS_H

// NT: Turn off C4244 Warinings (conversion warnings: float->int, double->float, etc):
#pragma warning( disable : 4244 )
// NT: Turn off warning C4305: 'initializing' : truncation from 'const double' to 'float'
#pragma warning( disable : 4305 )

#define MODEL_SCALE  1.0f
#define M_PI 3.141591f
#define PITCH  0
#define YAW    1
#define ROLL   2

#define DotProduct(x,y)			(x[0]*y[0]+x[1]*y[1]+x[2]*y[2])
#define CrossProduct(a, b, c) (c[0]=a[1]*b[2]-a[2]*b[1],c[1]=a[2]*b[0]-a[0]*b[2],c[2]=a[0]*b[1]-a[1]*b[0])
#define VectorSA(a, s, b, c)  (c[0]=a[1]*s*b[2]-a[2]*s*b[1],c[1]=a[2]*s*b[0]-a[0]*s*b[2],c[2]=a[0]*s*b[1]-a[1]*s*b[0])
#define VectorMA(a, s, b, c)  (c[0]=a[0]*s+b[0], c[1]=a[1]*s+b[1], c[2]=a[2]*s+b[2])
#define VectorSubtract(a,b,c)	(c[0]=a[0]-b[0],c[1]=a[1]-b[1],c[2]=a[2]-b[2])
#define VectorScale(a, s, b)  (b[0] = a[0] * s, b[1] = a[1] * s, b[2] = a[2] * s)
#define VectorAdd(a,b,c)		(c[0]=a[0]+b[0],c[1]=a[1]+b[1],c[2]=a[2]+b[2])
#define VectorCopy(a,b)			(b[0]=a[0],b[1]=a[1],b[2]=a[2])
#define VectorClear(a)			(a[0]=a[1]=a[2]=0)
#define VectorNegate(a,b)		(b[0]=-a[0],b[1]=-a[1],b[2]=-a[2])
#define VectorSet(v, x, y, z)	(v[0]=(x), v[1]=(y), v[2]=(z))
#define random()	((rand () & 0x7fff) / ((float)0x7fff))
#define FABS(a, b) if (a>=0) b = a; else b = -a;
/* sort so that a<=b */
#define FloatSort(a,b) if(a>b) {float c; c=a; a=b; b=c;}

#define GetTime(Ttick)  _asm push eax\
						      _asm push edx\
                        _asm _emit 0x0F\
                        _asm _emit 0x31\
                        _asm mov [Ttick], eax\
                        _asm pop edx\
                        _asm pop eax

typedef float vec3_t[3];
const vec3_t FORWARD = {1, 0, 0};
const vec3_t RIGHT = {0, 1, 0};
const vec3_t UP = {0, 0, 1};


// Given 3 Euler angles, we get three scaled vectors: (Forward, Right, Up).
   void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);
// Return true if two vectors are identical, false otherwise.
   inline bool VectorCompare (vec3_t v1, vec3_t v2);
// Return true if two vectors are identical, false otherwise.
   float VectorNormalize (vec3_t &v);
// Return length of a vector sqrt(v.v).
   inline float VectorLength(vec3_t v);
// Return distance between two points.
   float VectorDistance(vec3_t v1, vec3_t v2);
// Return true if point (end) is in front of point (start) oriented in (angles).
   bool InFront (vec3_t start, vec3_t angles, vec3_t end);
// Return YAW (Z-Angle) of vector.
   float VectorYaw (vec3_t vec);
// Convert vector to angles.
   void VectorAngles (vec3_t value1, vec3_t angles);
// Convert vector to matrix (OpenGL compatible).
   void AngleMatrix(vec3_t angle, float *mat);

// BS: 
// implements look at function for anyone to use if they so desire
inline void LookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez,
				   GLdouble aimx, GLdouble aimy, GLdouble aimz, 
				   GLdouble upx, GLdouble upy, GLdouble upz)
{
	static GLdouble m[16];
	vec3_t aim = {aimx - eyex, aimy - eyey, aimz - eyez};
	vec3_t up = {upx, upy, upz};
	vec3_t Ex;
	vec3_t Ey;
	vec3_t Ez;

	VectorNormalize(aim);
	Ez[0] = -1.0 * aim[0];
	Ez[1] = -1.0 * aim[1];
	Ez[2] = -1.0 * aim[2];

	CrossProduct(aim, up, Ex);
	VectorNormalize(Ex);
	CrossProduct(Ez, Ex, Ey);
	/**
	 * create a change of basis matrix
	 */
	m[0] = Ex[0];	m[4] = Ex[1];	m[8] = Ex[2];	m[12] = 0.0;
	m[1] = Ey[0];	m[5] = Ey[1];	m[9] = Ey[2];	m[13] = 0.0;
	m[2] = Ez[0];	m[6] = Ez[1];	m[10] = Ez[2];	m[14] = 0.0;
	m[3] = 0.0;		m[7] = 0.0;		m[11] = 0.0;	m[15] = 1.0;

	/**
	 * adjust to the new frame and translate to the camera position
	 */
	glMultMatrixd(m);
	glTranslated(-1.0 * eyex, -1.0 * eyey, -1.0 * eyez);
}

// BS: Generate surface of revolution given a set of data points
#define XAXIS			   0
#define YAXIS			   1
#define ZAXIS			   2
#define GENERATED		   0
#define NOT_GENERATED	   1

// BS: playing around with some textures
typedef struct text_coord_s 
{
	float s, t;
} text_coord_t;

void GenerateSurface(vec3_t dataPts[], int numPoints, int numSlices, int axis, vec3_t **surface);
void DrawSurface(vec3_t **surface, text_coord_t **text_coords, int numPoints, int numSlices);


#define NOT_FOUND          0xFFFFFFFF

#define G_MAX_EDICTS       2048
#define G_MAX_EDICTS       2048
#define G_MAX_MODELS       256
#define G_MAX_SKINS        256
#define G_MAX_PARTS        1024
#define G_MAX_MODELS       256
#define G_MAX_CMD2S        256
#define G_MAX_SONS         8
#define G_MAX_MODEL_PARTS  32
#define G_MAX_ACTIONS      64
#endif