
#include "./mesh.h"

#include "./shader.h"

#include "./sampler2D.h"

#include "./texture2D.h"

#include "./floatArray.h"

#include "./unsignedIntegerArray.h"

#include "./eventManager.h"

#include "./pipeline.h"


#include "./renderPasses/renderPassQuads.h"

#include "./renderPasses/renderPassFont.h"

#include "./renderPasses/renderPassCompute.h"

#include "./renderPasses/renderPassCompute2.h"

#include "./renderPasses/renderPassTesselation.h"



#include "./resourceManager.h"

#include "./windowManager.h"

#include "./event.h"


#include <math.h>

#include <stdio.h>

#include <stdlib.h>

#include <X11/Xlib.h>

#include <X11/keysym.h>

#define GL_GLEXT_PROTOTYPES

#include <GL/glext.h>

#include <GL/gl.h> // GL 1.1 functions 

#include <GL/glx.h>


#include <time.h>

#include <zlib.h>




event * 			globalEvent;

resourceManager	* 	resources;



class opengl{

	Display * 	mainDisplay;

	Window 		mainWindow;

	int 		MainScreen;

	Window 		RootWindow;


	int 					lastTime 		= clock();

	struct 		timespec	startTime;

	int 					frameCount		= 0;	



	sampler2D * testSampler;

	struct windowManager * 		windowManager		= new windowManager();

	

	struct eventManger * 		eventManger			= new eventManger();

	struct pipeline * 			pipeline			= new pipeline();




	initialize() {

		printf("initialize opengl.\n");

		resources 	= new resourceManager();

		this->setupWindow();

		this->setupManagers();

		this->showVersion();

		//this->createTexture();

		this->setupPipeline();

		//this->loadFont();

		this->setupTime();

		this->setupRenderLoop();

	}

	showExtensions() {

		GLint max_layers;

		glGetIntegerv ( GL_MAX_ARRAY_TEXTURE_LAYERS, &max_layers );

		printf("GL_MAX_ARRAY_TEXTURE_LAYERS:	%i\n", max_layers);


		GLint max_texture_size;

		glGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_texture_size);

		printf("GL_MAX_TEXTURE_SIZE:	%i\n", max_texture_size);


	}

	showVersion() {

		printf("opengl version : %s\n\n", glGetString(GL_VERSION) );

	}

	setupTime() {

		clock_gettime( CLOCK_REALTIME, &this->startTime );

	}

	setupManagers() {

		this->eventManger->mainDisplay = this->mainDisplay;

		this->eventManger->mainWindow = this->mainWindow;

		this->eventManger->RootWindow = this->RootWindow;

	}

	setupWindow() {

		this->windowManager->setupDisplay();

		this->windowManager->setupWindow();


		this->mainDisplay 	= this->windowManager->mainDisplay;

		this->mainWindow 	= this->windowManager->mainWindow;

		this->RootWindow 	= this->windowManager->RootWindow;

	}

	setupRenderLoop() {

		int IsProgramRunning 	= 1;

		while( IsProgramRunning ) {

		    while( XPending( this->mainDisplay ) ) {

		        XEvent GeneralEvent = {};

		        XNextEvent( this->mainDisplay, &GeneralEvent );

		        switch( GeneralEvent.type ) {

		            case ClientMessage: 
		            

		                IsProgramRunning = 0;

		            break;
		        }

		    }

			this->render();

		}

	}

	setupPipeline() {

		quads * quadsPass 			= new quads();

		font * fontPass 			= new font();

		compute * computePass 		= new compute();

		compute2 * computePass2 	= new compute2();

		tesselation * tesselationPass 	= new tesselation();


		//this->pipeline->addRenderPass( fontPass );

		this->pipeline->addRenderPass( quadsPass );

		//this->pipeline->addRenderPass( computePass );

		//this->pipeline->addRenderPass( computePass2 );

		//this->pipeline->addRenderPass( tesselationPass );


	}

	double clockToMilliseconds( clock_t ticks ){

		return ( ticks / ( double ) CLOCKS_PER_SEC );

	}

	render() {

		//this->clearColor( 0.0, 0.0, 0.0, 0.0 );

		glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

		this->clear( GL_DEPTH_BUFFER_BIT );

		globalEvent = this->eventManger->fetchEvent();

		this->pipeline->render();

		this->swapBuffers();

		//this->displayFPS();

	}

	displayFPS() {

		struct timespec 	now;

		clock_gettime( CLOCK_REALTIME, &now );

		this->frameCount++;

		int elapsedTime		= now.tv_sec - this->startTime.tv_sec;
    	
		if( elapsedTime != this->lastTime ) {

			printf("%i fps.\n\n",  this->frameCount  );
			
			this->lastTime = elapsedTime;

			this->frameCount = 0;

		}

	}

	clear( GLbitfield mask ) {

		 glClear( mask );

	}

	clearColor( float r, float g, float b, float a ) {

		glClearColor( r, g, b, a );

	}

	swapBuffers() {

		PFNGLXSWAPINTERVALEXTPROC 		glXSwapIntervalEXT;

		PFNGLXSWAPINTERVALMESAPROC 		glXSwapIntervalMESA;

		PFNGLXSWAPINTERVALSGIPROC 		glXSwapIntervalSGI;


		glXSwapIntervalEXT 			= ( PFNGLXSWAPINTERVALEXTPROC ) glXGetProcAddress( ( const GLubyte * ) "glXSwapIntervalEXT" );

		if ( glXSwapIntervalEXT != NULL ) {

			glXSwapIntervalEXT( this->mainDisplay, this->mainWindow, 0 );

		} else {

			glXSwapIntervalMESA = ( PFNGLXSWAPINTERVALMESAPROC ) glXGetProcAddress( ( const GLubyte * ) "glXSwapIntervalMESA" );

			if ( glXSwapIntervalMESA != NULL ) {

				glXSwapIntervalMESA( 0 );

			} else {

				glXSwapIntervalSGI = ( PFNGLXSWAPINTERVALSGIPROC ) glXGetProcAddress( ( const GLubyte * ) "glXSwapIntervalSGI" );
				
				if ( glXSwapIntervalSGI != NULL ) {

					glXSwapIntervalSGI( 0 );
				
				}
			}
		}

		glXSwapBuffers( this->mainDisplay, this->mainWindow );

	}

}




