#include "ext.hpp"

#define _INIT_FBO 
#define _INIT_GLSL
#define _INIT_VBO


void Ext::init()
{

	// Check if renderer is ati card or not..
	
	
	char buf[50];
	sprintf(buf, "%s", glGetString(GL_VENDOR));
	dmsMsg("Your graphics cards vendor is %s\n", buf);
	dmsMsg("Renderer %s\n", glGetString(GL_RENDERER));
	dmsMsg("Version %s\n", glGetString(GL_VERSION));

	initialized=true;
	
	glActiveTextureARB = (PFNGLCLIENTACTIVETEXTUREARBPROC)wglGetProcAddress("glActiveTextureARB");
	glMultiTexCoord2fARB = (PFNGLMULTITEXCOORD2FARBPROC)wglGetProcAddress ("glMultiTexCoord2fARB");

    if(!glActiveTextureARB || !glMultiTexCoord2fARB)
    {
        MessageBox(dmsGetHWND(),
              "Some needed OpenGL extensions could not be found.\nPlease update your video card drivers!\n\n[ext. funcs:glActiveTextureARB or glMultiTexCoord2fARB]",
              "ERROR",MB_TOPMOST|MB_OK|MB_ICONEXCLAMATION);
        exit(-1);
    }


	// get list of extensions
	char *ext = (char*)glGetString( GL_EXTENSIONS );



#ifdef _INIT_VBO

	if( strstr( ext, "GL_ARB_vertex_buffer_object" ) == NULL )
	{
		MessageBox(
			dmsGetHWND(),
			//"Your graphics card doesn't support the needed extensions.\n(GL_ARB_vertex_buffer_object extension was not found)",
			"Your graphics card didn't support framebufferobjects.\nTry updating your video card drivers \n(EXT_framebuffer_object extension was not found)",
			"ERROR",
			MB_TOPMOST|MB_OK|MB_ICONEXCLAMATION);
		exit(-1);
	}
	else
	{
		// Get Pointers To The GL Functions
		glGenBuffersARB = (PFNGLGENBUFFERSARBPROC) wglGetProcAddress("glGenBuffersARB");
		glBindBufferARB = (PFNGLBINDBUFFERARBPROC) wglGetProcAddress("glBindBufferARB");
		glBufferDataARB = (PFNGLBUFFERDATAARBPROC) wglGetProcAddress("glBufferDataARB");
		glDeleteBuffersARB = (PFNGLDELETEBUFFERSARBPROC) wglGetProcAddress("glDeleteBuffersARB");

        if( !glGenBuffersARB || !glBufferDataARB || !glDeleteBuffersARB || !glBindBufferARB )
        {
              MessageBox(dmsGetHWND(),
                   "Your graphics card doesn't support framebufferobjects.\nTry updating your video card drivers \n\n(not all EXT_framebuffer_object functions could be fetched)",
                   "ERROR",MB_TOPMOST|MB_OK|MB_ICONEXCLAMATION);
              exit(-1);
        }
	
	}

#endif

#ifdef _INIT_FBO

	//
	// EXT_framebuffer_object
	//

	if( strstr( ext, "EXT_framebuffer_object" ) == NULL )
	{
		MessageBox(dmsGetHWND(),
			"Your graphics card doesn't support framebufferobjects.\nTry updating your video card drivers \n(EXT_framebuffer_object extension was not found)","ERROR",
			MB_TOPMOST|MB_OK|MB_ICONEXCLAMATION);
		exit(-1);
	}
	else
	{
		glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC)wglGetProcAddress("glIsRenderbufferEXT");
		glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)wglGetProcAddress("glBindRenderbufferEXT");
		glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)wglGetProcAddress("glDeleteRenderbuffersEXT");
		glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)wglGetProcAddress("glGenRenderbuffersEXT");
		glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)wglGetProcAddress("glRenderbufferStorageEXT");
		glGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)wglGetProcAddress("glGetRenderbufferParameterivEXT");
		glIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC)wglGetProcAddress("glIsFramebufferEXT");
		glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)wglGetProcAddress("glBindFramebufferEXT");
		glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)wglGetProcAddress("glDeleteFramebuffersEXT");
		glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)wglGetProcAddress("glGenFramebuffersEXT");
		glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)wglGetProcAddress("glCheckFramebufferStatusEXT");
		glFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)wglGetProcAddress("glFramebufferTexture1DEXT");
		glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)wglGetProcAddress("glFramebufferTexture2DEXT");
		glFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)wglGetProcAddress("glFramebufferTexture3DEXT");
		glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)wglGetProcAddress("glFramebufferRenderbufferEXT");
		glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)wglGetProcAddress("glGetFramebufferAttachmentParameterivEXT");
		glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC)wglGetProcAddress("glGenerateMipmapEXT");

		if( !glIsRenderbufferEXT || !glBindRenderbufferEXT || !glDeleteRenderbuffersEXT || 
			!glGenRenderbuffersEXT || !glRenderbufferStorageEXT || !glGetRenderbufferParameterivEXT || 
			!glIsFramebufferEXT || !glBindFramebufferEXT || !glDeleteFramebuffersEXT || 
			!glGenFramebuffersEXT || !glCheckFramebufferStatusEXT || !glFramebufferTexture1DEXT || 
			!glFramebufferTexture2DEXT || !glFramebufferTexture3DEXT || !glFramebufferRenderbufferEXT||  
			!glGetFramebufferAttachmentParameterivEXT || !glGenerateMipmapEXT )
		{
			MessageBox(dmsGetHWND(),
				//"Could not get FBO working.\nOne or more EXT_framebuffer_object functions were not found.",
				"Your graphics card doesn't support framebufferobjects.\nTry updating your video card drivers \n(not all EXT_framebuffer_object functions could be fetched)",
				"ERROR",MB_TOPMOST|MB_OK|MB_ICONEXCLAMATION);
			exit(-1);
		}
    }


	// Käytetään ruudun taustana aina 800x600 tekstuuria yksinkertaisuuden vuoksi
    screenWidth = 800;
    screenHeight = 600;

	smallW = 400;
	smallH = 300;

	glGenFramebuffersEXT(1, &this->frameBufferTexture1024);
	glGenFramebuffersEXT(1, &this->frameBufferTexture512);
	glGenFramebuffersEXT(1, &this->frameBufferTexture256);
	glGenFramebuffersEXT(1, &this->frameBufferTexture128);

//	glGenFramebuffersEXT(1, &this->frameBufferScreen);
//	glGenFramebuffersEXT(1, &this->frameBufferSmallScreen);

	glGenRenderbuffersEXT(1, &this->depthRenderBufferTexture1024);
	glGenRenderbuffersEXT(1, &this->depthRenderBufferTexture512);
	glGenRenderbuffersEXT(1, &this->depthRenderBufferTexture256);
	glGenRenderbuffersEXT(1, &this->depthRenderBufferTexture128);

	// *****************************
	// Initialize depth render buffer
	// *****************************

	  glGenFramebuffersEXT (1, &depthFBO);

	  // initialize color texture
	  glGenTextures(1, &depthColTex);
	  glBindTexture(GL_TEXTURE_2D, depthColTex);
	  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  	  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  	  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  	  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  	  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
	  glBindTexture(GL_TEXTURE_2D, 0);

	  logFBOErrors("init depthCol");
	
	
	  glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, depthFBO);

		  // Bind color buffer
		  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,	GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D, depthColTex, 0);
		  logFBOErrors("init depth FBO - attach color");

		  GLuint depths[3] = { GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32 };


		  // Create depth texture [Find a version that works on this manufacturer
		  for (int t = 0; t < 3; t++)
		  {

			  // Create depth texture 
			  glGenTextures(1, &depthTex);
			  glBindTexture(GL_TEXTURE_2D,	 depthTex);
			  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
			  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
			  glTexImage2D(GL_TEXTURE_2D, 0, depths[t], 1024, 1024, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);	
			  glBindTexture(GL_TEXTURE_2D, 0);

			  glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depthTex, 0);
			  


	 		  if(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT)
			    break;

			glDeleteTextures(1, &depthTex);
		  }


		  		

		  if (t == 3)
		  {
			dmsMsg("\nFAILED: to find suitable depth texture \n");
			MessageBox(dmsGetHWND(),"Depth texture was not initialized!\n\nDepth related effects will not function properly.",
			"ERROR",MB_TOPMOST|MB_OK|MB_ICONEXCLAMATION);
			logFBOErrors("init depthTex");
		  }
		  else
		  {
			dmsMsg("Debug: Using depth t=%d  (%d) texture\n", t, depths[t]);
			glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
		  }


		  logFBOErrors("init depth FBO - attach depth");
		  
  
	  glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
	 

/**/
  // *****************************


//	glGenRenderbuffersEXT(1, &this->depthRenderBufferScreen);
//	glGenRenderbuffersEXT(1, &this->depthRenderBufferSmallScreen);

	// Initialize the render-buffer for usage as a depth buffer.
	// We don't really need this to render things into the frame-buffer object,
	// but without it the geometry will not be sorted properly.
	glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, depthRenderBufferTexture1024);
	glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, 1024, 1024);
	
	glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, depthRenderBufferTexture512);
	glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, 512, 512);
	
	glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, depthRenderBufferTexture256);
	glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, 256, 256);

	glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, depthRenderBufferTexture128);
	glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, 128, 128);

//	glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, depthRenderBufferScreen);
//	glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, screenWidth, screenHeight);

//	glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, depthRenderBufferSmallScreen);
//	glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, smallW, smallH);

	GLenum status = glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );

	switch( status )
	{
		case GL_FRAMEBUFFER_COMPLETE_EXT:
			//MessageBox(dmsGetHWND(),"GL_FRAMEBUFFER_COMPLETE_EXT!","SUCCESS",MB_TOPMOST| MB_OK|MB_ICONEXCLAMATION);
			break;
		case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
			MessageBox(dmsGetHWND(),"GL_FRAMEBUFFER_UNSUPPORTED_EXT! \n\nYour GFX cards current drivers do not support\nFrameBufferObjects extension. Please, upgrade your graphics card drivers.","ERROR",MB_TOPMOST| MB_OK|MB_ICONEXCLAMATION);
			//"Your graphics card didn't support framebufferobjects.\nTry updating your video card drivers \n(EXT_framebuffer_object extension was not found)",
			exit(0);
			break;
		default:
			exit(0);
	}


	this->createTexture(this->glowTexture1024ID, 1024,1024);
	this->createTexture(this->glowTexture1024ID2, 1024,1024);
	this->createTexture(this->glowTexture512ID, 512,512);
	this->createTexture(this->glowTexture512ID2, 512,512);
	this->createTexture(this->glowTexture256ID, 256,256);
	this->createTexture(this->glowTexture256ID2, 256,256);
	this->createTexture(this->glowTexture128ID, 128,128);
	this->createTexture(this->glowTexture128ID2, 128,128);

	this->createTexture(this->motionBlur1024, 1024,1024);


	// Disable framebuffer object
	glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );

#endif

#ifdef _INIT_GLSL

	//------------------------------------------
	// Shaders	
	char *str = (char *)glGetString(GL_EXTENSIONS);

	//add every OpenGL extension the program will need
	const char* neededExtensions[64] = {
		"GL_ARB_fragment_shader",
		"GL_ARB_fragment_program",
		"GL_ARB_shading_language_100",
		"GL_ARB_vertex_shader",
		"GL_ARB_shader_objects",
		"GL_ARB_shadow",
		"GL_ARB_depth_texture"
	};

	// Uncomment this for extension listing
	// MessageBox(dmsGetHWND(), str, "Error!", MB_OK);

	for(int i = 0; neededExtensions[i] != NULL; i++)
	{
		if (strstr(str, (char *)neededExtensions[i])==NULL)
		{
			MessageBox(dmsGetHWND(), 
				"Your graphics card doesn't support the needed extensions.\nNo required OpenGL extensions can be used. \n\n[GL_ARB_fragment_shader, GL_ARB_fragment_program, GL_ARB_shading_language_100,\nGL_ARB_vertex_shader, GL_ARB_shader_objects, GL_ARB_shadow, GL_ARB_depth_texture]", 
				"Error!",
				MB_TOPMOST | MB_ICONERROR | MB_OK);
			exit(0);
		}
	}

	glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) wglGetProcAddress("glCreateProgramObjectARB");
	glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) wglGetProcAddress("glDeleteObjectARB");
	glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) wglGetProcAddress("glCreateShaderObjectARB");
	glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) wglGetProcAddress("glShaderSourceARB");
	glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) wglGetProcAddress("glCompileShaderARB");
	glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) wglGetProcAddress("glGetObjectParameterivARB");
	glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) wglGetProcAddress("glAttachObjectARB");
	glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) wglGetProcAddress("glGetInfoLogARB");
	glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) wglGetProcAddress("glLinkProgramARB");
	glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) wglGetProcAddress("glUseProgramObjectARB");
	glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) wglGetProcAddress("glGetUniformLocationARB");
	glDeleteProgram = (PFNGLDELETEPROGRAMPROC) wglGetProcAddress("glDeleteProgram");
	glDeleteShader = (PFNGLDELETESHADERPROC) wglGetProcAddress("glDeleteShader");
	glIsProgram = (PFNGLISPROGRAMPROC) wglGetProcAddress("glIsProgram");
	glIsShader = (PFNGLISSHADERPROC) wglGetProcAddress("glIsShader");
	glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) wglGetProcAddress("glGetProgramInfoLog");
	glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) wglGetProcAddress("glGetShaderInfoLog");

	glUniform4fARB = (PFNGLUNIFORM4FARBPROC)wglGetProcAddress("glUniform4f");
	glUniform3fARB = (PFNGLUNIFORM3FARBPROC)wglGetProcAddress("glUniform3f");
	glUniform1fARB = (PFNGLUNIFORM1FARBPROC)wglGetProcAddress("glUniform1f");
	glUniform1iARB = (PFNGLUNIFORM1IARBPROC)wglGetProcAddress("glUniform1i");
	glGetUniformfvARB =(PFNGLGETUNIFORMFVPROC) wglGetProcAddress("glGetUniformfvARB");
	glGetUniformivARB =(PFNGLGETUNIFORMIVPROC) wglGetProcAddress("glGetUniformivARB");
	glUniform1i =(PFNGLUNIFORM1IARBPROC) wglGetProcAddress("glUniform1iARB");
	glUniform1i =(PFNGLUNIFORM1IPROC) wglGetProcAddress("glUniform1i");
	glUniform2i =(PFNGLUNIFORM2IPROC) wglGetProcAddress("glUniform2i");
	glUniform3i =(PFNGLUNIFORM3IPROC) wglGetProcAddress("glUniform3i");
	glUniform4i =(PFNGLUNIFORM4IPROC) wglGetProcAddress("glUniform4i");
	glUniform1fv =(PFNGLUNIFORM1FVPROC) wglGetProcAddress("glUniform1fv");
	glUniform2fv =(PFNGLUNIFORM2FVPROC) wglGetProcAddress("glUniform2fv");
	glUniform3fv =(PFNGLUNIFORM3FVPROC) wglGetProcAddress("glUniform3fv");
	glUniform4fv =(PFNGLUNIFORM4FVPROC) wglGetProcAddress("glUniform4fv");
	glUniform1iv =(PFNGLUNIFORM1IVPROC) wglGetProcAddress("glUniform1iv");
	glUniform2iv =(PFNGLUNIFORM2IVPROC) wglGetProcAddress("glUniform2iv");
	glUniform3iv =(PFNGLUNIFORM3IVPROC) wglGetProcAddress("glUniform3iv");
	glUniform4iv =(PFNGLUNIFORM4IVPROC) wglGetProcAddress("glUniform4iv");
	glUniformMatrix2fv =(PFNGLUNIFORMMATRIX2FVPROC) wglGetProcAddress("glUniformMatrix2fv");
	glUniformMatrix3fv =(PFNGLUNIFORMMATRIX3FVPROC) wglGetProcAddress("glUniformMatrix3fv");
	glUniformMatrix4fv =(PFNGLUNIFORMMATRIX4FVPROC) wglGetProcAddress("glUniformMatrix4fv");
	glValidateProgram =(PFNGLVALIDATEPROGRAMPROC) wglGetProcAddress("glValidateProgram");
	glVertexAttrib1d =(PFNGLVERTEXATTRIB1DPROC) wglGetProcAddress("glVertexAttrib1d");
	glVertexAttrib1dv =(PFNGLVERTEXATTRIB1DVPROC) wglGetProcAddress("glVertexAttrib1dv");
	glVertexAttrib1f =(PFNGLVERTEXATTRIB1FPROC) wglGetProcAddress("glVertexAttrib1f");
	glVertexAttrib1fv =(PFNGLVERTEXATTRIB1FVPROC) wglGetProcAddress("glVertexAttrib1fv");
	glVertexAttrib1s =(PFNGLVERTEXATTRIB1SPROC) wglGetProcAddress("glVertexAttrib1s");
	glVertexAttrib1sv =(PFNGLVERTEXATTRIB1SVPROC) wglGetProcAddress("glVertexAttrib1sv");
	glVertexAttrib2d =(PFNGLVERTEXATTRIB2DPROC) wglGetProcAddress("glVertexAttrib2d");
	glVertexAttrib2dv =(PFNGLVERTEXATTRIB2DVPROC) wglGetProcAddress("glVertexAttrib2dv");
	glVertexAttrib2f =(PFNGLVERTEXATTRIB2FPROC) wglGetProcAddress("glVertexAttrib2f");
	glVertexAttrib2fv =(PFNGLVERTEXATTRIB2FVPROC) wglGetProcAddress("glVertexAttrib2fv");
	glVertexAttrib2s =(PFNGLVERTEXATTRIB2SPROC) wglGetProcAddress("glVertexAttrib2s");
	glVertexAttrib2sv =(PFNGLVERTEXATTRIB2SVPROC) wglGetProcAddress("glVertexAttrib2sv");
	glVertexAttrib3d =(PFNGLVERTEXATTRIB3DPROC) wglGetProcAddress("glVertexAttrib3d");
	glVertexAttrib3dv =(PFNGLVERTEXATTRIB3DVPROC) wglGetProcAddress("glVertexAttrib3dv");
	glVertexAttrib3f =(PFNGLVERTEXATTRIB3FPROC) wglGetProcAddress("glVertexAttrib3f");
	glVertexAttrib3fv =(PFNGLVERTEXATTRIB3FVPROC) wglGetProcAddress("glVertexAttrib3fv");
	glVertexAttrib3s =(PFNGLVERTEXATTRIB3SPROC) wglGetProcAddress("glVertexAttrib3s");
	glVertexAttrib3sv =(PFNGLVERTEXATTRIB3SVPROC) wglGetProcAddress("glVertexAttrib3sv");
	glVertexAttrib4Nbv =(PFNGLVERTEXATTRIB4NBVPROC) wglGetProcAddress("glVertexAttrib4Nbv");
	glVertexAttrib4Niv =(PFNGLVERTEXATTRIB4NIVPROC) wglGetProcAddress("glVertexAttrib4Niv");
	glVertexAttrib4Nsv =(PFNGLVERTEXATTRIB4NSVPROC) wglGetProcAddress("glVertexAttrib4Nsv");
	glVertexAttrib4Nub =(PFNGLVERTEXATTRIB4NUBPROC) wglGetProcAddress("glVertexAttrib4Nub");
	glVertexAttrib4Nubv =(PFNGLVERTEXATTRIB4NUBVPROC) wglGetProcAddress("glVertexAttrib4Nubv");
	glVertexAttrib4Nuiv =(PFNGLVERTEXATTRIB4NUIVPROC) wglGetProcAddress("glVertexAttrib4Nuiv");
	glVertexAttrib4Nusv =(PFNGLVERTEXATTRIB4NUSVPROC) wglGetProcAddress("glVertexAttrib4Nusv");
	glVertexAttrib4bv =(PFNGLVERTEXATTRIB4BVPROC) wglGetProcAddress("glVertexAttrib4bv");
	glVertexAttrib4d =(PFNGLVERTEXATTRIB4DPROC) wglGetProcAddress("glVertexAttrib4d");
	glVertexAttrib4dv =(PFNGLVERTEXATTRIB4DVPROC) wglGetProcAddress("glVertexAttrib4dv");
	glVertexAttrib4f =(PFNGLVERTEXATTRIB4FPROC) wglGetProcAddress("glVertexAttrib4f");
	glVertexAttrib4fv =(PFNGLVERTEXATTRIB4FVPROC) wglGetProcAddress("glVertexAttrib4fv");
	glVertexAttrib4iv =(PFNGLVERTEXATTRIB4IVPROC) wglGetProcAddress("glVertexAttrib4iv");
/*
	// Do not uncomment - these cannot be fetched for some strange reason.

	glVertexAttrib4s =(PFNGLVERTEXATTRIB4SPROC) wglGetProcAddress("glVertexAttrib4s");
	glVertexAttrib4sv =(PFNGLVERTEXATTRIB4SVPROC) wglGetProcAddress("glVertexAttrib4sv");
	glVertexAttrib4ubv =(PFNGLVERTEXATTRIB4UBVPROC) wglGetProcAddress("glVertexAttrib4ubv");
	glVertexAttrib4uiv =(PFNGLVERTEXATTRIB4UIVPROC) wglGetProcAddress("glVertexAttrib4uiv");
	glVertexAttrib4us =(PFNGLVERTEXATTRIB4USVPROC) wglGetProcAddress("glVertexAttrib4us");
*/
	glVertexAttribPointer =(PFNGLVERTEXATTRIBPOINTERPROC) wglGetProcAddress("glVertexAttribPointer");

            // Check that we found all the extensions

        if( !glCreateProgramObjectARB || !glDeleteObjectARB || !glCreateShaderObjectARB || !glShaderSourceARB || !glCompileShaderARB ||
            !glGetObjectParameterivARB || !glAttachObjectARB || !glGetInfoLogARB || !glLinkProgramARB || !glUseProgramObjectARB ||
            !glGetUniformLocationARB || !glDeleteProgram || !glDeleteShader || !glIsProgram || !glIsShader || !glGetProgramInfoLog ||
            !glGetShaderInfoLog || !glUniform4fARB || !glUniform3fARB || !glUniform1fARB || !glUniform1iARB || !glGetUniformfvARB ||
            !glGetUniformivARB || !glUniform1i || !glUniform1i || !glUniform2i || !glUniform3i || !glUniform4i || !glUniform1fv ||
            !glUniform2fv || !glUniform3fv || !glUniform4fv || !glUniform1iv || !glUniform2iv || !glUniform3iv || !glUniform4iv ||
            !glUniformMatrix2fv || !glUniformMatrix3fv || !glUniformMatrix4fv || !glValidateProgram || !glVertexAttrib1d ||
            !glVertexAttrib1dv || !glVertexAttrib1f || !glVertexAttrib1fv || !glVertexAttrib1s || !glVertexAttrib1sv ||
            !glVertexAttrib2d || !glVertexAttrib2dv || !glVertexAttrib2f || !glVertexAttrib2fv || !glVertexAttrib2s ||
            !glVertexAttrib2sv || !glVertexAttrib3d || !glVertexAttrib3dv || !glVertexAttrib3f || !glVertexAttrib3fv ||
            !glVertexAttrib3s || !glVertexAttrib3sv || !glVertexAttrib4Nbv || !glVertexAttrib4Niv || !glVertexAttrib4Nsv ||
            !glVertexAttrib4Nub || !glVertexAttrib4Nubv || !glVertexAttrib4Nuiv || !glVertexAttrib4Nusv || !glVertexAttrib4bv ||
            !glVertexAttrib4d || !glVertexAttrib4dv || !glVertexAttrib4f || !glVertexAttrib4fv || !glVertexAttrib4iv ||
            //!glVertexAttrib4s || !glVertexAttrib4sv || !glVertexAttrib4ubv || !glVertexAttrib4uiv || !glVertexAttrib4us || 
			!glVertexAttribPointer
         )
		{
                MessageBox(dmsGetHWND(),
                             "Some needed OpenGL extensions functions could not be accessed.\nPlease update your video card drivers!\n\n[Fragment & Vertex shaders functions]",
                            "ERROR",MB_TOPMOST|MB_OK|MB_ICONEXCLAMATION);
                exit(-1);
		}

#endif
}

void Ext::deinit() {

#ifdef _INIT_FBO

	if(initialized==true) {

		// Free textures
		glDeleteTextures (1, &glowTexture1024ID);
		glDeleteTextures (1, &glowTexture1024ID2);
		glDeleteTextures (1, &glowTexture512ID);
		glDeleteTextures (1, &glowTexture512ID2);
		glDeleteTextures (1, &glowTexture256ID);
		glDeleteTextures (1, &glowTexture256ID2);
		glDeleteTextures (1, &glowTexture128ID);
		glDeleteTextures (1, &glowTexture128ID2);
		
		glDeleteTextures (1, &motionBlur1024);

//		glDeleteTextures (1, &smallScreenTextureID);
//		glDeleteTextures (1, &smallScreenTextureID2);
//		glDeleteTextures (1, &screenTextureID);


		// Free framebuffers
		glDeleteFramebuffersEXT(1, &frameBufferTexture1024);
		glDeleteFramebuffersEXT(1, &frameBufferTexture512);
		glDeleteFramebuffersEXT(1, &frameBufferTexture256);
		glDeleteFramebuffersEXT(1, &frameBufferTexture128);
//		glDeleteFramebuffersEXT(1, &frameBufferScreen);
//		glDeleteFramebuffersEXT(1, &frameBufferSmallScreen);

		// Free renderbuffers
		glDeleteRenderbuffersEXT(1, &depthRenderBufferTexture1024);
		glDeleteRenderbuffersEXT(1, &depthRenderBufferTexture512);
		glDeleteRenderbuffersEXT(1, &depthRenderBufferTexture256);
		glDeleteRenderbuffersEXT(1, &depthRenderBufferTexture128);
//		glDeleteRenderbuffersEXT(1, &depthRenderBufferScreen);
//		glDeleteRenderbuffersEXT(1, &depthRenderBufferSmallScreen);
		
	}
#endif
}

void Ext::createDepthTexture(GLuint &i, int w, int h) {

	GLuint texID;

  glGenTextures(1, &texID);
  glBindTexture(GL_TEXTURE_2D, texID);

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

  glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, w, h, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
  logFBOErrors("init1");

	i = texID;

}

void Ext::createTexture(GLuint &i, int w, int h) {

	GLuint texID;
	glGenTextures (1, &texID);
	glBindTexture(GL_TEXTURE_2D,texID);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	//glTexImage2D(GL_TEXTURE_2D, 0, 4, w, h, 0, GL_RGB, GL_FLOAT, 0);
	// Why did i have floats here before?
	//glTexImage2D(GL_TEXTURE_2D, 0, 4, w, h, 0, GL_RGB,  GL_UNSIGNED_BYTE, 0);
	glTexImage2D(GL_TEXTURE_2D, 0, 4, w, h, 0, GL_RGBA,  GL_UNSIGNED_BYTE, 0);
	i = texID;
}

void Ext::createTextureRECT(GLuint &i, int w, int h) {

	GLuint texID;
	glGenTextures (1, &texID);
	glBindTexture(GL_TEXTURE_RECTANGLE_ARB,texID);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
	//glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, w, h, 0, GL_RGB, GL_FLOAT, 0);
	glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, w, h, 0, GL_RGBA, GL_FLOAT, 0);
	i = texID;
}

void Ext::bindDepthFBO()
{

	glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, depthFBO);

	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, depthTex, 0);
	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D, depthColTex, 0);

	logFBOErrors("bindDepthTextureFBO1024");
	glViewport( 0, 0, 1024, 1024);
}


void Ext::bindTextureFBO1024(GLuint textureID)
{
    //"ruutu" osoittamaan framebufferobjektiin
	glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, frameBufferTexture1024);
	
    //glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, g_depthRenderBuffer ); //oli esimerkkisorsassa kommentoitu(?)
    
    //siihen kiinni tekstuuri (rendaa jotain -> menee tekstuuriin) 
	glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 
                                textureID, 0 );
    //renderbufferi kiinni (tarvitaan, se "ruutu" johon extensio rendaa ja joka sitten on kiinni 
    //framebufferissa)
	glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, 
                                GL_RENDERBUFFER_EXT, depthRenderBufferTexture1024);

	logFBOErrors("bindTextureFBO1024");

	glViewport( 0, 0, 1024, 1024);

}

void Ext::bindTextureFBO512(GLuint textureID)
{
    //"ruutu" osoittamaan framebufferobjektiin
	glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, frameBufferTexture512);

    //glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, g_depthRenderBuffer ); //oli esimerkkisorsassa kommentoitu(?)
    
    //siihen kiinni tekstuuri (rendaa jotain -> menee tekstuuriin) 
	glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 
                                textureID, 0 );
    //renderbufferi kiinni (tarvitaan, se "ruutu" johon extensio rendaa ja joka sitten on kiinni 
    //framebufferissa)
	glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, 
                                GL_RENDERBUFFER_EXT, depthRenderBufferTexture512);

	logFBOErrors("bindTextureFBO512");

	glViewport( 0, 0, 512, 512);
}

void Ext::bindTextureFBO256(GLuint textureID)
{
    //"ruutu" osoittamaan framebufferobjektiin
	glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, frameBufferTexture256);

    //glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, g_depthRenderBuffer ); //oli esimerkkisorsassa kommentoitu(?)
    
    //siihen kiinni tekstuuri (rendaa jotain -> menee tekstuuriin) 
	glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 
                                textureID, 0 );
    //renderbufferi kiinni (tarvitaan, se "ruutu" johon extensio rendaa ja joka sitten on kiinni 
    //framebufferissa)
	glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, 
                                GL_RENDERBUFFER_EXT, depthRenderBufferTexture256);

	logFBOErrors("bindTextureFBO256");

	glViewport( 0, 0, 256, 256);
}

void Ext::bindTextureFBO128(GLuint textureID)
{
    //"ruutu" osoittamaan framebufferobjektiin
	glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, frameBufferTexture128);

    //glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, g_depthRenderBuffer ); //oli esimerkkisorsassa kommentoitu(?)
    
    //siihen kiinni tekstuuri (rendaa jotain -> menee tekstuuriin) 
	glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 
                                textureID, 0 );
    //renderbufferi kiinni (tarvitaan, se "ruutu" johon extensio rendaa ja joka sitten on kiinni 
    //framebufferissa)
	glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, 
                                GL_RENDERBUFFER_EXT, depthRenderBufferTexture128);

	logFBOErrors("bindTextureFBO128");

	glViewport( 0, 0, 128, 128);
}
/*
void Ext::bindScreenFBO(GLuint textureID)
{
    //"ruutu" osoittamaan framebufferobjektiin
//	glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, frameBufferScreen);

    //glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, g_depthRenderBuffer ); //oli esimerkkisorsassa kommentoitu(?)
    
    //siihen kiinni tekstuuri (rendaa jotain -> menee tekstuuriin) 
//	glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,  GL_TEXTURE_RECTANGLE_ARB, 
  //                              textureID, 0 );
    //renderbufferi kiinni (tarvitaan, se "ruutu" johon extensio rendaa ja joka sitten on kiinni 
    //framebufferissa)
	//glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, 
//                                GL_RENDERBUFFER_EXT, depthRenderBufferScreen );

//	logFBOErrors("bindScreenFBO");

//	glViewport( 0, 0, screenWidth, screenHeight);
}


/*void Ext::bindSmallScreenFBO(GLuint textureID)
{
    //"ruutu" osoittamaan framebufferobjektiin
	glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, frameBufferSmallScreen);

    //glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, g_depthRenderBuffer ); //oli esimerkkisorsassa kommentoitu(?)
    
    //siihen kiinni tekstuuri (rendaa jotain -> menee tekstuuriin) 
	glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,  GL_TEXTURE_RECTANGLE_ARB, 
                                textureID, 0 );
    //renderbufferi kiinni (tarvitaan, se "ruutu" johon extensio rendaa ja joka sitten on kiinni 
    //framebufferissa)
	glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, 
                                GL_RENDERBUFFER_EXT, depthRenderBufferSmallScreen );

	logFBOErrors("bindSmallScreenFBO");

	glViewport( 0, 0, smallW, smallH);
}
*/
void Ext::unbindFBO()
{
    //nolla lienee varsinainen OpenGL:n rendercontexti
	glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
	// reset viewport
	dmsResetViewport();
}


void Ext::drawTexture(GLuint textureID) {

		// PIIRRÄ KUVA
		dmsPerspective2D(screenWidth, screenHeight);
		glLoadIdentity();
		glDisable(GL_BLEND);
		glDisable(GL_DEPTH_TEST);
		//glColor4f(1,1,1,0.2f);
		glColor3f(1,1,1);
		
		glEnable(GL_TEXTURE_2D);

		glBindTexture(GL_TEXTURE_2D, textureID);

			glBegin(GL_QUADS);
			glTexCoord2i(0, 0);
			glVertex2i(0, 0);
			glTexCoord2i(1, 0);
			glVertex2i(screenWidth, 0);
			glTexCoord2i(1, 1);
			glVertex2i(screenWidth, screenHeight);
			glTexCoord2i(0, 1);
			glVertex2i(0, screenHeight);
			glEnd();

		glDisable(GL_TEXTURE_2D);
		
		dmsPerspective3D();	
		glLoadIdentity();

} 

bool Ext::logFBOErrors() {
	return logFBOErrors("place undefined:");
}

bool Ext::logFBOErrors(char *kohta) {
	
	int status = glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
	switch( status )
	{
		case GL_FRAMEBUFFER_COMPLETE_EXT:
			//MessageBox(dmsGetHWND(),"GL_FRAMEBUFFER_COMPLETE_EXT!","SUCCESS",MB_TOPMOST|MB_OK|MB_ICONEXCLAMATION);
			break;

        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
            dmsMsg("%s: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT - Framebuffer incomplete,incomplete attachment\n",kohta);
            return false;
        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
            dmsMsg("%s: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT - Framebuffer incomplete,missing attachment\n",kohta);
            return false;
        case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
            dmsMsg("%s: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT - Framebuffer incomplete,attached images must have same dimensions\n",kohta);
            return false;
        case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
             dmsMsg("%s: GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT - Framebuffer incomplete,attached images must have same format\n",kohta);
            return false;
        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
            dmsMsg("%s: GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT - Framebuffer incomplete,missing draw buffer\n",kohta);
            return false;
        case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
            dmsMsg("%s: GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT - Framebuffer incomplete,missing read buffer\n",kohta);
            return false;
		case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
			dmsMsg("%s: GL_FRAMEBUFFER_UNSUPPORTED_EXT - Framebuffer not supported\n", kohta);
			char string[250];
			sprintf(string, "GL_FRAMEBUFFER_UNSUPPORTED_EXT! \n\nYour GFX cards current drivers do not support FrameBufferObjects extension. \nPlease, upgrade your graphics card drivers.\nIf newest drivers won't help you need to use other graphics cards.\n\nDebug info: \'%s\'", kohta);
			MessageBox(dmsGetHWND(),string,"ERROR",MB_TOPMOST| MB_OK|MB_ICONEXCLAMATION);
			exit(0);
			break;

		default:
			dmsMsg("%s: UNRESOLVED FRAMEBUFFER ERROR - Check ext loading\n", kohta);
				break;
//			exit(0);
	}
	return true;
}