(*
/*
// (C) by Vladimir Kladov, 2017

CLASS {AL4_OpenGL|_Delphi_VCL_FPC}, NATIVE, UNTESTED :
      IMPORT: {OpenGL} .

NATIVE:@"uses AL4_OpenGL, AL4_form, Forms"
		" {$IFDEF LINUX}"
		" {$ELSE}"
		"	, Windows, Messages "
		" {$ENDIF} ;" .
		
NATIVE: "{$I AL4_options.inc}" .		
		
*/
*)

unit AL4_OpenGL;

interface


{$I AL4_options.inc}

uses 
	 	SysUtils, Classes, Forms, Controls,
// use AL4 to access system functions (AL4.pas inserted by the compiler into
// a project folder)
     AL4,
// use All_classes from a project folder (generated for a certain project)
     All_classes,
     AL4_form, unitC_Control {to access NoneObj_C_Control},
     	StdCtrls, ExtCtrls, ComCtrls, Dialogs,
     {$IFNDEF LINUX}
	     		Windows, Messages,
     {$ENDIF}
     
     {$IFDEF SIMULATE_QUADRICS}
     	{$DEFINE NEED_MATH}
     {$ENDIF}
     
     {$IFDEF FPC}
     	gl, glu, openglcontext
     {$ELSE}
     	OpenGL
     {$ENDIF}
     {$IFDEF NEED_MATH}
     		, Math
     {$ENDIF}
     ;

type

    TOpenGLbox = class(
    	{$IFDEF FPC} 
    		TOpenGLControl
    	{$ELSE}
    		TWinControl
    	{$ENDIF})
    	
    public
        AL4Form: TAL4Form;
        Is_initialized: Boolean;
        {$IFDEF FPC}
        	procedure GLboxPaint(Sender: TObject);
        {$ELSE Delphi/VCL + Windows}
	        DC: HDC;
	        RC: HGLRC;
	        procedure WMPaint(var M: TMessage); message WM_PAINT;
	        procedure WMErase(var M: TMessage); message WM_ERASEBKGND;
        {$ENDIF}
        constructor Create(AOwner: TComponent); override;
        destructor Destroy; override;
        procedure Initialize_OpenGL;
    end;
    
function Do_Create_opengl_control(P: Integer; X_GL: Pointer): Integer;  
procedure Do_GenTextures(N: Integer; Textures: DynAInt);  
procedure Do_DeleteTextures(N: Integer; Textures: DynAInt);
function Do_IsTexture(Texture: Integer): Boolean;

var All_textures: TList;
var glBindTexture: procedure(Target: LongWord; Texture: LongWord); stdcall;
var glTexSubImage1D: procedure( target: LongWord; 
                                level: Integer; 
                                xoffset: Integer; 
                                width: Integer; 
                                format: LongWord; 
                                _type: LongWord; 
                                const pixels: Pointer); stdcall;
var glTexSubImage2D: procedure( target: LongWord;
                                level: Integer;
                                xoffset: Integer;
                                yoffset: Integer;
                                width: Integer;
                                height: Integer;
                                format: LongWord;
                                _type: LongWord;
                                const pixels: Pointer); stdcall;
var glPolygonOffset: procedure( Factor: GLFloat; Units: GLFloat ); stdcall;
var glPushClientAttrib: procedure( Mask: LongWord ); stdcall;
var glPopClientAttrib: procedure; stdcall;

{$IFDEF LINUX}
{$ELSE}
function GLProcAddress(const ProcName: String): Pointer;
{$ENDIF}
var GLLib: THandle;

procedure Turn_VSync_off;

type TglPolygonOffset = procedure(p1: GLFloat; p2: GLFloat); stdcall;
	 TglPushClientAttrib = procedure(p1: LongWord); stdcall;
	 TglPopClientAttrib = procedure; stdcall;
	 TglBindTexture = procedure(p1: LongWord; p2: LongWord); stdcall;
	 TglTexSubImage1D = procedure(p1: LongWord; p2,p3,p4: LongInt; 
	 	p5,p6: LongWord; const p7: Pointer); stdcall;
	 TglTexSubImage2D = procedure(p1: LongWord; p2,p3,p4,p5,p6: LongInt;
	 	p7,p8: LongWord; const p9: Pointer); stdcall;
	 	
function Is_linux: Boolean;

{$IFDEF SIMULATE_GLBEGIN_GLEND}
	{$DEFINE sim_glBEGIN_glEND_OR_QUADRICS}
{$ENDIF}
{$IFDEF SIMULATE_QUADRICS}
	{$DEFINE sim_glBEGIN_glEND_OR_QUADRICS}
{$ENDIF}


{$IFnDEF _D6orHigher}
type PInteger = ^Integer;
{$ENDIF}

{$IFDEF sim_glBEGIN_glEND_OR_QUADRICS}

{$IFNDEF FPC}
const 
  GL_VERTEX_ARRAY                   = $8074;
  GL_NORMAL_ARRAY                   = $8075;
  GL_COLOR_ARRAY                    = $8076;
  GL_TEXTURE_COORD_ARRAY            = $8078;
procedure glEnableClientState(aarray: GLenum); stdcall; external 'opengl32';
procedure glDisableClientState(aarray: GLenum); stdcall; external 'opengl32';
procedure glVertexPointer(size: GLint; atype: GLenum; stride: GLsizei; 
	const pointer:Pointer); stdcall; external 'opengl32';
procedure glColorPointer(size: GLint; atype: GLenum; stride: GLsizei;
	const pointer: Pointer); stdcall; external 'opengl32';
procedure glNormalPointer(atype: GLenum; stride: GLsizei; 
	const pointer: Pointer); stdcall; external 'opengl32'; 
procedure glTexCoordPointer(size: GLint; atype: GLenum; stride: GLsizei;
	const pointer:Pointer); stdcall; external 'opengl32';
procedure glDrawArrays(mode: GLenum; first: GLint; count: GLsizei);
	stdcall; external 'opengl32';
procedure glDrawElements(mode: GLenum; count: GLsizei; type_: GLenum;
	const indices:Pointer); stdcall; external 'opengl32';
{$ENDIF}
procedure sim_glBegin(mode: Integer);
procedure sim_glEnd;
function sim_glGenLists(Count: Integer): Integer;
procedure sim_glDeleteLists(List, Count: Integer);
procedure sim_glNewList(List, Mode: Integer);
procedure sim_glEndList;
function sim_glIsList(List: Integer): Boolean;
procedure sim_glListBase(Base: Integer);
procedure sim_glCallList(List: Integer);
procedure sim_glCallLists(Count: Integer; Lists: PInteger);
procedure sim_glVertex3f(X, Y, Z: GLFloat);
procedure sim_glVertex4f(X, Y, Z, W: GLFloat);
procedure sim_glTexCoord2f(X, Y: GLFloat);
procedure sim_glTexCoord3f(X, Y, Z: GLFloat);
procedure sim_glTexCoord4f(X, Y, Z, W: GLFloat);
procedure sim_glColor3f(R, G, B: GLFloat);
procedure sim_glColor4f(R, G, B, A: GLFloat);
procedure sim_glNormal3f(X, Y, Z: GLFloat);
procedure sim_glTranslatef(X, Y, Z: GLFloat);
{$ENDIF}

{$IFDEF sim_glBEGIN_glEND_OR_QUADRICS}
type
	Tsim_List = class
		BE_mode: Integer; // GL_LINES, GL_TRIANGLES, GL_QUADS, GL_QUAD_STRIP, ...
		Count_vertexes: Integer;
		Vertexes: packed array of GLFloat; // Vertex_Components coordinates per vertex
		TexCoords: packed array of GLFloat; // Tex_Components coordinates per vertex
		Colors: packed array of GLFloat; // 4 components per vertex
		Normals: packed array of GLFloat; // 3 coordinates per a normal
		Indices: packed array of SmallInt;
		//----------------------
		Used_TexCoord: Boolean;
		Used_Colors: Boolean;
		Used_Normals: Boolean;
		Vertex_Components: Integer; // 3 or 4
		Tex_Components: Integer; // 2, 3 or 4
		Color_Components: Integer; // 3 or 4
		Cur_Tex_Coord_X, Cur_Tex_Coord_Y, Cur_Tex_Coord_Z, 
			Cur_Tex_Coord_W: GLFloat;
		Cur_Normal_X, Cur_Normal_Y, Cur_Normal_Z: GLFloat;
		//----------------------
		Translate_X, Translate_Y, Translate_Z: GLFloat;
		//----------------------
		procedure Add_vertex(X, Y, Z, W: GLFloat; Components: Integer);
		procedure Add_tex_coord(X, Y, Z, W: GLFloat);
		procedure Add_color(R, G, B, A: GLFloat);
		procedure Add_normal(X, Y, Z: GLFloat);
		procedure Execute;
	end;
{$ENDIF}

{$IFDEF SIMULATE_QUADRICS}
type 
	 TQuadricDrawStyle = (qdsFill, qdsLine, qdsSilhouette, qdsPoint);
	 TQuadricShape = (qsCylinder, qsDisk, qsSphere);
	 
	 Tsim_Quadric = class
	 	Direction_inside: Boolean;
	 	Need_normals: Boolean;
	 	Normals_smooth: Boolean;
	 	Draw_style: TQuadricDrawStyle;
	 	Need_texture: Boolean;
	 	Def: Tsim_List;
	 	//----------------- parameters stored to define if to re-generate
	 	Shape: TQuadricShape;
	 	P_base, P_top, P_height, P_radius: GLFloat;
	 	P_slices, P_stacks, P_loops: GLint;
	 	P_inner, P_outer, P_start, P_sweep: GLFloat;
	 end;
	 
{$IFDEF USE_LISTS_OF_DESCRIPTORS}
var All_quadrics: TList;

function allocate_quadric(q: Tsim_Quadric): Integer;
procedure release_quadric(i: Integer);
{$ENDIF}
	 
function sim_gluNewQuadric: Tsim_Quadric;
procedure sim_gluDeleteQuadric(q: Tsim_Quadric);
procedure sim_gluQuadricDrawStyle(q: Tsim_Quadric; ds: GLenum);
procedure sim_gluQuadricOrientation(q: Tsim_Quadric; orientation: GLenum);
procedure sim_gluQuadricNormals(q: Tsim_Quadric; normals: GLenum);
procedure sim_gluQuadricTexture(q: Tsim_Quadric; texture: GLenum);
procedure sim_gluCylinder(q: Tsim_Quadric; base, top, height: GLFloat;
	slices, stacks: GLint);
procedure sim_gluPartialDisk(q: Tsim_Quadric; inner, outer: GLFloat;
	slices, loops: GLint; start, sweep: GLFloat);
procedure sim_gluDisk(q: Tsim_Quadric; inner, outer: GLFloat;
	slices, loops: GLint);
procedure sim_gluSphere(q: Tsim_Quadric; radius: GLFloat;
	slices, stacks: GLint);
{$ENDIF}


{$IFnDEF FPC}
function  gluBuild2DMipmaps (target: GLenum; components, width, height: GLint;
//																height
// was forgotten in Delphi5 OpenGL.pas
                             format, atype: GLenum; data: Pointer): Integer;
                             stdcall; external glu32;
{$ENDIF}

implementation

//-------------------------------------------------------- O P E N   G L   B O X

function Is_linux: Boolean;
begin
	RESULT := {$IFDEF LINUX} TRUE {$ELSE} FALSE {$ENDIF} ;
end;

(*
/*

FUN Is_linux ==> BOOL, NATIVE:
	"RESULT := Is_linux;" .

// Create Open GL control, return descriptor.
//-------------------------------------------
FUN Create_opengl_control({OpenGL} GL|_control) ==> INT, NATIVE :
        ---------------------------------------- 'redirect to GL control create'
        INT f|orm_handle = GL_control.Form_.Handle
        NATIVE "    RESULT := Do_Create_opengl_control(X_f, X_GL);" .
*/
*)
function Do_Create_opengl_control(P: Integer; X_GL: Pointer): Integer;
var Parent: TAL4Column;
    G: TOpenGLbox;
    F: TAL4Form;
begin
	F := form_from_handle(P);
    Parent := F.Get_current_column;
    G := TOpenGLbox.Create(Parent);
    G.AL4Form := Parent.Parent as TAL4Form;
    {$IFDEF FPC}
    	G.Tag := Int64(X_GL);
    {$ELSE}
    	G.Tag := Integer(X_GL);
    {$ENDIF}
    G.Parent := Parent;
    {$IFnDEF USE_CONTROL_3D}
    	G.TabStop := TRUE;
    {$ENDIF}
    Adjust_control_location(Parent, G);
    
    G.Initialize_OpenGL;
    
    Set_control_events(Parent, G);
    Set_Win_control_events(Parent, G);
    {$IFDEF USE_LISTS_OF_DESCRIPTORS}
    	Result := allocate_control(G);
    {$ELSE}
    	Result := Integer(G);
    {$ENDIF}
end;

procedure Do_GenTextures(N: Integer; Textures: DynAInt);  
var i, j: Integer;
begin
    if All_textures = nil then 
    begin 
        All_textures := TList.Create;
        All_textures.Add(Pointer(-1));
    end;
    for i := 0 to N-1 do
    begin
        j := All_textures.IndexOf(nil);
        if j < 0 then
        begin
            j := All_textures.Count;
            All_textures.Add(nil);
        end;
        All_textures[j] := Pointer(1);
        Textures.Add(MAXINT, j);
    end;
end;

procedure Do_DeleteTextures(N: Integer; Textures: DynAInt); 
var i, j: Integer;
begin
    if All_textures = nil then Exit;
    for i := 0 to N-1 do
    begin 
        if i >= Textures.Count() then Exit;
        j := Textures.GetIntegers(i);
        if (j >= 1) and (j < All_textures.Count) then
            All_textures[j] := nil;
    end;
end;

function Do_IsTexture(Texture: Integer): Boolean;
begin
    Result := (Texture > 0) and (Texture < All_textures.Count) and 
        (All_textures[Texture] = Pointer(1));
end;

{$IFDEF LINUX}
{$ELSE}
function GLProcAddress(const ProcName: String): Pointer;
begin
    Result := nil;
    if GLLib = 0 then
       GLLib := LoadLibrary('OpenGL32.dll');
    if GLLib = 0 then Exit;
    Result := GetProcAddress(GLLib, PChar(ProcName));
end;
{$ENDIF}

{ TOpenGLbox }

{$IFnDEF FPC}  

procedure setupPixelFormat(DC:HDC);
const
   pfd:TPIXELFORMATDESCRIPTOR = (
        nSize:sizeof(TPIXELFORMATDESCRIPTOR);	// size
        nVersion:1;			                    // version
        dwFlags:PFD_SUPPORT_OPENGL or PFD_DRAW_TO_WINDOW or
                PFD_DOUBLEBUFFER;	// support double-buffering
        iPixelType:PFD_TYPE_RGBA;	// color type
        cColorBits:24;			    // preferred color depth
        cRedBits:0; cRedShift:0;	// color bits (ignored)
        cGreenBits:0;  cGreenShift:0;
        cBlueBits:0; cBlueShift:0;
        cAlphaBits:0;  
        cAlphaShift:0;              // no alpha buffer
        cAccumBits: 0;
        cAccumRedBits: 0;  		    // no accumulation buffer,
        cAccumGreenBits: 0;     	// accum bits (ignored)
        cAccumBlueBits: 0;
        cAccumAlphaBits: 0;
        cDepthBits:16;			    // depth buffer
        cStencilBits:0;			    // no stencil buffer
        cAuxBuffers:0;			    // no auxiliary buffers
        iLayerType:PFD_MAIN_PLANE;  // main layer
        bReserved: 0;
        dwLayerMask: 0;             // no layer
        dwVisibleMask: 0;           // visible
        dwDamageMask: 0;            // damage masks
   );
var pixelFormat:integer;
begin
   pixelFormat := ChoosePixelFormat(DC, @pfd);
   if (pixelFormat = 0) then exit;
   if (not SetPixelFormat(DC, pixelFormat, @pfd)) then exit;
end;

{$ENDIF}

constructor TOpenGLbox.Create(
	AOwner: TComponent);
begin
  inherited;
  {$IFDEF FPC}
  	  //AlphaBits := 8;  
	  AutoResizeViewport := true;
	  MultiSampling := 4;
	  OnPaint := @GLboxPaint;
	  Invalidate;
  {$ELSE ?(Windows)?}
  {$ENDIF}
  Width := AL4_form.Points(200);
  Height := AL4_form.Points(200);
end;

destructor TOpenGLbox.Destroy;
begin
	{$IFDEF USE_LISTS_OF_DESCRIPTORS}
		release_control(Self);
	{$ENDIF}
    inherited;
end;

procedure TOpenGLbox.Initialize_OpenGL;
begin
	{$IFDEF FPC}
	{$ELSE}
	  DC := GetDC(Handle);
	  SetupPixelFormat(DC);
	  RC:=wglCreateContext(DC); //makes OpenGL window out of DC
	  wglMakeCurrent(DC, RC);   //makes OpenGL window active
	  //ReleaseDC(Handle, DC);
  	{$ENDIF}
  	Is_initialized := true;
end;

procedure paint_open_gl(
F: C_Form; Sender: C_Control);
var save: String;
begin
    save := F.F_menu_alias;
    F.F_menu_alias := Sender.F_Alias;
    try
	    operation_started(22, F, nil);
		try
	    F.M_Paint;
	    except on EStop: Stop_exception do;
	    end;
    finally
    	{$IFDEF FPC}
	    	F.F_menu_alias.Assign_String(save);
     	{$ELSE}
	    	F.F_menu_alias := save;
    	{$ENDIF}
    	operation_ended(22, F);
    end;    
end;

{$IFDEF FPC}

procedure TOpenGLbox.GLboxPaint(
	Sender: TObject);
var R: TRect;
    F: C_Form;
begin
	if not Is_initialized then
	begin
		//if true then 
		//	writeln('!calling TOpenGLbox.GLboxPaint but OpenGL is not initialized');
		Exit;
	end;
    R := GetClientRect();
    
    glViewport(0, 0, R.Right - R.Left, R.Bottom - R.Top);
    F := C_Form( AL4Form.AL4Object.Obj );
    paint_open_gl(F, C_Control(ref_obj_from_control(Self).Obj));
    SwapBuffers;
end;

{$ELSE DELPHI/VCL}

procedure TOpenGLbox.WMErase(
var M: TMessage);
begin
    M.Result := 1;
end;

procedure TOpenGLbox.WMPaint(
var M: TMessage);
var R: TRect;
    F: C_Form;
    Cogl: C_Control;
begin
    R := GetClientRect;
    wglMakeCurrent(DC, RC);
    
    glViewport(0, 0, R.Right - R.Left, R.Bottom - R.Top);
    
    F := C_Form( AL4Form.AL4Object.Obj );
    Cogl := C_Control((ref_obj_from_control(Self)).Obj); 
    paint_open_gl(F, Cogl);
    
    ValidateRect(Handle, nil);
    SwapBuffers(DC);
    M.Result := 0;
end;

{$ENDIF FPC_DELPHI}

{$IFDEF sim_glBEGIN_glEND_OR_QUADRICS}
var Temp_List: Tsim_List; 
	Cur_List: Tsim_List;
	Cur_List_index: Integer;
	New_List_Mode: Integer;

procedure sim_glBegin(mode: Integer);
begin
	if Cur_List = nil then
	begin
		if Temp_List = nil then
			Temp_List := Tsim_List.Create;
		Cur_List := Temp_List;
		Cur_List_index := 0;
	end;
	Cur_List.BE_mode := mode;
	Cur_List.Used_Colors := false;
	Cur_List.Used_TexCoord := false;
	Cur_List.Used_Normals := false;
	Cur_List.Count_vertexes := 0;
	Cur_List.Color_Components := 0;
	Cur_List.Tex_Components := 0;
	Cur_List.Vertex_Components := 0;
	Cur_List.Translate_X := 0;
	Cur_List.Translate_Y := 0;
	Cur_List.Translate_Z := 0;
	SetLength(Cur_List.Indices, 0);
end;

procedure sim_glEnd;
begin
	if Cur_List = nil then Exit;
	if New_List_Mode = GL_COMPILE then Exit;
	Cur_List.Execute;
end;

var sim_Lists: TList;

function sim_glGenLists(
Count: Integer): Integer;
var i, j: Integer;
begin
	Result := 0;
	if (Count <= 0) or (Count >= 1000) then Exit;
	if sim_Lists = nil then
	begin
		sim_Lists := TList.Create;
		sim_Lists.Add(nil);
	end;
	for i := 1 to sim_Lists.Count-Count do
	begin
		if sim_Lists[i] <> nil then continue;
		Result := i;
		for j := i+1 to i+Count-1 do
			if sim_Lists[j] <> nil then
			begin
				Result := 0;
				break;
			end;
		if Result > 0 then break;
	end;
	if Result = 0 then
	begin
		for i := sim_Lists.Count-1 downto 1 do
		begin
			if sim_Lists[i] <> nil then break;
			Result := i;
		end;
	end;
	if Result = 0 then Result := sim_Lists.Count;
	for i := Result to Result + Count-1 do
	begin
		if i >= sim_Lists.Count then sim_Lists.Add(nil);
		sim_Lists[i] := Tsim_List.Create;
	end;
end;

procedure sim_glDeleteLists(
List, Count: Integer);
var i: Integer;
begin
	if sim_Lists = nil then Exit;
	for i := List to List+Count-1 do
	begin
		if i >= sim_Lists.Count then Exit;
		if sim_Lists[i] = nil then continue;
		Tsim_List(sim_Lists[i]).Free;
		sim_Lists[i] := nil;
	end; 
end;

procedure sim_glNewList(
List, Mode: Integer);
begin
	if not sim_glIsList(List) then Exit;
	Tsim_List(sim_Lists[List]).Free;
	sim_Lists[List] := Tsim_List.Create;
	Cur_List := Tsim_List(sim_Lists[List]);
	Cur_List_index := List;
	New_List_Mode := Mode;
end;

procedure sim_glEndList;
begin
	Cur_List := nil;
	New_List_Mode := 0;
end;

function sim_glIsList(
List: Integer): Boolean;
begin
	Result := false;
	if (sim_Lists = nil) or (List <= 0) then Exit;
	if List >= sim_Lists.Count then Exit;
	if sim_Lists[List] = nil then Exit;
	Result := true;
end;

var sim_Base_list: Integer;

procedure sim_glListBase(Base: Integer);
begin
	sim_Base_list := Base;
end;

procedure sim_glCallList(List: Integer);
var sList: Tsim_List;
begin
	if not sim_glIsList(List) then Exit;
	sList := Tsim_List(sim_Lists[List]);
	sList.Execute;
end;

procedure sim_glCallLists(
Count: Integer; Lists: PInteger);
begin
	while Count > 0 do
	begin
		sim_glCallList(Lists^ + sim_Base_list);
		inc(Lists);
		dec(Count);
	end;
end;

procedure sim_glVertex3f(
X, Y, Z: GLFloat);
begin
	if Cur_List = nil then Exit;
	Cur_List.Add_vertex(X, Y, Z, 1, 3);
end;

procedure sim_glVertex4f(
X, Y, Z, W: GLFloat);
begin
	if Cur_List = nil then Exit;
	Cur_List.Add_vertex(X, Y, Z, W, 4);
end;

procedure sim_glTexCoord2f(
X, Y: GLFloat);
begin
	if Cur_List = nil then Exit;
	Cur_List.Used_TexCoord := true;
	Cur_List.Cur_tex_coord_X := X;
	Cur_List.Cur_tex_coord_Y := Y;
	Cur_List.Cur_tex_coord_Z := 0;
	Cur_List.Cur_tex_coord_W := 0;
	if Cur_List.Tex_Components = 0 then Cur_List.Tex_Components := 2;
end;

procedure sim_glTexCoord3f(
X, Y, Z: GLFloat);
begin
	if Cur_List = nil then Exit;
	Cur_List.Used_TexCoord := true;
	Cur_List.Cur_tex_coord_X := X;
	Cur_List.Cur_tex_coord_Y := Y;
	Cur_List.Cur_tex_coord_Z := Z;
	Cur_List.Cur_tex_coord_W := 0;
	if Cur_List.Tex_Components = 0 then Cur_List.Tex_Components := 3;
end;

procedure sim_glTexCoord4f(
X, Y, Z, W: GLFloat);
begin
	if Cur_List = nil then Exit;
	Cur_List.Used_TexCoord := true;
	Cur_List.Cur_tex_coord_X := X;
	Cur_List.Cur_tex_coord_Y := Y;
	Cur_List.Cur_tex_coord_Z := Z;
	Cur_List.Cur_tex_coord_W := W;
	if Cur_List.Tex_Components = 0 then Cur_List.Tex_Components := 4;
end;

var
	Last_color_R,
	Last_color_G,
	Last_color_B,
	Last_color_A: GLFloat;

procedure sim_glColor3f(
R, G, B: GLFloat);
begin
	if Cur_List = nil then Exit;
	Cur_List.Used_Colors := true;
	Last_color_R := R;
	Last_color_G := G;
	Last_color_B := B;
	Last_color_A := 1;
	if Cur_List.Color_Components = 0 then
		Cur_List.Color_Components := 4; //3; at list on one Android device
										// vlaue of 3 leads to glGetError=1281
										// =GL_INVALID_VALUE
end;

procedure sim_glColor4f(
R, G, B, A: GLFloat);
begin
	if Cur_List = nil then Exit;
	Last_color_R := R;
	Last_color_G := G;
	Last_color_B := B;
	Last_color_A := A;
	if Cur_List.Color_Components = 0 then
		Cur_List.Color_Components := 4;
end;

procedure sim_glNormal3f(
X, Y, Z: GLFloat);
begin
	if Cur_List = nil then Exit;
	Cur_List.Used_Normals := true;
	Cur_List.Cur_Normal_X := X;
	Cur_List.Cur_Normal_Y := Y;
	Cur_List.Cur_Normal_Z := Z;
end;

procedure sim_glTranslatef(
X, Y, Z: GLFloat);
begin
	if New_List_Mode <> GL_COMPILE then
		glTranslatef(X, Y, Z);
	if Cur_List <> nil then
	begin
		Cur_List.Translate_X := Cur_List.Translate_X + X;
		Cur_List.Translate_Y := Cur_List.Translate_Y + Y;
		Cur_List.Translate_Z := Cur_List.Translate_Z + Z;
	end;
end;

function Max(X, Y: Integer): Integer;
begin
	Result := X;
	if X < Y then Result := Y;
end;

procedure Tsim_List.Add_vertex(
X, Y, Z, W: GLFloat; Components: Integer);
begin
	if Count_vertexes = 0 then Vertex_Components := Components;
	if Count_vertexes + Vertex_Components >= Length(Vertexes) then
	begin
		SetLength(Vertexes, 
			Max( Length(Vertexes) + 1024,
				 Length(Vertexes) * 3 div 2));
	end; 
	Vertexes[Count_vertexes] := X;
	Vertexes[Count_vertexes+1] := Y;
	Vertexes[Count_vertexes+2] := Z;
	if Vertex_Components = 4 then
		Vertexes[Count_vertexes+3] := W;
	
	if Used_Colors then
		Add_color(Last_Color_R, Last_Color_G, Last_Color_B, Last_Color_A);
	if Used_TexCoord then
		Add_tex_coord(Cur_Tex_Coord_X, Cur_tex_coord_Y, Cur_tex_coord_Z, 
			Cur_Tex_Coord_W);
	if Used_Normals then
		Add_normal(Cur_Normal_X, Cur_Normal_Y, Cur_Normal_Z);
		
	inc(Count_vertexes, Vertex_Components);
end;

procedure Tsim_List.Add_tex_coord(
X, Y, Z, W: GLFloat);
var i: Integer;
begin
	Used_TexCoord := true;
	i := (Count_vertexes div Vertex_Components) * Tex_Components; 
	if i + Tex_Components >= Length(TexCoords) then
	begin
		SetLength(TexCoords, 
			Max( Length(TexCoords) + 1024,
				 Length(TexCoords) * 3 div 2));
	end; 
	TexCoords[i] := X;
	TexCoords[i+1] := Y;
	if Tex_Components <= 2 then Exit;
	TexCoords[i+2] := Z;
	if Tex_Components <= 3 then Exit;
	TexCoords[i+3] := W;
end;

procedure Tsim_List.Add_color(
R, G, B, A: GLFloat);
var i: Integer;
begin
	Used_Colors := true;
	i := (Count_vertexes div Vertex_Components) * Color_Components; 
	if i + Color_Components >= Length(Colors) then
	begin
		SetLength(Colors, 
			Max( Length(Colors) + 1024,
				 Length(Colors) * 3 div 2));
	end; 
	Colors[i] := R;
	Colors[i+1] := G;
	Colors[i+2] := B;
	if Color_Components <= 3 then Exit;
	Colors[i+3] := A;
end;

procedure Tsim_List.Add_normal(
X, Y, Z: GLFloat);
var i: Integer;
begin
	Used_Normals := true;
	i := (Count_vertexes div Vertex_Components) * 3; 
	if i + 3 >= Length(Normals) then
	begin
		SetLength(Normals, 
			Max( Length(Normals) + 1024,
				 Length(Normals) * 3 div 2));
	end; 
	Normals[i] := X;
	Normals[i+1] := Y;
	Normals[i+2] := Z;
end;

procedure Tsim_List.Execute;
var n, m, i, s, k: Integer;
	shape: Integer;
	min_v, max_v: Integer;
begin
	if Count_vertexes <> 0 then
	begin
		m := Count_vertexes div Vertex_Components;
		
		//if n = 0 then Exit; 
        //if true then writeln('start of Tsim_List.Execute ' + IntToStr(glGetError) +
        //    ', m=' + IntToStr(m));
		if Used_Colors then
		begin
			glEnableClientState(GL_COLOR_ARRAY);
			//if true then writeln('after glEnableClientState - ' + IntToStr(glGetError));
			glColorPointer(Color_Components, GL_FLOAT, 0, @Colors[0]);
            //if true then writeln('after glColorPointer - ' + IntToStr(glGetError) +
            //    ', Color_Components=' + IntToStr(Color_Components) +
            //    ', size of Colors=' + IntToStr(Length(Colors)) +
            //    ', vertices=' + IntToStr(m));
            //if true then writeln('Tsim_List.Execute 1 - ' + IntToStr(glGetError));
		end; 
		
		if Used_TexCoord then
		begin
			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
			glTexCoordPointer(Tex_Components, GL_FLOAT, 0, @TexCoords[0]);
			//if true then writeln('Tsim_List.Execute 2 - ' + IntToStr(glGetError));
		end; 
		
		if Used_Normals then
		begin
			glEnableClientState(GL_NORMAL_ARRAY);
			glNormalPointer(GL_FLOAT, 0, @Normals[0]);
			//if true then writeln('Tsim_List.Execute 3 - ' + IntToStr(glGetError));
		end;
		
		glVertexPointer(Vertex_Components, GL_FLOAT, 0, @Vertexes[0]);
        //if true then writeln('after glVertexPointer ' + IntToStr(glGetError) +
        //    ', Vertex_Components=' + IntToStr(Vertex_Components) +
        //    ', Length(Vertexes)=' + IntToStr(Length(Vertexes)));
		glEnableClientState(GL_VERTEX_ARRAY);
        //if true then writeln('Tsim_List.Execute 4 - ' + IntToStr(glGetError));
		
		shape := BE_mode;
		case shape of
		GL_QUADS: 
			begin
				//if true then writeln('GL_QUADS');
				n := m div 4;
				
				k := n * 6;
				if Length(Indices) < k then
					SetLength(Indices, k);
				s := 0;
				for i := 0 to n-1 do
				begin
					Indices[s] := i * 4;
					Indices[s+1] := i * 4 + 1;
					Indices[s+2] := i * 4 + 2;
					Indices[s+3] := i * 4 + 2;
					Indices[s+4] := i * 4 + 3;
					Indices[s+5] := i * 4;
					inc(s, 6);
				end;
                //if true then writeln('before glDrawElements GL_TRIANGLES:' +
                //    IntToStr(glGetError()));
				glDrawElements(GL_TRIANGLES, k, GL_UNSIGNED_SHORT, @Indices[0]);
                //if true then writeln('after glDrawElements GL_TRIANGLES:' +
                //    IntToStr(glGetError()));
			end;
		GL_QUAD_STRIP: //n := 0* (m - 2) div 2;
			begin
				//if true then writeln('GL_QUAD_STRIP');
				shape := GL_TRIANGLE_STRIP;
				glDrawArrays(shape, 0, m);
			end;
		GL_POLYGON: //n := 0* 1;
			begin
				//if true then writeln('GL_POLYGON');
				shape := GL_TRIANGLE_FAN;
				glDrawArrays(shape, 0, m);
			end;
		0:  if Length(Indices) > 0 then
			begin
				//if true then writeln('GL_TRIANGLES');
				// quadric generated
				glDrawElements(GL_TRIANGLES, 
				Length(Indices), GL_UNSIGNED_SHORT, @Indices[0]);
			end;
		else 
			glDrawArrays(shape, 0, m);
		end;
        //if true then writeln('Tsim_List.Execute 5 - ' + IntToStr(glGetError));
		
		glDisableClientState(GL_VERTEX_ARRAY);
		glDisableClientState(GL_COLOR_ARRAY);
		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
		glDisableClientState(GL_NORMAL_ARRAY);
        //if true then writeln('Tsim_List.Execute 6 - ' + IntToStr(glGetError));
	end;	
	glTranslatef(Translate_X, Translate_Y, Translate_Z);
    //if true then writeln('Tsim_List.Execute 7 - ' + IntToStr(glGetError));
end;
{$ENDIF}

{$IFDEF SIMULATE_QUADRICS}

{$IFDEF USE_LISTS_OF_DESCRIPTORS}

function allocate_quadric(q: Tsim_Quadric): Integer;
begin
	if All_quadrics = nil then
	begin
		All_quadrics := TList .Create();
		All_quadrics.Add(Tsim_Quadric.Create());
	end;
	Result := All_quadrics.IndexOf(nil);
	if Result < 0 then
	begin
		Result := All_quadrics.Count;
		All_quadrics.Add(nil);
	end;
	All_quadrics[Result] := q;
end;

procedure release_quadric(i: Integer);
begin
	if (i < 0) or (i >= All_quadrics.Count) then Exit;
	All_quadrics[i] := nil;
end;

{$ENDIF}

function sim_gluNewQuadric
: Tsim_Quadric;
begin
	Result := Tsim_Quadric.Create;
	Result.Need_normals := true;
	Result.Normals_smooth := true;
end;

procedure sim_gluDeleteQuadric(
q: Tsim_Quadric);
begin
	q.Free;
end;

procedure sim_gluQuadricDrawStyle(
q: Tsim_Quadric; ds: GLenum);
begin
	if q.Draw_style = qdsFill then Exit;
	case ds of
	GLU_FILL:	q.Draw_style := qdsFill;
	GLU_LINE:	q.Draw_style := qdsLine;
	GLU_SILHOUETTE: q.Draw_style := qdsSilhouette;
	GLU_POINT:	q.Draw_style := qdsPoint;
	else Exit;
	end;
	FreeAndNil(q.Def);
end;

procedure sim_gluQuadricOrientation(
q: Tsim_Quadric; orientation: GLenum);
begin
	case orientation of
	GLU_OUTSIDE:
		if q.Direction_inside then q.Direction_inside := false else Exit;
	GLU_INSIDE:
		if q.Direction_inside then Exit else q.Direction_inside := true;
	else Exit;
	end;
	FreeAndNil(q.Def);
end;

procedure sim_gluQuadricNormals(
q: Tsim_Quadric; normals: GLenum);
begin
	case normals of
	GLU_NONE:
		if q.Need_normals then q.Need_normals := false else Exit;
	GLU_FLAT:
		if q.Need_normals and not q.Normals_smooth then Exit
		else
		begin
			q.Need_normals := true;
			q.Normals_smooth := false;
		end;
	GLU_SMOOTH:
		if q.Need_normals and q.Normals_smooth then Exit
		else
		begin
			q.Need_normals := true;
			q.Normals_smooth := true;
		end;
	else Exit;
	end;
	FreeAndNil(q.Def);
end;

procedure sim_gluQuadricTexture(
q: Tsim_Quadric; texture: GLenum);
begin
	case texture of
	GLenum(GL_TRUE): if q.Need_texture then Exit else q.Need_texture := true;
	GLenum(GL_FALSE): if q.Need_texture then q.Need_texture := false else Exit;
	else Exit;
	end;
	FreeAndNil(q.Def);
end;

procedure swap(var a: array of SmallInt; i, j: Integer);
var x, y: GLint;
begin
	x := a[i];
	y := a[j];
	a[i] := y;
	a[j] := x;
end;

procedure apply_draw_mode(q: Tsim_Quadric);
begin
	case q.Draw_style of
	qdsFill: glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
	qdsLine: glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	qdsSilhouette: glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	qdsPoint: glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
	end;
end;

procedure sim_gluCylinder(
q: Tsim_Quadric; base, top, height: GLFloat;
slices, stacks: GLint);
var alpha, z, r: Double;
	i, j, k, v: Integer;
	nx, ny, nz: Double;
	rebuild: Integer;
begin
    //if true then
    //begin
    //    writeln('sim_gluCylinder q=' + IntToHex(Integer(q), 8) +
    //    ', q.Def=' + IntToHex(Integer(q.Def), 8));
    //end;
	rebuild := 0;
	if (q.Shape <> qsCylinder) then rebuild := 1;
	if (q.P_base <> base) then rebuild := 2;
	if (q.P_top <> top) then rebuild := 3;
	if (q.P_height <> height) then rebuild := 4; 
	if (q.P_slices <> slices) then rebuild := 5;
	if (q.P_stacks <> stacks) then rebuild := 6;
	if rebuild <> 0 then FreeAndNil(q.Def);
	if q.Def = nil then
	begin
        //if true then begin
        //    writeln('build CYLINDER ' + IntToHex(Integer(q), 8) +
        //    ' base=' + FloatToStr(base) + ' top=' + FloatToStr(top) +
        //    ' h=' + FloatToStr(height) +
        //    ' slices=' + IntToStr(slices) + ' stacks=' + IntToStr(stacks) +
        //    ', stored: ' + FloatToStr(q.P_base) + ', ' + FloatToStr(q.P_top) +
        //    ', ' + FloatToStr(q.P_height) + ', slices=' + IntToStr(q.P_slices) +
        //    ', stacks=' + IntToStr(q.P_stacks) +
        //    ', shape was ' + IntToStr(Integer(
        //    q.Shape)) + ' whereas new is ' + IntToStr(Integer(qsCylinder)) );
        //    writeln('REBUILD reason is ' +IntToStr(rebuild));
        //end;
	
		q.Shape := qsCylinder;
		q.P_base := base;
		q.P_top := top;
		q.P_height := height;
		q.P_slices := slices;
		q.P_stacks := stacks;
		if (stacks <= 0) or (slices <= 1) then Exit; 
		//if true then writeln('cylinder 2');
		
		q.Def := Tsim_List.Create();
		q.Def.BE_mode := 0;
		q.Def.Tex_Components := 2;
		q.Def.Vertex_Components := 3;
		glColor4f(Last_color_R, Last_Color_G, Last_Color_B, Last_Color_A);
		//if true then writeln('cylinder 3-1');
		
		SetLength( q.Def.Indices, 6 * stacks * slices );
		alpha := 0;
		k := 0;
		v := 0;
		//if true then writeln('cylinder 3-2');
		
		for i := 0 to slices do
		begin
			alpha := 2 * PI / slices * i;
			for j := 0 to stacks do
			begin
				z := height / stacks * j;
				r := base + (top - base) / stacks * j;
				if q.Need_texture then
				begin
					q.Def.Add_tex_coord(
						i / slices, j / stacks, 0, 0);
				end;
				if q.Need_normals then
				begin
					nx := cos(alpha);
					ny := sin(alpha);
					nz := 0;
					q.Def.Add_normal( nx, ny, nx );
				end;
				q.Def.Add_vertex(
					r * cos(alpha),
					r * sin(alpha),
					z, 1, 3);
				if (i < slices) and (j < stacks) then
				begin
					q.Def.Indices[k] := v;
					q.Def.Indices[k+1] := v+1;
					q.Def.Indices[k+2] := (v+1+(stacks+1));
					q.Def.Indices[k+3] := (v+1+(stacks+1));
					q.Def.Indices[k+4] := (v+(stacks+1));
					q.Def.Indices[k+5] := v;
					if q.Direction_inside then
					begin
						swap(q.Def.Indices, k+1, k+2);
						swap(q.Def.Indices, k+4, k+5);
					end;
					inc(k, 6);
				end;
				inc(v);
			end;
		end;
	end;
	//if true then writeln('cylinder 4');
	glPushAttrib(GL_POLYGON_BIT);
	apply_draw_mode(q);
	q.Def.Execute;
	glPopAttrib;
	//if true then writeln('cylinder 5 q.Def=' + IntToHex(Integer(q.Def), 8));
end;

procedure sim_gluPartialDisk(q: Tsim_Quadric; inner, outer: GLFloat;
	slices, loops: GLint; start, sweep: GLFloat);
var i, j, k, v: Integer;
	r, alpha: Double;
	nx, ny, nz: Double;
begin
	if (q.Shape <> qsDisk) or (q.P_inner <> inner) or (q.P_outer <> outer) or	
	   (q.P_slices <> slices) or (q.P_loops <> loops) or
	   (q.P_start <> start) or (q.P_sweep <> sweep) then
	   FreeAndNil(q.Def);
	if q.Def = nil then
	begin
		q.Shape := qsDisk;
		q.P_inner := inner;
		q.P_outer := outer;
		q.P_slices := slices;
		q.P_loops := loops;
		q.P_start := start;
		q.P_sweep := sweep;
		q.Def := Tsim_List.Create;
		q.Def.BE_mode := 0;
		q.Def.Tex_Components := 2;
		q.Def.Vertex_Components := 3;
		glColor4f(Last_color_R, Last_Color_G, Last_Color_B, Last_Color_A);
		SetLength( q.Def.Indices, 6 * loops * slices );
		if (loops < 1) or (slices < 1) then Exit;
		alpha := 0;
		k := 0;
		v := 0;
		for i := 0 to slices do
		begin
			alpha := (start + sweep / slices * i) * PI / 180;
			for j := 0 to loops do
			begin
				r := inner + (outer - inner) / loops * j;
				if q.Need_texture then
				begin
					q.Def.Add_tex_coord(
						i / slices, j / loops, 0, 0);
				end;
				if q.Need_normals then
				begin
					nx := 0;
					ny := 0;
					nz := 1;
					q.Def.Add_normal( nx, ny, nx );
				end;
				q.Def.Add_vertex(
					r * cos(alpha),
					r * sin(alpha),
					0, 1, 3);
				if (i < slices) and (j < loops) then
				begin
					q.Def.Indices[k] := v;
					q.Def.Indices[k+1] := v+1;
					q.Def.Indices[k+2] := v+1+(loops+1);
					q.Def.Indices[k+3] := v+1+(loops+1);
					q.Def.Indices[k+4] := v+(loops+1);
					q.Def.Indices[k+5] := v;
					if q.Direction_inside then
					begin
						swap(q.Def.Indices, k+1, k+2);
						swap(q.Def.Indices, k+4, k+5);
					end;
					inc(k, 6);
				end;
				inc(v);
			end;
		end;
	end;
	glPushAttrib(GL_POLYGON_BIT);
	apply_draw_mode(q);
	q.Def.Execute;
	glPopAttrib;
end;

procedure sim_gluDisk(
q: Tsim_Quadric; inner, outer: GLFloat;
slices, loops: GLint);
begin
	sim_gluPartialDisk(q, inner, outer, slices, loops, 0, 360);
end;

procedure sim_gluSphere(
q: Tsim_Quadric; radius: GLFloat; slices, stacks: GLint);
var alpha, z, r, fi: Double;
	i, j, k, v: Integer;
	nx, ny, nz: Double;
begin
	if (q.Shape <> qsSphere) or (q.P_radius <> radius)
	   or (q.P_slices <> slices) or (q.P_stacks <> stacks) then
	   FreeAndNil(q.Def);
	if q.Def = nil then
	begin
        //if true then writeln('build SPHERE ' + IntToHex(Integer(q), 8) +
        //    ' r=' + FloatToStr(radius) +
        //    ' slices=' + IntToStr(slices) + ' stacks=' + IntToStr(stacks) +
        //    ', stored: ' + FloatToStr(q.P_radius) + ', ' + IntToStr(q.P_slices) +
        //    ', ' + IntToStr(q.P_stacks) + ', shape was ' + IntToStr(Integer(
        //    q.Shape)) + ' whereas new is ' + IntToStr(Integer(qsSphere)) );
		q.Shape := qsSphere;
		q.P_radius := radius;
		q.P_slices := slices;
		q.P_stacks := stacks;
		if (stacks <= 0) or (slices <= 1) or (radius = 0) then Exit; 
		q.Def := Tsim_List.Create();
		q.Def.BE_mode := 0;
		q.Def.Tex_Components := 2;
		q.Def.Vertex_Components := 3;
		glColor4f(Last_color_R, Last_Color_G, Last_Color_B, Last_Color_A);
		SetLength( q.Def.Indices, 6 * stacks * slices );
		alpha := 0;
		k := 0;
		v := 0;
		for i := 0 to slices do
		begin
			alpha := 2 * PI / slices * i;
			for j := 0 to stacks do
			begin
				z := -radius + (2 * radius) / stacks * j;
				r := sqrt(radius * radius - z * z);
				if q.Need_texture then
				begin
					q.Def.Add_tex_coord(
						i / slices, j / stacks, 0, 0);
				end;
				if q.Need_normals then
				begin
					fi := arcsin(z / radius);
					nx := cos(alpha) * cos(fi);
					ny := sin(alpha) * cos(fi);
					nz := sin(fi);
					q.Def.Add_normal( nx, ny, nz);
				end;
				q.Def.Add_vertex(
					r * cos(alpha),
					r * sin(alpha),
					z, 1, 3);
				if (i < slices) and (j < stacks) then
				begin
					q.Def.Indices[k] := v;
					q.Def.Indices[k+1] := v+1;
					q.Def.Indices[k+2] := v+1+(stacks+1);
					q.Def.Indices[k+3] := v+1+(stacks+1);
					q.Def.Indices[k+4] := v+(stacks+1);
					q.Def.Indices[k+5] := v;
					if q.Direction_inside then
					begin
						swap(q.Def.Indices, k+1, k+2);
						swap(q.Def.Indices, k+4, k+5);
					end;
					inc(k, 6);
				end;
				inc(v);
			end;
		end;
	end;
	glPushAttrib(GL_POLYGON_BIT);
	apply_draw_mode(q);
	q.Def.Execute;
	glPopAttrib;
	//if true then writeln(IntToStr(glGetError) + ' after sphere');
end;

{$ENDIF}

(*
/*

FUN Format_pixels_from_internal_format_bitmap(
    INT I|nternal_format ) ==> INT
    :
    ----------------------------------------- 'for Delphi'
    CASE Is_linux ?
         //DEBUG: << "LINUX DETECTED I=" 
         //		CASE I ?
         //		[ GL_RGB ]: << "GL_RGB"
         //		[ 3 ]:		<< "3"
         //		[ 4 ]:		<< "4"
         //		[ GL_RGBA ]:<< "GL_RGBA"
         //		[ GL_BGRA ]:<< "GL_BGRA"
         //		ELSE		<< "[" I.S "]" ;
         //		<< #NL ;
	     CASE I ?
	     [GL_RGB, 3]: RESULT = GL_BGRA // GL_RGB //GL_BGR
	     ELSE RESULT = GL_RGBA // GL_BGRA
	     ;
    ELSE
	     CASE I ?
	     [GL_RGB, 3]: RESULT = GL_BGR
	     ELSE RESULT = GL_BGRA ;
    ; .

    
FUN Type_pixels_from_internal_format_bitmap(
    INT I|nternal_format ) ==> INT
    :
    ----------------------------------------- 'for Delphi'
    CASE I ?
    [GL_RGB, 3]: RESULT = GL_UNSIGNED_BYTE
    ELSE RESULT = GL_UNSIGNED_BYTE ; .
    
*/
*)

(*
/*

FUN Invalidate_open_gl_control(
INT H|andle_control), NATIVE :
       @"var G: TOpenGLbox;"
        "	{$IFDEF USE_LISTS_OF_DESCRIPTORS}"
        "    G := TOpenGLbox(All_controls[X_H]);"
        "	{$ELSE}"
        "    G := TOpenGLbox(X_H);"
        "	{$ENDIF}"
        "    if G = nil then Exit;"
        "    G.Invalidate();" .
        
FUN Update_open_gl_control(INT H|andle_control), NATIVE :
       @"var G: TOpenGLbox;"
        "	{$IFDEF USE_LISTS_OF_DESCRIPTORS}"
        "    G := TOpenGLbox(All_controls[X_H]);"
        "	{$ELSE}"
        "    G := TOpenGLbox(X_H);"
        "	{$ENDIF}"
        "    if G = nil then Exit;"
        "    G.Invalidate();"
        "	{$IFDEF LINUX}"
        "	{$ELSE}"
        "    G.Perform(WM_PAINT, 0, 0);"
        "    Turn_VSync_off;"
        "	{$ENDIF}"
        .
*/
*)
var VSync_turned_off: Boolean;

	{$IFDEF LINUX}
	{$ELSE}
type TwglSwapIntervalEXT = function(Param: LongInt): LongBool; stdcall;
var wglSwapIntervalEXT: TwglSwapIntervalEXT;
	{$ENDIF}

procedure Turn_VSync_off;
begin
	{$IFnDEF LINUX}
    wglSwapIntervalEXT := TwglSwapIntervalEXT(
    	wglGetProcAddress('wglSwapIntervalEXT'));
    if Assigned(wglSwapIntervalEXT) then wglSwapIntervalEXT(0);
    {$ENDIF}
end;

(*
/*
        
CONST STR : 
        NATIVE_import_OpenGL = @
        "uses AL4_form, "
        "{$IFDEF FPC} gl, glu "
        "{$ELSE} "
        "		OpenGL "
        "{$ENDIF}, AL4_OpenGL"
        ""
        "{$I AL4_options.inc}"
        ""

                NATIVE_glGetError = @
                "    RESULT := glGetError();"
    
                NATIVE_gluErrorString = @
                "    RESULT := gluErrorString(X_Code);"
    
                NATIVE_glGetString = @
                "    RESULT := PChar(glGetString(X_Name));"
    
        NATIVE_glViewport = @
        "    glViewport(X_X, X_Y, X_Width, X_Height);"
    
        NATIVE_glClearColor = @
        "    glClearColor(X_R, X_G, X_B, X_A);"
        
                NATIVE_glClearDepth = @
                "    glClearDepth(X_Depth);"
                
                NATIVE_glClearStencil = @
                "    glClearStencil(X_S);"
                
                NATIVE_glAccum = @
                "    glAccum(X_Op, X_Value);"
                
                NATIVE_glClearAccum = @
                "    glClearAccum(X_R, X_G, X_B, X_A);"
                
        NATIVE_glClear = @
        "    glClear(X_B);"
        
        NATIVE_glEnable = @
        "    glEnable(X_What);"
        
        NATIVE_glDisable = @
        "    glDisable(X_What);"
        
        NATIVE_glIsEnabled = @
        "    RESULT := {$IFDEF FPC}0 <>{$ENDIF}"
        "			   glIsEnabled({$IFDEF FPC}LongWord{$ENDIF}(X_What));"
        
        NATIVE_glGetBooleanv = @
        "var p: array[0..1] of Byte;"
        "    glGetBooleanv(X_What, @p[0]);"
        "    X_Params.Clear();"
        "    X_Params.Add(MAXINT, Byte(p[0] <> 0));"
        
        NATIVE_glGetIntegerv = @
        "var p: array[0..3] of Integer;"
        "var i: Integer;"
        "    glGetIntegerv(X_What, @p[0]);"
        "    X_Param.Clear();"
        "    for i := 0 to X_size-1 do"
        "        X_Param.Add(MAXINT, p[i]);"
        
        NATIVE_glGetDoublev = @
        "var p: array[0..3] of Double;"
        "var i: Integer;"
        "    glGetDoublev(X_What, @p[0]);"
        "    X_Param.Clear();"
        "    for i := 0 to X_size-1 do"
        "        X_Param.Add(MAXINT, p[i]);"
        
                NATIVE_glColorMask = @
                "    glColorMask("
                      "GLBoolean(X_Red),"
                      "GLBoolean(X_Green),"
                      "GLBoolean(X_Blue),"
                      "GLBoolean(X_Alpha));"
               
        NATIVE_glCullFace = @
        "    glCullFace(X_Side);"
        
        NATIVE_glDepthFunc = @
        "    glDepthFunc(X_Func);"
        
                NATIVE_glDepthMask = @
                "    glDepthMask(GLBoolean(X_Flag));"
                
                NATIVE_glDepthRange = @
                "    glDepthRange(X_Near, X_Far);"
                
                NATIVE_glLineWidth = @
                "    glLineWidth(X_Width);"
                
                NATIVE_glLineStipple = @
                "    glLineStipple(X_Factor, X_Pattern);"
                
                NATIVE_glPointSize = @
                "    glPointSize(X_Size);"
                
                NATIVE_glPolygonMode = @
                "       glPolygonMode(X_Face, X_Mode);"
                
                NATIVE_glPolygonOffset = @
                "	{$IFNDEF LINUX}"
                "    if (not Assigned(glPolygonOffset)) then"
                "       glPolygonOffset := "
                "		TglPolygonOffset("
                "		GLProcAddress('glPolygonOffset'));"
                "    if Assigned(glPolygonOffset) then"
                "	{$ENDIF}"
                "       glPolygonOffset(X_Factor, X_Units);"
                
                NATIVE_glHint = @
                "    glHint(X_Target, X_Mode);"
                
        NATIVE_glFrontFace = @
        "    glFrontFace(X_Orient);"
        
        NATIVE_glMatrixMode = @
        "    glMatrixMode(X_Mode);"
        
        NATIVE_glLoadIdentity = @
        "    glLoadIdentity();"
        
        NATIVE_glPushMatrix = @
        "    glPushMatrix();"
        
        NATIVE_glPopMatrix = @
        "    glPopMatrix();"
        
        NATIVE_glMultMatrixd = @
        "var p: array[0..15] of Double;"
        "var i: Integer;"
        "    for i := 0 to X_Matrix.Count()-1 do"
        "        p[i] := X_Matrix.GetReals(i);"
        "    glMultMatrixd(@p[0]);"
        
        NATIVE_glTranslated = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "	 sim_glTranslatef(X_X, X_Y, X_Z);"
        "	{$ELSE}"
        "    glTranslated(X_X, X_Y, X_Z);"
        "	{$ENDIF}"
        
        NATIVE_glTranslatef = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "	 sim_glTranslatef(X_X, X_Y, X_Z);"
        "	{$ELSE}"
        "    glTranslatef(X_X, X_Y, X_Z);"
        "	{$ENDIF}"
        
        NATIVE_glRotated = @
        "    glRotated(X_A, X_X, X_Y, X_Z);"
        
        NATIVE_glRotatef = @
        "    glRotatef(X_A, X_X, X_Y, X_Z);"
        
        NATIVE_glScaled = @
        "    glScaled(X_X, X_Y, X_Z);"
        
        NATIVE_glScalef = @
        "    glScalef(X_X, X_Y, X_Z);"
        
        NATIVE_gluPerspective = @
        "    gluPerspective(X_VerticalFOV, X_Aspect, X_Near, X_Far);"
                
                NATIVE_gluOrtho2D = @
                "    gluOrtho2D(X_Left, X_Right, X_Top, X_Bottom);"
                
                NATIVE_glOrtho = @
                "    glOrtho(X_Left, X_Right, X_Bottom, X_Top, X_Near, X_Far);"
                
                NATIVE_glFrustum = @
                "    glFrustum(X_Left, X_Right, X_Bottom, X_Top,"
                "       X_Near, X_Far);"
                
                NATIVE_gluProject = @
                "var m: array[0..15] of Double;"
                "var p: array[0..15] of Double;"
                "var v: array[0..3] of Integer;"
                "var r: array[0..2] of Double;"
                "var i: Integer;"
                "    for i := 0 to 15 do"
                "    begin"
                "        if i < X_Model.Count() then"
                "           m[i] := X_Model.GetReals(i);"
                "        if i < X_Project.Count() then"
                "           p[i] := X_Project.GetReals(i);"
                "    end;"
                "    for i := 0 to 3 do"
                "        if i < X_Viewport.Count() then"
                "           v[i] := X_Viewport.GetIntegers(i);"
                "	 r[0] := 0; r[1] := 0; r[2] := 0;"
                "	{$IFDEF FPC}"
                "    gluProject(X_X_obj, X_Y_obj, X_Z_obj,"
                "       @m[0], @p[0], @v[0], @r[0], @r[1], @r[2]);"
                "	{$ELSE}"
                "    gluProject(X_X_obj, X_Y_obj, X_Z_obj,"
                "       @m[0], @p[0], @v[0], r[0], r[1], r[2]);"
                "	{$ENDIF}"
                "    for i := 0 to 3 do"
                "        if i < X_XYZ_win.Count() then"
                "           X_XYZ_win.SetReals(i, r[i]);"
                
                NATIVE_gluUnProject = @
                "var m: array[0..15] of Double;"
                "var p: array[0..15] of Double;"
                "var v: array[0..3] of Integer;"
                "var r: array[0..2] of Double;"
                "var i: Integer;"
                "    for i := 0 to 15 do"
                "    begin"
                "        if i < X_Model.Count() then"
                "           m[i] := X_Model.GetReals(i);"
                "        if i < X_Project.Count() then"
                "           p[i] := X_Project.GetReals(i);"
                "    end;"
                "    for i := 0 to 3 do"
                "        if i < X_Viewport.Count() then"
                "           v[i] := X_Viewport.GetIntegers(i);"
                "	{$IFDEF FPC}"
                "    gluUnProject(X_X_win, X_Y_win, X_Z_win,"
                "       @m[0], @p[0], @v[0], @r[0], @r[1], @r[2]);"
                "	{$ELSE}"
                "    gluUnProject(X_X_win, X_Y_win, X_Z_win,"
                "       @m[0], @p[0], @v[0], r[0], r[1], r[2]);"
                "	{$ENDIF}"
                "    for i := 0 to 3 do"
                "        if i < X_XYZ_obj.Count() then"
                "           X_XYZ_obj.SetReals(i, r[i]);"
                
                NATIVE_glClipPlane = @
        "var p: array[0..3] of Double;"
        "var i: Integer;"
                "    for i := 0 to X_Equation.Count()-1 do"
                "        if i < 4 then"
                "           p[i] := X_Equation.GetReals(i);"
                "    glClipPlane(X_Plane, @p[0]);"
                
                NATIVE_glPushAttrib = @
                "    glPushAttrib(X_Mask);"
                
                NATIVE_glPopAttrib = @
                "    glPopAttrib();"
                
                NATIVE_glPushClientAttrib = @
                "	{$IFndef LINUX}"
                "    if not Assigned(glPushClientAttrib) then"
                "       glPushClientAttrib := TglPushClientAttrib("
                "			GLProcAddress("
                "           'glPushClientAttrib'));"
                "    if Assigned(glPushClientAttrib) then"
                "	{$ENDIF}"
                "       glPushClientAttrib(X_Mask);"
                
                NATIVE_glPopClientAttrib = @
                "	{$IFNDEF LINUX}"
                "    if not Assigned(glPopClientAttrib) then"
                "       glPopClientAttrib := TglPopClientAttrib("
                "		GLProcAddress('glPopClientAttrib'));"
                "    if Assigned(glPopClientAttrib) then"
                "	{$ENDIF}"
                "       glPopClientAttrib();"
                
        NATIVE_glBegin = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glBegin(X_Mode);"
        "	{$ELSE}"
        "    glBegin(X_Mode);"
        "	{$ENDIF}"
        
        NATIVE_glEnd = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glEnd;"
        "	{$ELSE}"
        "    glEnd;"
        "	{$ENDIF}"
        
                NATIVE_glListBase = @
                "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
                "    sim_glListBase(X_Base);"
                "	{$ELSE}"
                "    glListBase(X_Base);"
                "	{$ENDIF}"
                
                NATIVE_glGenLists = @
                "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
                "    RESULT := sim_glGenLists(X_Range);"
                "	{$ELSE}"
                "    RESULT := glGenLists(X_Range);"
                "	{$ENDIF}"
                
                NATIVE_glIsList = @
                "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
                "    RESULT := sim_glIsList(X_List);"
                "	{$ELSE}"
                "    RESULT := Boolean(glIsList(X_List));"
                "	{$ENDIF}"
                
                NATIVE_glNewList = @
                "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
                "    sim_glNewList(X_List, X_Mode);"
                "	{$ELSE}"
                "    glNewList(X_List, X_Mode);"
                "	{$ENDIF}"
                
                
                NATIVE_glEndList = @
                "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
                "    sim_glEndList;"
                "	{$ELSE}"
                "    glEndList;"
                "	{$ENDIF}"
                
                NATIVE_glCallList = @
                "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
                "    sim_glCallList(X_List);"
                "	{$ELSE}"
                "    glCallList(X_List);"
                "	{$ENDIF}"
                
                NATIVE_glCallLists = @
                "var lists: PInteger;"
                "var p: PInteger;"
                "var i: Integer;"
                "    if X_N <= 0 then X_N := X_Lists.Count();"
                "    if X_N > X_Lists.Count() then X_N := X_Lists.Count();"
                "    if X_N = 0 then Exit;"
                "    GetMem(lists, X_N * Sizeof(Integer));"
                "    p := lists;"
                "    for i := 0 to X_N-1 do"
                "    begin"
                "       p^ := X_Lists.GetIntegers(i);"
                "       inc(p);"
                "    end;"
                "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
                "    sim_glCallLists(X_N, lists);"
                "	{$ELSE}"
                "    glCallLists(X_N, GL_INT {X_TYPE}, lists);"
                "	{$ENDIF}"
                "    FreeMem(lists);"
                
                NATIVE_glDeleteLists = @
                "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
                "    sim_glDeleteLists(X_List, X_Range);"
                "	{$ELSE}"
                "    glDeleteLists(X_List, X_Range);"
                "	{$ENDIF}"
                
        NATIVE_glVertex2d = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glVertex3f(X_X, X_Y, 0);"
        "	{$ELSE}"
        "    glVertex2d(X_X, X_Y);"
        "	{$ENDIF}"
        
        NATIVE_glVertex2f = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glVertex3f(X_X, X_Y, 0);"
        "	{$ELSE}"
        "    glVertex2f(X_X, X_Y);"
        "	{$ENDIF}"
        
        NATIVE_glVertex3d = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glVertex3f(X_X, X_Y, X_Z);"
        "	{$ELSE}"
        "    glVertex3d(X_X, X_Y, X_Z);"
        "	{$ENDIF}"
        
        NATIVE_glVertex3f = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glVertex3f(X_X, X_Y, X_Z);"
        "	{$ELSE}"
        "    glVertex3f(X_X, X_Y, X_Z);"
        "	{$ENDIF}"
        
        NATIVE_glVertex4d = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glVertex4f(X_X, X_Y, X_Z, X_W);"
        "	{$ELSE}"
        "    glVertex4d(X_X, X_Y, X_Z, X_W);"
        "	{$ENDIF}"
        
        NATIVE_glVertex4f = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glVertex4f(X_X, X_Y, X_Z, X_W);"
        "	{$ELSE}"
        "    glVertex4f(X_X, X_Y, X_Z, X_W);"
        "	{$ENDIF}"
        
        NATIVE_glTexCoord1d = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glTexCoord2f(X_S, 0);"
        "	{$ELSE}"
        "    glTexCoord1d(X_S);"
        "	{$ENDIF}"
        
        NATIVE_glTexCoord1f = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glTexCoord2f(X_S, 0);"
        "	{$ELSE}"
        "    glTexCoord1f(X_S);"
        "	{$ENDIF}"
        
        NATIVE_glTexCoord2d = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glTexCoord2f(X_S, X_T);"
        "	{$ELSE}"
        "    glTexCoord2d(X_S, X_T);"
        "	{$ENDIF}"
        
        NATIVE_glTexCoord2f = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glTexCoord2f(X_S, X_T);"
        "	{$ELSE}"
        "    glTexCoord2f(X_S, X_T);"
        "	{$ENDIF}"
        
        NATIVE_glTexCoord3d = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glTexCoord3f(X_S, X_T, X_R);"
        "	{$ELSE}"
        "    glTexCoord3d(X_S, X_T, X_R);"
        "	{$ENDIF}"
        
        NATIVE_glTexCoord3f = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glTexCoord3f(X_S, X_T, X_R);"
        "	{$ELSE}"
        "    glTexCoord3f(X_S, X_T, X_R);"
        "	{$ENDIF}"
        
        NATIVE_glTexCoord4d = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glTexCoord4f(X_S, X_T, X_R, X_Q);"
        "	{$ELSE}"
        "    glTexCoord4d(X_S, X_T, X_R, X_Q);"
        "	{$ENDIF}"
        
        NATIVE_glTexCoord4f = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glTexCoord4f(X_S, X_T, X_R, X_Q);"
        "	{$ELSE}"
        "    glTexCoord4f(X_S, X_T, X_R, X_Q);"
        "	{$ENDIF}"
        
        NATIVE_glNormal3d = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glNormal3f(X_X, X_Y, X_Z);"
        "	{$ELSE}"
        "    glNormal3d(X_X, X_Y, X_Z);"
        "	{$ENDIF}"
        
        NATIVE_glNormal3f = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glNormal3f(X_X, X_Y, X_Z);"
        "	{$ELSE}"
        "    glNormal3f(X_X, X_Y, X_Z);"
        "	{$ENDIF}"
        
        NATIVE_glColor3d = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glColor4f(X_Red, X_Green, X_Blue, 1);"
        "	{$ELSE}"
        "    glColor3d(X_Red, X_Green, X_Blue);"
        "	{$ENDIF}"
        
        NATIVE_glColor3f = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glColor3f(X_Red, X_Green, X_Blue);"
        "	{$ELSE}"
        "    glColor3f(X_Red, X_Green, X_Blue);"
        "	{$ENDIF}"
        
        NATIVE_glColor4d = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    sim_glColor4f(X_Red, X_Green, X_Blue, X_Alpha);"
        "	{$ELSE}"
        "    glColor4d(X_Red, X_Green, X_Blue, X_Alpha);"
        "	{$ENDIF}"
        
        NATIVE_glColor4f = @
        "	{$IFDEF SIMULATE_GLBEGIN_GLEND}"
        "    glColor4f(X_Red, X_Green, X_Blue, X_Alpha);"
        "	{$ELSE}"
        "    glColor4f(X_Red, X_Green, X_Blue, X_Alpha);"
        "	{$ENDIF}"
        
        NATIVE_glGenTextures = @
        "    Do_GenTextures(X_N, X_Textures);"
        
        NATIVE_glIsTexture = @
        "    RESULT := Do_IsTexture(X_Texture);"
        //--------------- glIsTexture is not available in standard OpenGL12:
        //"    RESULT := glIsTexture(X_Texture);"
        //------------------------------------------------------------------
        
        NATIVE_glDeleteTextures = @
        "    Do_DeleteTextures(X_N, X_Textures);"
        //------------- glDeleteTextures is not available in standard OpenGL12:
        //"var t: PIntegerArray;"
        //"var i: Integer;"
        //"    if (X_N <= 0) then X_N := X_Textures.Count;"
        //"    if (X_N >= X_Textures.Count) X_N := X_Textures.Count - 1;"
        //"    if (X_N <= 0) return;"
        //"    GetMem(t, X_N * Sizeof(N));"
        //"    for i := 0 to X_N-1 do"
        //"        t[i] := X_Textures[i];"
        //"    glDeleteTextures( X_N, t );"
        //"    FreeMem(t);"
        //------------------------------------------------------------------
        
        NATIVE_glBindTexture = @
        "	{$IFNDEF LINUX}"
        "    if not Assigned(glBindTexture) then"
        "       glBindTexture := TglBindTexture("
        "		GLProcAddress('glBindTexture'));"
        "    if not Assigned(glBindTexture) then Exit;"
        "	{$ENDIF}"
        "    glBindTexture(X_Target, X_Texture);"
        
        NATIVE_glTexImage1D = @
        "    try "
        "    glTexImage1D(X_Target, X_Level, X_Internal_format,"
        "       X_Width, X_Border, X_Format, X_Type, X_Data.First_Byte());"
        "    except on e: Exception do begin"
        "                   AL4.Any_exception(e);"
        "           end;"
        "    end;"
        
        NATIVE_glTexSubImage1D = @
        "    try "
        "	{$IFNDEF LINUX}"
        "    if not Assigned(glTexSubImage1D) then"
        "       glTexSubImage1D := TglTexSubImage1D("
        "		GLProcAddress('glTexSubImage1D'));"
        "    if not Assigned(glTexSubImage1D) then Exit;"
        "	{$ENDIF}"
        ""
        "    glTexSubImage1D(X_Target, X_Level, X_X_offset,"
        "       X_Width, X_Format, X_Type, X_Data.First_Byte());"
        "    except on e: Exception do begin"
        "                   AL4.Any_exception(e);"
        "           end;"
        "    end;"
        
        NATIVE_glTexImage2D = @
        "    try "
        "    glTexImage2D(X_Target, X_Level, X_Internal_format,"
        "       X_Width, X_Height, X_Border, X_Format, X_Type,"
        "       X_Data.First_Byte());"
        "    except on e: Exception do begin"
        "                   AL4.Any_exception(e);"
        "           end;"
        "    end;"
        
        NATIVE_glTexSubImage2D = @
        "    try "
        "	{$IFNDEF LINUX}"
        "    if not Assigned(glTexSubImage2D) then"
        "       glTexSubImage2D := TglTexSubImage2D("
        "		GLProcAddress('glTexSubImage2D'));"
        "    if not Assigned(glTexSubImage2D) then Exit;"
        "	{$ENDIF}"
        ""
        "    glTexSubImage2D(X_Target, X_Level, X_X_offset,"
        "       X_Y_offset, X_Width, X_Height, X_Format, X_Type,"
        "       X_Data.First_Byte());"
        "    except on e: Exception do begin"
        "                   AL4.Any_exception(e);"
        "           end;"
        "    end;"
        
        NATIVE_gluBuild1DMipmaps = @
        "    gluBuild1DMipmaps(X_Target, X_Components, X_Width,"
        "       X_Format, X_Type, X_Data.First_Byte());"
        
        NATIVE_gluBuild2DMipmaps = @
        "    gluBuild2DMipmaps(X_Target, X_Components, X_Width,"
        "       X_Height, X_Format, X_Type, X_Data.First_Byte());"
        
        NATIVE_glTexParameteri = @
        "    glTexParameteri(X_Target, X_Pname, X_Param);"
        
        NATIVE_glTexParameterf = @
        "    glTexParameterf(X_Target, X_Pname, X_Param);"
        
        NATIVE_glTexParameterfv = @
        "var p: array[0..3] of GLFloat;"
        "var i: Integer;"
        "var n: Integer;"
        "    n := 4;"
        "    if (n > X_Param.Count()) then n := X_Param.Count();"
        "    for i := 0 to n-1 do"
        "        p[i] := X_Param.GetReals(i);"
        "    glTexParameterfv(X_Target, X_Pname, @p[0]);"
        
        NATIVE_glTexEnvi = @
        "    glTexEnvi(X_Target, X_Pname, X_Param);"
        
        NATIVE_glTexEnvf = @
        "    glTexEnvf(X_Target, X_Pname, X_Param);"
        
        NATIVE_glBlendFunc = @
        "    glBlendFunc(X_Sfactor, X_Dfactor);"
        
        NATIVE_glAlphaFunc = @
        "    glAlphaFunc(X_Func, X_Ref);"
        
        NATIVE_glStencilFunc = @
        "    glStencilFunc(X_Func, X_Ref, X_Mask);"
        
        NATIVE_glStencilOp = @
        "    glStencilOp(X_Ffail, X_Dpfail, X_Dppass);"
        
        NATIVE_glStencilMask = @
        "    glStencilMask(X_Mask);"
        
        NATIVE_glLightf = @
        "    glLightf(X_Light, X_Pname, X_Param);"
        
        NATIVE_glLightfv = @
        "var p: array[0..3] of GLFloat;"
        "var i: Integer;"
        "var n: Integer;"
        "    n := 4;"
        "    if (n > X_Param.Count()) then n := X_Param.Count();"
        "    for i := 0 to n-1 do"
        "        p[i] := X_Param.GetReals(i);"
        "    glLightfv(X_Light, X_Pname, @p[0]);"
        
        NATIVE_glLightModeli = @
        "    glLightModeli(X_Pname, X_Param);"
        
        NATIVE_glLightModelfv = @
        "var p: array[0..3] of GLFloat;"
        "var i: Integer;"
        "var n: Integer;"
        "    n := 4;"
        "    if (n > X_Param.Count()) then n := X_Param.Count();"
        "    for i := 0 to n-1 do"
        "        p[i] := X_Param.GetReals(i);"
        "    glLightModelfv(X_Pname, @p[0]);"
        
        NATIVE_glMaterialf = @
        "    glMaterialf(X_Face, X_Pname, X_Param);"
        
        NATIVE_glMaterialfv = @
        "var p: array[0..3] of GLFloat;"
        "var i: Integer;"
        "var n: Integer;"
        "    n := 4;"
        "    if (n > X_Param.Count()) then n := X_Param.Count();"
        "    for i := 0 to n-1 do"
        "        p[i] := X_Param.GetReals(i);"
        "    glMaterialfv(X_Face, X_Pname, @p[0]);"
        
        NATIVE_glMaterialiv = @
        "var p: array[0..2] of Integer;"
        "var i: Integer;"
        "var n: Integer;"
        "    n := 3;"
        "    if (n > X_Param.Count()) then n := X_Param.Count();"
        "    for i := 0 to n-1 do"
        "        p[i] := X_Param.GetIntegers(i);"
        "    glMaterialiv(X_Face, X_Pname, @p[0]);"
        
        NATIVE_glColorMaterial = @
        "    glColorMaterial(X_Face, X_Mode);"
        
        NATIVE_glFogi = @
        "    glFogi(X_Pname, X_Param);"
        
        NATIVE_glFogf = @
        "    glFogf(X_Pname, X_Param);"
        
        NATIVE_glFogfv = @
        "var p: array[0..3] of GLFloat;"
        "var i: Integer;"
        "var n: Integer;"
        "    n := 4;"
        "    if (n > X_Param.Count()) then n := X_Param.Count();"
        "    for i := 0 to n-1 do"
        "        p[i] := X_Param.GetReals(i);"
        "    glFogfv(X_Pname, @p[0]);"

        NATIVE_gluNewQuadric = @
        "	{$IFDEF SIMULATE_QUADRICS}"
        "	 {$IFDEF USE_LISTS_OF_DESCRIPTORS}"
        "    	RESULT := allocate_quadric(sim_gluNewQuadric());"
        "	 {$ELSE}"
        "    	RESULT := Integer(sim_gluNewQuadric());"
        "	 {$ENDIF}"
        "	{$ELSE}"
        "    RESULT := Integer(gluNewQuadric());"
        "	{$ENDIF}"
        
        NATIVE_gluDeleteQuadric = @
        "	{$IFDEF SIMULATE_QUADRICS}"
        "	 {$IFDEF USE_LISTS_OF_DESCRIPTORS}"
        "    	sim_gluDeleteQuadric(All_quadrics[X_Obj]);"
        "		release_quadric(X_Obj);"
        "	 {$ELSE}"
        "    	sim_gluDeleteQuadric(Pointer(X_Obj));"
        "	 {$ENDIF}"
        "	{$ELSE}"
        "    gluDeleteQuadric(Pointer(X_Obj));"
        "	{$ENDIF}"
        
        NATIVE_gluQuadricDrawStyle = @
        "	{$IFDEF SIMULATE_QUADRICS}"
        "	 {$IFDEF USE_LISTS_OF_DESCRIPTORS}"
        "    	sim_gluQuadricDrawStyle(All_quadrics[X_Obj], X_Style);"
        "	 {$ELSE}"
        "    	sim_gluQuadricDrawStyle(Pointer(X_Obj), X_Style);"
        "	 {$ENDIF}"
        "	{$ELSE}"
        "    gluQuadricDrawStyle(Pointer(X_Obj), X_Style);"
        "	{$ENDIF}"
        
        NATIVE_gluQuadricOrientation = @
        "	{$IFDEF SIMULATE_QUADRICS}"
        "	 {$IFDEF USE_LISTS_OF_DESCRIPTORS}"
        "    	sim_gluQuadricOrientation(All_quadrics[X_Obj], X_Orient);"
        "	 {$ELSE}"
        "    	sim_gluQuadricOrientation(Pointer(X_Obj), X_Orient);"
        "	 {$ENDIF}"
        "	{$ELSE}"
        "    gluQuadricOrientation(Pointer(X_Obj), X_Orient);"
        "	{$ENDIF}"
        
        NATIVE_gluQuadricTexture = @
        "	{$IFDEF SIMULATE_QUADRICS}"
        "	 {$IFDEF USE_LISTS_OF_DESCRIPTORS}"
        "    	sim_gluQuadricTexture(All_quadrics[X_Obj], Byte(X_Texture_c));"
        "	 {$ELSE}"
        "    	sim_gluQuadricTexture(Pointer(X_Obj), Byte(X_Texture_c));"
        "	 {$ENDIF}"
        "	{$ELSE}"
 		"		{$IFDEF FPC}"       
        "    gluQuadricTexture(Pointer(X_Obj), Byte(X_Texture_c));"
        "		{$ELSE}"
        "    gluQuadricTexture(Pointer(X_Obj), ByteBool(X_Texture_c));"
        "		{$ENDIF}"
        "	{$ENDIF}"
        
        NATIVE_gluQuadricNormals = @
        "	{$IFDEF SIMULATE_QUADRICS}"
        "	 {$IFDEF USE_LISTS_OF_DESCRIPTORS}"
        "    	sim_gluQuadricNormals(All_quadrics[X_Obj], X_Normals);"
        "	 {$ELSE}"
        "    	sim_gluQuadricNormals(Pointer(X_Obj), X_Normals);"
        "	 {$ENDIF}"
        "	{$ELSE}"
        "    gluQuadricNormals(Pointer(X_Obj), X_Normals);"
        "	{$ENDIF}"
        
        NATIVE_gluCylinder = @
        "	{$IFDEF SIMULATE_QUADRICS}"
        "	 {$IFDEF USE_LISTS_OF_DESCRIPTORS}"
        "		//if true then writeln('gluCylinder(' + IntToStr(X_Obj) + ')');"
        "    	sim_gluCylinder(All_quadrics[X_Obj],"
        "       	X_Base_r, X_Top_r, X_Height, X_Slices, X_Stacks);"
        "	 {$ELSE}"
        "    	sim_gluCylinder(Pointer(X_Obj),"
        "       	X_Base_r, X_Top_r, X_Height, X_Slices, X_Stacks);"
        "	 {$ENDIF}"
		"	{$ELSE}"
        "    gluCylinder(Pointer(X_Obj),"
        "       X_Base_r, X_Top_r, X_Height, X_Slices, X_Stacks);"
        "	{$ENDIF}"
        
        NATIVE_gluDisk = @
        "	{$IFDEF SIMULATE_QUADRICS}"
        "	 {$IFDEF USE_LISTS_OF_DESCRIPTORS}"
        "		//if true then writeln('gluDisk(' + IntToStr(X_Obj) + ')');"
        "    	sim_gluDisk(All_quadrics[X_Obj], "
        "			X_Inner_r, X_Outer_r, X_Slices, X_Loops);"
        "	 {$ELSE}"
        "    	sim_gluDisk(Pointer(X_Obj), "
        "			X_Inner_r, X_Outer_r, X_Slices, X_Loops);"
        "	 {$ENDIF}"
        "	{$ELSE}"
        "    gluDisk(Pointer(X_Obj), X_Inner_r, X_Outer_r, X_Slices, X_Loops);"
        "	{$ENDIF}"
        
        NATIVE_gluPartialDisk = @
        "	{$IFDEF SIMULATE_QUADRICS}"
        "	 {$IFDEF USE_LISTS_OF_DESCRIPTORS}"
        "		//if true then writeln('gluPartialDisk(' + IntToStr(X_Obj) + ')');"
        "    	sim_gluPartialDisk(All_quadrics[X_Obj],"
        "       	X_Inner_r, X_Outer_r, X_Slices, X_Loops, "
        "			X_Start_a, X_Sweep_a);"
        "	 {$ELSE}"
        "    	sim_gluPartialDisk(Pointer(X_Obj),"
        "       	X_Inner_r, X_Outer_r, X_Slices, X_Loops, "
        "			X_Start_a, X_Sweep_a);"
        "	 {$ENDIF}"
        "	{$ELSE}"
        "    gluPartialDisk(Pointer(X_Obj),"
        "       X_Inner_r, X_Outer_r, X_Slices, X_Loops, X_Start_a, X_Sweep_a);"
        "	{$ENDIF}"
        
        NATIVE_gluSphere = @
        "	{$IFDEF SIMULATE_QUADRICS}"
        "	 {$IFDEF USE_LISTS_OF_DESCRIPTORS}"
        "		//if true then writeln('gluSphere(' + IntToStr(X_Obj) + ')');"
        "    	sim_gluSphere(All_quadrics[X_Obj], "
        "			X_Radius, X_Slices, X_Stacks);"
        "	 {$ELSE}"
        "    	sim_gluSphere(Pointer(X_Obj), X_Radius, X_Slices, X_Stacks);"
        "	 {$ENDIF}"
        "	{$ELSE}"
        "    gluSphere(Pointer(X_Obj), X_Radius, X_Slices, X_Stacks);"
        "	{$ENDIF}"

        .        
*/
*)

end.
(*
/*
END
*/
*)



