///////////////////////////////////////////////////////////////////////
// Copyright (C) Andru 2007                                          //
// mail: dr.andru@gmail.com                                          //
// site: http://andru.2x4.ru                                         //
//                                                                   //
// OMEGA Engine is free software.                                    //
//                                                                   //
// You may 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 module 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 module.  If not, write to:                        //
// 	The Free Software Foundation, Inc.,                              //
// 	51 Franklin Street, Fifth Floor                                  //
// 	Boston, MA  02110-1301, USA.                                     //
///////////////////////////////////////////////////////////////////////
unit ENGINE_GL;

{$I DEFINES.pas}

interface
uses
  Windows,
  OpenGL,
  ENGINE_SCREEN,

  ENGINE_VAR,
  ENGINE_CONST,
  ENGINE_LOG,

  ENGINE_WINDOW,

  ENGINE_UTILS,

  UTILS
  ;


function GL_SetPixelFormat : Boolean;
function GL_CreateContext  : Boolean;

function GL_Init : Boolean;
procedure GL_Set2DMatrix;

function CheckExtension(const Extension: string): Boolean;

//----------------------------------------------------------------------------//
                                 IMPLEMENTATION
//----------------------------------------------------------------------------//

function CheckExtension;
  var
    ExtPos: Integer;
begin
ExtPos := Pos( Extension, ogl_Extensions );
Result := ExtPos > 0;
if Result Then
Result := ( ( ExtPos + Length( Extension ) - 1) = Length( ogl_Extensions ) )
          or ( ogl_Extensions[ ExtPos + Length( Extension ) ] = ' ' );

if Result Then
  begin
    if app_Log Then
      LOG_AddMessage( 13, PChar( Extension + ': TRUE' ) );
  end else
    if app_Log Then
      LOG_AddMessage( 13, PChar( Extension + ': FALSE' ) );
end;

procedure glVersionString( var Max, Min : Integer);
  var
    Buffer    : String;
    Separator : Integer;
Begin

Buffer := glGetString( GL_VERSION );

try
  Separator := Pos( '.', Buffer );
  if ( Separator > 1 )                           and
     ( Separator < Length( Buffer ) )            and
     ( Buffer[ Separator - 1 ] in [ '0'..'9' ] ) and
     ( Buffer[ Separator + 1 ] in [ '0'..'9' ] ) Then
    begin
      Dec( Separator );
      while ( Separator > 0 ) and ( Buffer[ Separator ] in [ '0'..'9' ] ) do Dec( Separator );
      Delete( Buffer, 1, Separator );
      Separator := Pos( '.', Buffer ) + 1;
      while ( Separator <= Length( Buffer ) ) and ( Buffer[ Separator ] in [ '0'..'9' ] ) do Inc( Separator );
      Delete( Buffer, Separator, 255 );
      Separator := Pos( '.', Buffer );
      Max := U_StrToInt( PChar( Copy( Buffer, 1, Separator - 1 ) ) );
      Min := U_StrToInt( PChar( Copy( Buffer, Separator + 1, 255 ) ) );
    end;
except
  Min := 0;
  Max := 0;
end;

End;

function GL_Init;
  var
    glMajorVersion, glMinorVersion : integer;
Begin
Result := FALSE;

glVersionString( glMajorVersion, glMinorVersion );
ogl_Version := glMajorVersion + glMinorVersion / 10;
if ogl_Version < 1.2 Then E_Warning( ERR_UNVALID_OPENGL );
if app_Log Then
  begin
    LOG_AddMessage( LOGT_ENGINE, PChar( 'GL_VERSION: ' + glGetString( GL_VERSION ) ) );
    LOG_AddMessage( LOGT_ENGINE, PChar( 'GL_VENDOR: ' + glGetString( GL_VENDOR ) ) );
    LOG_AddMessage( LOGT_ENGINE, PChar( 'GL_RENDERER: ' + glGetString( GL_RENDERER ) ) );    
  end;

ogl_Extensions := glGetString( GL_EXTENSIONS );
wglGetExtensionsStringARB := wglGetProcAddress( 'wglGetExtensionsStringARB' );
if Assigned( wglGetExtensionsStringARB ) Then
  ogl_Extensions := ogl_Extensions + ' ' + wglGetExtensionsStringARB( wglGetCurrentDC );

WGL_EXT_swap_control := CheckExtension( 'WGL_EXT_swap_control' );

wglSwapIntervalEXT    := wglGetProcAddress( 'wglSwapIntervalEXT' );
wglGetSwapIntervalEXT := wglGetProcAddress( 'wglGetSwapIntervalEXT' );

GL_ARB_texture_compression := CheckExtension( 'GL_ARB_texture_compression' );

GL_EXT_bgra := CheckExtension( 'GL_EXT_bgra' );
if not GL_EXT_bgra Then E_Warning( ERR_CANT_BGRA );

glGetIntegerv( GL_MAX_TEXTURE_SIZE, @ogl_MaxTextureSize );

glGetIntegerv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, @ogl_MaxAnisotropy );
ogl_Anisotropy := ogl_MaxAnisotropy;

if app_Log Then
  begin
    TempString := U_IntToStr( ogl_MaxTextureSize );
    LOG_AddMessage( LOGT_ENGINE, PChar( 'GL_MAX_TEXTURE_SIZE: ' + TempString + ' x ' + TempString ) );
    TempString := U_IntToStr( ogl_MaxAnisotropy );
    LOG_AddMessage( LOGT_ENGINE, PChar( 'GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT: ' + TempString ) );
  end;

if app_FullScreen Then
  begin
    ogl_Width  := scr_Width;
    ogl_Height := scr_Height;
  end else
    begin
      ogl_Width  := wnd_Width;
      ogl_Height := wnd_Height;
    end;
CropW := ogl_Width;
CropH := ogl_Height;

glHint( GL_LINE_SMOOTH_HINT,    GL_NICEST );
glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );

glClearColor( 0, 0, 0, 0 );

glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glAlphaFunc( GL_GREATER, 0 );
glDisable( GL_BLEND );
glDisable( GL_ALPHA_TEST );

glDisable( GL_DEPTH_TEST );

glEnable( GL_TEXTURE_2D );

Result := TRUE;

End;

function GL_SetPixelFormat;
  var
    nPixelFormat : Integer;
    pfd          : TPixelFormatDescriptor;

    gf, ga       : DWORD;
begin

Result := FALSE;

wglDeleteContext( wnd_GLRC );

FillChar( pfd, SizeOf( TPixelFormatDescriptor ), 0 );

with pfd do
  begin
    nSize           := SizeOf( TPIXELFORMATDESCRIPTOR );
    nVersion        := 1;
    dwFlags         := PFD_DRAW_TO_WINDOW or
                       PFD_SUPPORT_OPENGL or
                       PFD_DOUBLEBUFFER;
    iPixelType      := PFD_TYPE_RGBA;
    cColorBits      := scr_BPP;
    cDepthBits      := ogl_ZBits;
    cStencilBits    := ogl_Stencil;
    iLayerType      := PFD_MAIN_PLANE;
  end;

nPixelFormat := ChoosePixelFormat( wnd_DC, @pfd );
SetPixelFormat( wnd_DC, nPixelFormat, @pfd );

gf := pfd.dwFlags and PFD_GENERIC_FORMAT;
ga := pfd.dwFlags and PFD_GENERIC_ACCELERATED;

ogl_3DAccelerator := gf and ( not ga ) = 0;
if not ogl_3DAccelerator Then E_Warning( ERR_SOFTWARE );
{if gf and ga > 0 Then
  E_Error( 'Hardware MCD' )
else
  if ( not gf ) and ( not ga ) > 0 Then
    E_Error( 'Hardware ICD' );}

Result := TRUE;

end;

function GL_CreateContext;
Begin
Result := FALSE;

wnd_GLRC := wglCreateContext( wnd_DC );
if ( wnd_GLRC = 0 ) Then
  begin
    E_Error( ERR_CANT_GLCONTEXTC );
    app_Work := FALSE;
    Exit;
  end;

if ( not wglMakeCurrent( wnd_DC, wnd_GLRC ) ) Then
  begin
    E_Error( ERR_CANT_GLCONTEXTA );
    app_Work := FALSE;
    Exit;
  end;

Result := TRUE;
End;

procedure GL_Set2DMatrix;
Begin

glDisable( GL_DEPTH_TEST );
glMatrixMode( GL_PROJECTION );
glLoadIdentity;
gluOrtho2D( 0, ogl_Width, ogl_Height, 0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity;

End;

end.
