#include "ofGraphics.h"


//----------------------------------------------------------
// static 
GLuint 			precachedCircle;
static float	drawMode 		= OF_FILLED;
static bool 	bSetupCircle 	= false;
float 			bgColor[4] 		= {0,0,0,0};
void 			setupCircle();
bool 			bSmoothHinted 	= false;
bool 			bBakgroundAuto  = true;
int 			cornerMode 		= OF_RECTMODE_CORNER;
void			startSmoothing();
void 			endSmoothing();

//----------------------------------------------------------
void  ofSetRectMode(int mode){
	if (mode == OF_RECTMODE_CORNER) 		cornerMode = OF_RECTMODE_CORNER;
	else if (mode == OF_RECTMODE_CENTER) 	cornerMode = OF_RECTMODE_CENTER;
}

//----------------------------------------------------------
int ofGetRectMode(){
	return 	cornerMode;
}

//----------------------------------------------------------
void ofSetBackgroundAuto(bool bAuto){
	bBakgroundAuto = bAuto;
}

//----------------------------------------------------------
bool ofbClearBg(){
	return bBakgroundAuto;
}

//----------------------------------------------------------
float * ofBgColorPtr(){
	return bgColor;
}

//----------------------------------------------------------
bool ofbOriginBottomLeft(){
	return false;			
	// because people are certainly asking for it!
}

//----------------------------------------------------------
void ofBackground(int r, int g, int b){
	bgColor[0] = (float)r / (float)255.0f;
	bgColor[1] = (float)g / (float)255.0f;
	bgColor[2] = (float)b / (float)255.0f;
	bgColor[3] = 1.0f;
	// if we are in not-auto mode, then clear with a bg call...
	if (ofbClearBg() == false){
		glClearColor(bgColor[0],bgColor[1],bgColor[2], bgColor[3]);
		glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	}
}

//----------------------------------------------------------
void ofNoFill(){
	drawMode = OF_OUTLINE;
};

//----------------------------------------------------------
void ofFill(){
	drawMode = OF_FILLED;
};

//----------------------------------------------------------
void startSmoothing(){		
		glPushAttrib(GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT);
		glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
		glEnable(GL_LINE_SMOOTH);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

//----------------------------------------------------------
void endSmoothing(){
	glPopAttrib();
}

//----------------------------------------------------------
void setupCircle(){
	precachedCircle = glGenLists(1);
	glNewList(precachedCircle, GL_COMPILE);
	float angle = 0.0f;
	float angleAdder = M_TWO_PI / (float)CIRC_RESOLUTION;
	for (float i = 0; i < CIRC_RESOLUTION; i++){
		glVertex2f( cos(angle), sin(angle));
		angle += angleAdder;
	}
	glEndList();
	bSetupCircle = true;
}

//----------------------------------------------------------
void ofSetCircleResolution(int res){
	if (res > 1){
		precachedCircle = glGenLists(1);
		glNewList(precachedCircle, GL_COMPILE);
		float angle = 0.0f;
		float angleAdder = M_TWO_PI / (float)res;
		for (float i = 0; i < res; i++){
			glVertex2f( cos(angle), sin(angle));
			angle += angleAdder;
		}
		glEndList();
		bSetupCircle = true;
	}
}


//----------------------------------------------------------
void ofTriangle(float x1,float y1,float x2,float y2,float x3, float y3){
	

	// use smoothness, if requested:
	if (bSmoothHinted && drawMode == OF_OUTLINE) startSmoothing();
		
	// draw:
	glBegin( (drawMode == OF_FILLED) ? GL_TRIANGLES : GL_LINE_LOOP);   	
		glVertex2f(x1,y1);
		glVertex2f(x2,y2);
		glVertex2f(x3,y3);
	glEnd();
	
	// back to normal, if smoothness is on
	if (bSmoothHinted && drawMode == OF_OUTLINE) endSmoothing();	
}

//----------------------------------------------------------
void ofCircle(float x,float y, float radius){
	
	if (!bSetupCircle) setupCircle();
	
	// use smoothness, if requested:
	if (bSmoothHinted && drawMode == OF_OUTLINE) startSmoothing();
	
	// draw:
	glPushMatrix();
		glTranslatef(x, y, 0);
		glScalef(radius, radius, 1);
		glBegin( (drawMode == OF_FILLED) ? GL_POLYGON : GL_LINE_LOOP);   	
		glCallList(precachedCircle);
		glEnd();
	glPopMatrix();
	
	// back to normal, if smoothness is on
	if (bSmoothHinted && drawMode == OF_OUTLINE) endSmoothing();
	
}

//----------------------------------------------------------
void ofEllipse(float x, float y, float width, float height){
	
	if (!bSetupCircle) setupCircle();
	
	// use smoothness, if requested:
	if (bSmoothHinted && drawMode == OF_OUTLINE) startSmoothing();
	
	// draw:
	glPushMatrix();
		glTranslatef(x, y, 0);
		glScalef(width, height, 1);		
		glBegin( (drawMode == OF_FILLED) ? GL_POLYGON : GL_LINE_LOOP);   	
		glCallList(precachedCircle);
		glEnd();
	glPopMatrix();
	
	// back to normal, if smoothness is on
	if (bSmoothHinted && drawMode == OF_OUTLINE) endSmoothing();
}

//----------------------------------------------------------
void ofLine(float x1,float y1,float x2,float y2){

	// use smoothness, if requested:
	if (bSmoothHinted) startSmoothing();

	// draw:
	glBegin( GL_LINES ); 
		glVertex2f(x1,y1);
		glVertex2f(x2,y2);	
	glEnd();
	
	// back to normal, if smoothness is on
	if (bSmoothHinted) endSmoothing();
	
}

//----------------------------------------------------------
void ofRect(float x,float y,float w,float h){

	// use smoothness, if requested:
	if (bSmoothHinted && drawMode == OF_OUTLINE) startSmoothing();

	if (cornerMode == OF_RECTMODE_CENTER){
		glBegin( (drawMode == OF_FILLED) ? GL_QUADS : GL_LINE_LOOP);   	
		glVertex2f(x-w/2,y-h/2);
		glVertex2f(x+w/2,y-h/2);
		glVertex2f(x+w/2,y+h/2);
		glVertex2f(x-w/2,y+h/2);
		glEnd();
	} else {
		glBegin( (drawMode == OF_FILLED) ? GL_QUADS : GL_LINE_LOOP);   	
		glVertex2f(x,y);
		glVertex2f(x+w,y);
		glVertex2f(x+w,y+h);
		glVertex2f(x,y+h);
		glEnd();
	}
	// use smoothness, if requested:
	if (bSmoothHinted && drawMode == OF_OUTLINE) endSmoothing();
}

//----------------------------------------------------------
void ofSetColor(int _r, int _g, int _b){
	float r = (float)_r / 255.0f; r = MAX(0,MIN(r,1.0f));
	float g = (float)_g / 255.0f; g = MAX(0,MIN(g,1.0f));
	float b = (float)_b / 255.0f; b = MAX(0,MIN(b,1.0f));
	glColor3f(r,g,b);
}


//----------------------------------------------------------
void ofSetColor(int _r, int _g, int _b, int _a){
	float r = (float)_r / 255.0f; r = MAX(0,MIN(r,1.0f));
	float g = (float)_g / 255.0f; g = MAX(0,MIN(g,1.0f));
	float b = (float)_b / 255.0f; b = MAX(0,MIN(b,1.0f));
	float a = (float)_a / 255.0f; a = MAX(0,MIN(a,1.0f));
	
	glColor4f(r,g,b,a);
}

//----------------------------------------------------------
void ofSetColor(int hexColor){
	int r = (hexColor >> 16) & 0xff;
	int g = (hexColor >> 8) & 0xff;
	int b = (hexColor >> 0) & 0xff;
	ofSetColor(r,g,b);
}

//----------------------------------------------------------
void ofEnableAlphaBlending(){
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}

//----------------------------------------------------------
void ofDisableAlphaBlending(){
	glDisable(GL_BLEND);
}


//----------------------------------------------------------
void ofEnableSmoothing(){
	// please see:
	// http://www.opengl.org/resources/faq/technical/rasterization.htm
	bSmoothHinted = true;
}

//----------------------------------------------------------
void ofDisableSmoothing(){
	bSmoothHinted = false;
}
    
    

//--------------------------------------------------
void ofDrawBitmapString(char *string, float x, float y){  
	
	//---------------------------------------------------
	// 	for now this is fixed to the 8_BY_13 glut character
	//	http://pyopengl.sourceforge.net/documentation/manual/glutBitmapCharacter.3GLUT.html
	//---------------------------------------------------
	
	char *c;
	float yOffset = 0;
	float fontSize = 8.0f;
	glRasterPos2f(x,y);
	bool bOrigin = ofbOriginBottomLeft();
	for (c=string; *c != '\0'; c++)
	{
		if(*c == '\n')
		{ 
				
			yOffset += bOrigin ? -1 : 1 * (fontSize*1.7);  
			glRasterPos2f(x,y + (int)yOffset); 
		} else if (((int)*c) >= 32){	
			// < 32 = control characters - don't draw 
			// solves a bug with control characters 
			// getting drawn when they ought to not be
			glutBitmapCharacter(GLUT_BITMAP_8_BY_13, *c);
		}
	}
}

//----------------------------------------------------------
void ofSetupScreen(){

	int w, h;
	
	w = glutGet(GLUT_WINDOW_WIDTH);	
	h = glutGet(GLUT_WINDOW_HEIGHT);
	
	float halfFov, theTan, screenFov, aspect;
	screenFov 		= 60.0f;
	
	float eyeX 		= (float)w / 2.0;
	float eyeY 		= (float)h / 2.0;
	halfFov 		= PI * screenFov / 360.0;
	theTan 			= tanf(halfFov);
	float dist 		= eyeY / theTan;
	float nearDist 	= dist / 10.0;	// near / far clip plane
	float farDist 	= dist * 10.0;
	aspect 			= (float)w/(float)h;
	
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(screenFov, aspect, nearDist, farDist);
	gluLookAt(eyeX, eyeY, dist, 
	eyeX, eyeY, 0.0, 0.0, 1.0, 0.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	
	if (!ofbOriginBottomLeft()){
		glScalef(1, -1, 1);           // invert Y axis so increasing Y goes down.
  		glTranslatef(0, -h, 0);       // shift origin up to upper-left corner. 
	}
	
}
