//---------------------------------------------------------------------------
// Copyright (c) Allan Petersen, 2008.
/*
 * Version 1.1.6 of the TOpenGLAPPanel
 * This is a implementation of a OpenGL Component for Codegear Rad Studio 2009.

 * (c) Copyright 2008, Allan Petersen
 * ALL RIGHTS RESERVED
 * Permission to use, copy, modify, and distribute this software for
 * any purpose and without fee is hereby granted, provided that the above
 * copyright notice appear in all copies and that both the copyright notice
 * and this permission notice appear in supporting documentation, and that
 * the name of Allan Petersen not be used in advertising
 * or publicity pertaining to distribution of the software without specific,
 * written prior permission.
 *
 * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
 * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
 * FITNESS FOR A PARTICULAR PURPOSE.  IN NO EVENT SHALL ALLAN
 * PETERSEN BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
 * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
 * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
 * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
 * THIRD PARTIES, WHETHER OR NOT ALLAN PETERSEN HAS BEEN
 * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
 * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * www.allanpetersen.com
 *
 */

//---------------------------------------------------------------------------
//  Version History (sorry this is not very updated)
//  1.1.6, 2008-09-25  -   Codegear Rad Studio 2009 Support.
//						   for the moment keep ansistring in events, in the future use UnicodeString
//  1.1.5, 2008-09-25  -   Codegear Rad Studio 2009 Support.
//  1.1.4, 2007-11-02  -   Windows Vista Support with f_PFD_SUPPORT_COMPOSITION.
//  1.1.3, 2006-05-25  -   Fixed _T errors in compile.
//  1.1.2, 2006-02-06  -   Added multi Sample Support.
//  1.1.1, 2006-01-06  -   Support for BDS 2006
//  1.1.0, 2003-09-02  -   Removed a few memory leaks with help from Heath Raftery
//  1.0.9, 2003-05-27  -   Added WMEraseBkgnd, with a paint call.
//  1.0.8, 2003-05-09  -   Removed WMEraseBkgnd, it caused components to dissapear when
//                         added on top of this component in design mode.
//                         Added public PIXELFORMATDESCRIPTOR dpf for external test for
//                         hardware rendering etc.
//
//  ?.?.?, 2002.01.07  -   Cleaning up the code a bit
//                         Changing wglMakeCurrent to be independent of the event
//                         FOnInit changed to initialize independent of an existing event.
//  ?.?.?, 2000.08.15  -   Added LoadTGA () to load targa files.

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include <stdio.h>
#include "TOpenGLAPPanel.h"
#include "wglext.h"
#pragma package(smart_init)


// ---- New define in wingdi.h for vista
#define PFD_SUPPORT_COMPOSITION  0x00008000


// ---- Definition on targa header
typedef struct {
        unsigned char   id_length, colormap_type, image_type;
        unsigned short  colormap_index, colormap_length;
        unsigned char   colormap_size;
        unsigned short  x_origin, y_origin, width, height;
        unsigned char   pixel_size, attributes;
        } targaHeader;

//---------------------------------------------------------------------------
// Compontent Registration
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//
static inline void ValidCtrCheck(TOpenGLAPPanel *)
{
 new TOpenGLAPPanel(NULL);
}
//---------------------------------------------------------------------------
namespace Topenglappanel
{
   void __fastcall PACKAGE Register() {
     TComponentClass classes[1] = {__classid(TOpenGLAPPanel)};
     RegisterComponents("AP.Soft", classes, 0);
    }
}
//---------------------------------------------------------------------------
// Constructor and Destructor
//---------------------------------------------------------------------------
__fastcall TOpenGLAPPanel::TOpenGLAPPanel(TComponent* Owner)
        : TCustomPanel(Owner)
{
   AllowCreateParms = false;
   DoubleBuffered   = false;
   FdwFlags.Clear();
   FdwFlags << f_PFD_DRAW_TO_WINDOW << f_PFD_SUPPORT_OPENGL <<f_PFD_DOUBLEBUFFER << f_PFD_SUPPORT_COMPOSITION;

   FiPixelType=f_PFD_TYPE_RGBA;
   SavedPixelType=PFD_TYPE_RGBA;
   FcColorBits=32;
   FcDepthBits=32;
   FSwapBuffers=Auto;

   FOpenGLPrintScale=pglProportional;
   FOpenGLPixelsPerInch=96;

   Font3DEnabled=false;
   Font3DType= new TFont;
   Font3DType->Name="Arial";
   Font3DType->Style<< fsBold;
   Font3DType->Height=-9;
   Font3DType->Charset=ANSI_CHARSET;
   Font3DFirstGylph=32;
   Font3DNumGylph=96;
   Font3DMaxDeviation=1.0;
   Font3DExtrusion=0.1;
   Font3DFormat=f_WGL_FONT_POLYGONS;
   SavedFont3DFormat=WGL_FONT_POLYGONS;
   Font3DDefault=NULL;

   Font2DEnabled=false;
   Font2DType= new TFont;
   Font2DType->Name="Arial";
   Font2DType->Style<< fsBold;
   Font2DType->Height=-9;
   Font2DType->Charset=ANSI_CHARSET;
   Font2DFirstGylph=32;
   Font2DNumGylph=96;
   Font2DDefault=NULL;

   Ffps_Enabled = false;

   arbMultisampleSupported = false;
   
   QueryPerformanceFrequency(&Frequency);
}
//---------------------------------------------------------------------------
__fastcall TOpenGLAPPanel::~TOpenGLAPPanel()
{
	// ---- Cleaning up Font Types AP.2003.09.02
    delete Font2DType;
	delete Font3DType;
}
// don't do anything
static LRESULT CALLBACK MultiSampleOpenGLProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
  return DefWindowProc(hWnd,msg,wParam,lParam);
}
//===========================================================================
//	Name	 	: MultiSamplePixelFormat
//	Purpose	 	: Creating a dummy window to determine a pixel format for multi sample
//	Return		: 
//---------------------------------------------------------------------------
//	2006-02-24	Created by AP.
//===========================================================================
int  TOpenGLAPPanel::MultiSamplePixelFormat (void)
{
#define MULTISAMPLE_OPENGL_CLASS ("MultiSampleOpenGLClass")

	HDC    	LocalDisplayDeviceContext;
	HGLRC   LocalGLRenderingContext;
    int		arbMultisampleFormat;
	int		PixelFormatIndex;
	int		valid;
	WNDCLASSEX wcex;
	UINT	numFormats;
	PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB;
	float	fAttributes[] = {0,0};
	int iAttributes[] = {
		WGL_DRAW_TO_WINDOW_ARB,GL_TRUE,
		WGL_SUPPORT_OPENGL_ARB,GL_TRUE,
		WGL_ACCELERATION_ARB, 
		WGL_FULL_ACCELERATION_ARB,
		WGL_COLOR_BITS_ARB,24,
		WGL_ALPHA_BITS_ARB, 8,
		WGL_DEPTH_BITS_ARB, 16,
		WGL_STENCIL_BITS_ARB,0,
		WGL_DOUBLE_BUFFER_ARB,GL_TRUE,
		WGL_SAMPLE_BUFFERS_ARB,GL_TRUE,
		WGL_SAMPLES_ARB,4,
		0,0
		};

	PIXELFORMATDESCRIPTOR pfd =   {
								   sizeof(PIXELFORMATDESCRIPTOR), // size
								   1,                         // version 1
								   0,                             // Flags
								   SavedPixelType,                // Color Mode
								   FcColorBits,                   // Number of color bits
								   0,0,0,0,0,0,                   // RGB color bits with shift (not used)
								   1,0,                           // Alpha bits with shift     (not used)
								   FcAccBits,                     // Number of accumulator bits
								   0,0,0,0,                       // RGBA accumulator bits
								   FcDepthBits,                   // Number of bits for Z-Buffer Depth
								   0,                             // Stencil buffer depth
								   0,                             // Auxiliary buffer depth
								   PFD_MAIN_PLANE,                // Layer type
								   0,                             // Reserved
								   0,                             // Layer mask
								   0,                             // Visible mask
								   0                              // Damage mask
								  };
	if (FdwFlags.Contains(f_PFD_DRAW_TO_WINDOW))
		pfd.dwFlags |= PFD_DRAW_TO_WINDOW;

	if (FdwFlags.Contains(f_PFD_DRAW_TO_BITMAP))
		pfd.dwFlags |= PFD_DRAW_TO_BITMAP;

	if (FdwFlags.Contains(f_PFD_SUPPORT_GDI))
		pfd.dwFlags |= PFD_SUPPORT_GDI;
	else
		pfd.dwFlags |= PFD_DOUBLEBUFFER;
		
	if (FdwFlags.Contains(f_PFD_SUPPORT_OPENGL))
		pfd.dwFlags |= PFD_SUPPORT_OPENGL;

	if (FdwFlags.Contains(f_PFD_GENERIC_ACCELERATED))
		pfd.dwFlags |= PFD_GENERIC_ACCELERATED;

	if (FdwFlags.Contains(f_PFD_GENERIC_FORMAT))
		pfd.dwFlags |= PFD_GENERIC_FORMAT;

	if (FdwFlags.Contains(f_PFD_NEED_PALETTE))
		pfd.dwFlags |= PFD_NEED_PALETTE ;

	if (FdwFlags.Contains(f_PFD_NEED_SYSTEM_PALETTE))
		pfd.dwFlags |= PFD_NEED_SYSTEM_PALETTE;

	if (FdwFlags.Contains(f_PFD_STEREO))
		pfd.dwFlags |= PFD_STEREO;

	if (FdwFlags.Contains(f_PFD_SWAP_LAYER_BUFFERS))
		pfd.dwFlags |= PFD_SWAP_LAYER_BUFFERS;

	if (FdwFlags.Contains(f_PFD_SUPPORT_COMPOSITION))
		pfd.dwFlags |= PFD_SUPPORT_COMPOSITION;


try {
	// ---- registering the multi sample window
	ZeroMemory(&wcex,sizeof(wcex));
	wcex.cbSize			= sizeof(wcex);
	wcex.style			= CS_OWNDC;
	wcex.cbWndExtra		= 0; /* space for our pointer */
	wcex.lpfnWndProc	= MultiSampleOpenGLProc;
	wcex.hbrBackground	= NULL;
	wcex.hInstance		= Handle;
	wcex.hCursor		= LoadCursor(NULL,IDC_ARROW);
	wcex.lpszClassName	= MULTISAMPLE_OPENGL_CLASS;

	if (RegisterClassEx(&wcex) == 0) {
		FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, SystemMessage, 255, NULL);
		ErrorMsg = "RegisterClass:" + String(SystemMessage);
		return (-1);
		}
		
	// create dummy window
	HWND hMultiSampleWindow = CreateWindowEx(0L, MULTISAMPLE_OPENGL_CLASS,(""),WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,0,0,1,1,Handle,0, NULL,NULL);
	if (!hMultiSampleWindow) {
		FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, SystemMessage, 255, NULL);
		ErrorMsg = "MultiSample: " + String(SystemMessage);
		return (-1);
		}

	LocalDisplayDeviceContext = GetDC(hMultiSampleWindow);

	if ((PixelFormatIndex = ChoosePixelFormat(LocalDisplayDeviceContext,&pfd))==0) {
		ReleaseDC(hMultiSampleWindow,DisplayDeviceContext);
		DestroyWindow(hMultiSampleWindow);
		return (-1);
		}
	if (SetPixelFormat(LocalDisplayDeviceContext, PixelFormatIndex,&pfd)!=true) {
		ReleaseDC(hMultiSampleWindow,LocalDisplayDeviceContext);
		DestroyWindow(hMultiSampleWindow);
		return (-1);
		}
	 if ((LocalGLRenderingContext = wglCreateContext(LocalDisplayDeviceContext))==NULL) {
		ReleaseDC(hMultiSampleWindow, LocalDisplayDeviceContext);
		DestroyWindow(hMultiSampleWindow);
		return (-1);
		}
	if (wglMakeCurrent(LocalDisplayDeviceContext,LocalGLRenderingContext)==false) {
		wglMakeCurrent(NULL,NULL);
		wglDeleteContext(LocalGLRenderingContext);
		ReleaseDC(hMultiSampleWindow, LocalDisplayDeviceContext);
		return (-1);
		}

	wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC) wglGetProcAddress("wglChoosePixelFormatARB");
	if (!wglChoosePixelFormatARB) {
		wglMakeCurrent(NULL,NULL);
		wglDeleteContext(LocalGLRenderingContext);
		ReleaseDC(hMultiSampleWindow, LocalDisplayDeviceContext);
		return (-1);
		}

	if (!wglChoosePixelFormatARB) {
		wglMakeCurrent(NULL,NULL);
		wglDeleteContext(LocalGLRenderingContext);
		ReleaseDC(hMultiSampleWindow, LocalDisplayDeviceContext);
		return (-1);
		}
	// First We Check To See If We Can Get A Pixel Format For 4 Samples
	valid = wglChoosePixelFormatARB (LocalDisplayDeviceContext, iAttributes, fAttributes, 1, &arbMultisampleFormat, &numFormats);
	// If We Returned True, And Our Format Count Is Greater Than 1
	if (valid && numFormats >= 1) {
		// ok
		wglMakeCurrent(NULL,NULL);
		wglDeleteContext(LocalGLRenderingContext);
		ReleaseDC(hMultiSampleWindow, LocalDisplayDeviceContext);
		DestroyWindow(hMultiSampleWindow);
		return (arbMultisampleFormat);
		}
	// Our Pixel Format With 4 Samples Failed, Test For 2 Samples
	iAttributes[19] = 2;
	valid = wglChoosePixelFormatARB (LocalDisplayDeviceContext, iAttributes, fAttributes, 1, &arbMultisampleFormat, &numFormats);
	// If We Returned True, And Our Format Count Is Greater Than 1
	if (valid && numFormats >= 1) {
		// ok
		wglMakeCurrent(NULL,NULL);
		wglDeleteContext(LocalGLRenderingContext);
		ReleaseDC(hMultiSampleWindow, LocalDisplayDeviceContext);
		DestroyWindow(hMultiSampleWindow);
		return (arbMultisampleFormat);
		}
		
	// error
	wglMakeCurrent(NULL,NULL);
	wglDeleteContext(LocalGLRenderingContext);
	ReleaseDC(hMultiSampleWindow, LocalDisplayDeviceContext);
	DestroyWindow(hMultiSampleWindow);
	return (-1);
	}
catch (...) {
	return (-1);
	}
}
//---------------------------------------------------------------------------
//  Function    :   CreateGLContext ()
//  Description :   Creates the OpenGL Context handles
//
//  Author      :   AP
//  Date        :   07.01.2002
//  Comments    :
//---------------------------------------------------------------------------
bool  TOpenGLAPPanel::CreateGLContext(void)
{
	int  	FirstTickCount;
   	int		arbMultisampleFormat;
	int 	PixelFormatIndex;
	PIXELFORMATDESCRIPTOR pfd =   {
								   sizeof(PIXELFORMATDESCRIPTOR), // size
								   1,                         // version 1
								   0,                             // Flags
								   SavedPixelType,                // Color Mode
								   FcColorBits,                   // Number of color bits
								   0,0,0,0,0,0,                   // RGB color bits with shift (not used)
								   1,0,                           // Alpha bits with shift     (not used)
								   FcAccBits,                     // Number of accumulator bits
								   0,0,0,0,                       // RGBA accumulator bits
								   FcDepthBits,                   // Number of bits for Z-Buffer Depth
								   0,                             // Stencil buffer depth
								   0,                             // Auxiliary buffer depth
								   PFD_MAIN_PLANE,                // Layer type
								   0,                             // Reserved
								   0,                             // Layer mask
								   0,                             // Visible mask
								   0                              // Damage mask
								  };
	if (FdwFlags.Contains(f_PFD_DRAW_TO_WINDOW))
		pfd.dwFlags |= PFD_DRAW_TO_WINDOW;

	if (FdwFlags.Contains(f_PFD_DRAW_TO_BITMAP))
		pfd.dwFlags |= PFD_DRAW_TO_BITMAP;

	if (FdwFlags.Contains(f_PFD_SUPPORT_GDI))
		pfd.dwFlags |= PFD_SUPPORT_GDI;
	else
		pfd.dwFlags |= PFD_DOUBLEBUFFER;
		
	if (FdwFlags.Contains(f_PFD_SUPPORT_OPENGL))
		pfd.dwFlags |= PFD_SUPPORT_OPENGL;

	if (FdwFlags.Contains(f_PFD_GENERIC_ACCELERATED))
		pfd.dwFlags |= PFD_GENERIC_ACCELERATED;

	if (FdwFlags.Contains(f_PFD_GENERIC_FORMAT))
		pfd.dwFlags |= PFD_GENERIC_FORMAT;

	if (FdwFlags.Contains(f_PFD_NEED_PALETTE))
		pfd.dwFlags |= PFD_NEED_PALETTE ;

	if (FdwFlags.Contains(f_PFD_NEED_SYSTEM_PALETTE))
		pfd.dwFlags |= PFD_NEED_SYSTEM_PALETTE;

	if (FdwFlags.Contains(f_PFD_STEREO))
		pfd.dwFlags |= PFD_STEREO;

	if (FdwFlags.Contains(f_PFD_SWAP_LAYER_BUFFERS))
		pfd.dwFlags |= PFD_SWAP_LAYER_BUFFERS;


	arbMultisampleSupported = false;
	if (FMultiSample) {
		arbMultisampleFormat = MultiSamplePixelFormat ();
		if (arbMultisampleFormat != -1) {
			PixelFormatIndex = arbMultisampleFormat;
			arbMultisampleSupported = true;
			}
		else {
			FMultiSample = false;	// ---- Not supported
			}
		}
	
	DisplayDeviceContext = GetDC(this->Handle);

	if (!arbMultisampleSupported) {
		if ((PixelFormatIndex = ChoosePixelFormat(DisplayDeviceContext,&pfd))==0) {
			FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, SystemMessage, 255, NULL);
			ErrorMsg = "ChoosePixelFormat:" + String(SystemMessage);
			Error ();
			ReleaseDC(this->Handle,DisplayDeviceContext);
			return false;
			}
		}
	if (SetPixelFormat(DisplayDeviceContext,PixelFormatIndex,&pfd)!=true) {
		FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, SystemMessage, 255, NULL);
		ErrorMsg = "SetPixelFormat:" + String(SystemMessage);
		Error ();
		ReleaseDC(this->Handle,DisplayDeviceContext);
		return false;
		}

	if (pfd.dwFlags & PFD_DOUBLEBUFFER) {
	   DoubleBuffer=true;
	   }
	else {
	   DoubleBuffer=false;
	   }

	// ---- 
    DescribePixelFormat(DisplayDeviceContext,PixelFormatIndex,
                        sizeof(PIXELFORMATDESCRIPTOR),&pfd);
	dpf = pfd;
    if (dpf.dwFlags & PFD_NEED_PALETTE) {
        if (ConstructPalette(dpf)==false) {
            ReleaseDC(this->Handle,DisplayDeviceContext);
            return false;
            }
        }
    else {
        Palette=NULL;
        }

	 if ((GLRenderingContext = wglCreateContext(DisplayDeviceContext))==NULL) {
		   FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, SystemMessage, 255, NULL);
           ErrorMsg = "wglRenderingContext:" + String(SystemMessage);
           Error ();
		   if (Palette) {
               SelectPalette(DisplayDeviceContext,
                             GetStockObject(DEFAULT_PALETTE),false);
               if (DeleteObject(Palette)==false) {
                   ErrorMsg = "DeleteObject: Failed";
                   Error ();
                   }
              }
           ReleaseDC(this->Handle,DisplayDeviceContext);
           return false;
          }

    // ---- Activate this panel
    if (MakeOpenGLPanelCurrent() == false) {
        return false;
        }

    return true;
 }
//---------------------------------------------------------------------------
void  TOpenGLAPPanel::DestroyGLContext(void)
{
    if (Font3DDefault) {
        delete Font3DDefault;
        }
    if (Font2DDefault) {
        delete Font2DDefault;
        }
	wglMakeCurrent(NULL,NULL);
    if (GLRenderingContext!=NULL) {
        if (wglDeleteContext(GLRenderingContext)==false) {
           FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, SystemMessage, 255, NULL);
		   ErrorMsg = "wglDeleteContext:" + String(SystemMessage);
           Error ();
          }
        if ((Palette) && (DeleteObject(Palette)==false)) {
            FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, SystemMessage, 255, NULL);
            ErrorMsg = "DeleteObject Failed:" + String(SystemMessage);
            Error ();
            }
        }
    // ---- Deleting DisplayDeviceContext AP.2003.09.02
    if (DisplayDeviceContext != NULL) {
        if(ReleaseDC(Handle, DisplayDeviceContext) == 0) {
            FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, SystemMessage, 255, NULL);
            ErrorMsg = "ReleaseDC Failed:" + String(SystemMessage);
            Error ();
            }
        }
    return;
 }
 //---------------------------------------------------------------------------
 bool  TOpenGLAPPanel::ConstructPalette(PIXELFORMATDESCRIPTOR &pfd)
 {
    LOGPALETTE *LPalettep;
    WORD NumColors= (WORD)(1 << pfd.cColorBits);

    if (( LPalettep=(LOGPALETTE * )
         malloc(sizeof(LOGPALETTE)+(sizeof(PALETTEENTRY)*NumColors)))==NULL) {
         ErrorMsg = "ConstructPalette: Malloc failure";
         Error ();
         return false;
         }
    LPalettep->palVersion=0x300;
    LPalettep->palNumEntries=NumColors;

    int RedMask   =( 1 << pfd.cRedBits  ) -1;
    int GreenMask =( 1 << pfd.cGreenBits) -1;
    int BlueMask  =( 1 << pfd.cBlueBits ) -1;

    for (int i=0;i<NumColors;i++) {
           LPalettep->palPalEntry[i].peRed=(BYTE)
              ((((i >> pfd.cRedShift) & RedMask)     *255)/RedMask);
           LPalettep->palPalEntry[i].peGreen=(BYTE)
              ((((i >> pfd.cGreenShift) & GreenMask) *255)/GreenMask);
           LPalettep->palPalEntry[i].peBlue=(BYTE)
              ((((i >> pfd.cBlueShift) &  BlueMask)  *255)/BlueMask);
          }
    if ((Palette=CreatePalette(LPalettep))==NULL) {
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, SystemMessage, 255, NULL);
        ErrorMsg = "CreatePalette:" + String(SystemMessage);
        Error ();
        return false;
        }
    free(LPalettep);
    if (Palette) {
	    SelectPalette(DisplayDeviceContext, Palette, FALSE);
	    RealizePalette(DisplayDeviceContext);
        }
    return true;
 }
//---------------------------------------------------------------------------
void  TOpenGLAPPanel::Create3DFont(void)  {
     if (Font3DDefault) {
        delete Font3DDefault;
        }
     Font3DDefault=Create3DFont(Font3DType,Font3DFirstGylph,Font3DNumGylph,
                                Font3DMaxDeviation,Font3DExtrusion,
                                SavedFont3DFormat);
  }
//---------------------------------------------------------------------------
void  TOpenGLAPPanel::Create2DFont(void) {
     if (Font2DDefault) {
        delete Font2DDefault;
        }
     Font2DDefault=Create2DFont(Font2DType,Font2DFirstGylph,Font2DNumGylph);
}
//---------------------------------------------------------------------------
// Private Methods (Property)
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::SetPFDPixelType(const TPFDPixelTypes Value)
  {
     if (Value==f_PFD_TYPE_RGBA) {
        SavedPixelType=PFD_TYPE_RGBA;
        }
     else {
        SavedPixelType=PFD_TYPE_COLORINDEX;
        }
     FiPixelType=Value;
     //return;
  }
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::SetToolWindow (const bool Value)
{
    int     NewStyle;

    FToolWindow = Value;

    if (!AllowCreateParms) return;
    if (FToolWindow) {
        SetWindowLong (Handle,GWL_STYLE	, GetWindowLong(Handle,GWL_STYLE) | WS_CAPTION);
        SetWindowLong (Handle,GWL_EXSTYLE,  GetWindowLong(Handle,GWL_EXSTYLE) | WS_EX_TOOLWINDOW);
        }
    else {
        SetWindowLong (Handle,GWL_STYLE	, GetWindowLong(Handle,GWL_STYLE) &~WS_CAPTION);
        SetWindowLong (Handle,GWL_EXSTYLE,  GetWindowLong(Handle,GWL_EXSTYLE) &~WS_EX_TOOLWINDOW);
        }
    // ---- Updating the control
    Width += 1;
    Width -= 1;
}
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::SetBorder (const bool Value)
{
    FBorder = Value;

    if (!AllowCreateParms) return;
    if (FBorder) {
		SetWindowLong (Handle,GWL_EXSTYLE,  GetWindowLong(Handle,GWL_EXSTYLE) | WS_EX_CLIENTEDGE);
        }
    else {
        SetWindowLong (Handle,GWL_EXSTYLE,  GetWindowLong(Handle,GWL_EXSTYLE) &~WS_EX_CLIENTEDGE);
        }
	// ---- Updating the control
	SetWindowPos (Handle, 0, Left, Top, Width, Height, SWP_DRAWFRAME);
}
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::SetAllowResize (const bool Value)
{
    FAllowResize = Value;

    if (!AllowCreateParms) return;
    if (FAllowResize) {
        SetWindowLong (Handle,GWL_STYLE	, GetWindowLong(Handle,GWL_STYLE) | WS_SIZEBOX);
        }
    else {
        SetWindowLong (Handle,GWL_STYLE	, GetWindowLong(Handle,GWL_STYLE) &~WS_SIZEBOX);
        }
	// ---- Updating the control
	SetWindowPos (Handle, 0, Left, Top, Width, Height, SWP_DRAWFRAME);
}
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::SetPFDFlags(const TPFDFlagsSet Value)
  {
   TPFDFlagsSet Temp=Value;


    if ((Value.Contains(f_PFD_SUPPORT_GDI)) &&
        (Value.Contains(f_PFD_DOUBLEBUFFER))) {
        if (FdwFlags.Contains(f_PFD_SUPPORT_GDI)) {
            Temp >> f_PFD_SUPPORT_GDI;
            }
        else {
            Temp >> f_PFD_DOUBLEBUFFER;
            }
       }
   else {
    if ((!Value.Contains(f_PFD_SUPPORT_GDI)) &&
       (!Value.Contains(f_PFD_DOUBLEBUFFER))) {
        if (FdwFlags.Contains(f_PFD_SUPPORT_GDI)) {
            Temp  << f_PFD_DOUBLEBUFFER;
            }
        else {
            Temp << f_PFD_SUPPORT_GDI;
            }
       }
    }
   FdwFlags=Temp;
   return;
  }

//---------------------------------------------------------------------------
//  Function    :   SetPFDNumAccBits ()
//  Description :   Setting the number of accumulator bits
//
//  Author      :   AP
//  Date        :   07.01.2002
//  Comments    :
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::SetPFDNumAccBits(const BYTE Value)
{
   FcAccBits = Value;
}
//--------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::SetPFDNumColorBits(const BYTE Value)
{
   FcColorBits=Value;
}
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::SetPFDNumDepthBits(const BYTE Value)
{
   FcDepthBits=Value;
}
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::SetOpenGLPrintScale(const TOpenGLPrintScale Value)
{
   FOpenGLPrintScale=Value;
}
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::SetOpenGLPixelsPerInch(const int Value)
{
   FOpenGLPixelsPerInch=Value;
}
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::SetFont3DType(TFont* Value)
  {
   Font3DType->Assign(Value);
   return;
  }
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::SetFont3DFormat(const TFont3DFormat Value)
  {
    if (Value==f_WGL_FONT_LINES)
        SavedFont3DFormat=f_WGL_FONT_LINES;
    else
        SavedFont3DFormat=WGL_FONT_POLYGONS;
   Font3DFormat=Value;
   return;
  }
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::SetFont(TFont* Value)
  {
   Font2DType->Assign(Value);
   return;
  }
//---------------------------------------------------------------------------
// Protected Methods
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::WMCreate(TWMCreate &Message)
{
try {
    if (!CreateGLContext()) {
        ErrorMsg = "Open GL Context Create Failed";
        Error ();
        return;
       }

    if (Font3DEnabled)
        Create3DFont();
    if (Font2DEnabled)
        Create2DFont();

    SetToolWindow (FToolWindow);
    SetAllowResize (FAllowResize);
    SetBorder (FBorder);
        
    if (FOnInit)  {
        FOnInit(this);
        }
    }
catch (...)  {
    }

    return;
}
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::WMPaletteChanged(TWMPaletteChanged &Message)
{
    TWMQueryNewPalette Dummy;
    if (Message.PalChg==Handle)
        return;
    WMQueryNewPalette(Dummy);
    return;
}
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::WMQueryNewPalette(TWMQueryNewPalette &Message)
{
    UINT     num;
    HPALETTE OldPalette=SelectPalette(DisplayDeviceContext,Palette,FALSE);
    if ((num=RealizePalette(DisplayDeviceContext))==GDI_ERROR) {
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, SystemMessage, 255, NULL);
        ErrorMsg = "RealizePalette:" + String(SystemMessage);
        Error ();
        return;
        }
    if (MakeOpenGLPanelCurrent() == false) {
        Message.Result=0;
        return;
        }
    wglMakeCurrent(NULL, NULL);
    SelectPalette(GLRenderingContext,OldPalette,TRUE);
    if (num) InvalidateRect(Handle,NULL,TRUE); // Force Repaint
    Message.Result=num;
    return;
}
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::WMDestroy(TWMDestroy &Message)
{
	if (!ComponentState.Contains(csDesigning)) {
		DestroyGLContext();
		}
	TCustomPanel::Dispatch(&Message);
}
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::WMEraseBkgnd(TWMEraseBkgnd &Message)
{
    if (ComponentState.Contains(csDesigning)) {
        TCustomPanel::Dispatch(&Message);
        }
}
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::WMMove (TWMMove &Message)
{
    if (!FAllowMoving) {
        ReleaseCapture ();
        }
}
//---------------------------------------------------------------------------
void   __fastcall TOpenGLAPPanel::CreateParams(TCreateParams &Params)
{
    TCustomPanel::CreateParams(Params);

    Params.Style   |= (WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
    Params.WindowClass.style |= CS_OWNDC;    // Place Holder

    AllowCreateParms = true;

    if (FOnPreInit) FOnPreInit(this);
}
//---------------------------------------------------------------------------
void  __fastcall TOpenGLAPPanel::Error(void)
{
    if (FOnError) {
        FOnError(this);
        }
}
//---------------------------------------------------------------------------
void  __fastcall TOpenGLAPPanel::Paint(void)
{
    HPALETTE OldPalette;
    LARGE_INTEGER        StartTime;
    LARGE_INTEGER        StopTime;

    if (ComponentState.Contains(csDesigning)) {
        return;
        }

    if (Ffps_Enabled)
        QueryPerformanceCounter(&StartTime);

    if (FOnPaint) {
        if (Palette) {
            OldPalette = SelectPalette(DisplayDeviceContext,Palette,FALSE);
            if (!OldPalette) {
                FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, SystemMessage, 255, NULL);
                ErrorMsg = "SelectPalette:" + String(SystemMessage);
                Error ();
                return;
                }
            if (RealizePalette(DisplayDeviceContext)==GDI_ERROR)  {
                FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, SystemMessage, 255, NULL);
                ErrorMsg = "RealizePalette:" + String(SystemMessage);
                Error ();
                return;
                }
            }
        FOnPaint(this);
		if ((FSwapBuffers==Auto) && (DoubleBuffer)) {
			// With multithread applications, flush the drawing commands in any other threads drawing to the same window before calling SwapBuffers
			glFinish ();
			::SwapBuffers(DisplayDeviceContext);
			}
        if (Palette) {
            SelectPalette(DisplayDeviceContext,OldPalette,TRUE);
            }
      }
    if (Ffps_Enabled) {
        QueryPerformanceCounter(&StopTime);
        Fps = 1./(((float)StopTime.QuadPart - (float)StartTime.QuadPart) / (float)Frequency.QuadPart);
        }
}
//---------------------------------------------------------------------------
void  __fastcall TOpenGLAPPanel::Resize(void)
{
    if (FOnResize) {
        FOnResize(this);
        }
}
//---------------------------------------------------------------------------
// Public Methods
//---------------------------------------------------------------------------
bool  __fastcall TOpenGLAPPanel::MakeOpenGLPanelCurrent(void)
{
    if (GLRenderingContext == wglGetCurrentContext() && DisplayDeviceContext == wglGetCurrentDC()) return true;
    if (wglMakeCurrent(DisplayDeviceContext,GLRenderingContext)==false) {
        FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, SystemMessage, 255, NULL);
        ErrorMsg = "wglMakeCurrent:" + String(SystemMessage);
        Error ();
        return false;
        }
    return true;
}

//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::MakeOpenGLPanelNotCurrent(void)
{
    wglMakeCurrent(NULL, NULL);
}
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::SwapBuffers(void)
{
    if (DoubleBuffer) ::SwapBuffers(DisplayDeviceContext);
}
//---------------------------------------------------------------------------
bool __fastcall  TOpenGLAPPanel::PanelShareLists(TOpenGLAPPanel *WithOpenGLPanel)
{
    return(wglShareLists(this->GLRenderingContext,
                         WithOpenGLPanel->GLRenderingContext));
}
//---------------------------------------------------------------------------
BMPTexture * __fastcall TOpenGLAPPanel::LoadBMPTexture(AnsiString FileName, Boolean WithAlpha)
{
 Graphics::TBitmap * Bitmap= new Graphics::TBitmap();
 BMPTexture        * BMPTex =new BMPTexture();;
 try {
     int  Onedarray;

     Bitmap->LoadFromFile(FileName);
     if (WithAlpha) BMPTex->Components=4;
     else BMPTex->Components=3;
     BMPTex->Width= Bitmap->Width;
     BMPTex->Height=Bitmap->Height;
     BMPTex->Format=WithAlpha?GL_RGBA:GL_RGB;
     BMPTex->Type=GL_UNSIGNED_BYTE;
     BMPTex->Pixels = new GLubyte[BMPTex->Width*BMPTex->Height*BMPTex->Components];
     for (long i=0; i<BMPTex->Height; i++)
       for (long j=0; j<BMPTex->Width; j++) {
         Onedarray=i*BMPTex->Width*BMPTex->Components+j*BMPTex->Components;
         BMPTex->Pixels[Onedarray+0] =
                   GetRValue(Bitmap->Canvas->Pixels[j][BMPTex->Height-i-1]);
         BMPTex->Pixels[Onedarray+1] =
                   GetGValue(Bitmap->Canvas->Pixels[j][BMPTex->Height-i-1]);
         BMPTex->Pixels[Onedarray+2] =
                   GetBValue(Bitmap->Canvas->Pixels[j][BMPTex->Height-i-1]);
         if (WithAlpha) BMPTex->Pixels[Onedarray+3] = 255;
        }
     }
 catch (...)
  {
   delete  Bitmap;
   delete  BMPTex;
   return(NULL);
  }
  delete  Bitmap;
  return(BMPTex);

}

//
//---------------------------------------------------------------------------
//  Function    :   LoadTGA ()
//  Description :   Loads a Truevision Targa image file
//  Input       :
//  Output      :
//  Return Code :   0 : OK
//                 -1 : Failed to open file.
//                 -2 : Targa file version
//                 -3 : Targa color map not of 24/32 bit type
//
//  Author      :   AP
//  Date        :   15.08.2000
//  Comments    :   Remember to release "pixels" allocation
//---------------------------------------------------------------------------
int __fastcall  TOpenGLAPPanel::LoadTGA (AnsiString FileName,       // ---- Filename
                                         byte **pixels,
                                         unsigned int *width,
                                         unsigned int *height,
                                         unsigned int *format)
{
	int				columns,
                    rows,
                    numPixels;
	byte		   *ppixbuf;
	int				row,
                    column;
	FILE		   *pfile;
	byte		   *ptarga_rgba;
	targaHeader		targa_header;
    unsigned char   red,
                    green,
                    blue,
                    alphabyte;
    unsigned char   packetHeader,
                    packetSize,
                    jj;


	pfile = fopen (FileName.c_str(), "rb");
	if (!pfile) {
		return (-3);
        }

	//read targa header
	fread( &targa_header.id_length, sizeof(unsigned char), 1, pfile );
	fread( &targa_header.colormap_type, sizeof(unsigned char), 1, pfile );
	fread( &targa_header.image_type, sizeof(unsigned char), 1, pfile );

	fread( &targa_header.colormap_index, sizeof(unsigned short), 1, pfile);
	fread( &targa_header.colormap_length, sizeof(unsigned short), 1, pfile);

	fread( &targa_header.colormap_size, sizeof(unsigned char), 1, pfile);

	fread( &targa_header.x_origin, sizeof(unsigned short), 1, pfile);
	fread( &targa_header.y_origin, sizeof(unsigned short), 1, pfile);
	fread( &targa_header.width, sizeof(unsigned short), 1, pfile);
	fread( &targa_header.height, sizeof(unsigned short), 1, pfile);

	fread( &targa_header.pixel_size, sizeof(unsigned char), 1, pfile);
	fread( &targa_header.attributes, sizeof(unsigned char), 1, pfile);

    // ---- Verifying version, only type 2 and 10 targa images supported
	if (targa_header.image_type != 2 && targa_header.image_type != 10) {
        // ----
		return (-1);
        }

    // ---- Checking color map types, only 24/32 bit supported
	if (targa_header.colormap_type !=0 || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24)) {
		return (-2);
        }

	*format = targa_header.pixel_size;

	columns = targa_header.width;
	rows = targa_header.height;
	numPixels = columns * rows;

	if (width)
		*width = columns;

	if (height)
		*height = rows;

	ptarga_rgba = (unsigned char *) malloc(numPixels*4); // new unsigned char[numPixels*4];
	*pixels = ptarga_rgba;

	if (targa_header.id_length != 0) {
		fseek(pfile, targa_header.id_length, SEEK_CUR); // skip TARGA image comment
        }

    switch (targa_header.image_type) {
        case 2:
            // Uncompressed, RGB images
            for (row=rows-1; row>=0; row--) {
                ppixbuf = ptarga_rgba + row*columns*4;
                for (column=0; column<columns; column++) {
                    switch (targa_header.pixel_size) {
                        case 24:
                            blue  = getc(pfile);
                            green = getc(pfile);
                            red   = getc(pfile);
                            *ppixbuf++ = red;
                            *ppixbuf++ = green;
                            *ppixbuf++ = blue;
                            *ppixbuf++ = 255;
                            break;
                        case 32:
                            blue  = getc(pfile);
                            green = getc(pfile);
                            red   = getc(pfile);
                            alphabyte = getc(pfile);
                            *ppixbuf++ = red;
                            *ppixbuf++ = green;
                            *ppixbuf++ = blue;
                            *ppixbuf++ = alphabyte;
                            break;
                        }
                    }
                }
            break;
        case 10:
            // Runlength encoded RGB images
            for(row=rows-1; row>=0; row--) {
                ppixbuf = ptarga_rgba + row*columns*4;
                for(column=0; column<columns; ) {
                    packetHeader = getc(pfile);
                    packetSize = 1 + (packetHeader & 0x7f);
                    if (packetHeader & 0x80) {
                        // run-length packet
                        switch (targa_header.pixel_size) {
                            case 24:
                                blue  = getc (pfile);
                                green = getc (pfile);
                                red   = getc (pfile);
                                alphabyte = 255;
                                break;

                            case 32:
                                blue  = getc (pfile);
                                green = getc (pfile);
                                red   = getc (pfile);
                                alphabyte = getc(pfile);
                                break;
                            }
                        for (jj=0;jj<packetSize;jj++) {
                            *ppixbuf++=red;
                            *ppixbuf++=green;
                            *ppixbuf++=blue;
                            *ppixbuf++=alphabyte;
                            column++;
                            if (column==columns) {
                                // run spans across rows
                                column=0;
                                if (row>0)
                                    row--;
                                else
                                    goto breakOut;
                                ppixbuf = ptarga_rgba + row*columns*4;
                                }
                            }
                        }
                        else {
                            // non run-length packet
                            for(jj=0;jj<packetSize;jj++) {
                                switch (targa_header.pixel_size) {
                                    case 24:
                                        blue  = getc (pfile);
                                        green = getc (pfile);
                                        red   = getc (pfile);
                                        *ppixbuf++ = red;
                                        *ppixbuf++ = green;
                                        *ppixbuf++ = blue;
                                        *ppixbuf++ = 255;
                                        break;

                                    case 32:
                                        blue  = getc(pfile);
                                        green = getc(pfile);
                                        red   = getc(pfile);
                                        alphabyte = getc(pfile);
                                        *ppixbuf++ = red;
                                        *ppixbuf++ = green;
                                        *ppixbuf++ = blue;
                                        *ppixbuf++ = alphabyte;
                                        break;
                                        }
                                    column++;
                                    if (column==columns) {
                                        // pixel packet run spans across rows
                                        column=0;
                                        if (row>0)
                                            row--;
                                        else
                                            goto breakOut;
                                        ppixbuf = ptarga_rgba + row*columns*4;
                                        }
                                }
                            }
                        }
                breakOut:;
                }
                
	    }

	fclose(pfile);
	return 0;
}

//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::PrinTOpenGLAPPanel(void)
{
 Graphics::TBitmap *BitMap = new Graphics::TBitmap();
unsigned int        BitMapInfoSize,BitMapImageSize,
                    XPixelsPerInch,YPixelsPerInch,
                    XSizeInPixels,YSizeInPixels;
 void              *BitMapImage;
 BITMAPINFO        *BitMapInfo;
 RECT               Rect;

 BitMap->Height= Height;
 BitMap->Width = Width;
 BringToFront();
 Paint();
 BitMap->Canvas->CopyRect(ClientRect ,Canvas,ClientRect);
 XPixelsPerInch=GetDeviceCaps(Printer()->Handle,LOGPIXELSX);
 YPixelsPerInch=GetDeviceCaps(Printer()->Handle,LOGPIXELSY);

 Rect.left  =0.18*XPixelsPerInch;
 Rect.top   =0.18*YPixelsPerInch;

 if (FOpenGLPrintScale==pglPrintToFit)  {
     XSizeInPixels=GetDeviceCaps(Printer()->Handle,HORZRES)-2*Rect.left;
     YSizeInPixels=GetDeviceCaps(Printer()->Handle,VERTRES)-2*Rect.top;
     if (XSizeInPixels > YSizeInPixels) {
         Rect.right=BitMap->Width*(YSizeInPixels/BitMap->Height);
         Rect.bottom=YSizeInPixels;
        }
     else
        {
         Rect.right= XSizeInPixels;
         Rect.bottom = BitMap->Height* (XSizeInPixels / BitMap->Width);
        }
    }
 else
    if (FOpenGLPrintScale==pglProportional) {
     if (FOpenGLPixelsPerInch<=0)  FOpenGLPixelsPerInch=96;

     Rect.right =(int)(((float)BitMap->Width/(float)FOpenGLPixelsPerInch)*
                 (float)XPixelsPerInch)+Rect.left;
     Rect.bottom=(int)(((float)BitMap->Height/(float)FOpenGLPixelsPerInch)*
                 (float)YPixelsPerInch)+Rect.top;
    }
  else  {
     Rect.right =BitMap->Width+Rect.left;
     Rect.bottom=BitMap->Height+Rect.right;
    }

 GetDIBSizes(BitMap->Handle,BitMapInfoSize, BitMapImageSize);
 BitMapInfo=(BITMAPINFO *)malloc(BitMapInfoSize);
 BitMapImage=malloc(BitMapImageSize);
 if ((BitMapInfo==NULL) || (BitMapImage==NULL)) {
    ErrorMsg = "Print: Malloc Error";
    Error ();
   if (BitMapInfo) free(BitMapInfo);
   if (BitMapImage) free(BitMapImage);
   return;
  }
 Printer()->BeginDoc();
 GetDIB(BitMap->Handle,BitMap->Palette,BitMapInfo,BitMapImage);
 StretchDIBits(Printer()->Canvas->Handle,
              Rect.left,Rect.top,
              Rect.right-Rect.left,
              Rect.bottom-Rect.top,
              0,0,
              BitMap->Width,BitMap->Height,
              BitMapImage,
              BitMapInfo,
              DIB_RGB_COLORS,
              SRCCOPY);
 free(BitMapInfo);
 free(BitMapImage);
 Printer()->EndDoc();
 delete BitMap;
 return;
}
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::SaveOpenGLPanelToFile(const String &FileName)
{
    Graphics::TBitmap *BitMap = new Graphics::TBitmap();
    BitMap->Height= Height;
    BitMap->Width = Width;
    BringToFront();
    Paint();
    BitMap->Canvas->CopyRect(ClientRect ,Canvas,ClientRect);
    BitMap->SaveToFile(FileName);
    delete BitMap;
    return;
}
//---------------------------------------------------------------------------
OpenGLAPFont3D * __fastcall  TOpenGLAPPanel::Create3DFont(TFont *Font,
                                                     int FirstGylph,
                                                     int NumGylph,
                                                     float Deviation,
                                                     float Extrusion,
                                                     int Format)
{
 HFONT           HFont;
 LOGFONT         LogFont;
 GLuint          Base;
 OpenGLAPFont3D *Font3D;

 if (Font==NULL) return(NULL);
 if ((Base=glGenLists(NumGylph))==0) return(NULL);

 Font3D = new OpenGLAPFont3D();

 Font3D->FirstGylph=FirstGylph;
 Font3D->NumGylph=NumGylph;
 Font3D->ListBase=Base;
 Font3D->Extrusion=Extrusion;
 Font3D->GlyphMetrics= new GLYPHMETRICSFLOAT[NumGylph];
 GetObject(Font->Handle,sizeof(LOGFONT),&LogFont);
 HFont = CreateFontIndirect(&LogFont);
 SelectObject (DisplayDeviceContext, HFont);
 wglUseFontOutlines(DisplayDeviceContext, FirstGylph, NumGylph, Base,
                      Deviation, Extrusion, Format, Font3D->GlyphMetrics);
 DeleteObject(HFont);
 return(Font3D);
 }
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::Get3DTextSize(AnsiString Text,GLdouble *XYZ)
{
  Get3DTextSize(Font3DDefault,Text,XYZ);
}
//---------------------------------------------------------------------------
void __fastcall  TOpenGLAPPanel::Get3DTextSize(OpenGLAPFont3D *Font,
                                            AnsiString Text,GLdouble *XYZ)
{
 unsigned char *c=(unsigned char *)Text.c_str();
 int          Index,Length=strlen((char *)c)-1;

    if ((Font==NULL)||(XYZ==NULL)||(Length==0)) return;
    XYZ[0]=0.0;
    XYZ[1]=0.0;
    XYZ[2]=Font->Extrusion;
    for (int i=0;i<Length;i++) {
        Index=c[i]- Font->FirstGylph;
        if ((Index<0)||(Index>Font->NumGylph-1)) {
            XYZ[0]=XYZ[1]=XYZ[2]=0.0;
            return;
            }
       XYZ[0]+=Font->GlyphMetrics[Index].gmfCellIncX;
       XYZ[1]+=Font->GlyphMetrics[Index].gmfCellIncY;
      }
  Index=c[Length]- Font->FirstGylph;
  if ((Index<0)||(Index>Font->NumGylph-1)) {
      XYZ[0]=XYZ[1]=XYZ[2]=0.0;
      return;
      }
      XYZ[0]+=Font->GlyphMetrics[Index].gmfBlackBoxX;
      XYZ[1]+=Font->GlyphMetrics[Index].gmfBlackBoxY;
      return;
}
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::Draw3DText(AnsiString Text)
 {
  Draw3DText(Font3DDefault,Text);
 }
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::Draw3DText(OpenGLAPFont3D *Font,AnsiString Text)
{
  GLint  FaceMode;
  unsigned char *c=(unsigned char *)Text.c_str();
  int            Index,Length=strlen((char *)c);
  
    if ((Font==NULL)||(Length==0)) return;
    for (int i=0;i<Length;i++) {
        Index=c[i]- Font->FirstGylph;
        if ((Index<0)||(Index>Font->NumGylph-1)) return;
        }
    glPushAttrib(GL_LIST_BIT);
    glGetIntegerv(GL_FRONT_FACE,&FaceMode);
    glListBase(Font->ListBase-Font->FirstGylph);
    glCallLists (Length, GL_UNSIGNED_BYTE,c);
    glFrontFace(FaceMode);
    glPopAttrib();
    return;
}
//---------------------------------------------------------------------------
OpenGLAPFont2D * __fastcall TOpenGLAPPanel::Create2DFont(TFont *Font,
                                                     int FirstGylph,
                                                     int NumGylph)
{
 HFONT         HFont;
 LOGFONT       LogFont;
 GLuint        Base;

 if (Font==NULL) return(NULL);
 if ((Base=glGenLists(NumGylph))==0) return(NULL);
 OpenGLAPFont2D *Font2D=new OpenGLAPFont2D();
 Font2D->FirstGylph=FirstGylph;
 Font2D->NumGylph=NumGylph;
 Font2D->ListBase=Base;
 GetObject(Font->Handle,sizeof(LOGFONT),&LogFont);
  //  FYI To go from LogFont -> Handle use:
  //  Font->Handle =CreateFontIndirect(LogFont);
 HFont = CreateFontIndirect(&LogFont);
 SelectObject (DisplayDeviceContext, HFont);
 wglUseFontBitmaps(DisplayDeviceContext, FirstGylph, NumGylph, Base);
 DeleteObject(HFont);
 return(Font2D);
 }
//---------------------------------------------------------------------------
// Hint : Use glRasterPos3f() instead of glTranslatef
//        to position 2d text.      
//---------------------------------------------------------------------------
void __fastcall  TOpenGLAPPanel::Draw2DText(AnsiString Text)
{
    Draw2DText(Font2DDefault,Text);
}
//---------------------------------------------------------------------------
void __fastcall TOpenGLAPPanel::Draw2DText(OpenGLAPFont2D *Font,AnsiString Text)
{
  unsigned char *c=(unsigned char *)Text.c_str();
  int            Index,Length=strlen((char *)c);

    if ((Font==NULL)||(Length==0)) return;
    for (int i=0;i<Length;i++) {
         Index=c[i]- Font->FirstGylph;
         if ((Index<0)||(Index>Font->NumGylph-1)) return;
         }
    glPushAttrib(GL_LIST_BIT);
    glListBase(Font->ListBase-Font->FirstGylph);
    glCallLists (Length, GL_UNSIGNED_BYTE,c);
    glPopAttrib();
    return;
}
//---------------------------------------------------------------------------
//
//---------------------------------------------------------------------------
bool __fastcall TOpenGLAPPanel::QueryOpenGLExtention(AnsiString ExtentionName)
{
 char *GLExtentions,*LastChar,*ExtQName=ExtentionName.c_str();
 int   ExtLen,ExtQNameLen= strlen(ExtQName);
 if ((GLExtentions =(char *)glGetString(GL_EXTENSIONS))==NULL) return(false);

 LastChar = GLExtentions + strlen(GLExtentions);

 while (GLExtentions < LastChar) {
    ExtLen= strcspn(GLExtentions, " ");
    if ((ExtQNameLen == ExtLen) && (strncmp(ExtQName,GLExtentions,ExtLen) == 0))
        return true;
    GLExtentions += (ExtLen + 1);
    }
  return false;
}
//---------------------------------------------------------------------------
int __fastcall   TOpenGLAPPanel::GetDisplayBPP(void)
{
    int BPP;
    HDC DeviceContext=GetDC(NULL);
    BPP=GetDeviceCaps(DeviceContext,BITSPIXEL);
    ReleaseDC(NULL,DeviceContext);
    return(BPP);
}
//---------------------------------------------------------------------------
bool __fastcall TOpenGLAPPanel::SetDisplayBPP(int BPP)
{
  // Warning:: this code does not work correctly
  // It was intended to be executed in the OnPreInit Event
  // The display mode changes but then GL Initializaion Fails??
  DEVMODE LPDevMode;
  ZeroMemory(&LPDevMode,sizeof(LPDevMode));
  LPDevMode.dmSize=sizeof(LPDevMode);
  LPDevMode.dmBitsPerPel=BPP;
  LPDevMode.dmFields=DM_BITSPERPEL;
  return(ChangeDisplaySettings(&LPDevMode,0)==DISP_CHANGE_SUCCESSFUL?true:false);
}

