


#include <stdio.h>

#include <stdlib.h>

#include <X11/Xlib.h>

#include <GL/glx.h>

// Opengl is old

static int DoubleBufferAttributes[] = {
	GLX_RGBA,
	GLX_RED_SIZE, 1,
	GLX_GREEN_SIZE, 1,
	GLX_BLUE_SIZE, 1,
	GLX_DEPTH_SIZE, 12,
	GLX_DOUBLEBUFFER,
	None,
};



class opengl{

	Display * mainDisplay;

	Window mainWindow;

	initialize() {

		this->mainDisplay			= XOpenDisplay( 0 );

		int MainScreen				= XDefaultScreen( this->mainDisplay );

		Window RootWindow			= XDefaultRootWindow( this->mainDisplay );

		int empty;

		int ResultStatus			= glXQueryExtension( this->mainDisplay, &empty, &empty );

		XVisualInfo* VisualInfo		= glXChooseVisual( this->mainDisplay, MainScreen, DoubleBufferAttributes );

		GLXContext ShareList		= None;

		int IsDirectRendering		= True;

		GLXContext OpenGLContext	= glXCreateContext( this->mainDisplay, VisualInfo, ShareList, IsDirectRendering );



		int WindowX 			= 0;

		int WindowY 			= 0;

		int WindowWidth 		= 800;

		int WindowHeight 		= 600;

		int BorderWidth 		= 0;

		int WindowClass 		= InputOutput;

		int WindowDepth 		= VisualInfo->depth;


		Visual* WindowVisual 	= VisualInfo->visual;

		int AttributeValueMask 	= CWBackPixel | CWEventMask | CWColormap;


		XSetWindowAttributes WindowAttributes 	= {};

		WindowAttributes.colormap 				= XCreateColormap( this->mainDisplay, RootWindow, VisualInfo->visual, AllocNone);

		WindowAttributes.background_pixel 		= 0xffafe9af;

		WindowAttributes.event_mask 			= StructureNotifyMask | KeyPressMask | KeyReleaseMask | PointerMotionMask;

		this->mainWindow 						= XCreateWindow( this->mainDisplay, RootWindow, 
																WindowX, WindowY, WindowWidth, WindowHeight,
																BorderWidth, WindowDepth, WindowClass, WindowVisual,
																AttributeValueMask, &WindowAttributes);

		XStoreName( this->mainDisplay, this->mainWindow, "Opengl: Fixed function pipeline" );

		glXMakeCurrent( this->mainDisplay, this->mainWindow, OpenGLContext );

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

		Atom WM_DELETE_WINDOW 			= XInternAtom( this->mainDisplay, "WM_DELETE_WINDOW", False );

		if( !XSetWMProtocols( this->mainDisplay, this->mainWindow, &WM_DELETE_WINDOW, 1) ) {

		    printf( "Couldn't register WM_DELETE_WINDOW\n" );

		}

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

		this->createShaders();


		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();

		    }
		}

	}

	createShaders() {

		const char* vertex_shader =
		"#version 400\n"
		"in vec3 vp;"
		"void main() {"
		"  gl_Position = vec4(vp, 1.0);"
		"}";

		const char* fragment_shader =
		"#version 400\n"
		"out vec4 frag_colour;"
		"void main() {"
		"  frag_colour = vec4(0.5, 0.0, 0.5, 1.0);"
		"}";

		GLuint vs = glCreateShader(GL_VERTEX_SHADER);

		glShaderSource(vs, 1, &vertex_shader, NULL);
		glCompileShader(vs);


		GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
		glShaderSource(fs, 1, &fragment_shader, NULL);
		glCompileShader(fs);
	}

	render() {

		this->clearColor( 0.0, 1.0, 0.6, 1.0 );

		this->clear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

		this->begin( GL_TRIANGLES );

			this->color3f(1.0, 0.0, 0.0);
			this->vertex2f(0, 0.9);

			this->color3f(0.0, 1.0, 0.0);
			this->vertex2f(0.9, -0.9);

			this->color3f(1.0, 1.0, 1.0);
			this->vertex2f(-0.9, -0.9);

		this->end();

		this->flush();

	}

	vertex2f( float x, float y ) {

		glVertex2f( x, y );

	}

	color3f( float r, float g, float b ) {

		glColor3f( r, g, b );

	}

	clear( GLbitfield mask ) {

		 glClear( mask );

	}

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

		glClearColor( r, g, b, a );

	}

	begin( GLenum mode ) {

		glBegin( mode );

	}

	end() {

		glEnd();

	}

	flush() {

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

	}

}




