/*

// wrapper for {OpenGL} control, for Java/Android

CLASS {AL4_OpenGL|_Java_android}, NATIVE, UNTESTED :
      IMPORT: {OpenGL} ;
      
*/

import java.util.ArrayList;
import java.lang.Math.*;

import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import android.opengl.GLU;
import android.opengl.GLES11;
import android.opengl.GLES20;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;

import java.nio.ByteOrder;
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import java.nio.FloatBuffer;

import android.app.Activity;
import android.content.Context;
import android.app.ActivityManager;
import android.content.pm.ConfigurationInfo;
import android.widget.Toast;

import android.os.*;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.*;

public class AL4_OpenGL extends GLSurfaceView {

    public C_OpenGL C_Canvas;
    public C_Form   C_Form_parent;
    public static GL10 gl;
    boolean Invalidated;
    boolean is_drawing;
    
    AL4_OpenGL(AL4_form F, C_Form p, C_OpenGL c) {
    	super(AL4_form.context_activity);
    	
    	final ActivityManager activityManager 
    		= (ActivityManager) 
    		AL4_form.context_activity.getSystemService(
    		Context.ACTIVITY_SERVICE);
    	final ConfigurationInfo configurationInfo 
    		= activityManager.getDeviceConfigurationInfo();
    	final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
    	if (!supportsEs2)
    		Toast.makeText(AL4_form.context_activity,
    		"This device does not support OpenGL ES 2.0.",
    		Toast.LENGTH_LONG).show();
    		
    	//setEGLContextClientVersion(1); //-- if uncomment when not drawing any
    	
        C_Form_parent = p;
        C_Canvas = c;
    //AL4_system.WriteLine("before set renderer");
        setRenderer(new AL4_GLrenderer(this, F));
        \\setRenderMode(RENDERMODE_WHEN_DIRTY);
    //AL4_system.WriteLine("after set renderer");
    }
    
    	boolean measuring = false;
    
        @Override
        public void onMeasure(int wSpec, int hSpec) {
        	if (measuring) {
        		super.onMeasure(wSpec, hSpec); return;
        	} 
        	measuring = true;
        	try {
	            int wIn = MeasureSpec.getSize(wSpec);
	            int hIn = MeasureSpec.getSize(hSpec);
	            int wSet = -2;
	            int hSet = -2;
	            int w = wSet;
	            int h = hSet;
	            AL4_form.AL4Column col = AL4_form.Get_parent_column(this);
	            int col_w = 0;
            	if (col != null) {
            		col_w = col.Width_pixels;
            		if (col_w == 0) col_w = col.getWidth();
            	}
	            if (wSet <= -2 || wSet == 0 && col != null && col.Layout == 0) {
	            	if (col != null) {
	            		w = col_w;
        	//---------------------------------------------------------
            //AL4_system.WriteLine("onMeasure" +
            //(Looper.getMainLooper() == Looper.myLooper() ? "+onUI":"-onBG")
            //+ "parent column [" + col.Alias + "]:" +
            //" w=" + w + " Width_points=" + col.Width_points +
            //" Width_pixels=" + col.Width_pixels +
            //" col_w=" + col_w);
            //---------------------------------------------------------
	            		wIn = w;
	            	}
	            }
	            else {
	            }
	            
	            if (hSet <= -2 || col != null && col.getChildCount() == 1) {
	            	if (col != null) {
	            		h = col.getHeight();
	            		if (h < AL4_form.Points(col.Height_points))
	            			h = AL4_form.Points(col.Height_points);
	            		if (col.Height_pixels != 0) h = col.Height_pixels;
	            		hIn = h;
        	//---------------------------------------------------------
            //AL4_system.WriteLine("onMeasure"
            //+ "parent column [" + col.Alias + "]:" +
            //" h=" + h + " Height_points=" + col.Height_points +
            //" Height_pixels=" + col.Height_pixels);
            //---------------------------------------------------------
	            	}
	            }
	        	switch(MeasureSpec.getMode(wSpec)) {
	        	case MeasureSpec.EXACTLY:
					w = Math.max(wIn, w);
					if (col.Layout < 3)
						w = Math.min(w, col_w);
					break;
	        	case MeasureSpec.AT_MOST: w = Math.min(wIn, w); break;
	        	default: w = w; break;
	        	}
	        	switch(MeasureSpec.getMode(hSpec)) {
	        	case MeasureSpec.EXACTLY: h = Math.max(hIn, h); break;
	        	case MeasureSpec.AT_MOST: h = Math.min(hIn, h); break;
	        	default: h = h; break;
	        	}
	            if (w <= 0) w = wIn;
	            if (w <= 0) w = wSet; 
	            if (w <= 0) w = AL4_form.Points(100); 
	            if (h <= 0) h = hIn;
	            if (h <= 0) h = hSet; 
	            if (h <= 0) h = AL4_form.Points(100);
        //------------------------------------------------------
        //AL4_system.WriteLine(C_Canvas.F_Alias +
        //".onMeasure(" + AL4_form.AL4Column.spec(wSpec) + "," +
        //AL4_form.AL4Column.spec(hSpec) + ")" +
        //" / set[" + wSet + "," + hSet + "]" + " ==> (" + w + " x " + h + ")");
        //------------------------------------------------------
            	setMeasuredDimension(w, h);
        	}
        	finally {
        		measuring = false;
        	}
        }    

	/*
	// Create OpenGL control, return descriptor. 
	//-------------------------------------------
	FUN Create_opengl_control({OpenGL} GL|_control) ==> INT, NATIVE :
        ------------------------------------- 'dummy operation to use {Picture}'
        //{layout_image} layout_dummy = 'STRETCHED'
        ---------------------------------------- 'redirect to GL control create'
        INT f|orm_handle = GL_control.Form_.Handle
		//DEBUG: << "Create opengl control, f=" f.S #NL ;
        NATIVE "    RESULT = AL4_OpenGL.Do_Create_opengl_control(X_f, X_GL);" .
	*/
	public static int Do_Create_opengl_control(int H, Ref_obj X_GL)
	{
		return AL4_form.get_property_int(new Callable<Integer>(){
			@Override public Integer call() {
				try {
					AL4_form.AL4Column C = AL4_form.Get_parent_for_new_control(H);
					C_Form cForm = (C_Form)AL4_form.All_descr.get(C.Form_.Handle).Ref.Obj;
			        //GLProfile glp = GLProfile.get(GLProfile.GL2);
			        //GLCapabilities cap = new GLCapabilities( glp );
					AL4_OpenGL G = new AL4_OpenGL(C.Form_, cForm, (C_OpenGL)X_GL.Obj);
					//int Result = AL4_form.Alloc_descriptor(G, X_GL);
					int Result = AL4_form.add_control_multi_line(H, G, X_GL, 
							true // match_parent
							);
			    //AL4_system.WriteLine("after create openGL control, Handle=" + Result);
			
			        //AL4_form.adjust_control_size_position(C, G);
					AL4_form.Set_control_events(X_GL, G, true);
			    //AL4_system.WriteLine("************ Handle OpenGL of control: " +  Result);
			        return Result;
				}
				catch (Exception ex2) { AL4_form.report(ex2); }
				return 0;
			}
		});
	}
    
    
	public static final int GL_TRIANGLES 		= 4;
	public static final int GL_TRIANGLE_STRIP 	= 5;
	public static final int GL_TRIANGLE_FAN 	= 6;
	public static final int GL_QUADS 			= 7;
	public static final int GL_QUAD_STRIP 		= 8;
	public static final int GL_POLYGON 			= 9;
	public static final int GL_COMPILE 			= 0x1300;
	public static final int GLU_FILL = 0x000186ac;
	public static final int GLU_LINE = 0x000186ab;
	public static final int GLU_SILHOUETTE = 0x000186ad;
	public static final int GLU_POINT = 0x000186aa;
	public static final int GLU_NONE = 0x000186a2;
	public static final int GLU_FLAT = 0x000186a1;
	public static final int GLU_SMOOTH = 0x000186a0;
	public static final int GLU_OUTSIDE = 0x000186b4;
	public static final int GLU_INSIDE = 0x000186b5;
	
    
    public static class SimList {
    
    	public int BE_mode; // GL_LINES, GL_TRIANGLES, GL_QUADS, GL_QUAD_STRIP, ...
    	public int Count_vertexes;
    	
    	public FloatBuffer Vertexes = null;
    	public FloatBuffer TexCoords = null;
    	public FloatBuffer Colors = null;
    	public FloatBuffer Normals = null;
    	public ShortBuffer Indices = null;
    	
    	//-------------------------------------------------------
    	boolean Used_TexCoord;
    	boolean Used_Colors;
    	boolean Used_Normals;
    	public
    	int Vertex_Components; // 3 or 4
    	public
    	int Tex_Components; // 2 or 3 or 4
    	public
    	int Color_Components; // 3 or 4
    	public
    	float Cur_Tex_Coord_X, Cur_Tex_Coord_Y, Cur_Tex_Coord_Z, Cur_Tex_Coord_W;
    	public
    	float Cur_Normal_X, Cur_Normal_Y, Cur_Normal_Z;
    	public
    	float Translate_X, Translate_Y, Translate_Z;
    	//------------------------------------------
    	public void Add_vertex(float X, float Y, float Z, float W, int Comp_count) {
    		if (Count_vertexes == 0) Vertex_Components = Comp_count;
    		if (Vertexes == null || Vertexes.isDirect())
    			Vertexes = FloatBuffer.allocate(100);
    		if (Count_vertexes + Vertex_Components > Vertexes.limit()) {
        //AL4_system.WriteLine(".................. increase limit from " +
        //Vertexes.limit());
        		FloatBuffer old_fb = Vertexes;
        		int old_pos = old_fb.position();
        		Vertexes = FloatBuffer.allocate(Vertexes.limit() * 2 + 100);
        		old_fb.position(0);
        		Vertexes.put(old_fb);
        		Vertexes.position(old_pos);
        //AL4_system.WriteLine("================== new limit is " +
        //Vertexes.limit());
    		}
    		Vertexes.put(Count_vertexes, X);
    		Vertexes.put(Count_vertexes+1, Y);
    		Vertexes.put(Count_vertexes+2, Z);
    		if (Vertex_Components == 4)
    			Vertexes.put(Count_vertexes+3, W);
    			
    		if (Used_Colors)
    			Add_color(Last_Color_R, Last_Color_G, Last_Color_B, Last_Color_A);
    			
    		if (Used_TexCoord)
    			Add_tex_coord(Cur_Tex_Coord_X, Cur_Tex_Coord_Y, Cur_Tex_Coord_Z,
    			Cur_Tex_Coord_W);
    			
    		if (Used_Normals)
    			Add_normal(Cur_Normal_X, Cur_Normal_Y, Cur_Normal_Z);
    			
    		Count_vertexes += Vertex_Components;
        //AL4_system.WriteLine("after Add_vertex Count_vertexes=" + Count_vertexes);
    	}
    	
    	public void Add_tex_coord(float X, float Y, float Z, float W) {
    		if (TexCoords == null || TexCoords.isDirect())
    			TexCoords = FloatBuffer.allocate(100);
    		int i = (Count_vertexes / Vertex_Components) * Tex_Components;
    		if (i + Tex_Components > TexCoords.limit()) {
        		FloatBuffer old_fb = TexCoords;
        		int old_pos = old_fb.position();
        		TexCoords = FloatBuffer.allocate(TexCoords.limit() * 2 + 100);
        		old_fb.position(0);
        		TexCoords.put(old_fb);
        		TexCoords.position(old_pos);
    		}
    		TexCoords.position(i);
    		TexCoords.put(X);
    		TexCoords.put(Y);
    		if (Tex_Components <= 2) return;
    		TexCoords.put(Z);
    		if (Tex_Components <= 3) return;
    		TexCoords.put(W);
    	}
    	
    	public void Add_color(float R, float G, float B, float A) {
    		if (Colors == null || Colors.isDirect())
    			Colors = FloatBuffer.allocate(100);
    		int i = (Count_vertexes / Vertex_Components) * Color_Components;
    		if (i + Color_Components > Colors.limit()) {
        		FloatBuffer old_fb = Colors;
        		int old_pos = old_fb.position();
        		Colors = FloatBuffer.allocate(Colors.limit() * 2 + 100);
        		old_fb.position(0);
        		Colors.put(old_fb);
        		Colors.position(old_pos);
    		}
    		Colors.position(i);
    		Colors.put(R);
    		Colors.put(G);
    		Colors.put(B);
    		if (Color_Components <= 3) return;
    		Colors.put(A);
    	}
    	
    	public void Add_normal(float X, float Y, float Z) {
    		if (Normals == null || Normals.isDirect())
    			Normals = FloatBuffer.allocate(100);
    		int i = (Count_vertexes / Vertex_Components) * 3;
    		if (i + 3 > Normals.limit()) {
        		FloatBuffer old_fb = Normals;
        		int old_pos = old_fb.position();
        		Normals = FloatBuffer.allocate(Normals.limit() * 2 + 100);
        		old_fb.position(0);
        		Normals.put(old_fb);
        		Normals.position(old_pos);
    		}
    		Normals.position(i);
    		Normals.put(X);
    		Normals.put(Y);
    		Normals.put(Z);
    	}
    	
    	public void Execute() {
    		   Execute(false);
    	}
    	
    	public void Execute(boolean Logging) {
        //if (Logging)
        //AL4_system.WriteLine("execute: Count_vertexes=" + Count_vertexes +
        //" Vertex_Components=" + Vertex_Components);
    		if (Count_vertexes > 0) {
    			int m = Count_vertexes / Vertex_Components;
        //if (Logging)
        //AL4_system.WriteLine("m=" + m +
        //" Vertex_Components=" + Vertex_Components + "***********************\n"
        //+ "Used_Colors=" + Used_Colors + " Used_TexCoord=" + Used_TexCoord +
        //" Used_Normals=" + Used_Normals);
                if (Used_Colors) {
                	if (!Colors.isDirect()) {
    					FloatBuffer fb_old = Colors;
    					Colors = ByteBuffer.allocateDirect(
    						Count_vertexes / Vertex_Components * Color_Components
    						* 4)
    						.order(ByteOrder.nativeOrder())
    						.asFloatBuffer();
    					Colors.put(fb_old.array(), 0, Colors.limit());
    					Colors.position(0);
    				}
                    gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
                    gl.glColorPointer(Color_Components, GL10.GL_FLOAT, 0, Colors);
        //if (Logging)
        //AL4_system.WriteLine("Color_Components=" + Color_Components + " xxxxx\n" +
        //" Colors=" + Colors +
        //" errors:" + GLU.gluErrorString(GLES20.glGetError()) + " xxxxxxxxxxxxx");
                }
                if (Used_TexCoord) {
                	if (!TexCoords.isDirect()) {
    					FloatBuffer fb_old = TexCoords;
    					TexCoords = ByteBuffer.allocateDirect(
    						Count_vertexes / Vertex_Components 
    						* Tex_Components * 4)
    						.order(ByteOrder.nativeOrder())
    						.asFloatBuffer();
    					TexCoords.put(fb_old.array(), 0, TexCoords.limit());
    					TexCoords.position(0);
    				}
                    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
                    gl.glTexCoordPointer(Tex_Components, GL10.GL_FLOAT, 0, TexCoords);
        //if (Logging) {
        //AL4_system.WriteLine("Tex_Components=" + Tex_Components + " xxxxx\n" +
        //" TexCoords=" + TexCoords +
        //" errors:" + GLU.gluErrorString(GLES20.glGetError()) + " xxxxxxxxxxxxx");
        //for (int i = 0; i<TexCoords.limit(); i++)
        //AL4_system.Write(" " + i + ":" + TexCoords.get(i));
        //AL4_system.WriteLine(""); }
                }
                if (Used_Normals) {
                	if (!Normals.isDirect()) {
    					FloatBuffer fb_old = Normals;
    					Normals = ByteBuffer.allocateDirect(
    						Count_vertexes / Vertex_Components * 3 * 4
    						)
    						.order(ByteOrder.nativeOrder())
    						.asFloatBuffer();
    					Normals.put(fb_old.array(), 0, Normals.limit());
    					Normals.position(0);
    				}
                    gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
                    gl.glNormalPointer(GL10.GL_FLOAT, 0, Normals);
        //if (Logging) {
        //AL4_system.WriteLine(
        //" Normals=" + Normals + "****************************\n" +
        //" errors:" + GLU.gluErrorString(GLES20.glGetError()) + "****"); }
                }
    			{
    				if (!Vertexes.isDirect()) {
    					FloatBuffer fb_old = Vertexes;
    					Vertexes = ByteBuffer.allocateDirect(Count_vertexes * 4)
    						.order(ByteOrder.nativeOrder()).asFloatBuffer();
    					Vertexes.put(fb_old.array(), 0, Vertexes.limit());
    					Vertexes.position(0);
    				}
	    			gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
	    			gl.glVertexPointer(Vertex_Components, GL10.GL_FLOAT, 0, 
	    				Vertexes);
        //if (Logging) {
        //AL4_system.WriteLine(
        //" Vertexes=" + Vertexes +
        //"\nerrors:" + GLU.gluErrorString(GLES20.glGetError()) + "****\n" +
        //" BE_mode=" + (BE_mode==GL_QUADS?"GL_QUADS":"") +
        //(BE_mode==GL_QUAD_STRIP?"GL_QUAD_STRIP":"") +
        //(BE_mode==GL_POLYGON?"GL_POLYGON":"") +
        //BE_mode + "*************************************************");}
    			}
    			
    			int shape = BE_mode;
    			switch (shape) {
    			case GL_QUADS:
					int n = m / 4;
					int k = n * 6;                            	
					Indices = ByteBuffer.allocateDirect(k * 2)
						.order(ByteOrder.nativeOrder())
						.asShortBuffer();
					for (int i = 0; i < n; i++) {
						Indices.put((short)(i * 4));
						Indices.put((short)(i * 4 + 1));
						Indices.put((short)(i * 4 + 2));
						Indices.put((short)(i * 4 + 2));
						Indices.put((short)(i * 4 + 3));
						Indices.put((short)(i * 4));
					}
					Indices.position(0);
        //if (Logging)
        //AL4_system.WriteLine(" Vertexes=" + Vertexes + " Indices=" + Indices +
        //" n=" + n + " k=" + k + " ????????????????????????????? errors:" +
        //GLU.gluErrorString(GLES20.glGetError()) + "????????????????????");
	    			GLES20.glDrawElements(GL_TRIANGLES, Indices.limit(),
	    			GL10.GL_UNSIGNED_SHORT, Indices);
	    			break;
	    			
    			case GL_QUAD_STRIP:
					shape = GL_TRIANGLE_STRIP;
					GLES20.glDrawArrays(shape, 0, m);
					break;
					
    			case GL_POLYGON:
					shape = GL_TRIANGLE_FAN;
					GLES20.glDrawArrays(shape, 0, m);
					
    			case 0:
        //if (Logging)
        //AL4_system.WriteLine(" Vertexes=" + Vertexes + " Indices=" + Indices +
        //" m=" + m + " m/3=" + (m/3) + " +++++++++++++++++++++++++++ errors:" +
        //GLU.gluErrorString(GLES20.glGetError()) + "++++++++++++++++++");
					GLES20.glDrawElements(GL_TRIANGLES, Indices.limit(), // m / 3,
					GL10.GL_UNSIGNED_SHORT, Indices);
					break;
					
    			default:
					GLES20.glDrawArrays(shape, 0, m);
    			}
    			gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    			gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
    			gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    			gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
    		}
        //if (Logging)
        //AL4_system.WriteLine("before translate: " + Translate_X +
        //" " + Translate_Y + " " + Translate_Z + " errors:" +
        //GLU.gluErrorString(GLES20.glGetError()) + "*****************");
    		gl.glTranslatef(Translate_X, Translate_Y, Translate_Z);
    	}
    	
    } // end of SimList class
    
	public static SimList Temp_List = null; 
	public static SimList Cur_List = null;
	public static int Cur_List_index;
	public static int New_List_Mode;
	
	public static void sim_glBegin(int mode) {
		if (Cur_List == null) {
			if (Temp_List == null)
				Temp_List = new SimList();
			Cur_List = Temp_List;
			Cur_List_index = 0;
		}
		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;
		Cur_List.Indices = null;
	//AL4_system.WriteLine("sim_glBegin **************************************");
	}
	
	public static void sim_glEnd() {
		if (Cur_List == null) return;
		if (New_List_Mode != GL_COMPILE) {
	//AL4_system.WriteLine("sim_glEnd: before Execute ************************" +
	//GLU.gluErrorString(GLES20.glGetError()) + " Cur_List=" + Cur_List);
			Cur_List.Execute();
	//AL4_system.WriteLine("sim_glEnd ****************************************");
		}
		//Cur_List = null;
	}
	
	public static ArrayList<SimList> sim_Lists = new ArrayList<SimList>();
	
	public static int sim_glGenLists(int Count) {
		int Result = 0;
		if (Count <= 0 || Count >= 1000) return Result;
		if (sim_Lists == null) {
			sim_Lists = new ArrayList<SimList>();
			sim_Lists.add(null);
		}
		for (int i = 1; i <= sim_Lists.size()-Count; i++) {
			if (sim_Lists.get(i) != null) continue;
			Result = i;
			for (int j = i+1; j <= i+Count-1; j++) {
				if (sim_Lists.get(j) != null) {
					Result = 0;
					break;
				}
			}
			if (Result > 0) break;
		}
		if (Result == 0) {
			for (int i = sim_Lists.size()-1; i>= 1; i--) {
				if (sim_Lists.get(i) != null) break;
				Result = i;
			}
		}
		if (Result == 0) Result = sim_Lists.size();
		for (int i = Result; i <= Result + Count-1; i++) {
			if (i >= sim_Lists.size()) sim_Lists.add(null);
			sim_Lists.set(i, new SimList());
		}
		return Result;
	}
	
	public static void sim_glDeleteLists(int List, int Count) {
		if (sim_Lists == null) return;
		for (int i = List; i <= List+Count-1; i++) {
			if (i >= sim_Lists.size()) return;
			if (sim_Lists.get(i) == null) continue;
			sim_Lists.set(i, null);
		}
	}
	
	public static void sim_glNewList(int List, int Mode) {
		if (!sim_glIsList(List)) return;
		sim_Lists.set(List, new SimList());
		Cur_List = sim_Lists.get(List);
		Cur_List_index = List;
		New_List_Mode = Mode;
	}
	
	public static void sim_glEndList() {
		Cur_List = null;
		New_List_Mode = 0;
	}
	
	public static boolean sim_glIsList(int List) {
		if (sim_Lists == null || List <= 0) return false;
		if (List >= sim_Lists.size())return false;
		if (sim_Lists.get(List) == null) return false;
		return true;
	}
	
	public static int sim_Base_list;
	
	public static void sim_glListBase(int Base) {
		sim_Base_list = Base;
	}
	
	public static void sim_glCallList(int List) {
		if (!sim_glIsList(List)) return;
		SimList sList = sim_Lists.get(List);
		if (sList != null)
			sList.Execute(); //true);
	}
	
	public static void sim_glCallLists(int Count, int Type_dummy, int[] Lists) {
		for (int i = 0; i < Count; i++)
			sim_glCallList(Lists[i] + sim_Base_list);
	}
	
	public static void sim_glVertex3f(float X, float Y, float Z) {
		if (Cur_List == null) return;
		Cur_List.Add_vertex(X, Y, Z, 1, 3);
	}
	
	public static void sim_glVertex4f(float X, float Y, float Z, float W) {
		if (Cur_List == null) return;
		Cur_List.Add_vertex(X, Y, Z, W, 4);
	}
	
	public static void sim_glTexCoord2f(float X, float Y) {
		if (Cur_List == null) return;
		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) Cur_List.Tex_Components = 2;
	}
	
	public static void sim_glTexCoord3f(float X, float Y, float Z) {
		if (Cur_List == null) return;
		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) Cur_List.Tex_Components = 3;
	}
	
	public static void sim_glTexCoord4f(float X, float Y, float Z, float W) {
		if (Cur_List == null) return;
		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) Cur_List.Tex_Components = 4;
	}
	
	public static float Last_Color_R, Last_Color_G, Last_Color_B, Last_Color_A;
	
	public static void sim_glColor3f(float R, float G, float B) {
		Last_Color_R = R;
		Last_Color_G = G;
		Last_Color_B = B;
		Last_Color_A = 1f;
		AL4_OpenGL.gl.glColor4f(R, G, B, 1f);
		if (Cur_List == null) return;
		Cur_List.Used_Colors = true;
		if (Cur_List.Color_Components == 0)
			Cur_List.Color_Components = 4; //3; at list on one Android device
										   // value of 3 leads: glGetError=1281
										   // =GL_INVALID_VALUE
	}
	
	public static void sim_glColor4f(float R, float G, float B, float A) {
		Last_Color_R = R;
		Last_Color_G = G;
		Last_Color_B = B;
		Last_Color_A = A;
		AL4_OpenGL.gl.glColor4f(R, G, B, A);
		if (Cur_List == null) return;
		Cur_List.Used_Colors = true;
		if (Cur_List.Color_Components == 0)
			Cur_List.Color_Components = 4;
	}
	
	public static void sim_glNormal3f(float X, float Y, float Z) {
		if (Cur_List == null) return;
		Cur_List.Used_Normals = true;
		Cur_List.Cur_Normal_X = X;
		Cur_List.Cur_Normal_Y = Y;
		Cur_List.Cur_Normal_Z = Z;
	}
	
	public static void sim_glTranslatef(float X, float Y, float Z) {
		if (New_List_Mode != GL_COMPILE)
			gl.glTranslatef(X, Y, Z);
		if (Cur_List != null) {
			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;
		}
	}
	
	
	public static final int qdsFill = 0;
	public static final int qdsLine = 1;
	public static final int qdsSilhouette = 2;
	public static final int qdsPoint = 3;
	
	public static final int qsCylinder = 4;
	public static final int qsDisk = 5;
	public static final int qsSphere = 6;
	
	public static class SimQuadric {
		public boolean Direction_inside;
		public boolean Need_normals;
		public boolean Normals_smooth;
		public int Draw_style;
		public boolean Need_texture;
		public SimList Def;
		//---------------------- parameters stored to define if to re-generate
		public int Shape; // qsCylinder or qsDisk or qsSphere
		public float P_base, P_top, P_height, P_radius;
		public int P_slices, P_stacks, P_loops;
		public float P_inner, P_outer, P_start, P_sweep;
	}
	
	public static ArrayList<SimQuadric> All_quadrics = new ArrayList<SimQuadric>();
	
	public static int allocate_quadric(SimQuadric q) {
		if (All_quadrics.size() == 0)
			All_quadrics.add(new SimQuadric());
		int Result = All_quadrics.indexOf(null);
		if (Result < 0) {
			Result = All_quadrics.size();
			All_quadrics.add(null);
		}
		All_quadrics.set(Result, q);
		return Result;
	}
	
	public static void release_quadric(int i) {
		if (i <= 0 || i >= All_quadrics.size()) return;
		All_quadrics.set(i, null); 
	}
	
	public static int sim_gluNewQuadric() {
		SimQuadric q = new SimQuadric();
		q.Need_normals = true;
		q.Normals_smooth = true;
		return allocate_quadric(q);
	}
	
	public static void sim_gluDeleteQuadric(int n_quadric) {
		if (n_quadric <= 0 || n_quadric >= All_quadrics.size()) return;
		All_quadrics.set(n_quadric, null);
	}
	
	public static void sim_gluQuadricDrawStyle(int n_quadric, int ds) {
		SimQuadric q = All_quadrics.get(n_quadric);
		int new_style = q.Draw_style;
		switch (ds) {
		case GLU_FILL:	new_style = qdsFill; break;
		case GLU_LINE:	new_style = qdsLine; break;
		case GLU_SILHOUETTE: new_style = qdsSilhouette; break;
		case GLU_POINT:		new_style = qdsPoint; break;
		default: return;
		}
		if (new_style == q.Draw_style) return;
		q.Draw_style = new_style;
		q.Def = null;
	}
	
	public static void sim_gluQuadricOrientation(int n_quadric, int orientation) {
		SimQuadric q = All_quadrics.get(n_quadric);
		switch (orientation) {
		case GLU_OUTSIDE:
			if (q.Direction_inside) q.Direction_inside = false;
			else return;
			break;
		case GLU_INSIDE:
			if (q.Direction_inside) return;
			else q.Direction_inside = true;
			break;
		default: return;
		}
		q.Def = null;
	}
	
	public static void sim_gluQuadricNormals(int n_quadric, int normals) {
		SimQuadric q = All_quadrics.get(n_quadric);
		switch (normals) {
		case GLU_NONE:
			if (q.Need_normals) q.Need_normals = false;
			else return;
			break;
		case GLU_FLAT:
			if (q.Need_normals && !q.Normals_smooth) return;
			else {
				q.Need_normals = true;
				q.Normals_smooth = false;
			}
			break;
		case GLU_SMOOTH:
			if (q.Need_normals && q.Normals_smooth) return;
			else {
				q.Need_normals = true;
				q.Normals_smooth = true;
			}
			break;
		default: return;
		}
		q.Def = null;
	}
	
	public static void sim_gluQuadricTexture(int n_quadric, int texture) {
		SimQuadric q = All_quadrics.get(n_quadric);
		switch (texture) {
		case GL10.GL_TRUE:
			if (q.Need_texture) return;
			else q.Need_texture = true;
			break;
		case GL10.GL_FALSE:
			if (q.Need_texture) q.Need_texture = false;
			else return;
			break;
		default: return;
		}
		q.Def = null;
	}
	
	static void swap(int[] a, int i, int j) {
		int x = a[i];
		int y = a[j];
		a[i] = y;
		a[j] = x;
	}
	
	static void swap_sh(short[] a, int i, int j) {
		short x = a[i];
		short y = a[j];
		a[i] = y;
		a[j] = x;
	}
	
    //static void apply_draw_mode(SimQuadric q);
    //begin
    //end;

	public static void sim_gluCylinder(int n_quadric,
		float base, float top, float height, int slices, int stacks) {
		SimQuadric q = All_quadrics.get(n_quadric);
		while (6 * slices * stacks >= 32767) {
			if (slices > 30) slices = slices >>> 2;
			if (stacks > 30) stacks = stacks >>> 2;
		}
	    //if true then
	    //begin
	    //    writeln('sim_gluCylinder q=' + IntToHex(Integer(q), 8) +
	    //    ', q.Def=' + IntToHex(Integer(q.Def), 8));
	    //end;
		int rebuild = 0;
		if (q.Shape != qsCylinder) rebuild = 1;
		if (q.P_base != base) rebuild = 2;
		if (q.P_top != top) rebuild = 3;
		if (q.P_height != height) rebuild = 4; 
		if (q.P_slices != slices) rebuild = 5;
		if (q.P_stacks != stacks) rebuild = 6;
		if (rebuild != 0) q.Def = null;
		if (q.Def == null) {
    //AL4_system.WriteLine("build CYLINDER (" + rebuild + ")" + q +
    //" base=" + base + " top=" + top +
    //" h=" + height + " slices=" + slices + " stacks=" + stacks +
    //", stored: " + q.P_base + ", " + q.P_top +
    //", " + q.P_height + ", slices=" + q.P_slices +
    //", stacks=" + q.P_stacks +
    //", shape was " + q.Shape + " whereas new is " + qsCylinder );
		
			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 || slices <= 1) return; 
			//if true then writeln('cylinder 2');
			q.Def = new SimList();
			q.Def.BE_mode = 0;
			q.Def.Tex_Components = 2;
			q.Def.Vertex_Components = 3;
			Cur_List = q.Def;
			gl.glColor4f(Last_Color_R, Last_Color_G, Last_Color_B, Last_Color_A);
			sim_glColor4f(Last_Color_R, Last_Color_G, Last_Color_B, Last_Color_A);
    //AL4_system.WriteLine("cylinder color: " + Last_Color_R + " " + Last_Color_G +
    //" " + Last_Color_B + " " + Last_Color_A);
			
			q.Def.Indices = ByteBuffer.allocateDirect(6 * stacks * slices * 2)
						.order(ByteOrder.nativeOrder())
						.asShortBuffer(); 
			short v = 0;
			//if true then writeln('cylinder 3-2');
			short[] vv = new short[6];
			
			for (int i = 0; i <= slices; i++) {
				double alpha = 2 * Math.PI / slices * i;
				for (int j = 0; j <= stacks; j++) {
					double z = height / stacks * j;
					double r = base + (top - base) / stacks * j;
					if (q.Need_texture)
						sim_glTexCoord2f(i / slices, j / stacks);
					double nx = Math.cos(alpha);
					double ny = Math.sin(alpha);
					if (q.Need_normals) {
						double nz = 0;
						sim_glNormal3f( (float)nx, (float)ny, (float)nx );
					}
					q.Def.Add_vertex(
						(float)(r * nx),
						(float)(r * ny),
						(float)z, 1, 3);
					if (i < slices && j < stacks) {
						vv[0] = v;
						vv[1] = (short)(v+1);
						vv[2] = (short)(v+1+(stacks+1));
						vv[3] = (short)(v+1+(stacks+1));
						vv[4] = (short)(v+(stacks+1));
						vv[5] = v;    
						if (q.Direction_inside) {
							swap_sh(vv, 1, 2);
							swap_sh(vv, 4, 5);
						}
						q.Def.Indices.put(vv[0]);
						q.Def.Indices.put(vv[1]);
						q.Def.Indices.put(vv[2]);
						q.Def.Indices.put(vv[3]);
						q.Def.Indices.put(vv[4]);
						q.Def.Indices.put(vv[5]);
					}
					v += 1;
				}
			}
			q.Def.Indices.position(0);
			Cur_List = null;
		}
		//if true then writeln('cylinder 4');
		//apply_draw_mode(q);
		q.Def.Execute();
		//if true then writeln('cylinder 5 q.Def=' + IntToHex(Integer(q.Def), 8));
	}
	
	public static void sim_gluPartialDisk(int n_quadric,
		float inner, float outer, int slices, int loops,
		float start, float sweep) {
		SimQuadric q = All_quadrics.get(n_quadric);
		while (6 * slices * loops >= 32767) {
			if (slices > 30) slices = slices >>> 2;
			if (loops > 30) loops = loops >>> 2;
		}
		if (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 = null;
		if (q.Def == null) {
			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 = new SimList();
			q.Def.BE_mode = 0;
			q.Def.Tex_Components = 2;
			q.Def.Vertex_Components = 3;
			Cur_List = q.Def;
			gl.glColor4f(Last_Color_R, Last_Color_G, Last_Color_B, Last_Color_A);
			sim_glColor4f(Last_Color_R, Last_Color_G, Last_Color_B, Last_Color_A);
    //AL4_system.WriteLine("disk color: " + Last_Color_R + " " + Last_Color_G +
    //" " + Last_Color_B + " " + Last_Color_A);
			q.Def.Indices = ByteBuffer.allocateDirect(6 * loops * slices * 2)
						.order(ByteOrder.nativeOrder())
						.asShortBuffer(); 
			if (loops < 1 || slices < 1) return;
			short[] vv = new short[6];
			short v = 0;
			for (int i = 0; i <= slices; i++) {
				double alpha = (start + sweep / slices * i) * Math.PI / 180;
				for (int j = 0; j <= loops; j++) {
					double r = inner + (outer - inner) / loops * j;
					if (q.Need_texture)
						sim_glTexCoord2f(1f * i / slices,  1f * j / loops);
					if (q.Need_normals) {
                        //float nx = 0;
                        //float ny = 0;
                        //float nz = 1f;
                        //sim_glNormal3f( nx, ny, nx );
						sim_glNormal3f(0f, 0f, 1f);
					}
					q.Def.Add_vertex(
						(float)(r * Math.cos(alpha)),
						(float)(r * Math.sin(alpha)),
						0f, 1, 3);
					if (i < slices && j < loops) {
						vv[0] = v;
						vv[1] = (short)(v+1);
						vv[2] = (short)(v+1+(loops+1));
						vv[3] = (short)(v+1+(loops+1));
						vv[4] = (short)(v+(loops+1));    
						vv[5] = v;
						if (q.Direction_inside) {
							swap_sh(vv, 1, 2);
							swap_sh(vv, 4, 5);
						}
						q.Def.Indices.put(vv[0]);
						q.Def.Indices.put(vv[1]);
						q.Def.Indices.put(vv[2]);
						q.Def.Indices.put(vv[3]);
						q.Def.Indices.put(vv[4]);
						q.Def.Indices.put(vv[5]);
					}
					v += 1;
				}
			}
			q.Def.Indices.position(0);
			Cur_List = null;
		}
		q.Def.Execute();
	}
	
	public static void sim_gluDisk(int n_quadric,
		float inner, float outer, int slices, int loops) {
		sim_gluPartialDisk(n_quadric, inner, outer, slices, loops, 0, 360);
	}
	
	public static void sim_gluSphere(int n_quadric,
	float radius, int slices, int stacks) {
		SimQuadric q = All_quadrics.get(n_quadric);
		while (6 * slices * stacks >= 32767) {
			if (slices > 30) slices = slices >>> 2;
			if (stacks > 30) stacks = stacks >>> 2;
		}
		if (q.Shape != qsSphere || q.P_radius != radius
			|| q.P_slices != slices || q.P_stacks != stacks)
			q.Def = null;
		if (q.Def == null) {
            //AL4_system.WriteLine("build SPHERE " + q +
            //    " r=" + radius + " slices=" + slices + " stacks=" + stacks +
            //    ", stored: " + q.P_radius + ", " + q.P_slices +
            //    ", " + q.P_stacks + ", shape was " + q.Shape + " whereas new is "
            //    + qsSphere + " Need_normals=" + q.Need_normals);
			q.Shape = qsSphere;
			q.P_radius = radius;
			q.P_slices = slices;
			q.P_stacks = stacks;
			if (stacks <= 0 || slices <= 1 || radius == 0) return; 
			q.Def = new SimList();
			q.Def.BE_mode = 0;
			q.Def.Tex_Components = 2;
			q.Def.Vertex_Components = 3;
			Cur_List = q.Def;
			gl.glColor4f(Last_Color_R, Last_Color_G, Last_Color_B, Last_Color_A);
			sim_glColor4f(Last_Color_R, Last_Color_G, Last_Color_B, Last_Color_A);
    //AL4_system.WriteLine("sphere color: " + Last_Color_R + " " + Last_Color_G +
    //" " + Last_Color_B + " " + Last_Color_A);
			q.Def.Indices = ByteBuffer.allocateDirect(6 * stacks * slices * 2)
						.order(ByteOrder.nativeOrder())
						.asShortBuffer();
			short[] vv = new short[6];
			short v = 0;
			for (int i = 0; i <= slices; i++) {
				double alpha = 2.0 * Math.PI / slices * i;
				for (int j = 0; j <= stacks; j++) {
					double z = -radius + (2.0 * radius) / stacks * j;
					double r = Math.sqrt(radius * radius - z * z);
					if (q.Need_texture)
						//q.Def.Add_tex_coord(
						sim_glTexCoord2f(
							1f * i / slices, 1f * j / stacks);
					if (q.Need_normals) {
                        double fi = Math.asin(z / radius);
                        double nx = Math.cos(alpha) * Math.cos(fi);
                        double ny = Math.sin(alpha) * Math.cos(fi);
                        double nz = Math.sin(fi);
						sim_glNormal3f((float)nx, (float)ny, (float)nz);
					}
					q.Def.Add_vertex(
						(float)(r * Math.cos(alpha)),
						(float)(r * Math.sin(alpha)),
						(float)z, 1, 3);
					if (i < slices && j < stacks) {
						vv[0] = v;
						vv[1] = (short)(v+1);
						vv[2] = (short)(v+1+(stacks+1));
						vv[3] = (short)(v+1+(stacks+1));
						vv[4] = (short)(v+(stacks+1));
						vv[5] = v;
						if (q.Direction_inside) {
							swap_sh(vv, 1, 2);
							swap_sh(vv, 4, 5);
						}
						q.Def.Indices.put(vv[0]);
						q.Def.Indices.put(vv[1]);
						q.Def.Indices.put(vv[2]);
						q.Def.Indices.put(vv[3]);
						q.Def.Indices.put(vv[4]);
						q.Def.Indices.put(vv[5]);
					}
					v += 1;
				}
			}
			q.Def.Indices.position(0);
			Cur_List = null;
		}
		q.Def.Execute(); //true);
   //AL4_system.WriteLine("after sphere: " +
   //GLU.gluErrorString(GLES20.glGetError()));
	}
	
	
		
    public static class AL4_GLrenderer implements GLSurfaceView.Renderer {
        
        public AL4_form form;
        public C_OpenGL OpenGL_control;
        public AL4_OpenGL OpenGL_view;
        
        ByteBuffer byteBuffer;
        private FloatBuffer vertexBuffer;
        private float vertices[];
        private float angle = 0.0f;
        
        private ShortBuffer indicesBuffer;
        private short indices[];
        
        //public Handler mHandler;
        
        public AL4_GLrenderer(AL4_OpenGL view, AL4_form F) {
        	OpenGL_view = view;
            form = F;
            C_Form f = (C_Form)AL4_form.All_descr.get(F.Handle).Ref.Obj;
            C_OpenGL c = view.C_Canvas;
            OpenGL_control = c;
        }
        
        @Override
		public void onSurfaceCreated(GL10 gl_, EGLConfig config) {
			 gl = gl_;
			 
             //try{ AL4_system.WriteLine("++++++++++++++++++++ onSurfaceCreated");
             //} catch(Exception ex) {}
			 
		     GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		     // Depth buffer setup.
             //GLES20.glClearDepthf(1.0f);
             //// Enables depth testing.
             //GLES20.glEnable(GL10.GL_DEPTH_TEST);
             //// The type of depth testing to do.
             //GLES20.glDepthFunc(GL10.GL_LEQUAL);
             //// Really nice perspective calculations.
             GLES20.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
             
             gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 
             vertices = new float[]{ -0.5f, -0.5f, 0.0f, 
             						-0.5f, 0.5f, 0.0f, 
             						0.5f, -0.5f, 0.0f, 
             						0.5f, 0.5f, 0.0f };
             byteBuffer = ByteBuffer.allocateDirect(
             	vertices.length * 4);
             byteBuffer.order(ByteOrder.nativeOrder());
             vertexBuffer = byteBuffer.asFloatBuffer();
             vertexBuffer.put(vertices);
             vertexBuffer.position(0);
             
             indices = new short[]{0, 1, 2, 3};
             indicesBuffer = ByteBuffer.allocateDirect(
             	indices.length * 2)
             	.order(ByteOrder.nativeOrder())
             	.asShortBuffer();
             indicesBuffer.put(indices);
             indicesBuffer.position(0);
		}
        
        @Override
		public void onSurfaceChanged(GL10 gl_, int width, int height) {
			 gl = gl_;
			 GLES20.glViewport(0, 0, width, height);
             \\AL4_form.run_on_ui_thread(false, new Callable<Void>(){
             \\   @Override public Void call() {
                      try {
                          // Sets the current view port to the new size.
                          OpenGL_control.F_stored_width = AL4_form.Pixels(width);
                          OpenGL_control.F_stored_height = AL4_form.Pixels(height);
                          // Select the projection matrix
                          //GLES20.glMatrixMode(GL10.GL_PROJECTION);
                          //// Reset the projection matrix
                          //GLES20.glLoadIdentity();
                          //// Calculate the aspect ratio of the window
                          //GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f, 100.0f);
                          //// Select the modelview matrix
                          //GLES20.glMatrixMode(GL10.GL_MODELVIEW);
                          //// Reset the modelview matrix
                          //GLES20.glLoadIdentity();
			            
                           //try{ AL4_system.WriteLine("+++++++++++++++++ onSurfaceChanged " +
                           //(Looper.getMainLooper() == Looper.myLooper() ? "on ui":"not on ui"));
                           //} catch(Exception ex) { AL4_form.report(ex); }
                      }
                      catch (Exception ex2) { AL4_form.report(ex2); }
             \\       return null;
             \\   }
            \\});
		}
        
		@Override
		public void onDrawFrame(GL10 gl_) {
			AL4_form.locker.lock();
			try {
             if (OpenGL_view.is_drawing) {
    //AL4_system.Write("onDrawFrame but already is_drawing ==> return\n");
             	return;
             }
    //AL4_system.Write(">>>");
             gl = gl_;
             //OpenGL_view.is_drawing = true;
             
             //form.Disable_timers = true;
             try {
                 C_Form F = (C_Form)AL4_form.All_descr.get(form.Handle).Ref.Obj;
                 OpenGL_view.Invalidated = false;
				 
                 try {
                    //Ref_obj save_sender = F.F_sender;
                    //F.M_operation_started((byte)22, OpenGL_control.hard_link);
                    String save_alias = F.F_menu_alias;
                    F.F_menu_alias = OpenGL_control.F_Alias;
                    if (AL4_form.operation_started(F, 22, F.hard_link))
	                    try {
	                        //F.F_sender = OpenGL_control.hard_link;
	                        //try {
		                        F.M_paint();
	                        //}
	                        //finally {
	                        //    F.F_sender = save_sender;
	                        //}
	                    }
	                    finally {
	                    	F.F_menu_alias = save_alias;
	                    	AL4_form.operation_ended(F, 22);
	                    }
                 } catch(Exception e) { AL4_form.report(e); }
             }
             finally {
                //OpenGL_view.is_drawing = false;
                //form.Disable_timers = false;
             }
    //AL4_system.Write("<<<\n");
    		//mHandler.obtainMessage(1).sendToTarget();
             
             //GLES20.glClearColor(1.0f, 0.5f, 0.0f, 0.0f); 
             //GLES20.glClear(GL10.GL_COLOR_BUFFER_BIT);
            
            //gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
            //gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
            //gl.glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
            //gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
            ////gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
            //GLES20.glDrawElements(GL10.GL_TRIANGLE_STRIP, indices.length,
            //    GL10.GL_UNSIGNED_SHORT, indicesBuffer);
            ////gl.glLoadIdentity();
            //gl.glRotatef(angle, 1.0f, 1.0f, 1.0f);
            //angle++;
            //AL4_system.WriteLine("> " + GLU.gluErrorString(GLES20.glGetError()));
			}
			finally {
				AL4_form.locker.unlock();
			}
		}
        
    }

	/*
	// Invalidate OpenGL control
	//---------------------------
	
	FUN Invalidate_open_gl_control(
	INT H|andle_control), NATIVE : @
	"	AL4_OpenGL.do_Invalidate_open_gl_control(X_H);" .
	*/
	
	public static void do_Invalidate_open_gl_control(int X_H) {
        \\AL4_form.run_on_ui_thread(false, new Callable<Void>(){
        \\    @Override public Void call() {
                  \\try {
                  \\    AL4_form.locker.lock();
                  \\    try {
                  \\    AL4_OpenGL G = (AL4_OpenGL)AL4_form.All_descr.get(X_H).Jvc;
                  \\    try {
                  \\  //''AL4_system.WriteLine("before requestRender " + G);''
                  \\            if (X_H == 0)
                  \\            // || G.is_drawing)
                  \\                return
                  \\                null
                  \\                ;
                  \\              //if (G.Invalidated)
                  \\              //  return
                  \\              //  null
                  \\              //  ;
                  \\            //G.invalidate();
                  \\            G.requestRender();
                  \\            G.Invalidated = true;
                  \\  //''AL4_system.Write("&&& ");''
                  \\        }
                  \\        catch (Exception e) { AL4_form.report(e); }
                  \\    }
                  \\    finally {
                  \\        AL4_form.locker.unlock();
                  \\    }
                  \\}
                  \\catch (Exception ex2) { AL4_form.report(ex2); }
        \\        return null;
        \\    }
        \\});
	}
    
    /*


	// Update Open GL control
	//---------------------------
	
	FUN Update_open_gl_control(INT H|andle_control) :
		Invalidate_open_gl_control(H) .
       
    //------------------
    
    FUN Format_pixels_from_internal_format_bitmap(
        INT I|nternal_format ) ==> INT
        :
        ----------------------------------------- 'for Java'
        CASE I ?
        [GL_RGB]: RESULT = GL_RGB // GL_BGR
        [3]: RESULT = GL_BGR
        //[GL_RGBA]: RESULT = GL_BGRA
        ELSE RESULT = GL_RGBA 
        ; .

        
    FUN Type_pixels_from_internal_format_bitmap( INT I|nternal_format ) ==> INT
        :
        ----------------------------------------- 'for Java'
        CASE I ?
        [GL_RGB, 3, GL_RGBA]: RESULT = GL_UNSIGNED_BYTE
        //[GL_RGB]: RESULT = GL_UNSIGNED_INT_8_8_8_8
        ELSE RESULT = GL_UNSIGNED_INT_8_8_8_8 ; .
    
    */
 	public static String do_glGetString(int X_Name) {
		return AL4_form.get_property_string(new Callable<String>(){
			@Override public String call() {
				try {
                    if (AL4_OpenGL.gl != null)
                       return GLES20.glGetString(X_Name);
				}
				catch (Exception ex) { AL4_form.report(ex); }
				return "";
			}
		});
 	}
    
    
    /*
    CONST STR : 
        NATIVE_import_OpenGL = @
        "import android.opengl.GLSurfaceView;"
        "import java.nio.ByteBuffer;"
        "import java.nio.IntBuffer;"
        "import android.opengl.GLU;"
        "import javax.microedition.khronos.opengles.GL10;"
        "import javax.microedition.khronos.opengles.GL11;"
        "import android.opengl.GLES20;"
        "import android.opengl.GLUtils;"
        "import android.graphics.*;"

                NATIVE_glGetError = @
                "    RESULT = GLES20.glGetError();"
    
                NATIVE_gluErrorString = @
                "    RESULT = GLU.gluErrorString(X_Code);"
    
                NATIVE_glGetString = @
                "	 RESULT = AL4_OpenGL.do_glGetString(X_Name);"
    
        NATIVE_glViewport = @
        "    GLES20.glViewport(X_X, X_Y, X_Width, X_Height);"

        NATIVE_glClearColor = @
        "    GLES20.glClearColor("
        "       (float)X_R, (float)X_G, (float)X_B, (float)X_A);"
        
                NATIVE_glClearDepth = @
                "    GLES20.glClearDepthf((float)X_Depth);"
                
                NATIVE_glClearStencil = @
                "    GLES20.glClearStencil(X_S);"
                
                NATIVE_glAccum = @
                "    //GLES20.glAccum(X_Op, (float)X_Value);"
                
                NATIVE_glClearAccum = @
                "    //GLES20.glClearAccum("
                "    //(float)X_R, (float)X_G, (float)X_B, (float)X_A);"
                
        NATIVE_glClear = @
        "    GLES20.glClear(X_B);"
        
        NATIVE_glEnable = @
        "	 if (X_What != //GL_LINE_STIPPLE"
        "		0xb24)"
        "    	GLES20.glEnable(X_What);"
        
        NATIVE_glDisable = @
        "	 if (X_What != //GL_LINE_STIPPLE"
        "		0xb24)"
        "    GLES20.glDisable(X_What);"
        
        NATIVE_glIsEnabled = @
        "	 if (AL4_OpenGL.gl instanceof GL11)"
        "    	RESULT = ((GL11)AL4_OpenGL.gl).glIsEnabled(X_What);"
        
        NATIVE_glGetBooleanv = @
        "    boolean[] p = new boolean[1];"
        "    GLES20.glGetBooleanv(X_What, p, 0);"
        "    X_Params.Clear();"
        "    X_Params.Add(p[0]);"
        
        NATIVE_glGetIntegerv = @
        "    int[] p = new int[X_size];"
        "    GLES20.glGetIntegerv(X_What, p, 0);"
        "    X_Param.Clear();"
        "    for (int i = 0; i < p.length; i++)"
        "        X_Param.Add(p[i]);"
        
        NATIVE_glGetDoublev = @
        "    float[] p = new float[X_size];"
        "    GLES20.glGetFloatv(X_What, p, 0);"
        "    X_Param.Clear();"
        "    for (int i = 0; i < p.length; i++)"
        "        X_Param.Add(p[i]);"
        
                NATIVE_glColorMask = @
                "    GLES20.glColorMask(X_Red,"
                "       X_Green,"
                "       X_Blue,"
                "       X_Alpha);"
                
        NATIVE_glCullFace = @
        "    GLES20.glCullFace(X_Side);"
        
        NATIVE_glDepthFunc = @
        "    GLES20.glDepthFunc(X_Func);"
        
                NATIVE_glDepthMask = @
                "    GLES20.glDepthMask(X_Flag);"
                
                NATIVE_glDepthRange = @
                "    GLES20.glDepthRangef((float)X_Near, (float)X_Far);"
                
                NATIVE_glLineWidth = @
                "    GLES20.glLineWidth((float)X_Width);"
                
                NATIVE_glLineStipple = @
                "    //GLES20.glLineStipple(X_Factor, (short)X_Pattern);"
                
                NATIVE_glPointSize = @
                "    AL4_OpenGL.gl.glPointSize((float)X_Size);"
                
                NATIVE_glPolygonMode = @
                "    //GLES20.glPolygonMode(X_Face, X_Mode);"
                
                NATIVE_glPolygonOffset = @
                "    GLES20.glPolygonOffset((float)X_Factor,"
                "       (float)X_Units);"
                
                NATIVE_glHint = @
                "    GLES20.glHint(X_Target, X_Mode);"
                
        NATIVE_glFrontFace = @
        "    GLES20.glFrontFace(X_Orient);"
        
        NATIVE_glMatrixMode = @
        "    AL4_OpenGL.gl.glMatrixMode(X_Mode);"
        
        NATIVE_glLoadIdentity = @
        "    AL4_OpenGL.gl.glLoadIdentity();"
        
        NATIVE_glPushMatrix = @
        "    AL4_OpenGL.gl.glPushMatrix();"
        
        NATIVE_glPopMatrix = @
        "    AL4_OpenGL.gl.glPopMatrix();"
        
        NATIVE_glMultMatrixd = @
        "    float[] p = new float[16];"
        "    for (int i = 0; i < X_Matrix.Count(); i++)"
        "        p[i] = (float)X_Matrix.Get_item(i);"
        "    AL4_OpenGL.gl.glMultMatrixf(p, 0);"
        
        NATIVE_glTranslated = @
        "    AL4_OpenGL.gl.glTranslatef((float)X_X, (float)X_Y,"
        "       (float)X_Z);"
        
        NATIVE_glTranslatef = @
        "    AL4_OpenGL.sim_glTranslatef((float)X_X, (float)X_Y,"
        "       (float)X_Z);"
        
        NATIVE_glRotated = @
        "    AL4_OpenGL.gl.glRotatef("
        "		(float)X_A, (float)X_X, (float)X_Y, (float)X_Z);"
        
        NATIVE_glRotatef = @
        "    AL4_OpenGL.gl.glRotatef("
        "		(float)X_A, (float)X_X, (float)X_Y, (float)X_Z);"
        
        NATIVE_glScaled = @
        "    AL4_OpenGL.gl.glScalef((float)X_X, (float)X_Y, (float)X_Z);"
        
        NATIVE_glScalef = @
        "    AL4_OpenGL.gl.glScalef((float)X_X, (float)X_Y,"
        "       (float)X_Z);"
        
        NATIVE_gluPerspective = @
        "    GLU.gluPerspective(AL4_OpenGL.gl, (float)X_VerticalFOV,"
        "		(float)X_Aspect, (float)X_Near, (float)X_Far);"
        
                NATIVE_gluOrtho2D = @
                "    GLU.gluOrtho2D(AL4_OpenGL.gl, (float)X_Left,"
                "		(float)X_Right, (float)X_Top, (float)X_Bottom);"
                
                NATIVE_glOrtho = @
                "AL4_OpenGL.gl.glOrthof((float)X_Left, (float)X_Right, "
                "  (float)X_Bottom, (float)X_Top, (float)X_Near, (float)X_Far);"
                
                NATIVE_glFrustum = @
                "AL4_OpenGL.gl.glFrustumf((float)X_Left, (float)X_Right, "
                "  (float)X_Bottom, (float)X_Top, (float)X_Near, (float)X_Far);"
                
                NATIVE_gluProject = @
                "    float[] m = new float[16];"
                "    for (int i = 0; i < 16 && i < X_Model.Count(); i++)"
                "        m[i] = (float)X_Model.Get_item(i);"
                "    float[] p = new float[16];"
                "    for (int i = 0; i < 16 && i < X_Project.Count(); i++)"
                "        p[i] = (float)X_Project.Get_item(i);"
                "    int[] v = new int[4];"
                "    for (int i = 0; i < 4 && i < X_Viewport.Count(); i++)"
                "        v[i] = X_Viewport.Get_item(i);"
                "    float[] r = new float[3];"
                "	 GLU.gluProject("
                "		(float)X_X_obj, (float)X_Y_obj, (float)X_Z_obj,"
                "       m, 0, p, 0, v, 0, r, 0);"
                "    for (int i =0; i < 3 && i < X_XYZ_win.Count(); i++)"
                "       X_XYZ_win.Set_item(i, r[i]);"
                
                NATIVE_gluUnProject = @
                "    float[] m = new float[16];"
                "    for (int i = 0; i < 16 && i < X_Model.Count(); i++)"
                "        m[i] = (float)X_Model.Get_item(i);"
                "    float[] p = new float[16];"
                "    for (int i = 0; i < 16 && i < X_Project.Count(); i++)"
                "        p[i] = (float)X_Project.Get_item(i);"
                "    int[] v = new int[4];"
                "    for (int i = 0; i < 4 && i < X_Viewport.Count(); i++)"
                "        v[i] = X_Viewport.Get_item(i);"
                "    float[] r = new float[3];"
                "    GLU.gluUnProject("
                "		(float)X_X_win, (float)X_Y_win, (float)X_Z_win,"
                "       m, 0, p, 0, v, 0, r, 0);"
                "    for (int i = 0; i < 3 && i < X_XYZ_obj.Count(); i++)"
                "       X_XYZ_obj.Set_item(i, r[i]);"
                
                NATIVE_glClipPlane = @
                "	 if (AL4_OpenGL.gl instanceof GL11) {"
                "    	float[] p = new float[4];"
                "    	for (int i = 0; i < 4 && i < X_Equation.Count(); i++)"
                "        	p[i] = (float)X_Equation.Get_item(i);"
                "    	((GL11)AL4_OpenGL.gl).glClipPlanef(X_Plane, p, 0);"
                "	 }"
                
                NATIVE_glPushAttrib = @
                "    //glPushAttrib(X_Mask);"
                
                NATIVE_glPopAttrib = @
                "    //glPopAttrib();"
                
                NATIVE_glPushClientAttrib = @
                "    //glPushClientAttrib(X_Mask);"
                
                NATIVE_glPopClientAttrib = @
                "    //glPopClientAttrib();"
                
        NATIVE_glBegin = @
        "    AL4_OpenGL.sim_glBegin(X_Mode);"
        
        NATIVE_glEnd = @
        "    AL4_OpenGL.sim_glEnd();"
        
                NATIVE_glListBase = @
                "    AL4_OpenGL.sim_glListBase(X_Base);"
                
                NATIVE_glGenLists = @
                "    RESULT = AL4_OpenGL.sim_glGenLists(X_Range);"
                
                NATIVE_glIsList = @
                "    RESULT = AL4_OpenGL.sim_glIsList(X_List);"
                
                NATIVE_glNewList = @
                "    AL4_OpenGL.sim_glNewList(X_List, X_Mode);"
                
                NATIVE_glEndList = @
                "    AL4_OpenGL.sim_glEndList();"
                
                NATIVE_glCallList = @
                "    AL4_OpenGL.sim_glCallList(X_List);"
                
                NATIVE_glCallLists = @
                "    if (X_N <= 0) X_N = X_Lists.Count();"
                "    if (X_N > X_Lists.Count()) X_N = X_Lists.Count();"
                "    if (X_N == 0) return;"
                "    int[] lists = new int[X_N];"
                "    for (int i = 0; i < X_N; i++)"
                "       lists[i] = X_Lists.Get_item(i);"
                "    AL4_OpenGL.sim_glCallLists(X_N, X_Type, lists);"
                
                NATIVE_glDeleteLists = @
                "    AL4_OpenGL.sim_glDeleteLists(X_List, X_Range);"
                
                
        NATIVE_glVertex2d = @
        "    AL4_OpenGL.sim_glVertex3f((float)X_X, (float)X_Y, 0f);"
        
        NATIVE_glVertex2f = @
        "    AL4_OpenGL.sim_glVertex3f((float)X_X, (float)X_Y, 0f);"
        
        NATIVE_glVertex3d = @
        "    AL4_OpenGL.sim_glVertex3f((float)X_X, (float)X_Y, (float)X_Z);"
        
        NATIVE_glVertex3f = @
        "    AL4_OpenGL.sim_glVertex3f((float)X_X, (float)X_Y, (float)X_Z);"
        
        NATIVE_glVertex4d = @
        "    AL4_OpenGL.sim_glVertex4f((float)X_X, (float)X_Y, (float)X_Z,"
        "		(float)X_W);"
        
        NATIVE_glVertex4f = @
        "    AL4_OpenGL.sim_glVertex4f((float)X_X, (float)X_Y,"
        "       (float)X_Z, (float)X_W);"
        
        NATIVE_glTexCoord1d = @
        "    //GLES20.glTexCoord1d(X_S);"
        
        NATIVE_glTexCoord1f = @
        "    //GLES20.glTexCoord1f((float)X_S);"
        
        NATIVE_glTexCoord2d = @
        "    AL4_OpenGL.sim_glTexCoord2f((float)X_S, (float)X_T);"
        
        NATIVE_glTexCoord2f = @
        "    AL4_OpenGL.sim_glTexCoord2f((float)X_S, (float)X_T);"
        
        NATIVE_glTexCoord3d = @
        "    AL4_OpenGL.sim_glTexCoord3f((float)X_S, (float)X_T, (float)X_R);"
        
        NATIVE_glTexCoord3f = @
        "    AL4_OpenGL.sim_glTexCoord3f((float)X_S, (float)X_T, (float)X_R);"
        
        NATIVE_glTexCoord4d = @
        "    AL4_OpenGL.sim_glTexCoord4f((float)X_S, (float)X_T,"
        " 		(float)X_R, (float)X_Q);"
        
        NATIVE_glTexCoord4f = @
        "    AL4_OpenGL.sim_glTexCoord4f((float)X_S, (float)X_T,"
        "       (float)X_R, (float)X_Q);"
        
        NATIVE_glNormal3d = @
        "    AL4_OpenGL.sim_glNormal3f((float)X_X, (float)X_Y, (float)X_Z);"
        
        NATIVE_glNormal3f = @
        "    AL4_OpenGL.sim_glNormal3f((float)X_X, (float)X_Y, (float)X_Z);"
        
        NATIVE_glColor3d = @
        "    AL4_OpenGL.sim_glColor3f("
        "			(float)X_Red, (float)X_Green, (float)X_Blue);"
        
        NATIVE_glColor3f = @
        "    AL4_OpenGL.sim_glColor3f((float)X_Red, (float)X_Green,"
        "       (float)X_Blue);"
        
        NATIVE_glColor4d = @
        "    AL4_OpenGL.sim_glColor4f("
        "		(float)X_Red, (float)X_Green, (float)X_Blue, (float)X_Alpha);"
        
        NATIVE_glColor4f = @
        "    AL4_OpenGL.sim_glColor4f((float)X_Red, (float)X_Green,"
        "       (float)X_Blue, (float)X_Alpha);"
        
        NATIVE_glGenTextures = @
        "    if (X_N <= 0) return;"
        "    int[] t = new int[X_N];"
        "    GLES20.glGenTextures( X_N, t, 0 );"
        "    for (int i = 0; i < X_N; i++)"
        "        X_Textures.Add(t[i]);"
        
        NATIVE_glIsTexture = @
        "    RESULT = GLES20.glIsTexture(X_Texture);"
        
        NATIVE_glDeleteTextures = @
        "    if (X_N <= 0) X_N = X_Textures.Count();"
        "    if (X_N >= X_Textures.Count()) X_N = X_Textures.Count() - 1;"
        "    if (X_N <= 0) return;"
        "    int[] t = new int[X_N];"
        "    for (int i = 0; i < X_N; i++)"
        "        t[i] = X_Textures.Get_item(i);"
        "    GLES20.glDeleteTextures( X_N, t, 0);"
        
        NATIVE_glBindTexture = @
        "    GLES20.glBindTexture(X_Target, X_Texture);"
        
        NATIVE_glTexImage1D = @
        ""
        
        NATIVE_glTexSubImage1D = @
        ""
        
        NATIVE_glTexImage2D = @
        "    FixAByte_OnArray L = (FixAByte_OnArray)X_Data.BaseList;"
        "    ByteBuffer buffer = ByteBuffer.wrap("
        "       L.Array, L.Starting, L.Length);"
        "    GLES20.glTexImage2D(X_Target, X_Level, X_Internal_format,"
        "       X_Width, X_Height, X_Border, X_Format, X_Type,"
        "		buffer);"
        
        NATIVE_glTexSubImage2D = @
        "    FixAByte_OnArray L = (FixAByte_OnArray)X_Data.BaseList;"
        "    ByteBuffer buffer = ByteBuffer.wrap("
        "       L.Array, L.Starting, L.Length);"
        "    GLES20.glTexSubImage2D(X_Target, X_Level, X_X_offset,"
        "       X_Y_offset, X_Width, X_Height, X_Format, X_Type, buffer);"
        
        NATIVE_gluBuild1DMipmaps = @
        ""
        
        NATIVE_gluBuild2DMipmaps = @
        ""
        
        NATIVE_glTexParameteri = @
        "    GLES20.glTexParameterf(X_Target, X_Pname, X_Param);"
        
        NATIVE_glTexParameterf = @
        "    GLES20.glTexParameterf(X_Target, X_Pname,"
        "       (float)X_Param);"
        
        NATIVE_glTexParameterfv = @
        "    float[] p = new float[4];"
        "    int n = 4;"
        "    if (n > X_Param.Count()) n = X_Param.Count();"
        "    for (int i = 0; i < n; i++)"
        "        p[i] = (float)X_Param.Get_item(i);"
        "    GLES20.glTexParameterfv(X_Target, X_Pname, p, 0);"
        
        NATIVE_glTexEnvi = @
        "    AL4_OpenGL.gl.glTexEnvf(X_Target, X_Pname, X_Param);"
        
        NATIVE_glTexEnvf = @
        "    AL4_OpenGL.gl.glTexEnvf(X_Target, X_Pname, (float)X_Param);"
        
        NATIVE_glBlendFunc = @
        "    GLES20.glBlendFunc(X_Sfactor, X_Dfactor);"
        
        //NATIVE_glBlendFuncSeparate = @
        //"    GLES20.glBlendFuncSeparate(X_SrcRGB, X_DstRGB, X_SrcAlpha,"
        //"       X_DstAlpha);"
        
        //NATIVE_glBlendColor = @
        //"    GLES20.glBlendColor((float)X_Red, (float)X_Green,"
        //"       (float)X_Blue, (float)X_Alpha);"
        
        //NATIVE_glBlendEquation = @
        //"    GLES20.glBlendEquation(X_Mode);"
        
        //NATIVE_glBlendEquationSeparate = @
        //"    GLES20.glBlendEquationSeparate(X_ModeRGB, X_ModeAlpha);"
        
        NATIVE_glAlphaFunc = @
        "    AL4_OpenGL.gl.glAlphaFunc(X_Func, (float)X_Ref);"
        
        NATIVE_glStencilFunc = @
        "    GLES20.glStencilFunc(X_Func, X_Ref, X_Mask);"
        
        NATIVE_glStencilOp = @
        "    GLES20.glStencilOp(X_Ffail, X_Dpfail, X_Dppass);"
        
        NATIVE_glStencilMask = @
        "    GLES20.glStencilMask(X_Mask);"
        
        NATIVE_glLightf = @
        "    AL4_OpenGL.gl.glLightf(X_Light, X_Pname, (float)X_Param);"
        
        NATIVE_glLightfv = @
        "    float[] p = new float[4];"
        "    int n = 4;"
        "    if (n > X_Param.Count()) n = X_Param.Count();"
        "    for (int i = 0; i < n; i++)"
        "        p[i] = (float)X_Param.Get_item(i);"
        "    AL4_OpenGL.gl.glLightfv(X_Light, X_Pname, p, 0);"
        
        NATIVE_glLightModeli = @
        "	 if (X_Pname !=//GL_LIGHT_MODEL_LOCAL_VIEWER"
        "	 	0x00000b51)"
        "    	AL4_OpenGL.gl.glLightModelx(X_Pname, X_Param);"
        
        NATIVE_glLightModelfv = @
        "    float[] p = new float[4];"
        "    int n = 4;"
        "    if (n > X_Param.Count()) n = X_Param.Count();"
        "    for (int i = 0; i < n; i++)"
        "        p[i] = (float)X_Param.Get_item(i);"
        "    AL4_OpenGL.gl.glLightModelfv(X_Pname, p, 0);"
        
        NATIVE_glMaterialf = @
        "    AL4_OpenGL.gl.glMaterialf(X_Face, X_Pname, (float)X_Param);"
        
        NATIVE_glMaterialfv = @
        "    float[] p = new float[4];"
        "    int n = 4;"
        "    if (n > X_Param.Count()) n = X_Param.Count();"
        "    for (int i = 0; i < n; i++)"
        "        p[i] = (float)X_Param.Get_item(i);"
        "    AL4_OpenGL.gl.glMaterialfv(X_Face, X_Pname, p, 0);"
        
        NATIVE_glMaterialiv = @
        "    float[] p = new float[4];"
        "    int n = 4;"
        "    if (n > X_Param.Count()) n = X_Param.Count();"
        "    for (int i = 0; i < n; i++)"
        "        p[i] = X_Param.Get_item(i);"
        "    AL4_OpenGL.gl.glMaterialfv(X_Face, X_Pname, p, 0);"
        
        NATIVE_glColorMaterial = @
        "    //NOT SUPPORTED.glColorMaterial(X_Face, X_Mode);"
        
        NATIVE_glFogi = @
        "    AL4_OpenGL.gl.glFogf(X_Pname, X_Param);"
        
        NATIVE_glFogf = @
        "    AL4_OpenGL.gl.glFogf(X_Pname, (float)X_Param);"
        
        NATIVE_glFogfv = @
        "    float[] p = new float[4];"
        "    int n = 4;"
        "    if (n > X_Param.Count()) n = X_Param.Count();"
        "    for (int i = 0; i < n; i++)"
        "        p[i] = (float)X_Param.Get_item(i);"
        "    AL4_OpenGL.gl.glFogfv(X_Pname, p, 0);"
        
        NATIVE_gluNewQuadric = @
        "    RESULT = AL4_OpenGL.sim_gluNewQuadric();"
        
        NATIVE_gluDeleteQuadric = @
        "    AL4_OpenGL.sim_gluDeleteQuadric(X_Obj);"
        
        NATIVE_gluQuadricDrawStyle = @
        "    AL4_OpenGL.sim_gluQuadricDrawStyle(X_Obj, X_Style);"
        
        NATIVE_gluQuadricOrientation = @
        "    AL4_OpenGL.sim_gluQuadricOrientation(X_Obj, X_Orient);"
        
        NATIVE_gluQuadricTexture = @
        "    AL4_OpenGL.sim_gluQuadricTexture(X_Obj, X_Texture_c);"
        
        NATIVE_gluQuadricNormals = @
        "    AL4_OpenGL.sim_gluQuadricNormals(X_Obj, X_Normals);"
        
        NATIVE_gluCylinder = @
        "    AL4_OpenGL.sim_gluCylinder(X_Obj, "
        "		(float)X_Base_r, (float)X_Top_r, (float)X_Height,"
        "		X_Slices, X_Stacks);"
        
        NATIVE_gluDisk = @
        "    AL4_OpenGL.sim_gluDisk(X_Obj,"
        " 		(float)X_Inner_r, (float)X_Outer_r, X_Slices, X_Loops);"
        
        NATIVE_gluPartialDisk = @
        "    AL4_OpenGL.sim_gluPartialDisk(X_Obj,"
        "       (float)X_Inner_r, (float)X_Outer_r, X_Slices, X_Loops,"
        "		(float)X_Start_a, (float)X_Sweep_a);"
        
        NATIVE_gluSphere = @
        "    AL4_OpenGL.sim_gluSphere(X_Obj,"
        "		(float)X_Radius, X_Slices, X_Stacks);"
        
        .        
    */

}


/*
END
*/
