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..2f8e1e5d4 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,10 @@ #define NME_GLES + #ifndef NME_NO_GLES3COMPAT + #include + #define __gl2_h_ //Not needed for Android Platform >= 21 + #endif #include #include @@ -24,6 +31,9 @@ #include #include + #ifndef NME_NO_GLES3COMPAT + #include + #endif #elif defined(IPHONE) @@ -31,6 +41,10 @@ #include #include #include + #ifndef NME_NO_GLES3COMPAT + #include + #include + #endif //typedef CAEAGLLayer *WinDC; //typedef EAGLContext *GLCtx; diff --git a/project/src/opengl/OGLExport.cpp b/project/src/opengl/OGLExport.cpp index 898670426..fc1d78b14 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("createShader"); + return val_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,26 @@ 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 ) +{ + 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 ec8b6993f..ec27e1ea0 100644 --- a/project/src/sdl2/SDL2Stage.cpp +++ b/project/src/sdl2/SDL2Stage.cpp @@ -31,7 +31,6 @@ static int sgDesktopWidth = 0; static int sgDesktopHeight = 0; static Rect sgWindowRect = Rect(0, 0, 0, 0); static bool sgInitCalled = false; -//static bool sgJoystickEnabled = false; static bool sgGameControllerEnabled = false; static bool sgIsOGL2 = false; const int sgJoystickDeadZone = 1000; @@ -1806,9 +1805,13 @@ void CreateMainFrame(FrameCreationCallback inOnFrame, int inWidth, int inHeight, if (fullscreen) requestWindowFlags |= FullscreenMode; //SDL_WINDOW_FULLSCREEN_DESKTOP; #ifdef NME_ANGLE + int major = 3; + #ifdef NME_NO_GLES3COMPAT + major = 2; + #endif 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); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, major); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); #endif @@ -1938,6 +1941,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/GL3.hx b/src/nme/gl/GL3.hx new file mode 100644 index 000000000..b67c520f3 --- /dev/null +++ b/src/nme/gl/GL3.hx @@ -0,0 +1,41 @@ +package nme.gl; + +import nme.display.BitmapData; +import nme.utils.ArrayBuffer; +import nme.utils.ByteArray; +import nme.utils.IMemoryRange; +import nme.utils.ArrayBufferView; +import nme.geom.Matrix3D; +import nme.Lib; +import nme.Loader; + +#if (neko||cpp) +import nme.utils.Float32Array; +import nme.utils.Int32Array; +#end + + +@:nativeProperty +class GL3 +{ + + #if (neko||cpp) + + public static inline function bindVertexArray(vertexarray:GLVertexArray):Void + { + nme_gl_bind_vertexarray(vertexarray); + } + + public static inline function createVertexArray():GLVertexArray + { + return new GLVertexArray(GL.version, nme_gl_create_vertexarray()); + } + + + // Native Methods + private static var nme_gl_create_vertexarray = GL.load("nme_gl_create_vertexarray", 0); + private static var nme_gl_bind_vertexarray = GL.load("nme_gl_bind_vertexarray", 1); + + #end +} + 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..0a10f86d0 100644 --- a/src/nme/gl/Utils.hx +++ b/src/nme/gl/Utils.hx @@ -18,9 +18,17 @@ 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 +43,129 @@ class Utils return program; } + + public static function isGLES():Bool + { + initGLVersion(); + return _isGLES; + }; + + public static function isWebGL():Bool + { + initGLVersion(); + return _isWebGL; + }; + + //is GLES3, WebGL2, or OpenGL 3.3+ + public static function isGLES3compat():Bool + { + initGLVersion(); + return _isGLES3compat; + }; + + //Gets version as float and inits isGLES, isGLES3compat + public static function GLVersion():Float + { + initGLVersion(); + return _glVersion; + } + + //Inits glVersion, isGLES, isGLES3compat, isWebGL + public static function initGLVersion() + { + if(!_glVersionInit) + { + version = StringTools.ltrim(GL.getParameter(GL.VERSION)); + if(version.indexOf("OpenGL ES") >= 0) + { + _isGLES = true; + _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 + { + _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")); + } + } + + //Helper functions for writting gles3 shaders with gles2 fallback + //1) In VS: attribute -> IN(n) + //2) In VS: varying -> OUT() + //3) In FS: varyng -> IN() + //4) In FS: OUT_COLOR("color"): define the name output instead of gl_FragColor + //5) In FS: texture2D(x) -> TEXTURE(x) + //6) HEADER is included automatically in "createProgram" unless inAutoHeader is set to false + + public static function IN(slot:Int = -1):String + { + return slot < 0 ? IN_FS() : IN_VS(slot); + } + + public static function IN_FS():String + { + return isGLES3compat()? "\nin " : "\nvarying "; + } + + public static function IN_VS(slot:Int):String + { + return isGLES3compat()? + "\nlayout(location = " + slot + ") in " : + "\nattribute "; + } + + public static function OUT():String + { + return isGLES3compat()? "\nout " : "\nvarying "; + } + + public static function OUT_COLOR(fragColor:String):String + { + return isGLES3compat()? + "\nout vec4 "+fragColor+";\n" : + "\n#define "+fragColor+" gl_FragColor\n"; + } + + public static function TEXTURE( arg:String=null ):String + { + if(arg==null) + return isGLES3compat()? " texture" : " texture2D"; + else + return isGLES3compat()? + " texture(" + arg + ")" : + " texture2D(" + arg + ")"; + } + + 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" + ); + } + + private static var _isGLES:Bool; + private static var _isWebGL:Bool; + private static var _isGLES3compat:Bool; + private static var _glVersion:Float; + private static var _glVersionInit:Bool; }