/****************************/
/*   OPENGL SUPPORT.C	    */
/****************************/

/*	PangeaVR - 3D accelerated plug-in for viewing panoramas.

	©2005 Pangea Software, Inc.  All rights reserved.
	Pangea Software, PangeaVR and various logos are trademarks of Pangea Software, Inc.
	
	Written by Brian Greenstone,   brian@pangeasoft.net	
	
	This program and source code 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.  
	
	IMPORTANT:  The purpose in releasing this source code is to encourage others
				To port this program to other platforms, and to make improvments to it.
				However, to prevent things from getting out of control with lots of
				different versions of PangeaVR floating around the internet,
				Pangea Software, Inc. prohibits the public distribution of any versions
				of PangeaVR without prior approval from Pangea Software, Inc.
				
				Should you make any improvements to this source code and wish to
				have those changes rolled into an official release then you'll
				need to contact Pangea Software to have your modifications adapted.				
*/


/****************************/
/*    EXTERNALS             */
/****************************/

extern	MyInstanceType	gMyInstances[];


/****************************/
/*    PROTOTYPES            */
/****************************/

static void OGL_FreeFont(int instanceNum);
static void OGL_InitFont(int instanceNum);
static void FloatToString(float num, Str255 string); 
static void OGL_Camera_SetPlacementAndUpdateMatrices(int instanceNum);
static void DrawMySprites(int instanceNum);
static void DrawASprite(MySpriteType *sprite, float x, float y, float scale, Boolean yIsBottom);
static void DrawThumbnail(int instanceNum);



/****************************/
/*    CONSTANTS             */
/****************************/


/*********************/
/*    VARIABLES      */
/*********************/




/**************** OGL: INIT DRAW CONTEXT *********************/
//
// Creates the OpenGL draw context that we'll do all of our rendering into.
//

void OGL_InitDrawContext(int instanceNum)
{
#ifdef TARGET_OS_MAC

	if (OGL_CreateDrawContext_Mac(instanceNum))
		return;

#else

	if (OGL_CreateDrawContext_Windows(instanceNum))
		return;

#endif		
				/**************************/
				/* SET VARIOUS STATE INFO */
				/**************************/

	glClearColor(0, 0, 0, 1.0);
	
	{
		GLfloat	color[] = {1,1,1,1};									// set global material color to white
		glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
	}
	
	glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);	
	glEnable(GL_COLOR_MATERIAL);		
  	glEnable(GL_NORMALIZE);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);		// set default blend func
	glEnable(GL_BLEND);	
	glDisable(GL_CULL_FACE);	
  	
		
	
	if (aglGetError() != AGL_NO_ERROR)
		printf("OGL_InitDrawContext: aglGetError()!!!\n");
  	 	
	printf("OpenGL draw context created!\n");

  	 	
			/* INIT FONT */
			
	OGL_InitFont(instanceNum);


			/* LOAD SPRITES */
				
	LoadSpritesForInstance(instanceNum);


	
				
				
				/* SET CLIP RECT & DO INITIAL DRAW */
				
#ifdef TARGET_OS_MAC
	SetPaneClipRect_Mac(instanceNum);				
#else
	----- WINDOWS OR LINUX CODE GOES HERE -----
#endif		



			/*********************************************************************/
			/* IF THERE WAS A THUMBNAIL SPECIFIED IN THE INPUT PARAMETS, LOAD IT */
			/*********************************************************************/
			//
			// We do this here because we know that the Draw Context has been created, so it's safe to load 
			// the thumbnail now.
			//
		
	if (gMyInstances[instanceNum].thumbnailFilename[0] != 0x00)					// is there a thumbnail file?
	{
		LoadThumbnail(instanceNum, gMyInstances[instanceNum].streamURL);
	}


	OGL_DrawScene(instanceNum);
		
}


/***************** OGL:  DISPOSE DRAW CONTEXT ***********************/
//
// Disposes of all data created by OGL_InitDrawContext
//

void OGL_DisposeDrawContext(int instanceNum)
{
	if (gMyInstances[instanceNum].drawContext)
	{
		
				/* KILL DEBUG FONT */
				
		OGL_FreeFont(instanceNum);

				/* NUKE THE CONTEXT */

#ifdef TARGET_OS_MAC
		OGL_DisposeDrawContext_Mac(instanceNum);
#else
		----- WINDOWS OR LINUX CODE GOES HERE -----
#endif		
		
		gMyInstances[instanceNum].drawContext = nil;
	}
}


#pragma mark -


/******************* OGL DRAW SCENE *********************/
//
// This draws the entire scene.
//

void OGL_DrawScene(int instanceNum)
{	
	if (gMyInstances[instanceNum].drawContext == nil)
		return;


#ifdef TARGET_OS_MAC
	CalcFramesPerSecond_Mac(instanceNum);										// update our frame rate
  	aglSetCurrentContext(gMyInstances[instanceNum].drawContext);				// make context active
#else
	CalcFramesPerSecond_Windows(instanceNum);						
	wglMakeCurrent( gMyInstances[instanceNum].hdc, gMyInstances[instanceNum].drawContext );
#endif		


	glColor4f(1,1,1,1);

	if (aglGetError() != AGL_NO_ERROR)
		printf("OGL_DrawScene: aglGetError()!!!\n");
	if (OGL_CheckError() != GL_NO_ERROR)
		printf("OGL_DrawScene: glGetError()!!!\n");


				/*****************/
				/* CLEAR BUFFERS */
				/*****************/				
					
	glClear(GL_COLOR_BUFFER_BIT);



				/***************************/
				/* DRAW THE CUBE OR SPHERE */
				/***************************/
	
				/* GET UPDATED GLOBAL COPIES OF THE VARIOUS MATRICES */
				//
				// Our camera is never moving - the cube does all the moving.
				// Nevertheless, we update the camera matrices each frame just to be safe.
				//

	OGL_Camera_SetPlacementAndUpdateMatrices(instanceNum);

	if (gMyInstances[instanceNum].doEquirectangular)
		DrawTheSphere(instanceNum);
	else
		DrawTheCube(instanceNum);

	if (OGL_CheckError() != GL_NO_ERROR)
		printf("OGL_DrawScene: glGetError() After drawing cube or sphere.\n");


			/* DRAW DEBUG INFO */
			
//	OGL_DrawInt(instanceNum, gMyInstances[instanceNum].frameCount, 10,10);		
	gMyInstances[instanceNum].frameCount++;	
//	OGL_DrawFloat(instanceNum, gMyInstances[instanceNum].fps, 200,SPRITE_WINDOW_RANGE-50);		


				/****************/
				/* DRAW SPRITES */
				/****************/


	DrawMySprites(instanceNum);
	DrawThumbnail(instanceNum);
	
	if (OGL_CheckError() != GL_NO_ERROR)
		printf("OGL_DrawScene: glGetError() After drawing sprites\n");
	

            /**************/
			/* END RENDER */
			/**************/           	           	
	
							    	
           /* SWAP THE BUFFS */
           		
#ifdef TARGET_OS_MAC
	aglSwapBuffers(gMyInstances[instanceNum].drawContext);					// end render loop
#else
	SwapBuffers(gMyInstances[instanceNum].hdc);
#endif		
	
}


/************************ DRAW MY SPRITES ***************************/

static void DrawMySprites(int instanceNum)
{ 
float	y = 0, x = 0;
float	a, s, cs, cf, dx, oldDX;
float	percentage, barW, barH;
float	fps = gMyInstances[instanceNum].oneOverFPS;

	OGL_PushState();

	cf = gMyInstances[instanceNum].cubeFade;
	cs = gMyInstances[instanceNum].controllerScale * 1.3;								// get controller scale			

	if (gMyInstances[instanceNum].nonPower2)						// sprites don't use the rectangular stuff, so be sure its off
		glDisable(GL_TEXTURE_RECTANGLE_EXT);


			/********************/
			/* DRAW USER STRING */
			/********************/
			//
			// This is the text string that the user can set in the HTML parameters
			//
		

	if (gMyInstances[instanceNum].userString[0] > 0)
	{
		if (gMyInstances[instanceNum].cubeFade > 0)				// only show it when done loading
		{
			glEnable(GL_BLEND);
						
			glColor4f(0,0,0, gMyInstances[instanceNum].userStringAlpha);				// draw back shadow...
			OGL_DrawString(instanceNum, gMyInstances[instanceNum].userString, 224, SPRITE_WINDOW_RANGE-3);
			glColor4f(1,1,1, gMyInstances[instanceNum].userStringAlpha);				// ...then white text
			OGL_DrawString(instanceNum, gMyInstances[instanceNum].userString, 224-1, SPRITE_WINDOW_RANGE-3-1);
			
			if (gMyInstances[instanceNum].minimizeController)
			{
				gMyInstances[instanceNum].userStringAlpha -= gMyInstances[instanceNum].oneOverFPS * 3.0f;
				if (gMyInstances[instanceNum].userStringAlpha < 0.0f)
					gMyInstances[instanceNum].userStringAlpha = 0.0f;
			}
			else
			{
				gMyInstances[instanceNum].userStringAlpha += gMyInstances[instanceNum].oneOverFPS * 3.0f;
				if (gMyInstances[instanceNum].userStringAlpha > 1.0f)
					gMyInstances[instanceNum].userStringAlpha = 1.0f;
			}
		}
	}
	
	
	
		/*******************************/
		/* DRAW LOADING SPRITES / BARS */
		/*******************************/

			/* SET THE SPRITE STATE */

	Set2DSpriteState(instanceNum);
	glEnable(GL_TEXTURE_2D);
	
			/* DRAW LOGO */ 
			
	a = gMyInstances[instanceNum].loadingFade;
	
	if (gMyInstances[instanceNum].thumbnailFilename[0] != 0x00)	// if there's a thumbnail then shrink things down to get out of the way
	{
		cs *= .6f;
	}
			
	if (a > 0.0f)
	{ 
		glColor4f(1,1,1,a);
		x = 0;
		DrawASprite(&gMyInstances[instanceNum].sprites[SP_LOGO], x, y, cs * 2.5, false);		
		glColor3f(1,1,1);
	}
		
				
		/* DRAW LOADING THERMOMETER */
			
	x += cs * .23f;												// position it where we want it
	y += cs * .9f;
	barH = cs * .09;
			
	if (gMyInstances[instanceNum].drawLoadingBar)
	{
		int		numBytesLoaded	= gMyInstances[instanceNum].bytesDownloaded;
		int		fileSize		= gMyInstances[instanceNum].srcFileSize;
		
		if ((fileSize == 0) || (numBytesLoaded == 0))
			percentage = 0.0;
		else
			percentage = (float)numBytesLoaded / (float)fileSize;
	
		barW = percentage * cs * .925;							// calc width of thermo bar
		
		glDisable(GL_TEXTURE_2D);
	
		glColor3f(.8,0,0);		
		glBegin(GL_QUADS);
		
		glVertex2f(x, y);
		glVertex2f(x, y + barH);
		glVertex2f(x + barW, y + barH);
		glVertex2f(x + barW, y);

		glEnd();
		glColor3f(1,1,1);

		glEnable(GL_TEXTURE_2D);
	}


		/* DRAW DECODING THERMOMETER */
						
	if (gMyInstances[instanceNum].drawLoadingBar)
	{
		if (gMyInstances[instanceNum].doEquirectangular)
			percentage = (float)(gMyInstances[instanceNum].decodeStep + 1) / 8.0f;
		else
			percentage = (float)(gMyInstances[instanceNum].decodeStep + 1) / 6.0f;
	
	
		barW = percentage * cs * .925;							// calc width of thermo bar
		
		glDisable(GL_TEXTURE_2D);
	
		glColor3f(0,.6,0);		
		glBegin(GL_QUADS);
		
		glVertex2f(x, y);
		glVertex2f(x, y + barH);
		glVertex2f(x + barW, y + barH);
		glVertex2f(x + barW, y);

		glEnd();
		glColor3f(1,1,1);

		glEnable(GL_TEXTURE_2D);
	}



	if (cf == 0.0)											// if cube is totally faded then we're still loading, so don't draw anything else
		goto bail;
		

			/***********************/
			/* MOVE CONTROLLER BAR */
			/***********************/
			
	cs = gMyInstances[instanceNum].controllerScale;								// get controller scale			
			
	if (!gMyInstances[instanceNum].showController)								// do we even want to draw this?
		goto bail;
			
	gMyInstances[instanceNum].controllerMoved = false;							// assume it isnt moving

	oldDX = dx =  gMyInstances[instanceNum].controllerDX;
	x = gMyInstances[instanceNum].controllerX;								// get current x


			/* SEE IF MOVING TO MINIMIZE POSITION */
				
	if (gMyInstances[instanceNum].minimizeController)
	{
		float	minX = cs * -1.32;												// calc where x is when minimized
		
		if (x < minX)					// this can happen when a window is resized
			x = gMyInstances[instanceNum].controllerX = minX;
		
		if (dx != 0.0f)															// is it still moving?
		{
			
			dx -= 1500.0 * fps;													// apply delta
			
			if (x > minX)															// still need to minimize all the way?
			{
				x += fps * dx;
				if (x < minX)
				{
					x = minX + .001;
					dx *= -.3f;														// bounce it
					if (fabs(oldDX) < 10.0f)
					{
						dx = 0;
						x = minX;
					}
				}
				gMyInstances[instanceNum].controllerMoved = true;					// it moved
				gMyInstances[instanceNum].controllerX = x;							// update coord
			}
		}
	} 
	
			/* MOVE TO MAXIMIZED POSITION */
	else
	{
		float	maxX = 0;
		
		if (dx != 0.0f)															// is it still moving?
		{
			dx += 1500.0 * fps;														// apply delta
			
			if (x < maxX)															// still need to maximize all the way?
			{
				x += fps * dx;
				if (x > maxX)
				{
					x = maxX - .001;
					dx *= -.3f;														// bounce it
					if (fabs(oldDX) < 10.0f)
					{
						dx = 0;
						x = maxX;
					}
				}
				gMyInstances[instanceNum].controllerMoved = true;					// it moved
				gMyInstances[instanceNum].controllerX = x;							// update coord
			}
		}
	}
	
	gMyInstances[instanceNum].controllerDX = dx;							// update dx
	
	
			/***********************/
			/* DRAW CONTROLLER BAR */
			/***********************/


	y = gMyInstances[instanceNum].paneHeight;
	DrawASprite( &gMyInstances[instanceNum].sprites[SP_UIBAR], x, y, cs * 2, true);			// NOTE:  the * 2 here is because I increased the size of the sprite from 512 to 1024 and I didn't want to change all the other things that depend on this scale "cs" value.
	
	
			/* DRAW ZOOM-IN ICON */
		
	s = cs * .19;

	x += cs * .031; 
	y -= cs * .027;
	
	if (gMyInstances[instanceNum].hiliteZoomIn)
		DrawASprite(&gMyInstances[instanceNum].sprites[SP_ZOOMIN_ON], x, y, s, true);		
	else
		DrawASprite(&gMyInstances[instanceNum].sprites[SP_ZOOMIN_OFF], x, y, s, true);		


			/* DRAW ZOOM-OUT ICON */
							
	x += cs * .21;
	
	if (gMyInstances[instanceNum].hiliteZoomOut)
		DrawASprite(&gMyInstances[instanceNum].sprites[SP_ZOOMOUT_ON], x, y, s, true);		
	else
		DrawASprite(&gMyInstances[instanceNum].sprites[SP_ZOOMOUT_OFF], x, y, s, true);		


		/* DRAW PREFS ICON */
		
	x += cs * .85;
 	
	if (gMyInstances[instanceNum].hilitePrefsIcon)
		DrawASprite(&gMyInstances[instanceNum].sprites[SP_PREFS_ON], x, y, s, true);		
	else
		DrawASprite(&gMyInstances[instanceNum].sprites[SP_PREFS_OFF], x, y, s, true);		


		/* DRAW HIDE ICON */
		
	x += cs * .26;
 	
	if (gMyInstances[instanceNum].minimizeController)
		DrawASprite(&gMyInstances[instanceNum].sprites[SP_MAXIMIZE], x, y, s, true);		
	else
		DrawASprite(&gMyInstances[instanceNum].sprites[SP_MINIMIZE], x, y, s, true);		


bail:
	OGL_PopState();

	glDisable(GL_TEXTURE_2D);
	glDisable(GL_TEXTURE_RECTANGLE_EXT);
}


/********************* DRAW A SPRITE **********************/
//
// NOTE:  sprites are always power of 2, so we don't need to mess with the GL_TEXTURE_RECTANGLE_EXT stuff.
//

static void DrawASprite(MySpriteType *sprite, float x, float y, float scale, Boolean yIsBottom)
{
float	aspect;

	glBindTexture (GL_TEXTURE_2D, sprite->textureName);

	aspect = sprite->aspectRatio;

	if (yIsBottom)
		y -= scale * aspect;

	glBegin(GL_QUADS);
	glTexCoord2f(0,0);				glVertex2f(x,		y);
	glTexCoord2f(0, 1.0f);			glVertex2f(x,		y + (scale * aspect));
	glTexCoord2f(1.0f, 1.0f);		glVertex2f(x+scale, y + (scale * aspect));
	glTexCoord2f(1.0f, 0);			glVertex2f(x+scale, y);	
	glEnd();
}

#define	THUMBNAIL_SIZE	140.0

/****************** DRAW THUMBNAIL ***********************/

static void DrawThumbnail(int instanceNum)
{
	if (gMyInstances[instanceNum].thumbnailLoaded)
	{ 
 		float	a = gMyInstances[instanceNum].loadingFade;
	
				
		if (a > 0.01f)
		{
			float scale = gMyInstances[instanceNum].thumbnailScale;
			
			OGL_PushState();
		
					/* SET A SPECIFIC MATRIX STATE */
					
			glMatrixMode(GL_PROJECTION);
			glLoadIdentity();	
			gluPerspective (80,								// fov in degrees
					gMyInstances[instanceNum].aspectRatio,	// aspect
					10,										// hither
					2000);									// yon
			glMatrixMode(GL_MODELVIEW);
			glLoadIdentity();
			gluLookAt(	0, 0, 0,						// camera is always at 0,0,0
						0, 0, -1,						// camera always looks down the z-axis
						0, 1, 0);						// up vector

			glRotatef(100.0 * (1.0f - a), 0, 1, 0);

			if (gMyInstances[instanceNum].nonPower2)						// sprites don't use the rectangular stuff, so be sure its off
				glDisable(GL_TEXTURE_RECTANGLE_EXT);

			glEnable(GL_TEXTURE_2D);
			glEnable(GL_BLEND);


//			glColor4f(1,1,1,a);
			glColor3f(1,1,1);
			glBindTexture (GL_TEXTURE_2D, gMyInstances[instanceNum].thumbnailTexture);

			if (gMyInstances[instanceNum].thumbShape == 1)						// draw square
			{
				glBegin(GL_QUADS);
				glTexCoord2f(0,0);				glVertex3f(-THUMBNAIL_SIZE * scale, THUMBNAIL_SIZE * scale, -400);
				glTexCoord2f(0, 1.0f);			glVertex3f(-THUMBNAIL_SIZE * scale, -THUMBNAIL_SIZE * scale, -400);
				glTexCoord2f(1.0f, 1.0f);		glVertex3f(THUMBNAIL_SIZE * scale, -THUMBNAIL_SIZE * scale, -400);
				glTexCoord2f(1.0f, 0);			glVertex3f(THUMBNAIL_SIZE * scale, THUMBNAIL_SIZE * scale, -400);	
				glEnd();
			}
			else																// draw rectangle
			{
				glBegin(GL_QUADS);
				glTexCoord2f(0,0);				glVertex3f(-THUMBNAIL_SIZE * scale, THUMBNAIL_SIZE/2 * scale, -400);
				glTexCoord2f(0, 1.0f);			glVertex3f(-THUMBNAIL_SIZE * scale, -THUMBNAIL_SIZE/2 * scale, -400);
				glTexCoord2f(1.0f, 1.0f);		glVertex3f(THUMBNAIL_SIZE * scale, -THUMBNAIL_SIZE/2 * scale, -400);
				glTexCoord2f(1.0f, 0);			glVertex3f(THUMBNAIL_SIZE * scale, THUMBNAIL_SIZE/2 * scale, -400);	
				glEnd();
			}
			
			glColor3f(1,1,1);			
			OGL_PopState();
		}

	}
}


#pragma mark -


/***************** SET 2D SPRITE STATE *******************/
//
// Called to put OpenGL into a 2D ortho mode where the screen coords are 0,0 to SPRITE_WINDOW_RANGE,SPRITE_WINDOW_RANGE
//

void Set2DSpriteState(int instanceNum)
{
#ifdef TARGET_OS_MAC
  	aglSetCurrentContext(gMyInstances[instanceNum].drawContext);				// make context active
#else
	wglMakeCurrent( gMyInstances[instanceNum].hdc, gMyInstances[instanceNum].drawContext );
#endif		

	glDisable(GL_DEPTH_TEST);								// no z-buffer

			/* INIT MATRICES */
					
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	
								// note:  gCurrentPaneAspectRatio is used to keep thing square, regardless of how the draw context reshapes
								
//	glOrtho(0, SPRITE_WINDOW_RANGE * gMyInstances[instanceNum].aspectRatio, SPRITE_WINDOW_RANGE, 0, 0, 1);
	glOrtho(0, gMyInstances[instanceNum].paneWidth, gMyInstances[instanceNum].paneHeight, 0, 0, 1);
		
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();	
			
	glEnable(GL_BLEND);	
																															
}




#pragma mark -

/************************** OGL_INIT FONT **************************/

static void OGL_InitFont(int instanceNum)
{
#ifdef TARGET_OS_MAC
	OGL_InitFont_Mac(instanceNum);
#else
	OGL_InitFont_Windows(instanceNum);
#endif			
}


/******************* OGL_FREE FONT ***********************/

static void OGL_FreeFont(int instanceNum)
{
	if (gMyInstances[instanceNum].fontLoaded)
	{
#ifdef TARGET_OS_MAC
		OGL_FreeFont_Mac(instanceNum);	
#else
		OGL_FreeFont_Windows(instanceNum);
#endif		
		
		gMyInstances[instanceNum].fontLoaded = false;
	}
}

/**************** OGL_DRAW STRING ********************/

void OGL_DrawString(int instanceNum, Str255 s, GLint x, GLint y)
{
	if (!gMyInstances[instanceNum].fontLoaded)
		return;

#ifdef TARGET_OS_MAC
  	OGL_DrawString_Mac(instanceNum, s, x, y);
#else
	OGL_DrawString_Windows(instanceNum, s, x, y);
#endif		

}

/**************** OGL_DRAW FLOAT ********************/

void OGL_DrawFloat(int instanceNum, float f, GLint x, GLint y)
{

Str255	s;

	FloatToString(f,s);
	OGL_DrawString(instanceNum, s,x,y);
	
}



/**************** OGL_DRAW INT ********************/

void OGL_DrawInt(int instanceNum, int f, GLint x, GLint y)
{

Str255	s;

	NumToString(f,s);
	OGL_DrawString(instanceNum, s,x,y);

}


#pragma mark -


/******************* FLOAT TO STRING *******************/

static void FloatToString(float num, Str255 string)
{
Str255	sf;
long	i,f;

	i = num;						// get integer part
	
	
	f = (fabs(num)-fabs((float)i)) * 10000;		// reduce num to fraction only & move decimal --> 5 places	

	if ((i==0) && (num < 0))		// special case if (-), but integer is 0
	{
		string[0] = 2;
		string[1] = '-';
		string[2] = '0';
	}
	else
		NumToString(i,string);		// make integer into string
		
	NumToString(f,sf);				// make fraction into string
	
	string[++string[0]] = '.';		// add "." into string
	
	if (f >= 1)
	{
		if (f < 1000)
			string[++string[0]] = '0';	// add 1000's zero
		if (f < 100)
			string[++string[0]] = '0';	// add 100's zero
		if (f < 10)
			string[++string[0]] = '0';	// add 10's zero
	}
	
	for (i = 0; i < sf[0]; i++)
	{
		string[++string[0]] = sf[i+1];	// copy fraction into string
	}
}



#pragma mark -


/********************* PUSH STATE **************************/

void OGL_PushState(void)
{


		/* PUSH MATRIES WITH OPENGL */

	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();

	glMatrixMode(GL_MODELVIEW);										// in my code, I keep modelview matrix as the currently active one all the time.
	
}


/********************* POP STATE **************************/

void OGL_PopState(void)
{

		/* RETREIVE OPENGL MATRICES */
		
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();
	

}


/******************** OGL: CHECK ERROR ********************/

GLenum OGL_CheckError(void)
{
GLenum	err;
GLint	errPos;
GLubyte		*errString;

	err = glGetError();
	if (err != GL_NO_ERROR)
	{
		switch(err)
		{
			case	GL_INVALID_ENUM:
					printf("OGL_CheckError: GL_INVALID_ENUM\n");
					break;

			case	GL_INVALID_VALUE:
					printf("OGL_CheckError: GL_INVALID_VALUE\n");
					break;

			case	GL_INVALID_OPERATION:
					printf("OGL_CheckError: GL_INVALID_OPERATION\n");
					
					glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos);			// find error position
				
					errString = (GLubyte *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);
					
					printf(errString);
					printf("\n");
					
					break;

			case	GL_STACK_OVERFLOW:
					printf("OGL_CheckError: GL_STACK_OVERFLOW\n");
					break;

			case	GL_STACK_UNDERFLOW:
					printf("\pOGL_CheckError: GL_STACK_UNDERFLOW\n");
					break;

			case	GL_OUT_OF_MEMORY:
					printf("\pOGL_CheckError: GL_OUT_OF_MEMORY\n");
					break;	
					
			default:
					printf("\pOGL_CheckError: some other error %d\n", err);
		}		
	}
	
	return(err);
}



#pragma mark -


/************** OGL: CAMERA SET PLACEMENT & UPDATE MATRICES **********************/
//
// This is called by OGL_DrawScene to initialize all of the view matrices.
//

static void OGL_Camera_SetPlacementAndUpdateMatrices(int instanceNum)
{
	if (gMyInstances[instanceNum].drawContext == nil)
		return;

#ifdef TARGET_OS_MAC
  	aglSetCurrentContext(gMyInstances[instanceNum].drawContext);				// make context active
#else
	wglMakeCurrent( gMyInstances[instanceNum].hdc, gMyInstances[instanceNum].drawContext );
#endif		

	
			/**************************/
			/* INIT PROJECTION MATRIX */
			/**************************/
			
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();	
	
	
			/* SETUP STANDARD PERSPECTIVE CAMERA */

	gluPerspective (gMyInstances[instanceNum].fov,			// fov in degrees
					gMyInstances[instanceNum].aspectRatio,	// aspect
					10,										// hither
					2000);									// yon
	
			/* INIT MODELVIEW MATRIX */
			
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt(	0, 0, 0,						// camera is always at 0,0,0
				0, 0, -1,						// camera always looks down the z-axis
				0, 1, 0);						// up vector

}







