// http://stackoverflow.com/questions/14111052/adding-multi-window-support-to-android-application

        protected override void onCreate(Bundle savedInstanceState)
        {
            base.onCreate(savedInstanceState);

            //setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

            //this.ToFullscreen();

            var v = new RenderingContextView(this);
            var s = new SpiralSurface(v);

            this.setContentView(v);

            //this.TryHideActionbar(v);

            this.ShowToast("http://my.jsc-solutions.net");
        }
        // 3 years later!
        // port from http://www.learnopengles.com/android-lesson-six-an-introduction-to-texture-filtering/
        // Y:\opensource\github\Learn-OpenGLES-Tutorials\android\AndroidOpenGLESLessons\src\com\learnopengles\android\lesson6

        protected override void onCreate(global::android.os.Bundle savedInstanceState)
        {
            base.onCreate(savedInstanceState);

            //this.ToFullscreen();

            var fl = new FrameLayout(this);
            var ll = new LinearLayout(this);

            ll.setHorizontalGravity(Gravity.CENTER_HORIZONTAL);
            ll.setVerticalGravity(Gravity.BOTTOM);

            var button_set_min_filter = new Button(this).AttachTo(ll).WithText("Set min. filter");
            var button_set_mag_filter = new Button(this).AttachTo(ll).WithText("Set mag. filter");

            var v = new RenderingContextView(this).AttachTo(fl);
            var s = new ApplicationSurface(v, button_set_min_filter, button_set_mag_filter, this);

            ll.AttachTo(fl);


            #region density
            var displayMetrics = new DisplayMetrics();
            this.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);

            v.mDensity = displayMetrics.density;
            #endregion



            setContentView(fl);



            this.ShowToast("http://my.jsc-solutions.net");
        }
        protected override void onCreate(Bundle savedInstanceState)
        {
            base.onCreate(savedInstanceState);
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

            //this.ToFullscreen();

            var v = new RenderingContextView(this);

            v.onsurface +=
                gl =>
            {
                //var __gl = (ScriptCoreLib.Android.__WebGLRenderingContext)(object)gl;



                Log.wtf("AndroidGLDisturbActivity", "onsurface");

                // Create Vertex buffer (2 triangles)

                var buffer = gl.createBuffer();
                gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(-1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f), gl.STATIC_DRAW);



                // Create Program


                #region createProgram

                var program = gl.createProgram(
                    new DisturbVertexShader(),
                    new DisturbFragmentShader()
                    );



                gl.linkProgram(program);
                gl.useProgram(program);



                #endregion

                var uniforms = program.Uniforms(gl);

                #region loadTexture
                Func <android.graphics.Bitmap, ScriptCoreLib.JavaScript.WebGL.WebGLTexture> loadTexture = (image) =>
                {
                    var texture_ = gl.createTexture();

                    gl.enable(gl.TEXTURE_2D);
                    gl.bindTexture(gl.TEXTURE_2D, texture_);

                    //public void texImage2D(uint target, int level, uint internalformat, uint format, uint type, IHTMLCanvas canvas);
                    //public void texImage2D(uint target, int level, uint internalformat, uint format, uint type, IHTMLVideo video);
                    //public void texImage2D(uint target, int level, uint internalformat, uint format, uint type, ImageData pixels);
                    //public void texImage2D(uint target, int level, uint internalformat, int width, int height, int border, uint format, uint type, ArrayBufferView pixels);

                    //public void texImage2D(uint target, int level, uint internalformat, uint format, uint type, IHTMLImage image);
                    //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);

                    //GLUtils.texImage2D(
                    //    /*target*/ (int)gl.TEXTURE_2D,
                    //    /*level*/ 0,
                    //    /*internalformat*/(int)gl.RGBA,
                    //    image,
                    //    /*type*/  (int)gl.UNSIGNED_BYTE,
                    //    0
                    //);

                    GLUtils.texImage2D((int)gl.TEXTURE_2D, 0, image, 0);

                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, (int)gl.LINEAR);
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, (int)gl.LINEAR_MIPMAP_LINEAR);
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, (int)gl.REPEAT);
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, (int)gl.REPEAT);
                    gl.generateMipmap(gl.TEXTURE_2D);


                    // Recycle the bitmap, since its data has been loaded into OpenGL.
                    image.recycle();


                    return(texture_);
                };
                #endregion

                #region openFileFromAssets
                Func <string, InputStream> openFileFromAssets = (string spath) =>
                {
                    InputStream value = null;
                    try
                    {
                        value = this.getResources().getAssets().open(spath);
                    }
                    catch
                    {
                    }
                    return(value);
                };
                #endregion

                var texture__ = android.graphics.BitmapFactory.decodeStream(
                    openFileFromAssets("assets/AndroidGLDisturbActivity/disturb.jpg")
                    );
                var texture = loadTexture(
                    texture__
                    );

                var vertexPositionLocation = default(long);
                var textureLocation        = default(WebGLUniformLocation);

                var parameters_time         = 0L;
                var parameters_screenWidth  = 0;
                var parameters_screenHeight = 0;
                var parameters_aspectX      = 0.0f;
                var parameters_aspectY      = 1.0f;

                #region onresize
                v.onresize +=
                    (width, height) =>
                {
                    Log.wtf("AndroidGLDisturbActivity", "onresize");

                    parameters_screenWidth  = width;
                    parameters_screenHeight = height;

                    gl.viewport(0, 0, width, height);
                };
                #endregion


                #region onframe
                var framecount = 0;
                v.onframe +=
                    delegate
                {
                    var time = parameters_time / 1000f;

                    if (framecount == 0)
                    {
                        Log.wtf("AndroidGLDisturbActivity", "onframe " + ((object)time).ToString());
                    }

                    parameters_time += 100;

                    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

                    // Load program into GPU


                    // Get var locations

                    vertexPositionLocation = gl.getAttribLocation(program, "position");
                    textureLocation        = gl.getUniformLocation(program, "texture");

                    // Set values to program variables


                    var resolution = new __vec2 {
                        x = parameters_screenWidth, y = parameters_screenHeight
                    };

                    uniforms.time       = time;
                    uniforms.resolution = resolution;

                    //gl.uniform1f(gl.getUniformLocation(program, "time"), time);
                    //gl.uniform2f(gl.getUniformLocation(program, "resolution"), parameters_screenWidth, parameters_screenHeight);

                    gl.uniform1i(textureLocation, 0);
                    gl.activeTexture(gl.TEXTURE0);
                    gl.bindTexture(gl.TEXTURE_2D, texture);

                    // Render geometry

                    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
                    gl.vertexAttribPointer((uint)vertexPositionLocation, 2, gl.FLOAT, false, 0, 0);
                    gl.enableVertexAttribArray((uint)vertexPositionLocation);
                    gl.drawArrays(gl.TRIANGLES, 0, 6);
                    gl.disableVertexAttribArray((uint)vertexPositionLocation);



                    framecount++;
                };
                #endregion

                Log.wtf("AndroidGLDisturbActivity", "onsurface done");
            };


            this.setContentView(v);

            //this.TryHideActionbar(v);

            this.ShowToast("http://my.jsc-solutions.net");
        }
Exemple #4
0
        protected override void onCreate(Bundle savedInstanceState)
        {
            base.onCreate(savedInstanceState);

            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
            //this.ToFullscreen();

            var v = new RenderingContextView(this);

            v.onsurface +=
                gl =>
            {
                //var __gl = (ScriptCoreLib.Android.__WebGLRenderingContext)(object)gl;
                //Log.wtf("AndroidGLAccelerometerSpiralActivity", "onsurface");

                var buffer = gl.createBuffer();

                gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

                gl.bufferData(gl.ARRAY_BUFFER,
                              new Float32Array(
                                  -1.0f, -1.0f, 1.0f,
                                  -1.0f, -1.0f, 1.0f,
                                  1.0f, -1.0f, 1.0f,
                                  1.0f, -1.0f, 1.0f), gl.STATIC_DRAW);


                // Create Program


                var currentProgram = gl.createProgram();

                var vs = gl.createShader(new SpiralVertexShader());
                var fs = gl.createShader(new SpiralFragmentShader());

                gl.attachShader(currentProgram, vs);
                gl.attachShader(currentProgram, fs);

                gl.deleteShader(vs);
                gl.deleteShader(fs);

                gl.linkProgram(currentProgram);

                var parameters_time         = 0f;
                var parameters_screenWidth  = 0;
                var parameters_screenHeight = 0;
                var parameters_aspectX      = 0.0f;
                var parameters_aspectY      = 1.0f;

                #region onresize
                v.onresize +=
                    (width, height) =>
                {
                    //Log.wtf("AndroidGLAccelerometerSpiralActivity", "onresize");

                    parameters_screenWidth  = width;
                    parameters_screenHeight = height;

                    parameters_aspectX = (float)width / (float)height;
                    parameters_aspectY = 1.0f;

                    gl.viewport(0, 0, width, height);
                };
                #endregion

                var speed = 200f;
                var xx    = 0.5f;
                var yy    = 0.5f;

                #region onaccelerometer
                v.onaccelerometer +=
                    (x, y, z) =>
                {
                    speed = 10 + 200 * x / 10f + 200 * y / 10f;

                    var ay = y;
                    if (y < 0)
                    {
                        ay = -y;
                    }

                    yy = (10f - ay) / 10f;

                    if (yy < 0)
                    {
                        y = 0;
                    }

                    if (yy > 10)
                    {
                        yy = 10;
                    }

                    var ax = x;
                    if (x < 0)
                    {
                        ax = -x;
                    }

                    xx = (10f - ax) / 10f;

                    if (xx < 0)
                    {
                        x = 0;
                    }

                    if (xx > 10)
                    {
                        xx = 10;
                    }
                };
                #endregion


                #region onframe
                var framecount = 0;
                v.onframe +=
                    delegate
                {
                    var time = parameters_time / 1000f;

                    //if (framecount == 0)
                    //Log.wtf("AndroidGLAccelerometerSpiralActivity", "onframe " + ((object)yy).ToString());

                    parameters_time += speed;

                    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

                    // Load program into GPU

                    gl.useProgram(currentProgram);

                    // Get var locations

                    var vertex_position = gl.getAttribLocation(currentProgram, "position");

                    // Set values to program variables

                    //Log.wtf("AndroidGLAccelerometerSpiralActivity", "onframe " + ((object)yy).ToString());
                    gl.uniform1f(gl.getUniformLocation(currentProgram, "ucolor_1"), xx);
                    gl.uniform1f(gl.getUniformLocation(currentProgram, "ucolor_2"), yy);

                    gl.uniform1f(gl.getUniformLocation(currentProgram, "time"), time);
                    gl.uniform2f(gl.getUniformLocation(currentProgram, "resolution"), parameters_screenWidth, parameters_screenHeight);
                    gl.uniform2f(gl.getUniformLocation(currentProgram, "aspect"), parameters_aspectX, parameters_aspectY);



                    // Render geometry

                    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
                    //opengl.glVertexAttribPointer(vertex_position, 2, (int)gl.FLOAT, false, 0, 0);
                    gl.vertexAttribPointer((uint)vertex_position, 2, gl.FLOAT, false, 0, 0);
                    gl.enableVertexAttribArray((uint)vertex_position);
                    gl.drawArrays(gl.TRIANGLES, 0, 6);
                    gl.disableVertexAttribArray((uint)vertex_position);

                    framecount++;
                };
                #endregion

                //Log.wtf("AndroidGLAccelerometerSpiralActivity", "onsurface done");
            };


            this.setContentView(v);
            //this.TryHideActionbar(v);

            this.ShowToast("http://my.jsc-solutions.net");
        }
Exemple #5
0
        protected override void onCreate(Bundle savedInstanceState)
        {
            base.onCreate(savedInstanceState);
            setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

            //this.ToFullscreen();

            var v = new RenderingContextView(this);

            v.onsurface +=
                gl =>
            {
                //var __gl = (ScriptCoreLib.Android.__WebGLRenderingContext)(object)gl;

                Log.wtf("AndroidGLEscherDrosteEffectActivity", "onsurface");

                var program = gl.createProgram(
                    new EscherDorsteVertexShader(),
                    new EscherDorsteFragmentShader()
                    );

                gl.bindAttribLocation(program, 0, "position");

                gl.linkProgram(program);
                gl.useProgram(program);

                var uniforms = program.Uniforms(gl);


                #region loadTexture
                Func <android.graphics.Bitmap, ScriptCoreLib.JavaScript.WebGL.WebGLTexture> loadTexture = (image) =>
                {
                    var texture_ = gl.createTexture();

                    gl.enable(gl.TEXTURE_2D);
                    gl.bindTexture(gl.TEXTURE_2D, texture_);

                    //public void texImage2D(uint target, int level, uint internalformat, uint format, uint type, IHTMLCanvas canvas);
                    //public void texImage2D(uint target, int level, uint internalformat, uint format, uint type, IHTMLVideo video);
                    //public void texImage2D(uint target, int level, uint internalformat, uint format, uint type, ImageData pixels);
                    //public void texImage2D(uint target, int level, uint internalformat, int width, int height, int border, uint format, uint type, ArrayBufferView pixels);

                    //public void texImage2D(uint target, int level, uint internalformat, uint format, uint type, IHTMLImage image);
                    //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);

                    //E/AndroidRuntime( 5131): Caused by: java.lang.IllegalArgumentException: invalid Bitmap format
                    //E/AndroidRuntime( 5131):        at android.opengl.GLUtils.texImage2D(GLUtils.java:127)
                    //E/AndroidRuntime( 5131):        at AndroidGLEscherDrosteEffectActivity.Activities.ApplicationActivity___c__DisplayClass5___c__DisplayClass7._onCreate_b__1(ApplicationActivity___c__DisplayClass5___c__DisplayClass7.java:62)

                    //GLUtils.texImage2D(
                    //    /*target*/ (int)gl.TEXTURE_2D,
                    //    /*level*/ 0,
                    //    /*internalformat*/(int)gl.RGBA,
                    //    image,
                    //    /*type*/  (int)gl.UNSIGNED_BYTE,
                    //    0
                    //);

                    // Load the bitmap into the bound texture.
                    GLUtils.texImage2D((int)gl.TEXTURE_2D, 0, image, 0);


                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, (int)gl.LINEAR);
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, (int)gl.LINEAR_MIPMAP_LINEAR);
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, (int)gl.REPEAT);
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, (int)gl.REPEAT);
                    gl.generateMipmap(gl.TEXTURE_2D);


                    // Recycle the bitmap, since its data has been loaded into OpenGL.
                    image.recycle();


                    return(texture_);
                };
                #endregion

                #region openFileFromAssets
                Func <string, InputStream> openFileFromAssets = (string spath) =>
                {
                    InputStream value = null;
                    try
                    {
                        value = this.getResources().getAssets().open(spath);
                    }
                    catch
                    {
                    }
                    return(value);
                };
                #endregion

                var texture__ = android.graphics.BitmapFactory.decodeStream(
                    openFileFromAssets("assets/AndroidGLEscherDrosteEffectActivity/escher.jpg")
                    );
                var texture = loadTexture(
                    texture__
                    );

                gl.uniform1i(gl.getUniformLocation(program, "texture"), 0);

                gl.enableVertexAttribArray(0);


                var vertices = gl.createBuffer();
                gl.bindBuffer(gl.ARRAY_BUFFER, vertices);
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(
                                  -1f, -1f, -1f, 1f, 1f, -1f, 1f, 1f
                                  ), gl.STATIC_DRAW);
                gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);

                var indices = gl.createBuffer();
                gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indices);
                gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(
                                  0, 1, 2, 3
                                  ), gl.STATIC_DRAW);

                #region onresize
                v.onresize +=
                    (width, height) =>
                {
                    Log.wtf("AndroidGLEscherDrosteEffectActivity", "onresize");

                    gl.viewport(0, 0, width, height);

                    var h = (float)height / (float)width;
                    gl.uniform1f(gl.getUniformLocation(program, "h"), h);
                };
                #endregion

                var parameters_time = 0f;

                #region onframe
                var framecount = 0;
                v.onframe +=
                    delegate
                {
                    var t = parameters_time / 1000f;

                    if (framecount == 0)
                    {
                        Log.wtf("AndroidGLEscherDrosteEffectActivity", "onframe " + ((object)t).ToString());
                    }

                    parameters_time += 100;

                    uniforms.t = t;

                    //gl.uniform1f(gl.getUniformLocation(program, "t"), t);
                    gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_SHORT, 0);
                    gl.flush();

                    framecount++;
                };
                #endregion

                Log.wtf("AndroidGLEscherDrosteEffectActivity", "onsurface done");
            };


            this.setContentView(v);

            //this.TryHideActionbar(v);

            this.ShowToast("http://my.jsc-solutions.net");
        }
Exemple #6
0
        public ApplicationSurface(RenderingContextView v, Button button_set_min_filter, Button button_set_mag_filter, Activity OwnerActivity)
        {
            v.onsurface +=
                gl =>
            {
                //var __gl = (ScriptCoreLib.Android.__WebGLRenderingContext)(object)gl;

                #region fields

                /**
                 * Store the model matrix. This matrix is used to move models from object space (where each model can be thought
                 * of being located at the center of the universe) to world space.
                 */
                float[] mModelMatrix = new float[16];

                /**
                 * Store the view matrix. This can be thought of as our camera. This matrix transforms world space to eye space;
                 * it positions things relative to our eye.
                 */
                float[] mViewMatrix = new float[16];

                /** Store the projection matrix. This is used to project the scene onto a 2D viewport. */
                float[] mProjectionMatrix = new float[16];

                /** Allocate storage for the final combined matrix. This will be passed into the shader program. */
                float[] mMVPMatrix = new float[16];

                /** Store the accumulated rotation. */
                float[] mAccumulatedRotation = new float[16];

                /** Store the current rotation. */
                float[] mCurrentRotation = new float[16];

                /** A temporary matrix. */
                float[] mTemporaryMatrix = new float[16];

                /**
                 * Stores a copy of the model matrix specifically for the light position.
                 */
                float[] mLightModelMatrix = new float[16];

                /** Store our model data in a float buffer. */
                FloatBuffer mCubePositions;
                FloatBuffer mCubeNormals;
                FloatBuffer mCubeTextureCoordinates;
                FloatBuffer mCubeTextureCoordinatesForPlane;

                /** This will be used to pass in the transformation matrix. */
                ScriptCoreLib.JavaScript.WebGL.WebGLUniformLocation mMVPMatrixHandle;

                /** This will be used to pass in the modelview matrix. */
                ScriptCoreLib.JavaScript.WebGL.WebGLUniformLocation mMVMatrixHandle;

                /** This will be used to pass in the light position. */
                ScriptCoreLib.JavaScript.WebGL.WebGLUniformLocation mLightPosHandle;

                /** This will be used to pass in the texture. */
                ScriptCoreLib.JavaScript.WebGL.WebGLUniformLocation mTextureUniformHandle;

                /** This will be used to pass in model position information. */
                int mPositionHandle;

                /** This will be used to pass in model normal information. */
                int mNormalHandle;

                /** This will be used to pass in model texture coordinate information. */
                int mTextureCoordinateHandle;

                /** How many bytes per float. */
                int mBytesPerFloat = 4;

                /** Size of the position data in elements. */
                int mPositionDataSize = 3;

                /** Size of the normal data in elements. */
                int mNormalDataSize = 3;

                /** Size of the texture coordinate data in elements. */
                int mTextureCoordinateDataSize = 2;

                /** Used to hold a light centered on the origin in model space. We need a 4th coordinate so we can get translations to work when
                 *  we multiply this by our transformation matrices. */
                float[] mLightPosInModelSpace = new float[] { 0.0f, 0.0f, 0.0f, 1.0f };

                /** Used to hold the current position of the light in world space (after transformation via model matrix). */
                float[] mLightPosInWorldSpace = new float[4];

                /** Used to hold the transformed position of the light in eye space (after transformation via modelview matrix) */
                float[] mLightPosInEyeSpace = new float[4];

                /** This is a handle to our cube shading program. */
                ScriptCoreLib.JavaScript.WebGL.WebGLProgram mProgramHandle;

                /** This is a handle to our light point program. */
                ScriptCoreLib.JavaScript.WebGL.WebGLProgram mPointProgramHandle;

                /** These are handles to our texture data. */
                ScriptCoreLib.JavaScript.WebGL.WebGLTexture mBrickDataHandle;
                ScriptCoreLib.JavaScript.WebGL.WebGLTexture mGrassDataHandle;

                #endregion

                #region ontouchmove
                // These still work without volatile, but refreshes are not guaranteed to happen.
                /* volatile */
                float mDeltaX = 0;
                /* volatile */
                float mDeltaY = 0;

                v.ontouchmove +=
                    (x, y) =>
                {
                    mDeltaX += x;
                    mDeltaY += y;
                };
                #endregion

                #region Define points for a cube.

                // X, Y, Z
                float[] cubePositionData =
                {
                    // In OpenGL counter-clockwise winding is default. This means that when we look at a triangle,
                    // if the points are counter-clockwise we are looking at the "front". If not we are looking at
                    // the back. OpenGL has an optimization where all back-facing triangles are culled, since they
                    // usually represent the backside of an object and aren't visible anyways.

                    // Front face
                    -1.0f,  1.0f,  1.0f,
                    -1.0f, -1.0f,  1.0f,
                    1.0f,   1.0f,  1.0f,
                    -1.0f, -1.0f,  1.0f,
                    1.0f,  -1.0f,  1.0f,
                    1.0f,   1.0f,  1.0f,

                    // Right face
                    1.0f,   1.0f,  1.0f,
                    1.0f,  -1.0f,  1.0f,
                    1.0f,   1.0f, -1.0f,
                    1.0f,  -1.0f,  1.0f,
                    1.0f,  -1.0f, -1.0f,
                    1.0f,   1.0f, -1.0f,

                    // Back face
                    1.0f,   1.0f, -1.0f,
                    1.0f,  -1.0f, -1.0f,
                    -1.0f,  1.0f, -1.0f,
                    1.0f,  -1.0f, -1.0f,
                    -1.0f, -1.0f, -1.0f,
                    -1.0f,  1.0f, -1.0f,

                    // Left face
                    -1.0f,  1.0f, -1.0f,
                    -1.0f, -1.0f, -1.0f,
                    -1.0f,  1.0f,  1.0f,
                    -1.0f, -1.0f, -1.0f,
                    -1.0f, -1.0f,  1.0f,
                    -1.0f,  1.0f,  1.0f,

                    // Top face
                    -1.0f,  1.0f, -1.0f,
                    -1.0f,  1.0f,  1.0f,
                    1.0f,   1.0f, -1.0f,
                    -1.0f,  1.0f,  1.0f,
                    1.0f,   1.0f,  1.0f,
                    1.0f,   1.0f, -1.0f,

                    // Bottom face
                    1.0f,  -1.0f, -1.0f,
                    1.0f,  -1.0f,  1.0f,
                    -1.0f, -1.0f, -1.0f,
                    1.0f,  -1.0f,  1.0f,
                    -1.0f, -1.0f,  1.0f,
                    -1.0f, -1.0f, -1.0f,
                };

                // X, Y, Z
                // The normal is used in light calculations and is a vector which points
                // orthogonal to the plane of the surface. For a cube model, the normals
                // should be orthogonal to the points of each face.
                float[] cubeNormalData =
                {
                    // Front face
                    0.0f,   0.0f,  1.0f,
                    0.0f,   0.0f,  1.0f,
                    0.0f,   0.0f,  1.0f,
                    0.0f,   0.0f,  1.0f,
                    0.0f,   0.0f,  1.0f,
                    0.0f,   0.0f,  1.0f,

                    // Right face
                    1.0f,   0.0f,  0.0f,
                    1.0f,   0.0f,  0.0f,
                    1.0f,   0.0f,  0.0f,
                    1.0f,   0.0f,  0.0f,
                    1.0f,   0.0f,  0.0f,
                    1.0f,   0.0f,  0.0f,

                    // Back face
                    0.0f,   0.0f, -1.0f,
                    0.0f,   0.0f, -1.0f,
                    0.0f,   0.0f, -1.0f,
                    0.0f,   0.0f, -1.0f,
                    0.0f,   0.0f, -1.0f,
                    0.0f,   0.0f, -1.0f,

                    // Left face
                    -1.0f,  0.0f,  0.0f,
                    -1.0f,  0.0f,  0.0f,
                    -1.0f,  0.0f,  0.0f,
                    -1.0f,  0.0f,  0.0f,
                    -1.0f,  0.0f,  0.0f,
                    -1.0f,  0.0f,  0.0f,

                    // Top face
                    0.0f,   1.0f,  0.0f,
                    0.0f,   1.0f,  0.0f,
                    0.0f,   1.0f,  0.0f,
                    0.0f,   1.0f,  0.0f,
                    0.0f,   1.0f,  0.0f,
                    0.0f,   1.0f,  0.0f,

                    // Bottom face
                    0.0f,  -1.0f,  0.0f,
                    0.0f,  -1.0f,  0.0f,
                    0.0f,  -1.0f,  0.0f,
                    0.0f,  -1.0f,  0.0f,
                    0.0f,  -1.0f,  0.0f,
                    0.0f,  -1.0f, 0.0f
                };

                // S, T (or X, Y)
                // Texture coordinate data.
                // Because images have a Y axis pointing downward (values increase as you move down the image) while
                // OpenGL has a Y axis pointing upward, we adjust for that here by flipping the Y axis.
                // What's more is that the texture coordinates are the same for every face.
                float[] cubeTextureCoordinateData =
                {
                    // Front face
                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 0.0f,

                    // Right face
                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 0.0f,

                    // Back face
                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 0.0f,

                    // Left face
                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 0.0f,

                    // Top face
                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 0.0f,

                    // Bottom face
                    0.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 0.0f,
                    0.0f, 1.0f,
                    1.0f, 1.0f,
                    1.0f, 0.0f
                };

                // S, T (or X, Y)
                // Texture coordinate data.
                // Because images have a Y axis pointing downward (values increase as you move down the image) while
                // OpenGL has a Y axis pointing upward, we adjust for that here by flipping the Y axis.
                // What's more is that the texture coordinates are the same for every face.
                float[] cubeTextureCoordinateDataForPlane =
                {
                    // Front face
                    0.0f,   0.0f,
                    0.0f,  25.0f,
                    25.0f,  0.0f,
                    0.0f,  25.0f,
                    25.0f, 25.0f,
                    25.0f,  0.0f,

                    // Right face
                    0.0f,   0.0f,
                    0.0f,  25.0f,
                    25.0f,  0.0f,
                    0.0f,  25.0f,
                    25.0f, 25.0f,
                    25.0f,  0.0f,

                    // Back face
                    0.0f,   0.0f,
                    0.0f,  25.0f,
                    25.0f,  0.0f,
                    0.0f,  25.0f,
                    25.0f, 25.0f,
                    25.0f,  0.0f,

                    // Left face
                    0.0f,   0.0f,
                    0.0f,  25.0f,
                    25.0f,  0.0f,
                    0.0f,  25.0f,
                    25.0f, 25.0f,
                    25.0f,  0.0f,

                    // Top face
                    0.0f,   0.0f,
                    0.0f,  25.0f,
                    25.0f,  0.0f,
                    0.0f,  25.0f,
                    25.0f, 25.0f,
                    25.0f,  0.0f,

                    // Bottom face
                    0.0f,   0.0f,
                    0.0f,  25.0f,
                    25.0f,  0.0f,
                    0.0f,  25.0f,
                    25.0f, 25.0f,
                    25.0f, 0.0f
                };
                #endregion

                #region  Initialize the buffers.
                mCubePositions = ByteBuffer.allocateDirect(cubePositionData.Length * mBytesPerFloat)
                                 .order(ByteOrder.nativeOrder()).asFloatBuffer();
                mCubePositions.put(cubePositionData).position(0);

                mCubeNormals = ByteBuffer.allocateDirect(cubeNormalData.Length * mBytesPerFloat)
                               .order(ByteOrder.nativeOrder()).asFloatBuffer();
                mCubeNormals.put(cubeNormalData).position(0);

                mCubeTextureCoordinates = ByteBuffer.allocateDirect(cubeTextureCoordinateData.Length * mBytesPerFloat)
                                          .order(ByteOrder.nativeOrder()).asFloatBuffer();
                mCubeTextureCoordinates.put(cubeTextureCoordinateData).position(0);

                mCubeTextureCoordinatesForPlane = ByteBuffer.allocateDirect(cubeTextureCoordinateDataForPlane.Length * mBytesPerFloat)
                                                  .order(ByteOrder.nativeOrder()).asFloatBuffer();
                mCubeTextureCoordinatesForPlane.put(cubeTextureCoordinateDataForPlane).position(0);
                #endregion


                // Set the background clear color to black.
                gl.clearColor(0.0f, 0.0f, 0.0f, 0.0f);

                // Use culling to remove back faces.
                gl.enable(gl.CULL_FACE);

                // Enable depth testing
                gl.enable(gl.DEPTH_TEST);

                // Enable texture mapping
                gl.enable(gl.TEXTURE_2D);

                #region setLookAtM
                // Position the eye in front of the origin.
                float eyeX = 0.0f;
                float eyeY = 0.0f;
                float eyeZ = -0.5f;

                // We are looking toward the distance
                float lookX = 0.0f;
                float lookY = 0.0f;
                float lookZ = -5.0f;

                // Set our up vector. This is where our head would be pointing were we holding the camera.
                float upX = 0.0f;
                float upY = 1.0f;
                float upZ = 0.0f;

                // Set the view matrix. This matrix can be said to represent the camera position.
                // NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination of a model and
                // view matrix. In OpenGL 2, we can keep track of these matrices separately if we choose.
                Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
                #endregion


                #region mProgramHandle
                mProgramHandle = gl.createProgram(
                    new Shaders.per_pixel_tex_and_lightVertexShader(),
                    new Shaders.per_pixel_tex_and_lightFragmentShader()
                    );

                gl.bindAttribLocation(mProgramHandle, 0, "a_Position");
                gl.bindAttribLocation(mProgramHandle, 1, "a_Color");
                gl.bindAttribLocation(mProgramHandle, 2, "a_TexCoordinate");

                gl.linkProgram(mProgramHandle);
                #endregion

                // Define a simple shader program for our point.

                #region mPointProgramHandle
                mPointProgramHandle = gl.createProgram(
                    new Shaders.pointVertexShader(),
                    new Shaders.pointFragmentShader()
                    );

                gl.bindAttribLocation(mPointProgramHandle, 0, "a_Position");

                gl.linkProgram(mPointProgramHandle);
                #endregion


                #region loadTexture
                Func <android.graphics.Bitmap, ScriptCoreLib.JavaScript.WebGL.WebGLTexture> loadTexture = (bitmap) =>
                {
                    var textureHandle = gl.createTexture();

                    // Bind to the texture in OpenGL
                    gl.bindTexture(gl.TEXTURE_2D, textureHandle);

                    // Set filtering
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, (int)gl.NEAREST);
                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, (int)gl.NEAREST);

                    // Load the bitmap into the bound texture.
                    GLUtils.texImage2D((int)gl.TEXTURE_2D, 0, bitmap, 0);

                    // Recycle the bitmap, since its data has been loaded into OpenGL.
                    bitmap.recycle();


                    return(textureHandle);
                };
                #endregion

                #region openFileFromAssets
                Func <string, InputStream> openFileFromAssets = (string spath) =>
                {
                    InputStream value = null;
                    try
                    {
                        value = OwnerActivity.getResources().getAssets().open(spath);
                    }
                    catch
                    {
                    }
                    return(value);
                };
                #endregion


                // cant we use knownAssets yet?
                var stone_wall_public_domain = android.graphics.BitmapFactory.decodeStream(
                    openFileFromAssets("assets/AndroidOpenGLESLesson6Activity/stone_wall_public_domain.png")
                    );


                var noisy_grass_public_domain = android.graphics.BitmapFactory.decodeStream(
                    openFileFromAssets("assets/AndroidOpenGLESLesson6Activity/noisy_grass_public_domain.png")
                    );

                // Load the texture
                mBrickDataHandle = loadTexture(
                    stone_wall_public_domain
                    );

                gl.generateMipmap(gl.TEXTURE_2D);


                mGrassDataHandle = loadTexture(
                    noisy_grass_public_domain
                    );

                gl.generateMipmap(gl.TEXTURE_2D);



                // Initialize the accumulated rotation matrix
                Matrix.setIdentityM(mAccumulatedRotation, 0);

                #region onresize
                v.onresize +=
                    (width, height) =>
                {
                    // Set the OpenGL viewport to the same size as the surface.
                    gl.viewport(0, 0, width, height);

                    // Create a new perspective projection matrix. The height will stay the same
                    // while the width will vary as per aspect ratio.
                    float ratio  = (float)width / height;
                    float left   = -ratio;
                    float right  = ratio;
                    float bottom = -1.0f;
                    float top    = 1.0f;
                    float near   = 1.0f;
                    float far    = 1000.0f;

                    Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
                };
                #endregion


                #region TEXTURE_MIN_FILTER
                button_set_min_filter.AtClick(
                    delegate
                {
                    var builder = new AlertDialog.Builder(OwnerActivity);


                    builder.setTitle("Set TEXTURE_MIN_FILTER!");
                    builder.setItems(
                        new[] {
                        "NEAREST",
                        "LINEAR",
                        "NEAREST_MIPMAP_NEAREST",
                        "NEAREST_MIPMAP_LINEAR",
                        "LINEAR_MIPMAP_NEAREST",
                        "LINEAR_MIPMAP_LINEAR",
                    },
                        item =>
                    {
                        v.queueEvent(
                            delegate
                        {
                            int filter;

                            if (item == 0)
                            {
                                filter = (int)gl.NEAREST;
                            }
                            else if (item == 1)
                            {
                                filter = (int)gl.LINEAR;
                            }
                            else if (item == 2)
                            {
                                filter = (int)gl.NEAREST_MIPMAP_NEAREST;
                            }
                            else if (item == 3)
                            {
                                filter = (int)gl.NEAREST_MIPMAP_LINEAR;
                            }
                            else if (item == 4)
                            {
                                filter = (int)gl.LINEAR_MIPMAP_NEAREST;
                            }
                            else                                                      // if (item == 5)
                            {
                                filter = (int)gl.LINEAR_MIPMAP_LINEAR;
                            }

                            if (mBrickDataHandle != null)
                            {
                                if (mGrassDataHandle != null)
                                {
                                    gl.bindTexture(gl.TEXTURE_2D, mBrickDataHandle);
                                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter);
                                    gl.bindTexture(gl.TEXTURE_2D, mGrassDataHandle);
                                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter);
                                }
                            }
                        }
                            );
                    }
                        );


                    var dialog = builder.create();

                    dialog.setOwnerActivity(OwnerActivity);
                    dialog.show();
                }
                    );
                #endregion

                #region TEXTURE_MAG_FILTER
                button_set_mag_filter.AtClick(
                    delegate
                {
                    var builder = new AlertDialog.Builder(OwnerActivity);

                    builder.setTitle("Set TEXTURE_MAG_FILTER");
                    builder.setItems(
                        new[] {
                        "GL_NEAREST",
                        "GL_LINEAR"
                    },
                        item =>
                    {
                        v.queueEvent(
                            delegate
                        {
                            int filter;

                            if (item == 0)
                            {
                                filter = (int)gl.NEAREST;
                            }
                            else                                                      // if (item == 1)
                            {
                                filter = (int)gl.LINEAR;
                            }

                            if (mBrickDataHandle != null)
                            {
                                if (mGrassDataHandle != null)
                                {
                                    gl.bindTexture(gl.TEXTURE_2D, mBrickDataHandle);
                                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter);
                                    gl.bindTexture(gl.TEXTURE_2D, mGrassDataHandle);
                                    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter);
                                }
                            }
                        }
                            );
                    }
                        );

                    var dialog = builder.create();

                    dialog.setOwnerActivity(OwnerActivity);
                    dialog.show();
                }
                    );
                #endregion



                #region onframe
                v.onframe +=
                    delegate
                {
                    var sw = Stopwatch.StartNew();

                    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

                    // Do a complete rotation every 10 seconds.
                    long  time               = SystemClock.uptimeMillis() % 10000L;
                    long  slowTime           = SystemClock.uptimeMillis() % 100000L;
                    float angleInDegrees     = (360.0f / 10000.0f) * ((int)time);
                    float slowAngleInDegrees = (360.0f / 100000.0f) * ((int)slowTime);

                    var program = mProgramHandle;
                    // Set our per-vertex lighting program.
                    gl.useProgram(program);

                    var uniforms = program.Uniforms(gl);

                    // Set program handles for cube drawing.
                    mMVPMatrixHandle      = gl.getUniformLocation(program, "u_MVPMatrix");
                    mMVMatrixHandle       = gl.getUniformLocation(program, "u_MVMatrix");
                    mLightPosHandle       = gl.getUniformLocation(program, "u_LightPos");
                    mTextureUniformHandle = gl.getUniformLocation(program, "u_Texture");

                    mPositionHandle          = gl.getAttribLocation(program, "a_Position");
                    mNormalHandle            = gl.getAttribLocation(program, "a_Normal");
                    mTextureCoordinateHandle = gl.getAttribLocation(program, "a_TexCoordinate");

                    // Calculate position of the light. Rotate and then push into the distance.
                    Matrix.setIdentityM(mLightModelMatrix, 0);
                    Matrix.translateM(mLightModelMatrix, 0, 0.0f, 0.0f, -2.0f);
                    Matrix.rotateM(mLightModelMatrix, 0, angleInDegrees, 0.0f, 1.0f, 0.0f);
                    Matrix.translateM(mLightModelMatrix, 0, 0.0f, 0.0f, 3.5f);

                    Matrix.multiplyMV(mLightPosInWorldSpace, 0, mLightModelMatrix, 0, mLightPosInModelSpace, 0);
                    Matrix.multiplyMV(mLightPosInEyeSpace, 0, mViewMatrix, 0, mLightPosInWorldSpace, 0);

                    // Draw a cube.
                    // Translate the cube into the screen.
                    Matrix.setIdentityM(mModelMatrix, 0);
                    Matrix.translateM(mModelMatrix, 0, 0.0f, 0.8f, -3.5f);

                    // Set a matrix that contains the current rotation.
                    Matrix.setIdentityM(mCurrentRotation, 0);
                    Matrix.rotateM(mCurrentRotation, 0, mDeltaX, 0.0f, 1.0f, 0.0f);
                    Matrix.rotateM(mCurrentRotation, 0, mDeltaY, 1.0f, 0.0f, 0.0f);
                    mDeltaX = 0.1f;
                    mDeltaY = 0.1f;

                    // Multiply the current rotation by the accumulated rotation, and then set the accumulated rotation to the result.
                    Matrix.multiplyMM(mTemporaryMatrix, 0, mCurrentRotation, 0, mAccumulatedRotation, 0);
                    java.lang.System.arraycopy(mTemporaryMatrix, 0, mAccumulatedRotation, 0, 16);

                    // Rotate the cube taking the overall rotation into account.
                    Matrix.multiplyMM(mTemporaryMatrix, 0, mModelMatrix, 0, mAccumulatedRotation, 0);
                    java.lang.System.arraycopy(mTemporaryMatrix, 0, mModelMatrix, 0, 16);

                    // Set the active texture unit to texture unit 0.
                    gl.activeTexture(gl.TEXTURE0);

                    // Bind the texture to this unit.
                    gl.bindTexture(gl.TEXTURE_2D, mBrickDataHandle);

                    // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
                    gl.uniform1i(mTextureUniformHandle, 0);

                    // Pass in the texture coordinate information
                    mCubeTextureCoordinates.position(0);

                    opengl.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, (int)gl.FLOAT, false,
                                                 0, mCubeTextureCoordinates);

                    #region drawCube
                    Action drawCube =
                        delegate
                    {
                        // Pass in the position information
                        mCubePositions.position(0);
                        opengl.glVertexAttribPointer(mPositionHandle, mPositionDataSize, (int)gl.FLOAT, false,
                                                     0, mCubePositions);

                        gl.enableVertexAttribArray((uint)mPositionHandle);

                        // Pass in the normal information
                        mCubeNormals.position(0);
                        opengl.glVertexAttribPointer(mNormalHandle, mNormalDataSize, (int)gl.FLOAT, false,
                                                     0, mCubeNormals);

                        gl.enableVertexAttribArray((uint)mNormalHandle);

                        // This multiplies the view matrix by the model matrix, and stores the result in the MVP matrix
                        // (which currently contains model * view).
                        Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);

                        // Pass in the modelview matrix.
                        gl.uniformMatrix4fv(mMVMatrixHandle, false, mMVPMatrix);

                        // This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix
                        // (which now contains model * view * projection).
                        Matrix.multiplyMM(mTemporaryMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
                        java.lang.System.arraycopy(mTemporaryMatrix, 0, mMVPMatrix, 0, 16);

                        // Pass in the combined matrix.
                        gl.uniformMatrix4fv(mMVPMatrixHandle, false, mMVPMatrix);

                        // Pass in the light position in eye space.
                        gl.uniform3f(mLightPosHandle, mLightPosInEyeSpace[0], mLightPosInEyeSpace[1], mLightPosInEyeSpace[2]);

                        // Draw the cube.k
                        gl.drawArrays(gl.TRIANGLES, 0, 36);
                    };
                    #endregion

                    drawCube();

                    // Draw a plane
                    Matrix.setIdentityM(mModelMatrix, 0);
                    Matrix.translateM(mModelMatrix, 0, 0.0f, -2.0f, -5.0f);
                    Matrix.scaleM(mModelMatrix, 0, 25.0f, 1.0f, 25.0f);
                    Matrix.rotateM(mModelMatrix, 0, slowAngleInDegrees, 0.0f, 1.0f, 0.0f);

                    // Set the active texture unit to texture unit 0.
                    gl.activeTexture(gl.TEXTURE0);

                    // Bind the texture to this unit.
                    gl.bindTexture(gl.TEXTURE_2D, mGrassDataHandle);

                    // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
                    gl.uniform1i(mTextureUniformHandle, 0);

                    // Pass in the texture coordinate information
                    mCubeTextureCoordinatesForPlane.position(0);
                    opengl.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, (int)gl.FLOAT, false,
                                                 0, mCubeTextureCoordinatesForPlane);

                    gl.enableVertexAttribArray((uint)mTextureCoordinateHandle);

                    drawCube();


                    #region drawLight
                    Action drawLight =
                        delegate
                    {
                        var pointMVPMatrixHandle = gl.getUniformLocation(mPointProgramHandle, "u_MVPMatrix");
                        var pointPositionHandle  = gl.getAttribLocation(mPointProgramHandle, "a_Position");

                        // Pass in the position.
                        gl.vertexAttrib3f((uint)pointPositionHandle, mLightPosInModelSpace[0], mLightPosInModelSpace[1], mLightPosInModelSpace[2]);

                        // Since we are not using a buffer object, disable vertex arrays for this attribute.
                        gl.disableVertexAttribArray((uint)pointPositionHandle);

                        // Pass in the transformation matrix.
                        Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mLightModelMatrix, 0);
                        Matrix.multiplyMM(mTemporaryMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
                        java.lang.System.arraycopy(mTemporaryMatrix, 0, mMVPMatrix, 0, 16);

                        gl.uniformMatrix4fv(pointMVPMatrixHandle, false, mMVPMatrix);

                        // Draw the point.
                        gl.drawArrays(gl.POINTS, 0, 1);
                    };
                    #endregion

                    // Draw a point to indicate the light.
                    gl.useProgram(mPointProgramHandle);
                    drawLight();

                    sw.Stop();
                    OwnerActivity.runOnUiThread(
                        delegate
                    {
                        // Caused by: java.lang.ArithmeticException: divide by zero
                        // at AndroidOpenGLESLesson6Activity.Shaders.ApplicationSurface___c__DisplayClass0_4.__ctor_b__14(ApplicationSurface___c__DisplayClass0_4.java:28)
                        // ... 20 more
                        //Force finishing activity AndroidOpenGLESLesson6Activity.Activities /.AndroidOpenGLESLesson6Activity

                        OwnerActivity.setTitle(
                            "" + new { sw.ElapsedMilliseconds, fps = 1000.0 / sw.ElapsedMilliseconds });
                    }
                        );
                };
                #endregion
            };
        }