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.