{
    This file is part of Chentrah,
    Copyright (C) 2004-2008 Anton Rzheshevski (chebmaster@mail.ru).

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see http://www.gnu.org/licenses/

 **********************************************************************
 
   This file contains the OpenGL function variables initialization
   routine

 **********************************************************************}


{$ifdef windows}
{$ifdef cgekernel}
//If I try to use the plain ChoosePixelFormat() from the Windows module,
//  it yells "function variables of overloaded functions not allowed".
//W.T.F.
function gdiChoosePixelFormat
                                (p1:HDC; var p2:PIXELFORMATDESCRIPTOR):longint;
                                     external 'gdi32' name 'ChoosePixelFormat';
function gdiDescribePixelFormat (
         DC: HDC; p2: Integer; p3: UINT; var p4: TPixelFormatDescriptor): BOOL;
                                   external 'gdi32' name 'DescribePixelFormat';
function gdiGetPixelFormat
                      (p1:HDC):longint; external 'gdi32' name 'GetPixelFormat';
function gdiSetPixelFormat
                        (p1:HDC; p2:longint;p3:PPIXELFORMATDESCRIPTOR):WINBOOL;
                                        external 'gdi32' name 'SetPixelFormat';
function gdiSwapBuffers  (p1:HDC):WINBOOL; external 'gdi32' name 'SwapBuffers';

procedure  LoadFiveQuestionableWglFunctions;
{  http://www.opengl.org/resources/faq/technical/mswindows.htm  says:

    5.190 What do I need to know about mixing WGL and GDI calls?

    On the Win32 platform a number of platform specific
    function calls are duplicated in the OpenGL ICD mechanism and the GDI.
    This may cause confusion as they appear to be functionally identical,
    the only difference being whether wgl precedes the rest of the function
    name. To ensure correct operation of OpenGL use ChoosePixelformat,
    DescribePixelformat, GetPixelformat, SetPixelformat, and SwapBuffers,
    instead of the wgl equivalents,  wglChoosePixelformat,
    wglDescribePixelformat, wglGetPixelformat, wglSetPixelformat,
    and wglSwapBuffers. In all other cases use the wgl function where available.
    Using the five wgl functions is only of interest to developers run-time
    linking to an OpenGL driver. Not using the functions as described may
    result in a black OpenGL window, or a correctly functioning application
    in Windows 9x that produces a black OpenGL window on Windows NT/2000.
}
  function TLwF(fn: string; alta: pointer): pointer;
  var a: pointer;
  begin
    a:= GetGLProcAddress(PChar('wgl' + fn),'');
    if not (Config.Bool['opengl', 'LoadFiveQuestionablewglFunctions']
            or Config.bool['opengl','Use_Mesa_GL'])
      then a:=alta
      else if not Assigned(a) then begin
        a:=alta;
        if MotherState.DebugMode then AddLog('wgl' + fn + ' function not found in the OpenGL library.'
          +' Using the ' + fn + ' function from GDI (at %0)',[a]);
      end;
    Result:=a;
  end;
begin
  pointer(wglChoosePixelFormat):=TLwF('ChoosePixelFormat', @gdiChoosePixelFormat);
  pointer(wglDescribePixelformat):= TLwF('DescribePixelFormat', @gdiDescribePixelformat);
  pointer(wglGetPixelformat):= TLwF('GetPixelFormat',@gdiGetPixelformat);
  pointer(wglSetPixelformat):= TLwF('SetPixelFormat', @gdiSetPixelformat);
  pointer(wglSwapBuffers):= TLwF('SwapBuffers',@gdiSwapBuffers);
end;
{$endif}
{$endif}

procedure SwitchToFixedPipeline;
begin
  if Assigned(glBindFramebuffer)
    then glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0); //switch from FBO to the window framebuffer
  if Assigned(glUseProgram)
    then glUseProgram(0); //shut down the shaders
end;


procedure CheckGlError;
var ec: GLenum;
begin
  ec:= glGetError();
  if ec <> 0 then Die(RuEn(
      'Ошибка OpenGL, код %0h',
      'OpenGL error, code %0h'
    ),
    [IntToHex(ec, 8)]);
end;

procedure InitGlProcAddresses(Load2: boolean);
begin
  {Functions used by both the mother module and the game module
   (the mother module knows only the barest minimum, to be able
    to output error messages using Microsoft's OGL 1.1 ) }

  pointer(glGetString) := GetGLProcAddress( 'glGetString','');
  pointer(glGetIntegerv) := GetGLProcAddress( 'glGetIntegerv','');
  pointer(glGetFloatv):= GetGLProcAddress( 'glGetFloatv', '');
  pointer(glAlphaFunc) := GetGLProcAddress( 'glAlphaFunc','');
  pointer(glBegin) := GetGLProcAddress( 'glBegin','');
  pointer(glBindTexture) := GetGLProcAddress( 'glBindTexture','');
  pointer(glColor3f) := GetGLProcAddress( 'glColor3f','');
  pointer(glColor4f) := GetGLProcAddress( 'glColor4f','');
  pointer(glBlendFunc) := GetGLProcAddress( 'glBlendFunc','');
  pointer(glDeleteTextures) := GetGLProcAddress( 'glDeleteTextures','');
  pointer(glDisable) := GetGLProcAddress( 'glDisable','');
  pointer(glEnable) := GetGLProcAddress( 'glEnable','');
  pointer(glEnd) := GetGLProcAddress( 'glEnd','');
  pointer(glGenTextures) := GetGLProcAddress( 'glGenTextures','');
  pointer(glLoadIdentity) := GetGLProcAddress( 'glLoadIdentity','');
  pointer(glMatrixMode) := GetGLProcAddress( 'glMatrixMode','');
  pointer(glTexImage2D) := GetGLProcAddress( 'glTexImage2D','');
  pointer(glTexParameterf) := GetGLProcAddress( 'glTexParameterf','');
  pointer(glNormal3f) := GetGLProcAddress( 'glNormal3f','');
  pointer(glTexCoord2f) := GetGLProcAddress( 'glTexCoord2f','');
  pointer(glVertex2f) := GetGLProcAddress( 'glVertex2f','');
  pointer(glOrtho) := GetGLProcAddress( 'glOrtho','');
  pointer(glViewport) := GetGLProcAddress( 'glViewport','');
  pointer(glLineWidth) := GetGLProcAddress( 'glLineWidth','');
  pointer(glColor4fv) := GetGLProcAddress( 'glColor4fv','');
  pointer(glClear) := GetGLProcAddress( 'glClear','');
  pointer(glClearColor) := GetGLProcAddress( 'glClearColor','');
  pointer(glFlush) := GetGLProcAddress( 'glFlush','');
  pointer(glFinish) := GetGLProcAddress( 'glFinish','');
  pointer(glGetError):= GetGlProcAddress( 'glGetError', '');
  pointer(glScissor):= GetGlProcAddress( 'glScissor', '');
  pointer(glDepthMask) := GetGLProcAddress( 'glDepthMask','');

{$ifdef cgekernel}
  //Mother module specific stuff:
  // the "_Get..." version doesn't raise an error if function is not present
  pointer(glUseProgram) := _GetGLProcAddress( 'glUseProgramObjectARB');
  if not Assigned(glUseProgram)
    then pointer(glUseProgram) := _GetGLProcAddress( 'glUseProgram');
  pointer(glBindFramebuffer) := _GetGLProcAddress( 'glBindFramebufferEXT');
  if not Assigned(glBindFramebuffer)
    then pointer(glBindFramebuffer) := _GetGLProcAddress( 'glBindFramebuffer');
{$endif}
  
  //   := GetGLProcAddress( '');
  
{$ifndef cgekernel}
  //The functions used only by the game module:
  
  pointer(glVertex2fv) := GetGLProcAddress( 'glVertex2fv','');
  pointer(glVertex2i) := GetGLProcAddress( 'glVertex2i','');
  pointer(glVertex2iv) := GetGLProcAddress( 'glVertex2iv','');
  pointer(glVertex3f) := GetGLProcAddress( 'glVertex3f','');
  pointer(glVertex3fv) := GetGLProcAddress( 'glVertex3fv','');
  pointer(glVertex3i) := GetGLProcAddress( 'glVertex3i','');
  pointer(glVertex3iv) := GetGLProcAddress( 'glVertex3iv','');
  pointer(glVertex4f) := GetGLProcAddress( 'glVertex4f','');
  pointer(glVertex4fv) := GetGLProcAddress( 'glVertex4fv','');
  pointer(glVertex4i) := GetGLProcAddress( 'glVertex4i','');
  pointer(glVertex4iv) := GetGLProcAddress( 'glVertex4iv','');
  pointer(glVertexPointer) := GetGLProcAddress( 'glVertexPointer','');
  
  
  pointer(glCullFace) := GetGLProcAddress( 'glCullFace','');
  pointer(glDepthFunc) := GetGLProcAddress( 'glDepthFunc','');
  pointer(glFrustum) := GetGLProcAddress( 'glFrustum','');
  pointer(glPopMatrix) := GetGLProcAddress( 'glPopMatrix','');
  pointer(glPushMatrix) := GetGLProcAddress( 'glPushMatrix','');
  pointer(glRotatef) := GetGLProcAddress( 'glRotatef','');
  pointer(glScalef) := GetGLProcAddress( 'glScalef','');
  pointer(glTranslatef) := GetGLProcAddress( 'glTranslatef','');

  pointer(glAreTexturesResident):= GetGLProcAddress('glAreTexturesResident', '');


  if Load2 then begin
    //  ********************    FBO   ************************************
    pointer(glIsRenderbuffer) := GetGLProcAddress( 'glIsRenderbuffer','EXT');
    pointer(glBindRenderbuffer) := GetGLProcAddress( 'glBindRenderbuffer','EXT');
    pointer(glDeleteRenderbuffers) := GetGLProcAddress( 'glDeleteRenderbuffers','EXT');
    pointer(glGenRenderbuffers) := GetGLProcAddress( 'glGenRenderbuffers','EXT');
    pointer(glRenderbufferStorage) := GetGLProcAddress( 'glRenderbufferStorage','EXT');
    pointer(glGetRenderbufferParameteriv) := GetGLProcAddress( 'glGetRenderbufferParameteriv','EXT');

    pointer(glIsFramebuffer) := GetGLProcAddress( 'glIsFramebuffer','EXT');
    pointer(glBindFramebuffer) := GetGLProcAddress( 'glBindFramebuffer','EXT');
    pointer(glDeleteFramebuffers) := GetGLProcAddress( 'glDeleteFramebuffers','EXT');
    pointer(glGenFramebuffers) := GetGLProcAddress( 'glGenFramebuffers','EXT');
    pointer(glCheckFramebufferStatus) := GetGLProcAddress( 'glCheckFramebufferStatus','EXT');

    pointer(glFramebufferTexture1D) := GetGLProcAddress( 'glFramebufferTexture1D','EXT');
    pointer(glFramebufferTexture2D) := GetGLProcAddress( 'glFramebufferTexture2D','EXT');
    pointer(glFramebufferTexture3D) := GetGLProcAddress( 'glFramebufferTexture3D','EXT');

    pointer(glFramebufferRenderbuffer) := GetGLProcAddress( 'glFramebufferRenderbuffer','EXT');
    pointer(glGetFramebufferAttachmentParameteriv) := GetGLProcAddress( 'glGetFramebufferAttachmentParameteriv','EXT');
    pointer(glGenerateMipmap) := GetGLProcAddress( 'glGenerateMipmap','EXT');


  // *******************  GL_ARB_vertex_buffer_object  ************************
    pointer(glBindBuffer)  := GetGLProcAddress( 'glBindBuffer','ARB');
    pointer(glDeleteBuffers)  := GetGLProcAddress( 'glDeleteBuffers','ARB');
    pointer(glGenBuffers)  := GetGLProcAddress( 'glGenBuffers','ARB');
    pointer(glIsBuffer)  := GetGLProcAddress( 'glIsBuffer','ARB');

    pointer(glBufferData)  := GetGLProcAddress( 'glBufferData','ARB');
    pointer(glBufferSubData)  := GetGLProcAddress( 'glBufferSubData','ARB');
    pointer(glGetBufferSubData)  := GetGLProcAddress( 'glGetBufferSubData','ARB');

    pointer(glMapBuffer)  := GetGLProcAddress( 'glMapBuffer','ARB');

    pointer(glUnmapBuffer)  := GetGLProcAddress( 'glUnmapBuffer','ARB');

    pointer(glGetBufferParameteriv)  := GetGLProcAddress( 'glGetBufferParameteriv','ARB');
    pointer(glGetBufferPointerv)  := GetGLProcAddress( 'glGetBufferPointerv','ARB');



  // **** GL_ARB_fragment_shader | GL_ARB_vertex_shader | GL_ARB_shader_object *****

    pointer(glVertexAttrib1f) := GetGLProcAddress2( 'glVertexAttrib1f','ARB', '');
    pointer(glVertexAttrib1s) := GetGLProcAddress2( 'glVertexAttrib1s','ARB', '');
    pointer(glVertexAttrib1d) := GetGLProcAddress2( 'glVertexAttrib1d','ARB', '');
    pointer(glVertexAttrib2f) := GetGLProcAddress2( 'glVertexAttrib2f','ARB', '');
    pointer(glVertexAttrib2s) := GetGLProcAddress2( 'glVertexAttrib2s','ARB', '');
    pointer(glVertexAttrib2d) := GetGLProcAddress2( 'glVertexAttrib2d','ARB', '');
    pointer(glVertexAttrib3f) := GetGLProcAddress2( 'glVertexAttrib3f','ARB', '');
    pointer(glVertexAttrib3s) := GetGLProcAddress2( 'glVertexAttrib3s','ARB', '');
    pointer(glVertexAttrib3d) := GetGLProcAddress2( 'glVertexAttrib3d','ARB', '');
    pointer(glVertexAttrib4f) := GetGLProcAddress2( 'glVertexAttrib4f','ARB', '');
    pointer(glVertexAttrib4s) := GetGLProcAddress2( 'glVertexAttrib4s','ARB', '');
    pointer(glVertexAttrib4d) := GetGLProcAddress2( 'glVertexAttrib4d','ARB', '');
    pointer(glVertexAttrib4Nub) := GetGLProcAddress2( 'glVertexAttrib4Nub','ARB', '');

    pointer(glVertexAttrib1fv) := GetGLProcAddress2( 'glVertexAttrib1fv','ARB', '');
    pointer(glVertexAttrib1sv) := GetGLProcAddress2( 'glVertexAttrib1sv','ARB', '');
    pointer(glVertexAttrib1dv) := GetGLProcAddress2( 'glVertexAttrib1dv','ARB', '');
    pointer(glVertexAttrib2fv) := GetGLProcAddress2( 'glVertexAttrib2fv','ARB', '');
    pointer(glVertexAttrib2sv) := GetGLProcAddress2( 'glVertexAttrib2sv','ARB', '');
    pointer(glVertexAttrib2dv) := GetGLProcAddress2( 'glVertexAttrib2dv','ARB', '');
    pointer(glVertexAttrib3fv) := GetGLProcAddress2( 'glVertexAttrib3fv','ARB', '');
    pointer(glVertexAttrib3sv) := GetGLProcAddress2( 'glVertexAttrib3sv','ARB', '');
    pointer(glVertexAttrib3dv) := GetGLProcAddress2( 'glVertexAttrib3dv','ARB', '');
    pointer(glVertexAttrib4fv) := GetGLProcAddress2( 'glVertexAttrib4fv','ARB', '');
    pointer(glVertexAttrib4sv) := GetGLProcAddress2( 'glVertexAttrib4sv','ARB', '');
    pointer(glVertexAttrib4dv) := GetGLProcAddress2( 'glVertexAttrib4dv','ARB', '');
    pointer(glVertexAttrib4iv) := GetGLProcAddress2( 'glVertexAttrib4iv','ARB', '');
    pointer(glVertexAttrib4bv) := GetGLProcAddress2( 'glVertexAttrib4bv','ARB', '');

    pointer(glVertexAttrib4ubv) := GetGLProcAddress2( 'glVertexAttrib4ubv','ARB', '');
    pointer(glVertexAttrib4usv) := GetGLProcAddress2( 'glVertexAttrib4usv','ARB', '');
    pointer(glVertexAttrib4uiv) := GetGLProcAddress2( 'glVertexAttrib4uiv','ARB', '');

    pointer(glVertexAttrib4Nbv) := GetGLProcAddress2( 'glVertexAttrib4Nbv','ARB', '');
    pointer(glVertexAttrib4Nsv) := GetGLProcAddress2( 'glVertexAttrib4Nsv','ARB', '');
    pointer(glVertexAttrib4Niv) := GetGLProcAddress2( 'glVertexAttrib4Niv','ARB', '');
    pointer(glVertexAttrib4Nubv) := GetGLProcAddress2( 'glVertexAttrib4Nubv','ARB', '');
    pointer(glVertexAttrib4Nusv) := GetGLProcAddress2( 'glVertexAttrib4Nusv','ARB', '');
    pointer(glVertexAttrib4Nuiv) := GetGLProcAddress2( 'glVertexAttrib4Nuiv','ARB', '');

    pointer(glVertexAttribPointer) := GetGLProcAddress2( 'glVertexAttribPointer','ARB', '');

    pointer(glEnableVertexAttribArray) := GetGLProcAddress2( 'glEnableVertexAttribArray','ARB', '');
    pointer(glDisableVertexAttribArray) := GetGLProcAddress2( 'glDisableVertexAttribArray','ARB', '');

    pointer(glBindAttribLocation) := GetGLProcAddress2( 'glBindAttribLocation','ARB', '');

    pointer(glGetActiveAttrib) := GetGLProcAddress2( 'glGetActiveAttrib','ARB', '');

    pointer(glGetAttribLocation) := GetGLProcAddress2( 'glGetAttribLocation','ARB', '');

    pointer(glGetVertexAttribdv) := GetGLProcAddress2( 'glGetVertexAttribdv','ARB', '');
    pointer(glGetVertexAttribfv) := GetGLProcAddress2( 'glGetVertexAttribfv','ARB', '');
    pointer(glGetVertexAttribiv) := GetGLProcAddress2( 'glGetVertexAttribiv','ARB', '');
    pointer(glGetVertexAttribPointerv) := GetGLProcAddress2( 'glGetVertexAttribPointerv','ARB', '');


    pointer(glDeleteShader) := GetGLProcAddress2( 'glDelete', 'ObjectARB', 'Shader');
    pointer(glDeleteProgram ):= GetGLProcAddress2( 'glDelete', 'ObjectARB', 'Program');

    pointer(glGetHandle) := GetGLProcAddress( 'glGetHandle','ARB');

    pointer(glDetachShader) := GetGLProcAddress2( 'glDetach', 'ObjectARB', 'Shader');

    pointer(glCreateShader) := GetGLProcAddress2( 'glCreateShader','ObjectARB', '');

    pointer(glShaderSource) := GetGLProcAddress2( 'glShaderSource','ARB', '');

    pointer(glCompileShader) := GetGLProcAddress2( 'glCompileShader','ARB', '');

    pointer(glCreateProgram) := GetGLProcAddress2( 'glCreateProgram', 'ObjectARB', '');

    pointer(glAttachShader) := GetGLProcAddress2( 'glAttach', 'ObjectARB', 'Shader');

    pointer(glLinkProgram) := GetGLProcAddress2( 'glLinkProgram','ARB', '');

    pointer(glUseProgram) := GetGLProcAddress2( 'glUseProgram','ObjectARB', '');

    pointer(glValidateProgram) := GetGLProcAddress2( 'glValidateProgram','ARB', '');

    pointer(glUniform1f) := GetGLProcAddress2( 'glUniform1f','ARB', '');
    pointer(glUniform2f) := GetGLProcAddress2( 'glUniform2f','ARB', '');
    pointer(glUniform3f) := GetGLProcAddress2( 'glUniform3f','ARB', '');
    pointer(glUniform4f) := GetGLProcAddress2( 'glUniform4f','ARB', '');

    pointer(glUniform1i) := GetGLProcAddress2( 'glUniform1i','ARB', '');
    pointer(glUniform2i) := GetGLProcAddress2( 'glUniform2i','ARB', '');
    pointer(glUniform3i) := GetGLProcAddress2( 'glUniform3i','ARB', '');
    pointer(glUniform4i) := GetGLProcAddress2( 'glUniform4i','ARB', '');

    pointer(glUniform1fv) := GetGLProcAddress2( 'glUniform1fv','ARB', '');
    pointer(glUniform2fv) := GetGLProcAddress2( 'glUniform2fv','ARB', '');
    pointer(glUniform3fv) := GetGLProcAddress2( 'glUniform3fv','ARB', '');
    pointer(glUniform4fv) := GetGLProcAddress2( 'glUniform4fv','ARB', '');

    pointer(glUniform1iv) := GetGLProcAddress2( 'glUniform1iv','ARB', '');
    pointer(glUniform2iv) := GetGLProcAddress2( 'glUniform2iv','ARB', '');
    pointer(glUniform3iv) := GetGLProcAddress2( 'glUniform3iv','ARB', '');
    pointer(glUniform4iv) := GetGLProcAddress2( 'glUniform4iv','ARB', '');

    pointer(glUniformMatrix2fv) := GetGLProcAddress2( 'glUniformMatrix2fv','ARB', '');
    pointer(glUniformMatrix3fv) := GetGLProcAddress2( 'glUniformMatrix3fv','ARB', '');
    pointer(glUniformMatrix4fv) := GetGLProcAddress2( 'glUniformMatrix4fv','ARB', '');

    pointer(glGetShaderParameteriv) := GetGLProcAddress2( 'glGet','ObjectParameterivARB','Shaderiv');
    pointer(glGetProgramParameteriv) := GetGLProcAddress2( 'glGet','ObjectParameterivARB','Programiv');

    pointer(glGetShaderInfoLog) := GetGLProcAddress2( 'glGet', 'InfoLogARB', 'ShaderInfoLog');
    pointer(glGetProgramInfoLog) := GetGLProcAddress2( 'glGet', 'InfoLogARB', 'ProgramInfoLog');

    pointer(glGetAttachedShaders) := GetGLProcAddress2( 'glGetAttached', 'ObjectsARB', 'Shaders');

    pointer(glGetUniformLocation) := GetGLProcAddress2( 'glGetUniformLocation','ARB', '');

    pointer(glGetActiveUniform) := GetGLProcAddress2( 'glGetActiveUniform','ARB', '');

    pointer(glGetUniformfv) := GetGLProcAddress2( 'glGetUniformfv','ARB', '');
    pointer(glGetUniformiv) := GetGLProcAddress2( 'glGetUniformiv','ARB', '');

    pointer(glGetShaderSource) := GetGLProcAddress2( 'glGetShaderSource','ARB', '');

    pointer(glGetObjectParameterfv) := GetGlProcAddress2( 'glGetObjectParameterfv', 'ARB', '');
    pointer(glGetObjectParameteriv) := GetGlProcAddress2( 'glGetObjectParameteriv', 'ARB', '');
    pointer(glGetInfoLog) := GetGlProcAddress2( 'glGetInfoLog', 'ARB', '');


    //    pointer() := GetGlProcAddress( '', 'ARB');

  end;
{$endif}



end;
  


