Can't get GLES2Context to work in Android

@GameStudioHx Got it

Maybe you have to gl.viewport and gl.clear the first time, or maybe the browser allocates a surface that is too small (or presumes this is a non-visible context)

For Babylon, is it using WebGL2, or WebGL features? WebGL2 features are not fully supported (yet) on the desktop

Thanks

@singmajesty BabylonHx works perfectly in browser, cpp windows build doesn’t work (android too). Its using WebGL2 features (BJS has webgl1 fallback but i’ve decided not to do that in BHX - less work for me)
“WebGL2 features are not fully supported (yet) on the desktop” - this makes sense now!!
Do you know which features exactly? CodeXL doesn’t detect any errors. I’ve also tried GLItercept and the log looks ok.
I’m only trying the most basic example from BHX - to render a plane. There are a few UBOs and VBOs and they look fine in CodeXL.
Do you plan to fully support WebGL2 features on all targets soon?

Here is the new listing:

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
{
	#if html5
	private var gl:WebGL2Context;
	#elseif desktop
	private var gl:GLRenderContext;
	#else
	private var gl:GLES2Context;
	#end

	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
	{
		// super.onWindowCreate(window);

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

			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
	{
		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)
	{
		#if html5
		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 setObjectVertex(vertex:Float32Array)
	{
		vertexBuffer = vertex;

		gl.bindBuffer(gl.ARRAY_BUFFER, glVertexBuffer);
		#if html5
		gl.bufferData(gl.ARRAY_BUFFER, vertexBuffer, gl.STATIC_DRAW);
		#else
		gl.bufferData(gl.ARRAY_BUFFER, vertexBuffer.length * Float32Array.BYTES_PER_ELEMENT, DataPointer.fromArrayBufferView(vertexBuffer), gl.STATIC_DRAW);
		#end
		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);
		#if html5
		gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, image.width, image.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, image.data);
		#else
		gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, image.width, image.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, DataPointer.fromArrayBufferView(image.data));
		#end
		gl.bindTexture(gl.TEXTURE_2D, null);

		texCoordBuffer = texCoord;

		gl.bindBuffer(gl.ARRAY_BUFFER, glTexCoordBuffer);
		#if html5
		gl.bufferData(gl.ARRAY_BUFFER, texCoordBuffer, gl.STATIC_DRAW);
		#else
		gl.bufferData(gl.ARRAY_BUFFER, texCoordBuffer.length * Float32Array.BYTES_PER_ELEMENT, DataPointer.fromArrayBufferView(texCoordBuffer), gl.STATIC_DRAW);
		#end
		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);

		#if html5
		gl.uniformMatrix4fv(glCameraMatrixUniform, false, cameraMatrix);
		gl.uniformMatrix4fv(glObjectMatrixUniform, false, objectMatrix);
		gl.uniform4fv(glObjectMaterialUniform, materialBuffer);
		#else
		gl.uniformMatrix4fv(glCameraMatrixUniform, 1, false, DataPointer.fromArrayBufferView(cameraMatrix));
		gl.uniformMatrix4fv(glObjectMatrixUniform, 1, false, DataPointer.fromArrayBufferView(objectMatrix));
		gl.uniform4fv(glObjectMaterialUniform, 1, DataPointer.fromArrayBufferView(materialBuffer));
		#end

		gl.uniform1i(glTextureUniform, 0);

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

It works with Neko on Windows, HTML5, and Android (finally!).

There’s still one thing: if I type ‘lime build html5’, and then double-click the generated ‘index.html’, the browser window contents remain blank. It does not happen if I type ‘lime test html5’, though.

Can someone tell me if it works with other OpenGL targets (linux, macos, ios)?

If you double-click index.html you’ll get black screen because your example uses an image asset and browser is blocking it for security reasons. This throws an exception - check your browser console output.

I see.

Concerning my previous listing, it is better to insert the following lines in the ‘render’ function:

if(!preloader.complete)
{
  gl.viewport(0, 0, width, height);
  gl.clearColor(1.0, 0.0, 0.0, 1.0);
  #if html5
  gl.clearDepth(1.0);
  #else
  gl.clearDepthf(1.0);
  #end
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  return;
}

This prevents artifacts from showing up in Android.

Well, I’d like to say thanks, fellow coders. I really appreciated your help. I’m sorry I couldn’t be of more help, though. So, until next time :).