/**
 * Initialize an OpenGL context so that shaders can be compiled.
 */
static void PlatformInitOpenGL(void*& ContextPtr, void*& PrevContextPtr, int InMajorVersion, int InMinorVersion)
{
	static FPlatformOpenGLContext ShaderCompileContext = {0};

	ContextPtr = (void*)wglGetCurrentDC();
	PrevContextPtr = (void*)wglGetCurrentContext();

	if (ShaderCompileContext.OpenGLContext == NULL && InMajorVersion && InMinorVersion)
	{
		PlatformCreateDummyGLWindow(&ShaderCompileContext);

		// Disable warning C4191: 'type cast' : unsafe conversion from 'PROC' to 'XXX' while getting GL entry points.
		#pragma warning(push)
		#pragma warning(disable:4191)

		if (wglCreateContextAttribsARB == NULL)
		{
			// Create a dummy context so that wglCreateContextAttribsARB can be initialized.
			ShaderCompileContext.OpenGLContext = wglCreateContext(ShaderCompileContext.DeviceContext);
			check(ShaderCompileContext.OpenGLContext);
			PlatformMakeGLContextCurrent(&ShaderCompileContext);
			wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
			check(wglCreateContextAttribsARB);
			wglDeleteContext(ShaderCompileContext.OpenGLContext);
		}

		// Create a context so that remaining GL function pointers can be initialized.
		PlatformCreateOpenGLContextCore(&ShaderCompileContext, InMajorVersion, InMinorVersion, /*InParentContext=*/ NULL);
		check(ShaderCompileContext.OpenGLContext);
		PlatformMakeGLContextCurrent(&ShaderCompileContext);

		if (glCreateShader == NULL)
		{
			// Initialize all entry points.
			#define GET_GL_ENTRYPOINTS(Type,Func) Func = (Type)wglGetProcAddress(#Func);
			ENUM_GL_ENTRYPOINTS(GET_GL_ENTRYPOINTS);

			// Check that all of the entry points have been initialized.
			bool bFoundAllEntryPoints = true;
			#define CHECK_GL_ENTRYPOINTS(Type,Func) if (Func == NULL) { bFoundAllEntryPoints = false; UE_LOG(LogOpenGLShaderCompiler, Warning, TEXT("Failed to find entry point for %s"), TEXT(#Func)); }
			ENUM_GL_ENTRYPOINTS(CHECK_GL_ENTRYPOINTS);
			checkf(bFoundAllEntryPoints, TEXT("Failed to find all OpenGL entry points."));
		}

		// Restore warning C4191.
		#pragma warning(pop)
	}
	PlatformMakeGLContextCurrent(&ShaderCompileContext);
}
/**
 * Loads all OpenGL extensions.  
 * @todo UE4: For now we assume this cannot fail                   
 */
void LoadOpenGLExtensions()
{
#if PLATFORM_WINDOWS
	if( !bOpenGLExtensionsLoaded )
	{
		//@todo UE4: Assumes the video card supports these for now.
		bOpenGLExtensionsLoaded = true;
		glGenBuffers				=(PFNGLGENBUFFERSARBPROC)			wglGetProcAddress("glGenBuffers");
		glBindBuffer				=(PFNGLBINDBUFFERARBPROC)			wglGetProcAddress("glBindBuffer");
		glBufferData				=(PFNGLBUFFERDATAARBPROC)			wglGetProcAddress("glBufferData");
		glDeleteBuffers				=(PFNGLDELETEBUFFERSARBPROC)		wglGetProcAddress("glDeleteBuffers");
		glMapBuffer					=(PFNGLMAPBUFFERARBPROC)			wglGetProcAddress("glMapBuffer");
		glUnmapBuffer				=(PFNGLUNMAPBUFFERARBPROC)			wglGetProcAddress("glUnmapBuffer");
		glDrawRangeElements			=(PFNGLDRAWRANGEELEMENTSPROC)		wglGetProcAddress("glDrawRangeElements");
		glBlendEquation				=(PFNGLBLENDEQUATIONPROC)			wglGetProcAddress("glBlendEquation");
		glActiveTexture				=(PFNGLACTIVETEXTUREARBPROC)		wglGetProcAddress("glActiveTexture");

		glCreateShader				=(PFNGLCREATESHADERPROC)			wglGetProcAddress("glCreateShader");
		glShaderSource				=(PFNGLSHADERSOURCEPROC)			wglGetProcAddress("glShaderSource");
		glCompileShader				=(PFNGLCOMPILESHADERPROC)			wglGetProcAddress("glCompileShader");
		glGetShaderInfoLog			=(PFNGLGETSHADERINFOLOGPROC)		wglGetProcAddress("glGetShaderInfoLog");
		glCreateProgram				=(PFNGLCREATEPROGRAMPROC)			wglGetProcAddress("glCreateProgram");
		glAttachShader				=(PFNGLATTACHSHADERPROC)			wglGetProcAddress("glAttachShader");
		glDetachShader				=(PFNGLDETACHSHADERPROC)			wglGetProcAddress("glDetachShader");
		glLinkProgram				=(PFNGLLINKPROGRAMPROC)				wglGetProcAddress("glLinkProgram");
		glGetProgramInfoLog			=(PFNGLGETPROGRAMINFOLOGPROC)		wglGetProcAddress("glGetProgramInfoLog");
		glUseProgram				=(PFNGLUSEPROGRAMPROC)				wglGetProcAddress("glUseProgram");
		glDeleteShader				=(PFNGLDELETESHADERPROC)			wglGetProcAddress("glDeleteShader");
		glDeleteProgram				=(PFNGLDELETEPROGRAMPROC)			wglGetProcAddress("glDeleteProgram");
		glGetShaderiv				=(PFNGLGETPROGRAMIVPROC)			wglGetProcAddress("glGetShaderiv");
		glGetProgramiv				=(PFNGLGETPROGRAMIVPROC)			wglGetProcAddress("glGetProgramiv");
		glGetUniformLocation		=(PFNGLGETUNIFORMLOCATIONPROC)		wglGetProcAddress("glGetUniformLocation");
		glUniform1f					=(PFNGLUNIFORM1FPROC)				wglGetProcAddress("glUniform1f");
		glUniform2f					=(PFNGLUNIFORM2FPROC)				wglGetProcAddress("glUniform2f");
		glUniform3f					=(PFNGLUNIFORM3FPROC)				wglGetProcAddress("glUniform3f");
		glUniform3fv				=(PFNGLUNIFORM3FVPROC)				wglGetProcAddress("glUniform3fv");
		glUniform4f					=(PFNGLUNIFORM4FPROC)				wglGetProcAddress("glUniform4f");
		glUniform4fv				=(PFNGLUNIFORM4FVPROC)				wglGetProcAddress("glUniform4fv");
		glUniform1i					=(PFNGLUNIFORM1IPROC)				wglGetProcAddress("glUniform1i");
		glUniformMatrix4fv			=(PFNGLUNIFORMMATRIX4FVPROC)		wglGetProcAddress("glUniformMatrix4fv");
		glVertexAttribPointer       =(PFNGLVERTEXATTRIBPOINTERPROC)		wglGetProcAddress("glVertexAttribPointer");
		glBindAttribLocation		=(PFNGLBINDATTRIBLOCATIONPROC)		wglGetProcAddress("glBindAttribLocation");	
		glEnableVertexAttribArray	=(PFNGLENABLEVERTEXATTRIBARRAYPROC)	wglGetProcAddress("glEnableVertexAttribArray");
		glDisableVertexAttribArray	=(PFNGLDISABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glDisableVertexAttribArray");
		glGetActiveAttrib			=(PFNGLGETACTIVEATTRIBPROC)			wglGetProcAddress("glGetActiveAttrib");
		glGetActiveUniform			=(PFNGLGETACTIVEUNIFORMPROC)		wglGetProcAddress("glGetActiveUniform");
		glGetAttachedShaders		=(PFNGLGETATTACHEDSHADERSPROC)		wglGetProcAddress("glGetAttachedShaders");
		glGetAttribLocation			=(PFNGLGETATTRIBLOCATIONPROC)		wglGetProcAddress("glGetAttribLocation");
	}
#elif PLATFORM_LINUX
#define GET_GL_ENTRYPOINTS(Type,Func) { Func = reinterpret_cast<Type>(SDL_GL_GetProcAddress(#Func)); if (NULL == Func) { UE_LOG(LogInit, Fatal, TEXT("Failed to find entry point for %s"), TEXT(#Func)); }}
	ENUM_GL_ENTRYPOINTS(GET_GL_ENTRYPOINTS);
#endif
	// If extensions are needed for your platform add support for them here 
}
bool PlatformInitOpenGL()
{
	static bool bInitialized = false;
	static bool bOpenGLSupported = false;
	if (!bInitialized)
	{
		// Disable warning C4191: 'type cast' : unsafe conversion from 'PROC' to 'XXX' while getting GL entry points.
		#pragma warning(push)
		#pragma warning(disable:4191)

		// Create a dummy context so that wglCreateContextAttribsARB can be initialized.
		FPlatformOpenGLContext DummyContext;
		PlatformCreateDummyGLWindow(&DummyContext);
		DummyContext.OpenGLContext = wglCreateContext(DummyContext.DeviceContext);
		check(DummyContext.OpenGLContext);
		ContextMakeCurrent(DummyContext.DeviceContext, DummyContext.OpenGLContext);
		wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
		if (wglCreateContextAttribsARB)
		{
			int MajorVersion = 0;
			int MinorVersion = 0;

			ContextMakeCurrent(NULL,NULL);
			wglDeleteContext(DummyContext.OpenGLContext);
			PlatformOpenGLVersionFromCommandLine(MajorVersion, MinorVersion);
			PlatformCreateOpenGLContextCore(&DummyContext, MajorVersion, MinorVersion, NULL);	
			if (DummyContext.OpenGLContext)
			{
				bOpenGLSupported = true;
				ContextMakeCurrent(DummyContext.DeviceContext, DummyContext.OpenGLContext);
			}
			else
			{
				UE_LOG(LogRHI,Error,TEXT("OpenGL %d.%d not supported by driver"),MajorVersion,MinorVersion);
			}
		}

		if (bOpenGLSupported)
		{
			// Retrieve the OpenGL DLL.
			void* OpenGLDLL = FPlatformProcess::GetDllHandle(TEXT("opengl32.dll"));
			if (!OpenGLDLL)
			{
				UE_LOG(LogRHI,Fatal,TEXT("Couldn't load opengl32.dll"));
			}

			// Initialize entry points required by Unreal from opengl32.dll
			#define GET_GL_ENTRYPOINTS_DLL(Type,Func) Func = (Type)FPlatformProcess::GetDllExport(OpenGLDLL,TEXT(#Func));
			ENUM_GL_ENTRYPOINTS_DLL(GET_GL_ENTRYPOINTS_DLL);

			// Release the OpenGL DLL.
			FPlatformProcess::FreeDllHandle(OpenGLDLL);

			// Initialize all entry points required by Unreal.
			#define GET_GL_ENTRYPOINTS(Type,Func) Func = (Type)wglGetProcAddress(#Func);
			ENUM_GL_ENTRYPOINTS(GET_GL_ENTRYPOINTS);
			ENUM_GL_ENTRYPOINTS_OPTIONAL(GET_GL_ENTRYPOINTS);

			// Restore warning C4191.
			#pragma warning(pop)

			// Check that all of the entry points have been initialized.
			bool bFoundAllEntryPoints = true;
			#define CHECK_GL_ENTRYPOINTS(Type,Func) if (Func == NULL) { bFoundAllEntryPoints = false; UE_LOG(LogRHI, Warning, TEXT("Failed to find entry point for %s"), TEXT(#Func)); }
			ENUM_GL_ENTRYPOINTS_DLL(CHECK_GL_ENTRYPOINTS);
			ENUM_GL_ENTRYPOINTS(CHECK_GL_ENTRYPOINTS);
			checkf(bFoundAllEntryPoints, TEXT("Failed to find all OpenGL entry points."));

			FString VendorName( ANSI_TO_TCHAR((const ANSICHAR*)glGetString(GL_VENDOR) ) );
			if ( VendorName.Contains(TEXT("ATI ")) )
			{
				// Workaround for AMD driver not handling GL_SRGB8_ALPHA8 in glTexStorage2D() properly (gets treated as non-sRGB)
				glTexStorage1D = NULL;
				glTexStorage2D = NULL;
				glTexStorage3D = NULL;
			}
		}

		// The dummy context can now be released.
		if (DummyContext.OpenGLContext)
		{
			ContextMakeCurrent(NULL,NULL);
			wglDeleteContext(DummyContext.OpenGLContext);
		}
		ReleaseDC(DummyContext.WindowHandle, DummyContext.DeviceContext);
		check(DummyContext.bReleaseWindowOnDestroy);
		DestroyWindow(DummyContext.WindowHandle);

	}
	return bOpenGLSupported;
}