/****************************/
/*			MAIN.C			*/
/* (c)2004 Pangea Software  */
/* By Brian Greenstone      */
/****************************/


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

static void DrawSpinningCube(void);
static void MoveCube(void);
static void InitApplication(void);
static void GetGameNib(void);


/**************************/
/*    EXTERNS             */
/**************************/

extern	Boolean						gPlayInWindow;
extern	short						gDesiredColorDepth, gDesiredRezH, gDesiredRezV;
extern	CGDirectDisplayID			gCGDisplayID;
extern	int							gFrameCounter, gMouseDeltaX;
extern	GLuint						gVertexArrayRangeObjects[];
extern	float						gFramesPerSecond, gOneOverFramesPerSecond;
extern	float						gGammaBrightness;
extern	long						gMouseWheelDelta;

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

typedef struct
{
	OGLPoint3D		points[8];
	OGLColorRGBA	colors[8];
	GLint			quads[6*4];

}CubeDataType;

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

Boolean				gQuitApplication = false;

CFBundleRef 		gBundle = nil;
IBNibRef 			gNibs = nil;


		/* GEOMETRY DATA FOR CUBE */

CubeDataType	gCubeMesh =
{
			/* POINTS */
				
	-1, -1, 1,					// left/bottom/front
	-1,-1,-1,					// left/bottom/rear
	1,-1,-1,					// right/bottom/rear
	1,-1,1,						// right/bottom/front
	-1, 1, 1,					// left/top/front
	-1,1,-1,					// left/top/rear
	1,1,-1,						// right/top/rear
	1,1,1,						// right/top/front	

			/* COLORS */
	0,0,0,1,					
	1,0,0,1,					
	0,1,0,1,				
	0,0,1,1,				
	1,1,1,1,				
	1,1,0,1,			
	0,1,1,1,				
	1,0,1,1,			

			/* QUADS */
			
	0,1,2,3,					// bottom face
	7,6,5,4,					// top face
	4,5,1,0,					// left face
	7,3,2,6,					// right face
	7,4,0,3,					// front face
	5,6,2,1						// rear face
};


float	gCubeRotX = 0, gCubeRotY = 0;


/***************** INITIALIZE GEOMETRY ********************/

static void InitializeGeometry(void)
{
			/* ASSIGN CUBE'S DATA TO VAR #0 */
			
	OGL_AssignVertexArrayRangeMemory(sizeof(CubeDataType), &gCubeMesh, 0);
}


/***************** DRAW SCENE GEOMETRY *******************/
//
// Called from DrawOpenGLScene() when it's time to submit our
// geometry data to OpenGL.
//

void DrawSceneGeometry(void)
{
static	OGLPoint3D	cameraCoord = {0,0,10};
static	OGLPoint3D	lookAtPt	= {0,0,0};
static	OGLVector3D	upVec		= {0,1,0};
static	float	wobble = 0;

			/* DRAW A FRAME COUNTER & FPS IN THE UPPER-LEFT CORNER */
			
	OGL_DrawString("\pframe #:", 20, 20);
	OGL_DrawInt(gFrameCounter, 70, 20);

	OGL_DrawString("\pfps:", 20, 40);
	OGL_DrawInt(gFramesPerSecond, 70, 40);
	
	OGL_DrawString("\pmouse wheel delta:", 20, 60);
	OGL_DrawInt(gMouseWheelDelta, 110, 60);
	
	OGL_DrawString("\pmouse delta X:", 20, 80);
	OGL_DrawInt(gMouseDeltaX, 110, 80);
	

			
			/* DRAW MESSAGE IN OPPOSITE CORNER */
			
	OGL_DrawString("\pType Command-Q to Quit", 500, 440);
		
	

			/* SET CAMERA & STATE */
	
	wobble += gOneOverFramesPerSecond * 1.2f;			// make camera zoom in-out
	cameraCoord.z = 50.0f + sin(wobble) * 40.0f;
	
	OGL_SetCamera(&cameraCoord, &lookAtPt, &upVec);
	OGL_SetColor4f(1,1,1,1);	
	OGL_DisableLighting();
	OGL_DisableTexture2D();
	OGL_DisableBlend();
	
			/* DRAW CUBE */
			
	DrawSpinningCube();
}



/***************** DRAW SPINNING CUBE *******************/

static void DrawSpinningCube(void)
{
		
			/* MAKE THE CUBE'S VAR MEMORY ACTIVE */
				
	glBindVertexArrayAPPLE(gVertexArrayRangeObjects[0]);		// bind to VAR #0
	
	
			/* SCALE AND ROTATE */
			
	glScalef(3,3,3);
	glRotatef(gCubeRotX,1,0,0);
	glRotatef(gCubeRotY,0,1,0);



			/* INIT THE VERTEX ARRAYS */
						
	glEnableClientState(GL_VERTEX_ARRAY);			// point to points
	glVertexPointer(3, GL_FLOAT, 0, gCubeMesh.points);	

	glColorPointer(4, GL_FLOAT, 0, gCubeMesh.colors);
	glEnableClientState(GL_COLOR_ARRAY);			// point to vertex colors

	glDisableClientState(GL_TEXTURE_COORD_ARRAY);	// no uv's
	glDisableClientState (GL_NORMAL_ARRAY);			// no normals

		
			/* SUBMIT THE VERTEX ARRAYS */

	glDrawElements(GL_QUADS, 4*6, GL_UNSIGNED_INT, gCubeMesh.quads);
		
}


/******************** MOVE CUBE ************************/
//
// Called to rotate the cube.
//

static void MoveCube(void)
{
	gCubeRotX += 300.0f * gOneOverFramesPerSecond;		// spin 300 degrees per second on x-axis
	gCubeRotY += 100.0f * gOneOverFramesPerSecond;		// spin 100 degrees per second on y-axis
}


#pragma mark -

/******************** INIT APPLICATION ************************/
//
// Called from main() to setup all the initial application stuff.
// 

static void InitApplication(void)
{

			/* DO SOME RESOURCE INITS */
			
	SetDefaultDirectory();						// set app's default directory
	GetGameNib();								// get ref to our .nib file
	GetMyApplicationResourcesFolder();			// get FSSpec and FSRef to our Resources folder
	
	
			/* ASK USER FOR VIDEO SETTINGS */
			
	DoScreenModeDialog();

	
	if (gPlayInWindow)							// play in window or full screen?
		CreateGameWindow();		
	else	
		SwitchDisplayMode(gDesiredRezH, gDesiredRezV, gDesiredColorDepth);	
	
	CalcDisplayVRAM();							// calc amount of VRAM on this display
	

			/* GET OPENGL GOING */
				
	OGL_CreateDrawContext();					// create the draw context
	OGL_InitFont();								// init an AGL font to use
	InitializeGeometry();						// allocate the VAR memory for the geometry mesh data
	
	
			/* INIT OUR GAMMA */
			
	InitGammaValues();
	
	
		/* INSTALL OUR EVENT HANDLER CALLBACK */
			
	InitMyEventHandler();
	
	
			/* INIT AUDIO SYSTEM */
			
	InitAudio();

}


/******************** GET GAME NIB *********************/
//
// Our dialog resources are all stored in the Game.nib file.
// This code creates a reference to that .nib file so that we can
// easily get to the resources whenever we need to.
//

static void GetGameNib(void)
{
OSStatus	iErr;
			
	gBundle = CFBundleGetMainBundle();
	if (gBundle == nil)
		DoFatalAlert("\pCannot locate Main Bundle!");
		
	iErr = CreateNibReferenceWithCFBundle(gBundle, CFSTR("Game"), &gNibs);			// note:  we don't need the ".nib" extension in the filename
	if (iErr != noErr)
		DoFatalAlert("\pCreateNibReferenceWithCFBundle failed!");
}

#pragma mark -

/********************* MY MAIN LOOP **********************/

static pascal void MyMainLoop (EventLoopTimerRef  theTimer, void* userData)
{
	#pragma unused (theTimer, userData)

			/* EXIT EVENT LOOP IF QUIT FLAG SET */
			
	if (gQuitApplication)
		QuitApplicationEventLoop();

				/*************************/
				/* DO 1 PASS OF THE LOOP */
				/*************************/
				
	CalcFramesPerSecond();					// calc FPS

			/* MOVE & UPDATE STUFF */
			
	GammaFadeInOneFrame(2.0);				// do 2-second fade-in
	MoveCube();								// move cube
	
	
			/* DRAW SCENE */
				
	OGL_DrawScene();
				
}	


/************************ MAIN **************************/

int main(void)
{
			/* INITIALIZE THINGS */

	InitApplication();
			
			
				/* DIM DISPLAY */
		
	if (!gPlayInWindow)							// only gamma fade if full-screen
	{
		gGammaBrightness = 0;
		SetGammaFade(0);
	}
	
	
			/* PLAY A SONG */
			
//	PlaySong("\pSong.m4a", true);
	OAL_PlaySound3D(2, nil, nil, 1.0, 1.0, AL_TRUE);
	
	
			/* DO THE MAIN LOOP */

	SetMyMainLoopEventTimer(MyMainLoop);		// install the main loop timer
	
	RunApplicationEventLoop();					// process all the timer events

	RemoveMyMainLoopEventTimer();				// we're all done, so cleanup
	
			
	
		/* DO A 1.0 SECOND FADE OUT */
			
	if (!gPlayInWindow)					// don't do gamma fades if playing in window
		GammaFadeOut(1.0);
	
}










