Can't get GLES2Context to work in Android

Hi everyone. I can’t seem to get this working in Android. Neko under Window 10 works fine. First, let me show you the project.xml file.

<?xml version="1.0" encoding="utf-8"?>
<project>

	<meta title="Test" package="com.ruicuco.test" version="1.0.0" company="Rui Cuco" />
	<app main="Main" path="Export" file="Test" />

	<config:android min-sdk-version="15" target-sdk-version="15" />
	<config:android glEsVersion="0x00020000" required="true" />

	<source path="Source" />

	<haxelib name="lime" />

	<assets path="Assets" rename="assets" />

	<window orientation="landscape" fps="30" background="#000000" vsync="true" hardware="true"
		require-shaders="true" depth-buffer="true" />
	<window if="desktop" fullscreen="false" width="384" height="256" resizable="false" />
	<window if="mobile" fullscreen="true" />
</project>

Next, comes Matrix.hx, a simple utility class, containing the usual methods to work with matrices.

package;

import lime.utils.Float32Array;

abstract Matrix(Float32Array) from Float32Array to Float32Array
{
	private inline function new(array:Array<Float>)
	{
		this = new Float32Array(array);
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public static function initFromArrayOfFloats(array:Array<Float>):Matrix
	{
		if(array.length == 16)
		{
			return new Matrix(array);
		}
		else
		{
			return null;
		}
	}

	public static function initFromIdentity():Matrix
	{
		return new Matrix([
			1.0, 0.0, 0.0, 0.0,
			0.0, 1.0, 0.0, 0.0,
			0.0, 0.0, 1.0, 0.0,
			0.0, 0.0, 0.0, 1.0]);
	}

	public static function initFromTranslation(x:Float, y:Float, z:Float):Matrix
	{
		return new Matrix([
			1.0, 0.0, 0.0, 0.0,
			0.0, 1.0, 0.0, 0.0,
			0.0, 0.0, 1.0, 0.0,
			x,   y,   z,   1.0]);
	}

	public static function initFromScale(x:Float, y:Float, z:Float):Matrix
	{
		return new Matrix([
			x,   0.0, 0.0, 0.0,
			0.0, y,   0.0, 0.0,
			0.0, 0.0, z,   0.0,
			0.0, 0.0, 0.0, 1.0]);
	}

	public static function initFromXRotation(a:Float):Matrix
	{
		var c = Math.cos(a);
		var s = Math.sin(a);

		return new Matrix([
			1.0, 0.0, 0.0, 0.0,
			0.0, c,   s,   0.0,
			0.0, -s,  c,   0.0,
			0.0, 0.0, 0.0, 1.0]);
	}

	public static function initFromYRotation(a:Float):Matrix
	{
		var c = Math.cos(a);
		var s = Math.sin(a);

		return new Matrix([
			c,   0.0, -s,  0.0,
			0.0, 1.0, 0.0, 0.0,
			s,   0.0, c,   0.0,
			0.0, 0.0, 0.0, 1.0]);
	}

	public static function initFromZRotation(a:Float):Matrix
	{
		var c = Math.cos(a);
		var s = Math.sin(a);

		return new Matrix([
			c,   s,   0.0, 0.0,
			-s,  c,   0.0, 0.0,
			0.0, 0.0, 1.0, 0.0,
			0.0, 0.0, 0.0, 1.0]);
	}

	public static function initFromPerspective(l:Float, r:Float, b:Float, t:Float,
		n:Float, f:Float):Matrix
	{
		return new Matrix([
			2.0 * n / (r - l), 0.0,               0.0,                    0.0,
			0.0,               2.0 * n / (t - b), 0.0,                    0.0,
			(r + l) / (r - l), (t + b) / (t - b), -(f + n) / (f - n),     -1.0,
			0.0,               0.0,               -2.0 * f * n / (f - n), 0.0]);
	}

	public static function initFromOrthographic(l:Float, r:Float, b:Float, t:Float,
		n:Float, f:Float):Matrix
	{
		return new Matrix([
			2.0 / (r - l),      0.0,                0.0,                0.0,
			0.0,                2.0 / (t - b),      0.0,                0.0,
			0.0,                0.0,                -2.0 / (f - n),     0.0,
			-(r + l) / (r - l), -(t + b) / (t - b), -(f + n) / (f - n), 1.0]);
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	@:op(A + B) public static function matrixAdd(lhs:Matrix, rhs:Matrix):Matrix
	{
		return new Matrix([
			lhs[0]  + rhs[0],  lhs[1]  + rhs[1],  lhs[2]  + rhs[2],  lhs[3]  + rhs[3],
			lhs[4]  + rhs[4],  lhs[5]  + rhs[5],  lhs[6]  + rhs[6],  lhs[7]  + rhs[7],
			lhs[8]  + rhs[8],  lhs[9]  + rhs[9],  lhs[10] + rhs[10], lhs[11] + rhs[11],
			lhs[12] + rhs[12], lhs[13] + rhs[13], lhs[14] + rhs[14], lhs[15] + rhs[15]]);
	}

	@:op(A - B) public static function matrixSubtract(lhs:Matrix, rhs:Matrix):Matrix
	{
		return new Matrix([
			lhs[0]  - rhs[0],  lhs[1]  - rhs[1],  lhs[2]  - rhs[2],  lhs[3]  - rhs[3],
			lhs[4]  - rhs[4],  lhs[5]  - rhs[5],  lhs[6]  - rhs[6],  lhs[7]  - rhs[7],
			lhs[8]  - rhs[8],  lhs[9]  - rhs[9],  lhs[10] - rhs[10], lhs[11] - rhs[11],
			lhs[12] - rhs[12], lhs[13] - rhs[13], lhs[14] - rhs[14], lhs[15] - rhs[15]]);
	}

	@:op(A * B) public static function matrixMultiply(lhs:Matrix, rhs:Matrix):Matrix
	{
		return new Matrix([
			lhs[0]  * rhs[0] + lhs[1]  * rhs[4] + lhs[2]  * rhs[8]  + lhs[3]  * rhs[12],
			lhs[0]  * rhs[1] + lhs[1]  * rhs[5] + lhs[2]  * rhs[9]  + lhs[3]  * rhs[13],
			lhs[0]  * rhs[2] + lhs[1]  * rhs[6] + lhs[2]  * rhs[10] + lhs[3]  * rhs[14],
			lhs[0]  * rhs[3] + lhs[1]  * rhs[7] + lhs[2]  * rhs[11] + lhs[3]  * rhs[15],

			lhs[4]  * rhs[0] + lhs[5]  * rhs[4] + lhs[6]  * rhs[8]  + lhs[7]  * rhs[12],
			lhs[4]  * rhs[1] + lhs[5]  * rhs[5] + lhs[6]  * rhs[9]  + lhs[7]  * rhs[13],
			lhs[4]  * rhs[2] + lhs[5]  * rhs[6] + lhs[6]  * rhs[10] + lhs[7]  * rhs[14],
			lhs[4]  * rhs[3] + lhs[5]  * rhs[7] + lhs[6]  * rhs[11] + lhs[7]  * rhs[15],

			lhs[8]  * rhs[0] + lhs[9]  * rhs[4] + lhs[10] * rhs[8]  + lhs[11] * rhs[12],
			lhs[8]  * rhs[1] + lhs[9]  * rhs[5] + lhs[10] * rhs[9]  + lhs[11] * rhs[13],
			lhs[8]  * rhs[2] + lhs[9]  * rhs[6] + lhs[10] * rhs[10] + lhs[11] * rhs[14],
			lhs[8]  * rhs[3] + lhs[9]  * rhs[7] + lhs[10] * rhs[11] + lhs[11] * rhs[15],

			lhs[12] * rhs[0] + lhs[13] * rhs[4] + lhs[14] * rhs[8]  + lhs[15] * rhs[12],
			lhs[12] * rhs[1] + lhs[13] * rhs[5] + lhs[14] * rhs[9]  + lhs[15] * rhs[13],
			lhs[12] * rhs[2] + lhs[13] * rhs[6] + lhs[14] * rhs[10] + lhs[15] * rhs[14],
			lhs[12] * rhs[3] + lhs[13] * rhs[7] + lhs[14] * rhs[11] + lhs[15] * rhs[15]]);
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	@:arrayAccess public function get(i:Int):Float
	{
		return this[i];
	}

	@:arrayAccess public function set(i:Int, x:Float):Float
	{
		return this[i] = x;
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	@:to public function asString():String
	{
		return
			"[" + this[0]  + " " + this[1]  + " " + this[2]  + " " + this[3]  +
			" " + this[4]  + " " + this[5]  + " " + this[6]  + " " + this[7]  +
			" " + this[8]  + " " + this[9]  + " " + this[10] + " " + this[11] +
			" " + this[12] + " " + this[13] + " " + this[14] + " " + this[15] + "]";
	}
}

Finally, here is the Main.hx class.

package;

import lime.app.Application;

import lime.graphics.Renderer;
import lime.graphics.opengl.*;

import lime.system.System;

import lime.ui.KeyCode;
import lime.ui.KeyModifier;
import lime.ui.Window;

import lime.utils.DataPointer;
import lime.utils.Float32Array;
import lime.utils.GLUtils;

class Main extends Application
{
	#if desktop
	private static var gl:WebGL2Context;
	#else
	private static var gl:GLES2Context;
	#end

	private var glProgram:GLProgram;

	private var glVertexBuffer:GLBuffer;
	private var glVertexAttribute:Int;

	private var glCameraMatrixUniform:GLUniformLocation;
	private var glObjectMatrixUniform:GLUniformLocation;

	private var glObjectMaterialUniform:GLUniformLocation;

	private var cameraMatrix:Matrix;
	private var objectMatrix:Matrix;

	private var objectBuffer:Float32Array;
	private var objectMaterial:Float32Array;

	private var mainContextInited:Bool;

	private var width:Int;
	private var height:Int;

	private var angle:Float;

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function new()
	{
		super();

		mainContextInited = false;

		angle = 0.0;
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public override function update(delta:Int):Void
	{
		super.update(delta);

		angle += delta / 1000.0;
		if(angle >= 360.0)
			angle %= 360.0;
	}

	public override function render(renderer:Renderer)
	{
		super.render(renderer);

		if(!preloader.complete)
			return;

		switch(renderer.context)
		{
			case OPENGL(opengl):
				gl = opengl;
				if(!mainContextInited)
				{
					mainContextInit();

					mainContextInited = true;
				}

				mainContextRender();

			default:
		}
	}

	public override function onKeyDown(window:Window, keyCode:KeyCode, modifier:KeyModifier)
	{
		super.onKeyDown(window, keyCode, modifier);

		if(keyCode == APP_CONTROL_BACK || keyCode == ESCAPE)
		{
			System.exit(0);
		}
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function mainContextInit():Void
	{
		width = Application.current.config.windows[0].width;
		height = Application.current.config.windows[0].height;

		var vertexSource = 
			"attribute vec4 aVertex;

			uniform mat4 uCameraMatrix;
			uniform mat4 uObjectMatrix;

			uniform vec4 uObjectMaterial;

			varying vec4 vObjectMaterial;

			void main(void)
			{
				vObjectMaterial = uObjectMaterial;

				gl_Position = uCameraMatrix * (uObjectMatrix * aVertex);	
			}";

		var fragmentSource = 
			#if !desktop
			"precision mediump float;" +
			#end
			"varying vec4 vObjectMaterial;

			void main(void)
			{
				gl_FragColor = vObjectMaterial;
			}";

		glProgram = GLUtils.createProgram(vertexSource, fragmentSource);
		gl.useProgram(glProgram);

		glVertexBuffer = gl.createBuffer();

		gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
		gl.enable(gl.BLEND);

		gl.frontFace(gl.CCW);

		gl.cullFace(gl.BACK);
		gl.enable(gl.CULL_FACE);

		gl.depthFunc(gl.LESS);
		gl.enable(gl.DEPTH_TEST);

		glVertexAttribute = gl.getAttribLocation(glProgram, "aVertex");

		glCameraMatrixUniform = gl.getUniformLocation(glProgram, "uCameraMatrix");
		glObjectMatrixUniform = gl.getUniformLocation(glProgram, "uObjectMatrix");

		glObjectMaterialUniform = gl.getUniformLocation(glProgram, "uObjectMaterial");
	}

	public function mainContextRender():Void
	{
	    var X = 0.525731112119133606;
	    var Z = 0.850650808352039932;
	    var icosaedronVertex = [
	        X, 0.0, Z, 0.0, Z, X, -X, 0.0, Z,       //  1,  4,  0
	        0.0, Z, X, -Z, X, 0.0, -X, 0.0, Z,      //  4,  9,  0
	        0.0, Z, X, 0.0, Z, -X, -Z, X, 0.0,      //  4,  5,  9
	        Z, X, 0.0, 0.0, Z, -X, 0.0, Z, X,       //  8,  5,  4
	        X, 0.0, Z, Z, X, 0.0, 0.0, Z, X,        //  1,  8,  4
	        X, 0.0, Z, Z, -X, 0.0, Z, X, 0.0,       //  1, 10,  8
	        Z, -X, 0.0, X, 0.0, -Z, Z, X, 0.0,      // 10,  3,  8
	        Z, X, 0.0, X, 0.0, -Z, 0.0, Z, -X,      //  8,  3,  5
	        X, 0.0, -Z, -X, 0.0, -Z, 0.0, Z, -X,    //  3,  2,  5
	        X, 0.0, -Z, 0.0, -Z, -X, -X, 0.0, -Z,   //  3,  7,  2
	        X, 0.0, -Z, Z, -X, 0.0, 0.0, -Z, -X,    //  3, 10,  7
	        Z, -X, 0.0, 0.0, -Z, X, 0.0, -Z, -X,    // 10,  6,  7
	        0.0, -Z, X, -Z, -X, 0.0, 0.0, -Z, -X,   //  6, 11,  7
	        0.0, -Z, X, -X, 0.0, Z, -Z, -X, 0.0,    //  6,  0, 11
	        0.0, -Z, X, X, 0.0, Z, -X, 0.0, Z,      //  6,  1,  0
	        Z, -X, 0.0, X, 0.0, Z, 0.0, -Z, X,      // 10,  1,  6
	        -Z, -X, 0.0, -X, 0.0, Z, -Z, X, 0.0,    // 11,  0,  9
	        -X, 0.0, -Z, -Z, -X, 0.0, -Z, X, 0.0,   //  2, 11,  9
	        0.0, Z, -X, -X, 0.0, -Z, -Z, X, 0.0,    //  5,  2,  9
	        -Z, -X, 0.0, -X, 0.0, -Z, 0.0, -Z, -X]; // 11,  2,  7

		setViewport(0, 0, width, height);

		setClearColor(255, 0, 0, 255);
		setClearDepth(1.0);
		clear();

		var ratio = height / width;
		cameraMatrix = Matrix.initFromPerspective(-6.0, 6.0, -6.0 * ratio, 6.0 * ratio, 20.0, 100.0);
		cameraMatrix = Matrix.initFromTranslation(0.0, 0.0, -30.0) * cameraMatrix;

		var buffer = new Float32Array(icosaedronVertex);
		setObjectGeometry(buffer);

		objectMatrix = Matrix.initFromYRotation(angle);
		setObjectMaterial(0.5, 0.5, 0.5, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(3.0, 0.0, 3.0) * objectMatrix;
		setObjectMaterial(1.0, 1.0, 0.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(3.0, 0.0, -3.0) * objectMatrix;
		setObjectMaterial(1.0, 0.0, 1.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(-3.0, 0.0, 3.0) * objectMatrix;
		setObjectMaterial(0.0, 1.0, 1.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(-3.0, 0.0, -3.0) * objectMatrix;
		setObjectMaterial(1.0, 1.0, 1.0, 1.0);
		renderObject();

		flush();
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function setViewport(x:Int, y:Int, w:Int, h:Int)
	{
		gl.viewport(x, y, w, h);
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function setClearColor(r:Int, g:Int, b:Int, a:Int)
	{
		gl.clearColor(r, g, b, a);
	}

	public function setClearDepth(d:Float)
	{
		#if desktop
		gl.clearDepth(d);
		#else
		gl.clearDepthf(d);
		#end
	}

	public function clear()
	{
		gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function flush()
	{
		gl.flush();
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function setObjectGeometry(vertex:Float32Array)
	{
		objectBuffer = vertex;

		gl.bindBuffer(gl.ARRAY_BUFFER, glVertexBuffer);
		#if desktop
		gl.bufferData(gl.ARRAY_BUFFER, objectBuffer, gl.STATIC_DRAW);
		#else
		gl.bufferData(gl.ARRAY_BUFFER, objectBuffer.length, DataPointer.fromArrayBufferView(objectBuffer), gl.STATIC_DRAW);
		#end
		gl.bindBuffer(gl.ARRAY_BUFFER, null);
	}

	public function setObjectMaterial(r:Float, g:Float, b:Float, a:Float)
	{
		objectMaterial = new Float32Array([r, g, b, a]);
	}

	public function renderObject()
	{
		#if desktop
		gl.uniformMatrix4fv(glCameraMatrixUniform, false, cameraMatrix);
		gl.uniformMatrix4fv(glObjectMatrixUniform, false, objectMatrix);
		gl.uniform4fv(glObjectMaterialUniform, objectMaterial);
		#else
		gl.uniformMatrix4fv(glCameraMatrixUniform, 16 * Float32Array.BYTES_PER_ELEMENT, false, DataPointer.fromArrayBufferView(cameraMatrix));
		gl.uniformMatrix4fv(glObjectMatrixUniform, 16 * Float32Array.BYTES_PER_ELEMENT, false, DataPointer.fromArrayBufferView(objectMatrix));
		gl.uniform4fv(glObjectMaterialUniform, 4 * Float32Array.BYTES_PER_ELEMENT, DataPointer.fromArrayBufferView(objectMaterial));
		#end

		gl.bindBuffer(gl.ARRAY_BUFFER, glVertexBuffer);
		gl.vertexAttribPointer(glVertexAttribute, 3, gl.FLOAT, false, 3 * Float32Array.BYTES_PER_ELEMENT, 0);

		gl.enableVertexAttribArray(glVertexAttribute);
		gl.drawArrays(gl.TRIANGLES, 0, Math.floor(objectBuffer.length / 3));
		gl.disableVertexAttribArray(glVertexAttribute);
	}
}

This class has some helper methods at the bottom, along with mainContextInit(), mostly borrowed from a lime sample, and also mainContextRender(), which does all the rendering work. Additionally, there are the usual overrides from the lime Application class.

Please, forgive me for posting the entire classes, instead of just one function or excerpt, but like this you can copy and paste and test the project in an easier way. I have no idea what I’m doing wrong, though. Can you help? Thanks.

Does it work if you use WebGLContext on Android instead? Do you get errors? Does it work if you use GLES2Context on desktop? (The API should be compatible with OpenGL 4.5 or so)

No, no contexts work in Android. No, just a red display. No. The static GL doesn’t work either.

Does the Lime SimpleImage sample work for you?

Yes, it works fine.Could it be because I’m targeting Android 15 and not 19?

Possibly, although we have API 19 as our target SDK, our minimum SDK version supported is more like 11

Actually, I just tried Android 19 and I also cannot get it to work. Is it just my setup or does this happen to someone else too? Possibly, I’m just forgetting some simple detail or something.

Compare with the sample demos, to see if maybe you can add your code over the top, or find what’s different. It may be possible, though, that some little things have an impact. For example, not rendering at all (if(!preloader.complete) return;) might upset some windowing systems, you may need to gl.viewport or gl.clear at the very least

Adding <window depth-buffer="true" /> might also help

Well, I’ve managed to get it working with the statics GL class. Here is the latest listing.

package;

import lime.Assets;

import lime.app.Application;

import lime.graphics.Image;
import lime.graphics.Renderer;
import lime.graphics.opengl.*;

import lime.system.System;

import lime.ui.KeyCode;
import lime.ui.KeyModifier;
import lime.ui.Window;

import lime.utils.DataPointer;
import lime.utils.Float32Array;
import lime.utils.GLUtils;

class Main extends Application
{
	private var glProgram:GLProgram;

	private var glVertexAttribute:Int;
	private var glTexCoordAttribute:Int;

	private var glCameraMatrixUniform:GLUniformLocation;
	private var glObjectMatrixUniform:GLUniformLocation;
	private var glTextureUniform:GLUniformLocation;
	private var glObjectMaterialUniform:GLUniformLocation;

	private var glVertexBuffer:GLBuffer;
	private var glTexCoordBuffer:GLBuffer;

	private var glTexture:GLTexture;

	private var cameraMatrix:Matrix;
	private var objectMatrix:Matrix;

	private var vertexBuffer:Float32Array;
	private var texCoordBuffer:Float32Array;
	private var materialBuffer:Float32Array;

	private var image:Image;

	private var mainContextInited:Bool;

	private var width:Int;
	private var height:Int;

	private var angle:Float;

	private var icoVertexes:Float32Array;
	private var icoTexCoords:Float32Array;

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function new()
	{
		super();

		mainContextInited = false;

		angle = 0.0;
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public override function update(delta:Int):Void
	{
		super.update(delta);

		angle += delta / 1000.0;
		if(angle >= 360.0)
			angle %= 360.0;
	}

	public override function render(renderer:Renderer)
	{
		super.render(renderer);

		switch(renderer.context)
		{
			case OPENGL(opengl):
				if(!preloader.complete)
				{
					GL.clearColor(0.0, 0.0, 0.0, 1.0);
					GL.clearDepthf(1.0);
					GL.clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT);

					return;
				}

				if(!mainContextInited)
				{
					mainContextInit();

					mainContextInited = true;
				}

				GL.useProgram(glProgram);

				GL.enableVertexAttribArray(glVertexAttribute);
				GL.enableVertexAttribArray(glTexCoordAttribute);

				#if desktop
				GL.enable(GL.TEXTURE_2D);
				#end

				mainContextRender();

				GL.bindBuffer(GL.ARRAY_BUFFER, null);

				GL.bindTexture(GL.TEXTURE_2D, null);

				#if desktop
				GL.disable(GL.TEXTURE_2D);
				#end

				GL.disableVertexAttribArray(glVertexAttribute);
				GL.disableVertexAttribArray(glTexCoordAttribute);

				GL.useProgram(null);

			default:
		}
	}

	public override function onKeyDown(window:Window, keyCode:KeyCode, modifier:KeyModifier)
	{
		super.onKeyDown(window, keyCode, modifier);

		if(keyCode == APP_CONTROL_BACK || keyCode == ESCAPE)
		{
			System.exit(0);
		}
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function mainContextInit():Void
	{
		width = Application.current.config.windows[0].width;
		height = Application.current.config.windows[0].height;

		var vertSource =
			"attribute vec4 aVertex;
			attribute vec2 aTexCoord;

			uniform mat4 uCameraMatrix;
			uniform mat4 uObjectMatrix;

			uniform vec4 uObjectMaterial;

			varying vec2 vTexCoord;
			varying vec4 vObjectMaterial;

			void main(void)
			{
				vTexCoord = aTexCoord;
				vObjectMaterial = uObjectMaterial;

				gl_Position = uCameraMatrix * (uObjectMatrix * aVertex);
			}";

		var fragSource =
			#if mobile
			"precision mediump float;" +
			#end
			"varying vec2 vTexCoord;
			varying vec4 vObjectMaterial;

			uniform sampler2D uTexture;

			void main(void)
			{
				gl_FragColor = vObjectMaterial * texture2D(uTexture, vTexCoord);
			}";

		glProgram = GLUtils.createProgram(vertSource, fragSource);

		glVertexAttribute = GL.getAttribLocation(glProgram, "aVertex");
		glTexCoordAttribute = GL.getAttribLocation(glProgram, "aTexCoord");

		glCameraMatrixUniform = GL.getUniformLocation(glProgram, "uCameraMatrix");
		glObjectMatrixUniform = GL.getUniformLocation(glProgram, "uObjectMatrix");

		glObjectMaterialUniform = GL.getUniformLocation(glProgram, "uObjectMaterial");

		glTextureUniform = GL.getUniformLocation(glProgram, "uTexture");

		glVertexBuffer = GL.createBuffer();
		glTexCoordBuffer = GL.createBuffer();

		glTexture = GL.createTexture();

		GL.frontFace(GL.CCW);

		GL.cullFace(GL.BACK);
		GL.enable(GL.CULL_FACE);

		GL.depthFunc(GL.LESS);
		GL.enable(GL.DEPTH_TEST);

		GL.enable(GL.BLEND);
		GL.blendFunc(GL.ONE, GL.ONE_MINUS_SRC_ALPHA);

	    var X = 0.525731112119133606;
	    var Z = 0.850650808352039932;
	    var icosaedronVertex = [
	        X, 0.0, Z, 0.0, Z, X, -X, 0.0, Z,       //  1,  4,  0
	        0.0, Z, X, -Z, X, 0.0, -X, 0.0, Z,      //  4,  9,  0
	        0.0, Z, X, 0.0, Z, -X, -Z, X, 0.0,      //  4,  5,  9
	        Z, X, 0.0, 0.0, Z, -X, 0.0, Z, X,       //  8,  5,  4
	        X, 0.0, Z, Z, X, 0.0, 0.0, Z, X,        //  1,  8,  4
	        X, 0.0, Z, Z, -X, 0.0, Z, X, 0.0,       //  1, 10,  8
	        Z, -X, 0.0, X, 0.0, -Z, Z, X, 0.0,      // 10,  3,  8
	        Z, X, 0.0, X, 0.0, -Z, 0.0, Z, -X,      //  8,  3,  5
	        X, 0.0, -Z, -X, 0.0, -Z, 0.0, Z, -X,    //  3,  2,  5
	        X, 0.0, -Z, 0.0, -Z, -X, -X, 0.0, -Z,   //  3,  7,  2
	        X, 0.0, -Z, Z, -X, 0.0, 0.0, -Z, -X,    //  3, 10,  7
	        Z, -X, 0.0, 0.0, -Z, X, 0.0, -Z, -X,    // 10,  6,  7
	        0.0, -Z, X, -Z, -X, 0.0, 0.0, -Z, -X,   //  6, 11,  7
	        0.0, -Z, X, -X, 0.0, Z, -Z, -X, 0.0,    //  6,  0, 11
	        0.0, -Z, X, X, 0.0, Z, -X, 0.0, Z,      //  6,  1,  0
	        Z, -X, 0.0, X, 0.0, Z, 0.0, -Z, X,      // 10,  1,  6
	        -Z, -X, 0.0, -X, 0.0, Z, -Z, X, 0.0,    // 11,  0,  9
	        -X, 0.0, -Z, -Z, -X, 0.0, -Z, X, 0.0,   //  2, 11,  9
	        0.0, Z, -X, -X, 0.0, -Z, -Z, X, 0.0,    //  5,  2,  9
	        -Z, -X, 0.0, -X, 0.0, -Z, 0.0, -Z, -X]; // 11,  2,  7

		var icasaedronTexCoord = [
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0];

		icoVertexes = new Float32Array(icosaedronVertex);
		icoTexCoords = new Float32Array(icasaedronTexCoord);

		image = Assets.getImage("assets/lime.png");
	}

	public function mainContextRender():Void
	{
		setViewport(0, 0, width, height);

		setClearColor(1.0, 0.0, 0.0, 1.0);
		setClearDepth(1.0);
		clear();

		var ratio = height / width;
		cameraMatrix = Matrix.initFromPerspective(-6.0, 6.0, -6.0 * ratio, 6.0 * ratio, 20.0, 100.0);
		cameraMatrix = Matrix.initFromTranslation(0.0, 0.0, -30.0) * cameraMatrix;
		cameraMatrix = Matrix.initFromXRotation(0.15) * cameraMatrix;

		setObjectGeometry(icoVertexes);
		setObjectTexture(image, icoTexCoords);

		objectMatrix = Matrix.initFromYRotation(angle);
		setObjectMaterial(0.0, 0.0, 1.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(3.0, 0.0, 3.0) * objectMatrix;
		setObjectMaterial(1.0, 1.0, 0.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(3.0, 0.0, -3.0) * objectMatrix;
		setObjectMaterial(1.0, 0.0, 1.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(-3.0, 0.0, 3.0) * objectMatrix;
		setObjectMaterial(0.0, 1.0, 1.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(-3.0, 0.0, -3.0) * objectMatrix;
		setObjectMaterial(0.0, 1.0, 0.0, 1.0);
		renderObject();

		flush();
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function setViewport(x:Int, y:Int, w:Int, h:Int)
	{
		GL.viewport(x, y, w, h);
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function setClearColor(r:Float, g:Float, b:Float, a:Float)
	{
		GL.clearColor(Math.floor(r * 255.0), Math.floor(g * 255.0), Math.floor(b * 255.0), Math.floor(a * 255.0));
	}

	public function setClearDepth(d:Float)
	{
		GL.clearDepthf(d);
	}

	public function clear()
	{
		GL.clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT);
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function flush()
	{
		GL.flush();
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function setObjectGeometry(vertex:Float32Array)
	{
		vertexBuffer = vertex;

		GL.bindBuffer(GL.ARRAY_BUFFER, glVertexBuffer);
		GL.bufferData(GL.ARRAY_BUFFER, vertexBuffer.length * Float32Array.BYTES_PER_ELEMENT, DataPointer.fromArrayBufferView(vertexBuffer), GL.STATIC_DRAW);
		GL.bindBuffer(GL.ARRAY_BUFFER, null);
	}

	public function setObjectTexture(image:Image, texCoord:Float32Array)
	{
		GL.bindTexture(GL.TEXTURE_2D, glTexture);
		GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MIN_FILTER, GL.LINEAR);
		GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_MAG_FILTER, GL.LINEAR);
		GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_S, GL.CLAMP_TO_EDGE);
		GL.texParameteri(GL.TEXTURE_2D, GL.TEXTURE_WRAP_T, GL.CLAMP_TO_EDGE);
		GL.texImage2D(GL.TEXTURE_2D, 0, GL.RGBA, image.width, image.height, 0, GL.RGBA, GL.UNSIGNED_BYTE, DataPointer.fromArrayBufferView(image.data));
		GL.bindTexture(GL.TEXTURE_2D, null);

		texCoordBuffer = texCoord;

		GL.bindBuffer(GL.ARRAY_BUFFER, glTexCoordBuffer);
		GL.bufferData(GL.ARRAY_BUFFER, texCoordBuffer.length * Float32Array.BYTES_PER_ELEMENT, DataPointer.fromArrayBufferView(texCoordBuffer), GL.STATIC_DRAW);
		GL.bindBuffer(GL.ARRAY_BUFFER, null);
	}

	public function setObjectMaterial(r:Float, g:Float, b:Float, a:Float)
	{
		materialBuffer = new Float32Array([r, g, b, a]);
	}

	public function renderObject()
	{
		GL.activeTexture(GL.TEXTURE0);
		GL.bindTexture(GL.TEXTURE_2D, glTexture);

		GL.bindBuffer(GL.ARRAY_BUFFER, glVertexBuffer);
		GL.vertexAttribPointer(glVertexAttribute, 3, GL.FLOAT, false, 0, 0);

		GL.bindBuffer(GL.ARRAY_BUFFER, glTexCoordBuffer);
		GL.vertexAttribPointer(glTexCoordAttribute, 2, GL.FLOAT, false, 0, 0);

		GL.uniformMatrix4fv(glCameraMatrixUniform, 1, false, DataPointer.fromArrayBufferView(cameraMatrix));
		GL.uniformMatrix4fv(glObjectMatrixUniform, 1, false, DataPointer.fromArrayBufferView(objectMatrix));
		GL.uniform4fv(glObjectMaterialUniform, 1, DataPointer.fromArrayBufferView(materialBuffer));

		GL.uniform1i(glTextureUniform, 0);

		GL.drawArrays(GL.TRIANGLES, 0, Math.round(vertexBuffer.length / 3));
	}
}

I’ve added textures, so you’ll need ‘lime.png’ in your assets folder. Still no luck with Android, though. But, if I ever get it working, at least it will be the same code for all platforms, instead of WebGL for desktop and GL ES 2 for mobile.

For what it is worth, Lime uses WebGL on HTML5, OpenGL on the desktop and OpenGL ES 2+ on mobile targets. We had WebGL as the only GL API (being cross-platform) in previous releases, but some time ago added the WebGLContext, WebGL2Context, GLES2Context and GLES3Context types as APIs over the static GL or the ordinary GLRenderContext type. This gave us the ability to begin supporting true GLES APIs, without breaking support for WebGL.

You should be able to use WebGL APIs on all platforms (with the exception of HTML5 specifics such as textImage2D using a canvas), or the GLES2Context should make the API a bit more like GLES, and give you access to things such as explicit size values on upload (rather than having to make a new typed array for each size)

I have a similar problem with BabylonHx (which I’m updating and trying to make working with latest Lime).

Right now only Web build works and only if I create WebGLContext myself (like here https://github.com/vujadin/BabylonHx/blob/master/com/babylonhx/Engine.hx#L404).

If I use glcontext provided by Lime, only gl.clearColor() result is visible, no geometry/textures, no nothing…

I’m not sure if I did a pull, but here’s what I did when I tested it before:

I’ve just checked your changes… but in the meantime BabylonJS people have done a lot of stuff (they support webgl2 now) and now I’m trying to catch up with their progress.
The biggest problem for me is that WebGLInspector doesn’t work with Lime JS builds anymore (Lime official samples too) - problem is probably in webgl context handling in Lime and without this tool it its impossible to debug project of this size.

I believe we try to support WebGLInspector here:

I haven’t used WebGLInspector before, though. Do you have a link to it? The Lime 4 approach to GL (in general) would be to use a GL instance (like in JS) but to use the WebGLRenderContext to make it behave as WebGL1 on all targets.

Otherwise, if you used WebGL2RenderContext, that would work on compatible browsers, but wouldn’t all work on native. We could work on adding native support where possible for the same API

I’ve modified Cuco’s example to use WebGL2Context and cpp build works (windows target) but web does not (only red screen):

package;

import lime.Assets;

import lime.app.Application;

import lime.graphics.Image;
import lime.graphics.Renderer;
import lime.graphics.opengl.*;

import lime.system.System;

import lime.ui.KeyCode;
import lime.ui.KeyModifier;
import lime.ui.Window;

import lime.utils.DataPointer;
import lime.utils.Float32Array;
import lime.utils.GLUtils;

class Main extends Application
{
	private var glProgram:GLProgram;

	private var glVertexAttribute:Int;
	private var glTexCoordAttribute:Int;

	private var glCameraMatrixUniform:GLUniformLocation;
	private var glObjectMatrixUniform:GLUniformLocation;
	private var glTextureUniform:GLUniformLocation;
	private var glObjectMaterialUniform:GLUniformLocation;

	private var glVertexBuffer:GLBuffer;
	private var glTexCoordBuffer:GLBuffer;

	private var glTexture:GLTexture;

	private var cameraMatrix:Matrix;
	private var objectMatrix:Matrix;

	private var vertexBuffer:Float32Array;
	private var texCoordBuffer:Float32Array;
	private var materialBuffer:Float32Array;

	private var image:Image;

	private var mainContextInited:Bool;

	private var width:Int;
	private var height:Int;

	private var angle:Float;

	private var icoVertexes:Float32Array;
	private var icoTexCoords:Float32Array;
	
	var gl:WebGL2Context;

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function new()
	{
		super();

		mainContextInited = false;

		angle = 0.0;
	}
	
	override public function onWindowCreate(window:Window) {
		switch (window.renderer.context) {
			case OPENGL (gl):
				this.gl = gl;
				
			default:
				//
		}
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public override function update(delta:Int):Void
	{
		super.update(delta);

		angle += delta / 1000.0;
		if(angle >= 360.0)
			angle %= 360.0;
	}

	public override function render(renderer:Renderer)
	{
				
		if(!preloader.complete)
		{
			gl.clearColor(0.0, 0.0, 0.0, 1.0);
			gl.clearDepth(1.0);
			gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

			return;
		}

		if(!mainContextInited)
		{
			mainContextInit();

			mainContextInited = true;
		}

		gl.useProgram(glProgram);

		gl.enableVertexAttribArray(glVertexAttribute);
		gl.enableVertexAttribArray(glTexCoordAttribute);

		/*#if desktop
		gl.enable(gl.TEXTURE_2D);
		#end*/

		mainContextRender();

		gl.bindBuffer(gl.ARRAY_BUFFER, null);

		gl.bindTexture(gl.TEXTURE_2D, null);

		/*#if desktop
		gl.disable(gl.TEXTURE_2D);
		#end*/

		gl.disableVertexAttribArray(glVertexAttribute);
		gl.disableVertexAttribArray(glTexCoordAttribute);

		gl.useProgram(null);

	}

	public override function onKeyDown(window:Window, keyCode:KeyCode, modifier:KeyModifier)
	{
		super.onKeyDown(window, keyCode, modifier);

		if(keyCode == APP_CONTROL_BACK || keyCode == ESCAPE)
		{
			System.exit(0);
		}
	}
	
	override public function onWindowResize(window:Window, width:Int, height:Int) {
		this.width = width;
		this.height = height;
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function mainContextInit():Void
	{
		width = Application.current.config.windows[0].width;
		height = Application.current.config.windows[0].height;

		var vertSource =
			#if (mobile || js)
			"precision mediump float;" +
			#end
			"attribute vec4 aVertex;
			attribute vec2 aTexCoord;

			uniform mat4 uCameraMatrix;
			uniform mat4 uObjectMatrix;

			uniform vec4 uObjectMaterial;

			varying vec2 vTexCoord;
			varying vec4 vObjectMaterial;

			void main(void)
			{
				vTexCoord = aTexCoord;
				vObjectMaterial = uObjectMaterial;

				gl_Position = uCameraMatrix * (uObjectMatrix * aVertex);
			}";

		var fragSource =
			#if (mobile || js)
			"precision mediump float;" +
			#end
			"varying vec2 vTexCoord;
			varying vec4 vObjectMaterial;

			uniform sampler2D uTexture;

			void main(void)
			{
				gl_FragColor = vObjectMaterial * texture2D(uTexture, vTexCoord);
			}";

		glProgram = GLUtils.createProgram(vertSource, fragSource);

		glVertexAttribute = gl.getAttribLocation(glProgram, "aVertex");
		glTexCoordAttribute = gl.getAttribLocation(glProgram, "aTexCoord");

		glCameraMatrixUniform = gl.getUniformLocation(glProgram, "uCameraMatrix");
		glObjectMatrixUniform = gl.getUniformLocation(glProgram, "uObjectMatrix");

		glObjectMaterialUniform = gl.getUniformLocation(glProgram, "uObjectMaterial");

		glTextureUniform = gl.getUniformLocation(glProgram, "uTexture");

		glVertexBuffer = gl.createBuffer();
		glTexCoordBuffer = gl.createBuffer();

		glTexture = gl.createTexture();

		gl.frontFace(gl.CCW);

		gl.cullFace(gl.BACK);
		gl.enable(gl.CULL_FACE);

		gl.depthFunc(gl.LESS);
		gl.enable(gl.DEPTH_TEST);

		gl.enable(gl.BLEND);
		gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);

	    var X = 0.525731112119133606;
	    var Z = 0.850650808352039932;
	    var icosaedronVertex = [
	        X, 0.0, Z, 0.0, Z, X, -X, 0.0, Z,       //  1,  4,  0
	        0.0, Z, X, -Z, X, 0.0, -X, 0.0, Z,      //  4,  9,  0
	        0.0, Z, X, 0.0, Z, -X, -Z, X, 0.0,      //  4,  5,  9
	        Z, X, 0.0, 0.0, Z, -X, 0.0, Z, X,       //  8,  5,  4
	        X, 0.0, Z, Z, X, 0.0, 0.0, Z, X,        //  1,  8,  4
	        X, 0.0, Z, Z, -X, 0.0, Z, X, 0.0,       //  1, 10,  8
	        Z, -X, 0.0, X, 0.0, -Z, Z, X, 0.0,      // 10,  3,  8
	        Z, X, 0.0, X, 0.0, -Z, 0.0, Z, -X,      //  8,  3,  5
	        X, 0.0, -Z, -X, 0.0, -Z, 0.0, Z, -X,    //  3,  2,  5
	        X, 0.0, -Z, 0.0, -Z, -X, -X, 0.0, -Z,   //  3,  7,  2
	        X, 0.0, -Z, Z, -X, 0.0, 0.0, -Z, -X,    //  3, 10,  7
	        Z, -X, 0.0, 0.0, -Z, X, 0.0, -Z, -X,    // 10,  6,  7
	        0.0, -Z, X, -Z, -X, 0.0, 0.0, -Z, -X,   //  6, 11,  7
	        0.0, -Z, X, -X, 0.0, Z, -Z, -X, 0.0,    //  6,  0, 11
	        0.0, -Z, X, X, 0.0, Z, -X, 0.0, Z,      //  6,  1,  0
	        Z, -X, 0.0, X, 0.0, Z, 0.0, -Z, X,      // 10,  1,  6
	        -Z, -X, 0.0, -X, 0.0, Z, -Z, X, 0.0,    // 11,  0,  9
	        -X, 0.0, -Z, -Z, -X, 0.0, -Z, X, 0.0,   //  2, 11,  9
	        0.0, Z, -X, -X, 0.0, -Z, -Z, X, 0.0,    //  5,  2,  9
	        -Z, -X, 0.0, -X, 0.0, -Z, 0.0, -Z, -X]; // 11,  2,  7

		var icasaedronTexCoord = [
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0];

		icoVertexes = new Float32Array(icosaedronVertex);
		icoTexCoords = new Float32Array(icasaedronTexCoord);

		image = Assets.getImage("assets/lime.png");
	}

	public function mainContextRender():Void
	{
		setViewport(0, 0, width, height);

		setClearColor(1.0, 0.0, 0.0, 1.0);
		setClearDepth(1.0);
		clear();

		var ratio = height / width;
		cameraMatrix = Matrix.initFromPerspective(-6.0, 6.0, -6.0 * ratio, 6.0 * ratio, 20.0, 100.0);
		cameraMatrix = Matrix.initFromTranslation(0.0, 0.0, -30.0) * cameraMatrix;
		cameraMatrix = Matrix.initFromXRotation(0.15) * cameraMatrix;

		setObjectGeometry(icoVertexes);
		setObjectTexture(image, icoTexCoords);

		objectMatrix = Matrix.initFromYRotation(angle);
		setObjectMaterial(0.0, 0.0, 1.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(3.0, 0.0, 3.0) * objectMatrix;
		setObjectMaterial(1.0, 1.0, 0.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(3.0, 0.0, -3.0) * objectMatrix;
		setObjectMaterial(1.0, 0.0, 1.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(-3.0, 0.0, 3.0) * objectMatrix;
		setObjectMaterial(0.0, 1.0, 1.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(-3.0, 0.0, -3.0) * objectMatrix;
		setObjectMaterial(0.0, 1.0, 0.0, 1.0);
		renderObject();

		flush();
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function setViewport(x:Int, y:Int, w:Int, h:Int)
	{
		gl.viewport(x, y, w, h);
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function setClearColor(r:Float, g:Float, b:Float, a:Float)
	{
		gl.clearColor(Math.floor(r * 255.0), Math.floor(g * 255.0), Math.floor(b * 255.0), Math.floor(a * 255.0));
	}

	public function setClearDepth(d:Float)
	{
		gl.clearDepth(d);
	}

	public function clear()
	{
		gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function flush()
	{
		gl.flush();
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function setObjectGeometry(vertex:Float32Array)
	{
		vertexBuffer = vertex;

		gl.bindBuffer(gl.ARRAY_BUFFER, glVertexBuffer);
		gl.bufferData(gl.ARRAY_BUFFER, vertexBuffer, gl.STATIC_DRAW);
		gl.bindBuffer(gl.ARRAY_BUFFER, null);
	}

	public function setObjectTexture(image:Image, texCoord:Float32Array)
	{
		gl.bindTexture(gl.TEXTURE_2D, glTexture);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
		gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, image.width, image.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, image.data);
		gl.bindTexture(gl.TEXTURE_2D, null);

		texCoordBuffer = texCoord;

		gl.bindBuffer(gl.ARRAY_BUFFER, glTexCoordBuffer);
		gl.bufferData(gl.ARRAY_BUFFER, texCoordBuffer, gl.STATIC_DRAW);
		gl.bindBuffer(gl.ARRAY_BUFFER, null);
	}

	public function setObjectMaterial(r:Float, g:Float, b:Float, a:Float)
	{
		materialBuffer = new Float32Array([r, g, b, a]);
	}

	public function renderObject()
	{
		gl.activeTexture(gl.TEXTURE0);
		gl.bindTexture(gl.TEXTURE_2D, glTexture);

		gl.bindBuffer(gl.ARRAY_BUFFER, glVertexBuffer);
		gl.vertexAttribPointer(glVertexAttribute, 3, gl.FLOAT, false, 0, 0);

		gl.bindBuffer(gl.ARRAY_BUFFER, glTexCoordBuffer);
		gl.vertexAttribPointer(glTexCoordAttribute, 2, gl.FLOAT, false, 0, 0);

		gl.uniformMatrix4fv(glCameraMatrixUniform, false, cameraMatrix);
		gl.uniformMatrix4fv(glObjectMatrixUniform, false, objectMatrix);
		gl.uniform4fv(glObjectMaterialUniform, materialBuffer);

		gl.uniform1i(glTextureUniform, 0);

		gl.drawArrays(gl.TRIANGLES, 0, Math.round(vertexBuffer.length / 3));
	}
}

Strange thing is that if I manually create WebGL2 render context BabylonHx works fine, but if I use WebGL2 context provided by Lime it won’t work.

Here’s webglinspector http://benvanik.github.io/WebGL-Inspector/
You can also install it in chrome as extension from google webstore

I fixed it by adding setViewport(0, 0, width, height); at line 94. You need to set the viewport on the first render, or some WebGL implementations will not show anything later :confused:

I couldn’t get it working, not even after adding the viewport command. It’s probably my setup, I think. I’m running Windows 10 and my browser is Google Chrome. I also tried it on Microsoft Edge, also without succes. A strange thing happened: when I typed ‘lime test html5’, the window contents went all red, but when I did ‘lime build html5’ and then double-clicked the generated ‘index.html’, the window contents remained blank.

As for Android, I’m calling in the big guns: I’ve ordered a book! It should arrive next week, or so. Perhaps it’s the order of the OpenGL commands that matter. I’ve checked the parameters and they seem to be ok, so it must be that or something else. I’d like the following code to work with all OpenGL targets, except possibly html5:

package;

import lime.Assets;

import lime.app.Application;

import lime.graphics.Image;
import lime.graphics.Renderer;
import lime.graphics.GLRenderContext;
import lime.graphics.opengl.*;

import lime.system.System;

import lime.ui.KeyCode;
import lime.ui.KeyModifier;
import lime.ui.Window;

import lime.utils.DataPointer;
import lime.utils.Float32Array;
import lime.utils.GLUtils;

class Main extends Application
{
	private var gl:GLRenderContext;

	private var glProgram:GLProgram;

	private var glVertexAttribute:Int;
	private var glTexCoordAttribute:Int;

	private var glCameraMatrixUniform:GLUniformLocation;
	private var glObjectMatrixUniform:GLUniformLocation;
	private var glTextureUniform:GLUniformLocation;
	private var glObjectMaterialUniform:GLUniformLocation;

	private var glVertexBuffer:GLBuffer;
	private var glTexCoordBuffer:GLBuffer;

	private var glTexture:GLTexture;

	private var cameraMatrix:Matrix;
	private var objectMatrix:Matrix;

	private var vertexBuffer:Float32Array;
	private var texCoordBuffer:Float32Array;
	private var materialBuffer:Float32Array;

	private var image:Image;

	private var mainContextNotInited:Bool;

	private var width:Int;
	private var height:Int;

	private var angle:Float;

	private var icoVertexes:Float32Array;
	private var icoTexCoords:Float32Array;

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function new()
	{
		super();

		mainContextNotInited = true;

		angle = 0.0;
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public override function update(delta:Int):Void
	{
		// super.update(delta);

		angle += delta / 1000.0;
		if(angle >= 360.0)
			angle %= 360.0;
	}

	public override function render(renderer:Renderer)
	{
		// super.render(renderer);

		switch(renderer.context)
		{
			case OPENGL(opengl):
				gl = opengl;

				if(!preloader.complete)
				{
					gl.viewport(0, 0, Application.current.config.windows[0].width, Application.current.config.windows[0].height);
					gl.clearColor(0.0, 0.0, 0.0, 1.0);
					gl.clearDepthf(1.0);
					gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

					return;
				}

				if(mainContextNotInited)
				{
					mainContextInit();

					mainContextNotInited = false;
				}

				gl.useProgram(glProgram);

				gl.enableVertexAttribArray(glVertexAttribute);
				gl.enableVertexAttribArray(glTexCoordAttribute);

				#if desktop
				gl.enable(gl.TEXTURE_2D);
				#end

				mainContextRender();

				gl.bindBuffer(gl.ARRAY_BUFFER, null);

				gl.bindTexture(gl.TEXTURE_2D, null);

				#if desktop
				gl.disable(gl.TEXTURE_2D);
				#end

				gl.disableVertexAttribArray(glVertexAttribute);
				gl.disableVertexAttribArray(glTexCoordAttribute);

				gl.useProgram(null);

			default:
		}
	}

	public override function onKeyDown(window:Window, keyCode:KeyCode, modifier:KeyModifier)
	{
		// super.onKeyDown(window, keyCode, modifier);

		if(keyCode == APP_CONTROL_BACK || keyCode == ESCAPE)
		{
			System.exit(0);
		}
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function mainContextInit():Void
	{
		width = Application.current.config.windows[0].width;
		height = Application.current.config.windows[0].height;

		var vertSource =
			#if (mobile || html5)
			"precision mediump float;" +
			#end
			"attribute vec4 aVertex;
			attribute vec2 aTexCoord;

			uniform mat4 uCameraMatrix;
			uniform mat4 uObjectMatrix;

			uniform vec4 uObjectMaterial;

			varying vec2 vTexCoord;
			varying vec4 vObjectMaterial;

			void main(void)
			{
				vTexCoord = aTexCoord;
				vObjectMaterial = uObjectMaterial;

				gl_Position = uCameraMatrix * (uObjectMatrix * aVertex);
			}";

		var fragSource =
			#if (mobile || html5)
			"precision mediump float;" +
			#end
			"varying vec2 vTexCoord;
			varying vec4 vObjectMaterial;

			uniform sampler2D uTexture;

			void main(void)
			{
				gl_FragColor = vObjectMaterial * texture2D(uTexture, vTexCoord);
			}";

		glProgram = GLUtils.createProgram(vertSource, fragSource);

		glVertexAttribute = gl.getAttribLocation(glProgram, "aVertex");
		glTexCoordAttribute = gl.getAttribLocation(glProgram, "aTexCoord");

		glCameraMatrixUniform = gl.getUniformLocation(glProgram, "uCameraMatrix");
		glObjectMatrixUniform = gl.getUniformLocation(glProgram, "uObjectMatrix");

		glObjectMaterialUniform = gl.getUniformLocation(glProgram, "uObjectMaterial");

		glTextureUniform = gl.getUniformLocation(glProgram, "uTexture");

		glVertexBuffer = gl.createBuffer();
		glTexCoordBuffer = gl.createBuffer();

		glTexture = gl.createTexture();

		gl.frontFace(gl.CCW);

		gl.cullFace(gl.BACK);
		gl.enable(gl.CULL_FACE);

		gl.depthFunc(gl.LESS);
		gl.enable(gl.DEPTH_TEST);

		gl.enable(gl.BLEND);
		gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);

	    var X = 0.525731112119133606;
	    var Z = 0.850650808352039932;
	    var icosaedronVertex = [
	        X, 0.0, Z, 0.0, Z, X, -X, 0.0, Z,       //  1,  4,  0
	        0.0, Z, X, -Z, X, 0.0, -X, 0.0, Z,      //  4,  9,  0
	        0.0, Z, X, 0.0, Z, -X, -Z, X, 0.0,      //  4,  5,  9
	        Z, X, 0.0, 0.0, Z, -X, 0.0, Z, X,       //  8,  5,  4
	        X, 0.0, Z, Z, X, 0.0, 0.0, Z, X,        //  1,  8,  4
	        X, 0.0, Z, Z, -X, 0.0, Z, X, 0.0,       //  1, 10,  8
	        Z, -X, 0.0, X, 0.0, -Z, Z, X, 0.0,      // 10,  3,  8
	        Z, X, 0.0, X, 0.0, -Z, 0.0, Z, -X,      //  8,  3,  5
	        X, 0.0, -Z, -X, 0.0, -Z, 0.0, Z, -X,    //  3,  2,  5
	        X, 0.0, -Z, 0.0, -Z, -X, -X, 0.0, -Z,   //  3,  7,  2
	        X, 0.0, -Z, Z, -X, 0.0, 0.0, -Z, -X,    //  3, 10,  7
	        Z, -X, 0.0, 0.0, -Z, X, 0.0, -Z, -X,    // 10,  6,  7
	        0.0, -Z, X, -Z, -X, 0.0, 0.0, -Z, -X,   //  6, 11,  7
	        0.0, -Z, X, -X, 0.0, Z, -Z, -X, 0.0,    //  6,  0, 11
	        0.0, -Z, X, X, 0.0, Z, -X, 0.0, Z,      //  6,  1,  0
	        Z, -X, 0.0, X, 0.0, Z, 0.0, -Z, X,      // 10,  1,  6
	        -Z, -X, 0.0, -X, 0.0, Z, -Z, X, 0.0,    // 11,  0,  9
	        -X, 0.0, -Z, -Z, -X, 0.0, -Z, X, 0.0,   //  2, 11,  9
	        0.0, Z, -X, -X, 0.0, -Z, -Z, X, 0.0,    //  5,  2,  9
	        -Z, -X, 0.0, -X, 0.0, -Z, 0.0, -Z, -X]; // 11,  2,  7

		var icasaedronTexCoord = [
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0];

		icoVertexes = new Float32Array(icosaedronVertex);
		icoTexCoords = new Float32Array(icasaedronTexCoord);

		image = Assets.getImage("assets/lime.png");
	}

	public function mainContextRender():Void
	{
		setViewport(0, 0, width, height);

		setClearColor(1.0, 0.0, 0.0, 1.0);
		setClearDepth(1.0);
		clear();

		var ratio = height / width;
		cameraMatrix = Matrix.initFromPerspective(-6.0, 6.0, -6.0 * ratio, 6.0 * ratio, 20.0, 100.0);
		cameraMatrix = Matrix.initFromTranslation(0.0, 0.0, -30.0) * cameraMatrix;
		cameraMatrix = Matrix.initFromXRotation(0.15) * cameraMatrix;

		setObjectVertex(icoVertexes);
		setObjectTexture(image, icoTexCoords);

		objectMatrix = Matrix.initFromYRotation(angle);
		setObjectMaterial(0.0, 0.0, 1.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(3.0, 0.0, 3.0) * objectMatrix;
		setObjectMaterial(1.0, 1.0, 0.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(3.0, 0.0, -3.0) * objectMatrix;
		setObjectMaterial(1.0, 0.0, 1.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(-3.0, 0.0, 3.0) * objectMatrix;
		setObjectMaterial(0.0, 1.0, 1.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(-3.0, 0.0, -3.0) * objectMatrix;
		setObjectMaterial(0.0, 1.0, 0.0, 1.0);
		renderObject();

		flush();
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function setViewport(x:Int, y:Int, w:Int, h:Int)
	{
		gl.viewport(x, y, w, h);
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function setClearColor(r:Float, g:Float, b:Float, a:Float)
	{
		gl.clearColor(Math.floor(r * 255.0), Math.floor(g * 255.0), Math.floor(b * 255.0), Math.floor(a * 255.0));
	}

	public function setClearDepth(d:Float)
	{
		gl.clearDepthf(d);
	}

	public function clear()
	{
		gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function flush()
	{
		gl.flush();
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function setObjectVertex(vertex:Float32Array)
	{
		vertexBuffer = vertex;

		gl.bindBuffer(gl.ARRAY_BUFFER, glVertexBuffer);
		gl.bufferData(gl.ARRAY_BUFFER, vertexBuffer.length * Float32Array.BYTES_PER_ELEMENT, DataPointer.fromArrayBufferView(vertexBuffer), gl.STATIC_DRAW);
		gl.bindBuffer(gl.ARRAY_BUFFER, null);
	}

	public function setObjectTexture(image:Image, texCoord:Float32Array)
	{
		gl.bindTexture(gl.TEXTURE_2D, glTexture);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
		gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, image.width, image.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, DataPointer.fromArrayBufferView(image.data));
		gl.bindTexture(gl.TEXTURE_2D, null);

		texCoordBuffer = texCoord;

		gl.bindBuffer(gl.ARRAY_BUFFER, glTexCoordBuffer);
		gl.bufferData(gl.ARRAY_BUFFER, texCoordBuffer.length * Float32Array.BYTES_PER_ELEMENT, DataPointer.fromArrayBufferView(texCoordBuffer), gl.STATIC_DRAW);
		gl.bindBuffer(gl.ARRAY_BUFFER, null);
	}

	public function setObjectMaterial(r:Float, g:Float, b:Float, a:Float)
	{
		materialBuffer = new Float32Array([r, g, b, a]);
	}

	public function renderObject()
	{
		gl.activeTexture(gl.TEXTURE0);
		gl.bindTexture(gl.TEXTURE_2D, glTexture);

		gl.bindBuffer(gl.ARRAY_BUFFER, glVertexBuffer);
		gl.vertexAttribPointer(glVertexAttribute, 3, gl.FLOAT, false, 0, 0);

		gl.bindBuffer(gl.ARRAY_BUFFER, glTexCoordBuffer);
		gl.vertexAttribPointer(glTexCoordAttribute, 2, gl.FLOAT, false, 0, 0);

		gl.uniformMatrix4fv(glCameraMatrixUniform, 1, false, DataPointer.fromArrayBufferView(cameraMatrix));
		gl.uniformMatrix4fv(glObjectMatrixUniform, 1, false, DataPointer.fromArrayBufferView(objectMatrix));
		gl.uniform4fv(glObjectMaterialUniform, 1, DataPointer.fromArrayBufferView(materialBuffer));

		gl.uniform1i(glTextureUniform, 0);

		gl.drawArrays(gl.TRIANGLES, 0, Math.round(vertexBuffer.length / 3));
	}
}

I mean, the default GLRenderContext should be correctly initialized for any platform, so I’m working with that in mind. I’m also trying to avoid #if directives where possible, but I think the original Main.hx I posted on this page is more close to what the finished code will be.

@Cuco the viewport command (inside the !preloader.complete) fixed the sample code @GameStudioHx posted for me, but I will try the other sample code, too

this works for me on both cpp (windows) and js targets on both win7 and win10:

package;

import lime.Assets;
import lime.graphics.opengl.GLBuffer;
import lime.graphics.opengl.GLProgram;
import lime.graphics.opengl.GLTexture;
import lime.graphics.opengl.GLUniformLocation;

import lime.app.Application;

import lime.graphics.Image;
import lime.graphics.Renderer;
import lime.graphics.opengl.WebGL2Context;

import lime.system.System;

import lime.ui.KeyCode;
import lime.ui.KeyModifier;
import lime.ui.Window;

import lime.utils.DataPointer;
import lime.utils.Float32Array;
import lime.utils.GLUtils;

class Main extends Application
{
	private var gl:WebGL2Context;

	private var glProgram:GLProgram;

	private var glVertexAttribute:Int;
	private var glTexCoordAttribute:Int;

	private var glCameraMatrixUniform:GLUniformLocation;
	private var glObjectMatrixUniform:GLUniformLocation;
	private var glTextureUniform:GLUniformLocation;
	private var glObjectMaterialUniform:GLUniformLocation;

	private var glVertexBuffer:GLBuffer;
	private var glTexCoordBuffer:GLBuffer;

	private var glTexture:GLTexture;

	private var cameraMatrix:Matrix;
	private var objectMatrix:Matrix;

	private var vertexBuffer:Float32Array;
	private var texCoordBuffer:Float32Array;
	private var materialBuffer:Float32Array;

	private var image:Image;

	private var mainContextNotInited:Bool;

	private var width:Int;
	private var height:Int;

	private var angle:Float;

	private var icoVertexes:Float32Array;
	private var icoTexCoords:Float32Array;
	
	var isReady = false;
	
	
	public function new()
	{
		super();

		mainContextNotInited = true;

		angle = 0.0;
	}
	
	override public function onWindowCreate(window:Window):Void {
		switch (window.renderer.context) {
			case OPENGL (gl):
				this.gl = gl;						
				
			default:
				//
		}
	}

	public override function update(delta:Int):Void
	{
		// super.update(delta);

		angle += delta / 1000.0;
		if(angle >= 360.0)
			angle %= 360.0;
	}

	public override function render(renderer:Renderer)
	{
		// super.render(renderer);

		if(!preloader.complete) {
			return;
		}

		gl.useProgram(glProgram);

		gl.enableVertexAttribArray(glVertexAttribute);
		gl.enableVertexAttribArray(glTexCoordAttribute);

		#if desktop
		gl.enable(gl.TEXTURE_2D);
		#end

		mainContextRender();

		gl.bindBuffer(gl.ARRAY_BUFFER, null);

		gl.bindTexture(gl.TEXTURE_2D, null);

		#if desktop
		gl.disable(gl.TEXTURE_2D);
		#end

		gl.disableVertexAttribArray(glVertexAttribute);
		gl.disableVertexAttribArray(glTexCoordAttribute);

		gl.useProgram(null);

	}

	public override function onKeyDown(window:Window, keyCode:KeyCode, modifier:KeyModifier)
	{
		// super.onKeyDown(window, keyCode, modifier);

		if(keyCode == APP_CONTROL_BACK || keyCode == ESCAPE)
		{
			System.exit(0);
		}
	}

	override public function onWindowResize(window:Window, width:Int, height:Int) {
		this.width = width;
		this.height = height;
	}
	
	override public function onPreloadComplete() {
		width = window.width;
		height = window.height;

		var vertSource =
			#if (mobile || html5)
			"precision mediump float;" +
			#end
			"attribute vec4 aVertex;
			attribute vec2 aTexCoord;

			uniform mat4 uCameraMatrix;
			uniform mat4 uObjectMatrix;

			uniform vec4 uObjectMaterial;

			varying vec2 vTexCoord;
			varying vec4 vObjectMaterial;

			void main(void)
			{
				vTexCoord = aTexCoord;
				vObjectMaterial = uObjectMaterial;

				gl_Position = uCameraMatrix * (uObjectMatrix * aVertex);
			}";

		var fragSource =
			#if (mobile || html5)
			"precision mediump float;" +
			#end
			"varying vec2 vTexCoord;
			varying vec4 vObjectMaterial;

			uniform sampler2D uTexture;

			void main(void)
			{
				gl_FragColor = vObjectMaterial * texture2D(uTexture, vTexCoord);
			}";

		glProgram = GLUtils.createProgram(vertSource, fragSource);

		glVertexAttribute = gl.getAttribLocation(glProgram, "aVertex");
		glTexCoordAttribute = gl.getAttribLocation(glProgram, "aTexCoord");

		glCameraMatrixUniform = gl.getUniformLocation(glProgram, "uCameraMatrix");
		glObjectMatrixUniform = gl.getUniformLocation(glProgram, "uObjectMatrix");

		glObjectMaterialUniform = gl.getUniformLocation(glProgram, "uObjectMaterial");

		glTextureUniform = gl.getUniformLocation(glProgram, "uTexture");

		glVertexBuffer = gl.createBuffer();
		glTexCoordBuffer = gl.createBuffer();

		glTexture = gl.createTexture();

		gl.frontFace(gl.CCW);

		gl.cullFace(gl.BACK);
		gl.enable(gl.CULL_FACE);

		gl.depthFunc(gl.LESS);
		gl.enable(gl.DEPTH_TEST);

		gl.enable(gl.BLEND);
		gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);

	    var X = 0.525731112119133606;
	    var Z = 0.850650808352039932;
	    var icosaedronVertex = [
	        X, 0.0, Z, 0.0, Z, X, -X, 0.0, Z,       //  1,  4,  0
	        0.0, Z, X, -Z, X, 0.0, -X, 0.0, Z,      //  4,  9,  0
	        0.0, Z, X, 0.0, Z, -X, -Z, X, 0.0,      //  4,  5,  9
	        Z, X, 0.0, 0.0, Z, -X, 0.0, Z, X,       //  8,  5,  4
	        X, 0.0, Z, Z, X, 0.0, 0.0, Z, X,        //  1,  8,  4
	        X, 0.0, Z, Z, -X, 0.0, Z, X, 0.0,       //  1, 10,  8
	        Z, -X, 0.0, X, 0.0, -Z, Z, X, 0.0,      // 10,  3,  8
	        Z, X, 0.0, X, 0.0, -Z, 0.0, Z, -X,      //  8,  3,  5
	        X, 0.0, -Z, -X, 0.0, -Z, 0.0, Z, -X,    //  3,  2,  5
	        X, 0.0, -Z, 0.0, -Z, -X, -X, 0.0, -Z,   //  3,  7,  2
	        X, 0.0, -Z, Z, -X, 0.0, 0.0, -Z, -X,    //  3, 10,  7
	        Z, -X, 0.0, 0.0, -Z, X, 0.0, -Z, -X,    // 10,  6,  7
	        0.0, -Z, X, -Z, -X, 0.0, 0.0, -Z, -X,   //  6, 11,  7
	        0.0, -Z, X, -X, 0.0, Z, -Z, -X, 0.0,    //  6,  0, 11
	        0.0, -Z, X, X, 0.0, Z, -X, 0.0, Z,      //  6,  1,  0
	        Z, -X, 0.0, X, 0.0, Z, 0.0, -Z, X,      // 10,  1,  6
	        -Z, -X, 0.0, -X, 0.0, Z, -Z, X, 0.0,    // 11,  0,  9
	        -X, 0.0, -Z, -Z, -X, 0.0, -Z, X, 0.0,   //  2, 11,  9
	        0.0, Z, -X, -X, 0.0, -Z, -Z, X, 0.0,    //  5,  2,  9
	        -Z, -X, 0.0, -X, 0.0, -Z, 0.0, -Z, -X]; // 11,  2,  7

		var icasaedronTexCoord = [
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0,
			0.0, 0.0, 1.0, 0.0, 1.0, 1.0];

		icoVertexes = new Float32Array(icosaedronVertex);
		icoTexCoords = new Float32Array(icasaedronTexCoord);

		image = Assets.getImage("assets/lime.png");
	}

	public function mainContextRender():Void
	{
		setClearColor(1.0, 0.0, 0.0, 1.0);
		setClearDepth(1.0);
		clear();
		
		setViewport(0, 0, width, height);

		var ratio = height / width;
		cameraMatrix = Matrix.initFromPerspective(-6.0, 6.0, -6.0 * ratio, 6.0 * ratio, 20.0, 100.0);
		cameraMatrix = Matrix.initFromTranslation(0.0, 0.0, -30.0) * cameraMatrix;
		cameraMatrix = Matrix.initFromXRotation(0.15) * cameraMatrix;

		setObjectVertex(icoVertexes);
		setObjectTexture(image, icoTexCoords);

		objectMatrix = Matrix.initFromYRotation(angle);
		setObjectMaterial(0.0, 0.0, 1.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(3.0, 0.0, 3.0) * objectMatrix;
		setObjectMaterial(1.0, 1.0, 0.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(3.0, 0.0, -3.0) * objectMatrix;
		setObjectMaterial(1.0, 0.0, 1.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(-3.0, 0.0, 3.0) * objectMatrix;
		setObjectMaterial(0.0, 1.0, 1.0, 1.0);
		renderObject();

		objectMatrix = Matrix.initFromYRotation(angle);
		objectMatrix = Matrix.initFromTranslation(-3.0, 0.0, -3.0) * objectMatrix;
		setObjectMaterial(0.0, 1.0, 0.0, 1.0);
		renderObject();

		flush();
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function setViewport(x:Int, y:Int, w:Int, h:Int)
	{
		gl.viewport(x, y, w, h);
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function setClearColor(r:Float, g:Float, b:Float, a:Float)
	{
		gl.clearColor(Math.floor(r * 255.0), Math.floor(g * 255.0), Math.floor(b * 255.0), Math.floor(a * 255.0));
	}

	public function setClearDepth(d:Float)
	{
		gl.clearDepth(d);
	}

	public function clear()
	{
		gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function flush()
	{
		gl.flush();
	}

	// ------------------------------------------------------------------------------------------------------------------------------------------------------
	public function setObjectVertex(vertex:Float32Array)
	{
		vertexBuffer = vertex;

		gl.bindBuffer(gl.ARRAY_BUFFER, glVertexBuffer);
		gl.bufferData(gl.ARRAY_BUFFER, vertexBuffer, gl.STATIC_DRAW);
		gl.bindBuffer(gl.ARRAY_BUFFER, null);
	}

	public function setObjectTexture(image:Image, texCoord:Float32Array)
	{
		gl.bindTexture(gl.TEXTURE_2D, glTexture);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
		gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, image.width, image.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, image.data);
		gl.bindTexture(gl.TEXTURE_2D, null);

		texCoordBuffer = texCoord;

		gl.bindBuffer(gl.ARRAY_BUFFER, glTexCoordBuffer);
		gl.bufferData(gl.ARRAY_BUFFER, texCoordBuffer, gl.STATIC_DRAW);
		gl.bindBuffer(gl.ARRAY_BUFFER, null);
	}

	public function setObjectMaterial(r:Float, g:Float, b:Float, a:Float)
	{
		materialBuffer = new Float32Array([r, g, b, a]);
	}

	public function renderObject()
	{
		gl.activeTexture(gl.TEXTURE0);
		gl.bindTexture(gl.TEXTURE_2D, glTexture);

		gl.bindBuffer(gl.ARRAY_BUFFER, glVertexBuffer);
		gl.vertexAttribPointer(glVertexAttribute, 3, gl.FLOAT, false, 0, 0);

		gl.bindBuffer(gl.ARRAY_BUFFER, glTexCoordBuffer);
		gl.vertexAttribPointer(glTexCoordAttribute, 2, gl.FLOAT, false, 0, 0);

		gl.uniformMatrix4fv(glCameraMatrixUniform, false, cameraMatrix);
		gl.uniformMatrix4fv(glObjectMatrixUniform, false, objectMatrix);
		gl.uniform4fv(glObjectMaterialUniform, materialBuffer);

		gl.uniform1i(glTextureUniform, 0);

		gl.drawArrays(gl.TRIANGLES, 0, Math.round(vertexBuffer.length / 3));
	}
}

here’s web version: http://babylonhx.com/lime5/

still no luck with BabylonHx though… but I’ve found this great tool for webgl debugging https://github.com/BabylonJS/Spector.js its actually made by BabylonJS people. For cpp target opengl debugging I’m using CodeXL, and both Spector.js and CodeXL are showing exactly the same output (the sequence of GL command call) but cpp target still shows empty screen…