diff --git a/project/ToolkitBuild.xml b/project/ToolkitBuild.xml
index 25e23194d..c515aa26b 100644
--- a/project/ToolkitBuild.xml
+++ b/project/ToolkitBuild.xml
@@ -4,9 +4,12 @@
+
+
+
@@ -191,6 +194,7 @@
+
@@ -484,7 +488,8 @@
diff --git a/project/include/Hardware.h b/project/include/Hardware.h
index 9af77f161..4b009fd96 100644
--- a/project/include/Hardware.h
+++ b/project/include/Hardware.h
@@ -130,6 +130,7 @@ class HardwareRenderer : public HardwareContext
virtual void DestroyShader(unsigned int inShader)=0;
virtual void DestroyFramebuffer(unsigned int inBuffer)=0;
virtual void DestroyRenderbuffer(unsigned int inBuffer)=0;
+ virtual void DestroyVertexarray(unsigned int inBuffer)=0;
#ifdef NME_S3D
virtual void EndS3DRender()=0;
diff --git a/project/src/opengl/OGL.h b/project/src/opengl/OGL.h
index 675896d4e..6837eae85 100644
--- a/project/src/opengl/OGL.h
+++ b/project/src/opengl/OGL.h
@@ -8,6 +8,9 @@
#define NME_GLES
#define GL_GLEXT_PROTOTYPES
+#ifndef NME_NO_GLES3COMPAT
+ #include
+#endif
#include
#include
@@ -15,6 +18,12 @@
#define NME_GLES
+#ifndef NME_NO_GLES3COMPAT
+ #include
+ #if defined(ANDROID)
+ #define __gl2_h_ //For Android Platform < 21
+ #endif
+#endif
#include
#include
@@ -22,11 +31,18 @@
#define NME_GLES
+#ifndef NME_NO_GLES3COMPAT
+ #include
+#endif
#include
#include
#elif defined(IPHONE)
+#ifndef NME_NO_GLES3COMPAT
+ #include
+ #include
+#endif
#include
#include
#include
diff --git a/project/src/opengl/OGLExport.cpp b/project/src/opengl/OGLExport.cpp
index 898670426..d63f5f98c 100644
--- a/project/src/opengl/OGLExport.cpp
+++ b/project/src/opengl/OGLExport.cpp
@@ -46,6 +46,7 @@ enum ResoType
resoProgram, //4
resoFramebuffer, //5
resoRenderbuffer, //6
+ resoVertexarray, //7 (GLES3)
};
const char *getTypeString(int inType)
@@ -59,6 +60,7 @@ const char *getTypeString(int inType)
case resoProgram: return "Program";
case resoFramebuffer: return "Framebuffer";
case resoRenderbuffer: return "Renderbuffer";
+ case resoVertexarray: return "Vertexarray";
}
return "Unknown";
}
@@ -306,6 +308,9 @@ class NmeResource : public nme::Object
case resoRenderbuffer:
ctx->DestroyRenderbuffer(id);
break;
+ case resoVertexarray:
+ ctx->DestroyVertexarray(id);
+ break;
}
}
type = resoNone;
@@ -638,7 +643,6 @@ value nme_gl_get_parameter(value pname_val)
case GL_SAMPLE_BUFFERS:
case GL_SAMPLES:
case GL_SCISSOR_TEST:
- case GL_SHADING_LANGUAGE_VERSION:
case GL_STENCIL_BACK_FAIL:
case GL_STENCIL_BACK_FUNC:
case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
@@ -663,6 +667,7 @@ value nme_gl_get_parameter(value pname_val)
case GL_VENDOR:
case GL_VERSION:
+ case GL_SHADING_LANGUAGE_VERSION:
case GL_RENDERER:
strings = 1;
break;
@@ -794,6 +799,17 @@ GL_GEN_RESO(buffer,glGenBuffers,resoBuffer)
GL_GEN_RESO(framebuffer,glGenFramebuffers,resoFramebuffer)
GL_GEN_RESO(render_buffer,glGenRenderbuffers,resoRenderbuffer)
+//GLES3
+#ifdef NME_NO_GLES3COMPAT
+value nme_gl_create_vertexarray(value inType)
+{
+ DBGFUNC("create vertex array needs NME_GLES3COMPAT");
+ return alloc_int(-1);
+}
+DEFINE_PRIM(nme_gl_create_vertexarray,0);
+#else
+GL_GEN_RESO(vertexarray,glGenVertexArrays,resoVertexarray)
+#endif
// --- Stencil -------------------------------------------
@@ -1376,9 +1392,12 @@ value nme_gl_shader_source(value inId,value inSource)
const char *lines = source.c_str();
#ifdef NME_GLES
// TODO - do something better here
- std::string buffer;
- buffer = std::string("precision mediump float;\n") + hxToStdString(source);
- lines = buffer.c_str();
+ if (lines[0]!='#' && lines[1]!='v')
+ {
+ std::string buffer;
+ buffer = std::string("precision mediump float;\n") + hxToStdString(source);
+ lines = buffer.c_str();
+ }
#endif
glShaderSource(id,1,&lines,0);
@@ -1756,9 +1775,27 @@ value nme_gl_get_render_buffer_parameter(value target, value pname)
}
DEFINE_PRIM(nme_gl_get_render_buffer_parameter,2);
-// --- Drawing -------------------------------
+
+// --- GLES3: VertexArray
+
+value nme_gl_bind_vertexarray(value inId )
+{
+ DBGFUNC("bindVertexArray");
+ int id = getResourceId(inId,resoVertexarray);
+#ifndef NME_NO_GLES3COMPAT
+ glBindVertexArray(id);
+#endif
+ return alloc_null();
+}
+DEFINE_PRIM(nme_gl_bind_vertexarray,1);
+
+
+
+
+// --- Drawing -------------------------------
+
value nme_gl_draw_arrays(value inMode, value inFirst, value inCount)
{
DBGFUNC("drawArrays");
diff --git a/project/src/opengl/OpenGLContext.cpp b/project/src/opengl/OpenGLContext.cpp
index fb4b3a699..9afb0ff49 100644
--- a/project/src/opengl/OpenGLContext.cpp
+++ b/project/src/opengl/OpenGLContext.cpp
@@ -154,6 +154,18 @@ class OGLContext : public HardwareRenderer
else
glDeleteRenderbuffers(1,&inBuffer);
}
+ void DestroyVertexarray(unsigned int inBuffer)
+ {
+ if ( !IsMainThread() )
+ {
+ mHasZombie = true;
+ mZombieVertexarrays.push_back(inBuffer);
+ }
+#ifndef NME_NO_GLES3COMPAT
+ else
+ glDeleteVertexArrays(1,&inBuffer);
+#endif
+ }
void OnContextLost()
@@ -164,6 +176,7 @@ class OGLContext : public HardwareRenderer
mZombieShaders.resize(0);
mZombieFramebuffers.resize(0);
mZombieRenderbuffers.resize(0);
+ mZombieVertexarrays.resize(0);
mHasZombie = false;
}
@@ -277,6 +290,14 @@ class OGLContext : public HardwareRenderer
glDeleteRenderbuffers(mZombieRenderbuffers.size(),&mZombieRenderbuffers[0]);
mZombieRenderbuffers.resize(0);
}
+
+ if (mZombieVertexarrays.size())
+ {
+ #ifndef NME_NO_GLES3COMPAT
+ glDeleteVertexArrays(mZombieVertexarrays.size(),&mZombieVertexarrays[0]);
+ #endif
+ mZombieVertexarrays.resize(0);
+ }
}
@@ -316,6 +337,7 @@ class OGLContext : public HardwareRenderer
mZombieShaders.resize(0);
mZombieFramebuffers.resize(0);
mZombieRenderbuffers.resize(0);
+ mZombieVertexarrays.resize(0);
ReloadExtentions();
}
@@ -771,6 +793,7 @@ class OGLContext : public HardwareRenderer
QuickVec mZombieShaders;
QuickVec mZombieFramebuffers;
QuickVec mZombieRenderbuffers;
+ QuickVec mZombieVertexarrays;
GPUProg *mProg[PROG_COUNT];
diff --git a/project/src/sdl2/SDL2Stage.cpp b/project/src/sdl2/SDL2Stage.cpp
index acecdd584..5e6c79b78 100644
--- a/project/src/sdl2/SDL2Stage.cpp
+++ b/project/src/sdl2/SDL2Stage.cpp
@@ -1550,8 +1550,13 @@ void CreateMainFrame(FrameCreationCallback inOnFrame, int inWidth, int inHeight,
#ifdef NME_ANGLE
SDL_GL_SetAttribute(SDL_GL_CONTEXT_EGL, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
+ int major = 3;
+ #ifdef NME_NO_GLES3COMPAT
+ major = 2;
+ #endif
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
+ DLOG("1 ");
#endif
if (opengl)
@@ -1642,6 +1647,12 @@ void CreateMainFrame(FrameCreationCallback inOnFrame, int inWidth, int inHeight,
if (opengl) renderFlags |= SDL_RENDERER_ACCELERATED;
if (opengl && vsync) renderFlags |= SDL_RENDERER_PRESENTVSYNC;
+ #ifdef NME_ANGLE
+ //needs to be just before SDL_CreateRenderer because SDL_GetWindowFlags resets it
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
+ #endif
+
renderer = SDL_CreateRenderer (window, -1, renderFlags);
if (opengl)
@@ -1653,6 +1664,16 @@ void CreateMainFrame(FrameCreationCallback inOnFrame, int inWidth, int inHeight,
sgIsOGL2 = false;
}
+ #ifdef NME_ANGLE
+ if (!renderer && opengl && major>2)
+ {
+ fprintf(stderr, "GLES3 is not available. Retrying with GLES2. (%s)\n", SDL_GetError());
+ major = 2;
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major);
+ SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
+ }
+ else
+ #endif
if (!renderer && (inFlags & wfHW_AA_HIRES || inFlags & wfHW_AA)) {
// if no window was created and AA was enabled, disable AA and try again
fprintf(stderr, "Multisampling is not available. Retrying without. (%s)\n", SDL_GetError());
diff --git a/src/nme/gl/GL.hx b/src/nme/gl/GL.hx
index 5231ec467..9bfc3f28d 100644
--- a/src/nme/gl/GL.hx
+++ b/src/nme/gl/GL.hx
@@ -501,6 +501,11 @@ class GL
nme_gl_bind_texture(target, texture);
}
+ public static inline function bindVertexArray(vertexarray:GLVertexArray):Void
+ {
+ nme_gl_bind_vertexarray(vertexarray);
+ }
+
public static inline function blendColor(red:Float, green:Float, blue:Float, alpha:Float):Void
{
nme_gl_blend_color(red, green, blue, alpha);
@@ -621,6 +626,11 @@ class GL
return new GLTexture(version, nme_gl_create_texture());
}
+ public static inline function createVertexArray():GLVertexArray
+ {
+ return new GLVertexArray(version, nme_gl_create_vertexarray());
+ }
+
public static inline function cullFace(mode:Int):Void
{
nme_gl_cull_face(mode);
@@ -1310,6 +1320,10 @@ class GL
private static var nme_gl_vertex_attrib4fv = load("nme_gl_vertex_attrib4fv", 2);
private static var nme_gl_vertex_attrib_pointer = load("nme_gl_vertex_attrib_pointer", -1);
private static var nme_gl_viewport = load("nme_gl_viewport", 4);
+
+ //gles3
+ private static var nme_gl_create_vertexarray = load("nme_gl_create_vertexarray", 0);
+ private static var nme_gl_bind_vertexarray = load("nme_gl_bind_vertexarray", 1);
#else // not (neko||cpp)
// Stub to get flixel to compile
diff --git a/src/nme/gl/GLVertexArray.hx b/src/nme/gl/GLVertexArray.hx
new file mode 100644
index 000000000..ae05c8400
--- /dev/null
+++ b/src/nme/gl/GLVertexArray.hx
@@ -0,0 +1,18 @@
+package nme.gl;
+#if (!flash)
+
+@:nativeProperty
+class GLVertexArray extends GLObject
+{
+ public function new(inVersion:Int, inId:Dynamic)
+ {
+ super(inVersion, inId);
+ }
+
+ override function getType():String
+ {
+ return "VertexArray";
+ }
+}
+
+#end
diff --git a/src/nme/gl/Utils.hx b/src/nme/gl/Utils.hx
index 5794fb643..f99342d67 100644
--- a/src/nme/gl/Utils.hx
+++ b/src/nme/gl/Utils.hx
@@ -18,9 +18,20 @@ class Utils
return shader;
}
- public static function createProgram(inVertexSource:String, inFragmentSource:String)
+ public static function createProgram(inVertexSource:String, inFragmentSource:String, inAutoHeader:Bool = true)
{
var program = GL.createProgram();
+ if(inAutoHeader)
+ {
+ if( !StringTools.startsWith(inVertexSource,"#v") )
+ {
+ inVertexSource = HEADER(GL.VERTEX_SHADER) + inVertexSource;
+ }
+ if( !StringTools.startsWith(inFragmentSource,"#v") )
+ {
+ inFragmentSource = HEADER(GL.FRAGMENT_SHADER) + inFragmentSource;
+ }
+ }
var vshader = createShader(inVertexSource, GL.VERTEX_SHADER);
var fshader = createShader(inFragmentSource, GL.FRAGMENT_SHADER);
GL.attachShader(program, vshader);
@@ -35,5 +46,135 @@ class Utils
return program;
}
+
+ public static function isGLES():Bool
+ {
+ if(!_glVersionInit)
+ GLVersion();
+
+ return _isGLES;
+ };
+
+ public static function isWebGL():Bool
+ {
+ if(!_glVersionInit)
+ GLVersion();
+
+ return _isWebGL;
+ };
+
+ //is GLES3 or OpenGL 3.3
+ public static function isGLES3compat():Bool
+ {
+ if(!_glVersionInit)
+ GLVersion();
+
+ return _isGLES3compat;
+ };
+
+ //Gets version as float and inits isGLES, isGLES3compat
+ public static function GLVersion():Float
+ {
+ if(!_glVersionInit)
+ {
+ var version = GL.getParameter(GL.VERSION);
+ //trace("shading language: "+version);
+
+ version = StringTools.ltrim(version);
+ if(version.indexOf("OpenGL ES")>=0)
+ {
+ _isGLES = true;
+ _isWebGL = false;
+ _glVersion = Std.parseFloat(version.split(" ")[2]);
+ _isGLES3compat = (_glVersion>=3.0);
+ }
+ else if(version.indexOf("WebGL")>=0)
+ {
+ _isGLES = true; //a kind of GLES
+ _isWebGL = true;
+ _glVersion = Std.parseFloat(version.split(" ")[1]);
+ _isGLES3compat = (_glVersion>=2.0);
+ }
+ else
+ {
+ _isGLES = false;
+ _isWebGL = false;
+ _glVersion = Std.parseFloat(version.split(" ")[0]);
+ _isGLES3compat = (_glVersion>=3.3);
+ }
+ _glVersionInit = true;
+ //trace("version: "+_glVersion+" is GLES: "+(_isGLES?"true":"false")+", is GLES3 compatible:"+(_isGLES3compat?"true":"false"));
+ }
+ return _glVersion;
+ }
+
+ //Helper functions for writting compatible gles3/gles2 shader sources
+ //1) In VS: attribute -> IN(n)
+ //2) In VS: varying -> OUT()
+ //2a) In FS: varyng -> IN()
+ //3) In FS: OUT_COLOR("color"): define the name output instead of gl_FragColor
+ //5) HEADER is included automatically in "createProgram" unless inAutoHeader is set to false
+
+ public static inline function IN(slot:Int = -1):String
+ {
+ return slot < 0 ? IN_FS() : IN_VS(slot);
+ }
+
+ public static inline function IN_FS():String
+ {
+ return isGLES3compat()?
+ "\nin " :
+ "\nvarying ";
+ }
+
+ public static inline function IN_VS(slot:Int):String
+ {
+ return isGLES3compat()?
+ "\nlayout(location = " + slot + ") in " :
+ "\nattribute ";
+ }
+
+ public static inline function OUT():String
+ {
+ return isGLES3compat()?
+ "\nout" :
+ "\nvarying";
+ }
+
+ public static inline function OUT_COLOR(fragColor:String):String
+ {
+ return isGLES3compat()?
+ "\nout vec4 "+fragColor+";\n" :
+ "\n#define "+fragColor+" gl_FragColor\n";
+ }
+
+ public static inline function TEXTURE():String
+ {
+ return isGLES3compat()?
+ " texture" :
+ " texture2D";
+ }
+
+ private static inline function HEADER(type:Int):String
+ {
+ return isGLES3compat()?
+ (
+ _isGLES?
+ "#version 300 es\nprecision mediump float; \n" :
+ "#version 330 core\n"
+ )
+ :
+ (
+ _isGLES?
+ "#version 100\nprecision mediump float; \n" :
+ "#version 110\n"
+ );
+ }
+
+ public static var _isGLES:Bool;
+ public static var _isWebGL:Bool;
+ public static var _isGLES3compat:Bool;
+ public static var _glVersion:Float;
+ public static var _glVersionInit:Bool;
}