diff --git a/examples/example1/src/example1.d b/examples/example1/src/example1.d index e5a50cf9..45652fda 100644 --- a/examples/example1/src/example1.d +++ b/examples/example1/src/example1.d @@ -1217,12 +1217,12 @@ static if (ENABLE_OPENGL) { /// this is OpenGLDrawableDelegate implementation private void doDraw(Rect windowRect, Rect rc) { - Log.v("GlGears: MyOpenglWidget.doDraw() draw gears"); if (!openglEnabled) { Log.v("GlGears: OpenGL is disabled"); return; } - _oldApi = !!glLightfv; + import dlangui.graphics.glsupport : glSupport; + _oldApi = glSupport.legacyMode; if (_oldApi) { drawUsingOldAPI(rc); } else { @@ -1238,9 +1238,7 @@ static if (ENABLE_OPENGL) { _initCalled = true; glxgears_init(); } - Log.v("GlGears: calling reshape()"); glxgears_reshape(rc); - Log.v("GlGears: calling draw()"); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); @@ -1469,14 +1467,12 @@ static if (ENABLE_OPENGL) { static GLfloat[4] green = [ 0.0, 0.8, 0.2, 1.0 ]; static GLfloat[4] blue = [ 0.2, 0.2, 1.0, 1.0 ]; - Log.d("GlGears: init - calling glLightfv"); glLightfv(GL_LIGHT0, GL_POSITION, pos.ptr); glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); - Log.d("GlGears: init - calling genlists"); /* make the gears */ gear1 = glGenLists(1); glNewList(gear1, GL_COMPILE); diff --git a/examples/opengl/src/openglexample.d b/examples/opengl/src/openglexample.d index 98293dd1..65413710 100644 --- a/examples/opengl/src/openglexample.d +++ b/examples/opengl/src/openglexample.d @@ -9,11 +9,15 @@ extern (C) int UIAppMain(string[] args) { // embed resources listed in views/resources.list into executable embeddedResourceList.addResources(embedResourcesFromList!("resources.list")()); + // the old API example works on old context because of OpenGL deprecation model + // otherwise there will be GL_INVALID_OPERATION error + // new API functions on a modern graphics card will work even if you set context version to 1.0 + Platform.instance.GLVersionMajor = 2; + Platform.instance.GLVersionMinor = 1; + // create window Window window = Platform.instance.createWindow("DlangUI OpenGL Example", null, WindowFlag.Resizable, 800, 700); - VerticalLayout contentLayout = new VerticalLayout(); - static if (ENABLE_OPENGL) { window.mainWidget = new MyOpenglWidget(); } else { @@ -147,9 +151,7 @@ class MyOpenglWidget : VerticalLayout { _initCalled = true; glxgears_init(); } - Log.v("GlGears: calling reshape()"); glxgears_reshape(rc); - Log.v("GlGears: calling draw()"); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); @@ -162,22 +164,31 @@ class MyOpenglWidget : VerticalLayout { ~this() { if (_program) destroy(_program); + if (_vao) + destroy(_vao); + if (_vbo) + destroy(_vbo); if (_tx) destroy(_tx); } MyGLProgram _program; GLTexture _tx; + VAO _vao; + VBO _vbo; /// New API example (OpenGL3+, shaders) void drawUsingNewAPI(Rect windowRect, Rect rc) { if (!_program) { - _program = new MyGLProgram(); + _program = new MyGLProgram; + _program.compile(); createMesh(); + auto buf = _program.createBuffers(vertices, colors, texcoords); + _vao = buf[0]; + _vbo = buf[1]; } if (!_program.check()) return; - if (!_tx.isValid) { Log.e("Invalid texture"); return; @@ -208,7 +219,7 @@ class MyOpenglWidget : VerticalLayout { // ======= PMV matrix ===================== mat4 projectionViewModelMatrix = projectionMatrix * viewMatrix * modelMatrix; - _program.execute(vertices, colors, texcoords, _tx.texture, true, projectionViewModelMatrix.m); + _program.execute(_vao, cast(int)vertices.length / 3, _tx.texture, true, projectionViewModelMatrix.m); checkgl!glDisable(GL_CULL_FACE); checkgl!glDisable(GL_DEPTH_TEST); @@ -306,23 +317,13 @@ class MyGLProgram : GLProgram { return matrixLocation >= 0 && vertexLocation >= 0 && colAttrLocation >= 0 && texCoordLocation >= 0; } - bool execute(float[] vertices, float[] colors, float[] texcoords, Tex2D texture, bool linear, float[16] matrix) { - if(!check()) - return false; + import std.typecons : Tuple, tuple; + Tuple!(VAO, VBO) createBuffers(float[] vertices, float[] colors, float[] texcoords) { - glEnable(GL_BLEND); - checkgl!glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - bind(); - checkgl!glUniformMatrix4fv(matrixLocation, 1, false, matrix.ptr); - - texture.setup(); - texture.setSamplerParams(linear); - - VAO vao = new VAO(); - - VBO vbo = new VBO(); + VBO vbo = new VBO; vbo.fill([vertices, colors, texcoords]); + VAO vao = new VAO; glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, cast(void*) 0); glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, cast(void*) (vertices.length * vertices[0].sizeof)); glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, cast(void*) (vertices.length * vertices[0].sizeof + colors.length * colors[0].sizeof)); @@ -331,19 +332,22 @@ class MyGLProgram : GLProgram { glEnableVertexAttribArray(colAttrLocation); glEnableVertexAttribArray(texCoordLocation); - checkgl!glDrawArrays(GL_TRIANGLES, 0, cast(int)vertices.length / 3); + return tuple(vao, vbo); + } - glDisableVertexAttribArray(vertexLocation); - glDisableVertexAttribArray(colAttrLocation); - glDisableVertexAttribArray(texCoordLocation); + void execute(VAO vao, int vertsCount, Tex2D texture, bool linear, float[16] matrix) { - unbind(); + bind(); + checkgl!glUniformMatrix4fv(matrixLocation, 1, false, matrix.ptr); - destroy(vbo); - destroy(vao); + texture.setup(); + texture.setSamplerParams(linear); + + vao.bind(); + checkgl!glDrawArrays(GL_TRIANGLES, 0, vertsCount); texture.unbind(); - return true; + unbind(); } } @@ -550,14 +554,12 @@ static void glxgears_init() static GLfloat[4] green = [ 0.0, 0.8, 0.2, 1.0 ]; static GLfloat[4] blue = [ 0.2, 0.2, 1.0, 1.0 ]; - Log.d("GlGears: init - calling glLightfv"); glLightfv(GL_LIGHT0, GL_POSITION, pos.ptr); glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); - Log.d("GlGears: init - calling genlists"); /* make the gears */ gear1 = glGenLists(1); glNewList(gear1, GL_COMPILE); diff --git a/src/dlangui/graphics/gldrawbuf.d b/src/dlangui/graphics/gldrawbuf.d index f7b1c067..e73bd2f0 100644 --- a/src/dlangui/graphics/gldrawbuf.d +++ b/src/dlangui/graphics/gldrawbuf.d @@ -80,8 +80,6 @@ class GLDrawBuf : DrawBuf, GLConfigCallback { glSupport.beforeRenderGUI(); _scene.draw(); glSupport.queue.flush(); - GLProgram.unbind(); - glSupport.destroyBuffers(); glSupport.flushGL(); destroy(_scene); _scene = null; @@ -836,8 +834,6 @@ public: glSupport.queue.flush(); glSupport.setOrthoProjection(_windowRect, _rc); glSupport.clearDepthBuffer(); - //glEnable(GL_BLEND); - //checkgl!glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); _handler(_windowRect, _rc); glSupport.setOrthoProjection(_windowRect, _windowRect); } diff --git a/src/dlangui/graphics/glsupport.d b/src/dlangui/graphics/glsupport.d index feaff91c..675650a3 100644 --- a/src/dlangui/graphics/glsupport.d +++ b/src/dlangui/graphics/glsupport.d @@ -281,15 +281,9 @@ class GLProgram : dlangui.graphics.scene.mesh.GraphicsEffect { initialized = false; } - /// returns true if program is ready for use (compiles program if not yet compiled) - bool check() - { - if (error) - return false; - if (!initialized) - if (!compile()) - return false; - return true; + /// returns true if program is ready for use + bool check() { + return !error && initialized; } static GLuint currentProgram; @@ -645,7 +639,7 @@ private float[] convertColors(uint[] cols) pure nothrow { return colors; } -__gshared GLSupport _glSupport; +private __gshared GLSupport _glSupport; @property GLSupport glSupport() { if (!_glSupport) { Log.f("GLSupport is not initialized"); @@ -657,7 +651,7 @@ __gshared GLSupport _glSupport; return _glSupport; } -/// initialize OpenGL suport helper (call when current OpenGL context is initialized) +/// initialize OpenGL support helper (call when current OpenGL context is initialized) bool initGLSupport(bool legacy = false) { import dlangui.platforms.common.platform : setOpenglEnabled; if (_glSupport && _glSupport.valid) @@ -701,12 +695,7 @@ bool initGLSupport(bool legacy = false) { if (!_glSupport) { Log.d("glSupport not initialized: trying to create"); _glSupport = new GLSupport(legacy); - if (_glSupport.valid || _glSupport.initShaders()) { - Log.v("shaders are ok"); - setOpenglEnabled(); - Log.v("OpenGL is initialized ok"); - return true; - } else { + if (!_glSupport.valid) { Log.e("Failed to compile shaders"); version (Android) { // do not recreate legacy mode @@ -715,19 +704,21 @@ bool initGLSupport(bool legacy = false) { if (_glSupport.legacyMode == legacy) { Log.i("Trying to reinit GLSupport with legacy flag ", !legacy); _glSupport = new GLSupport(!legacy); - if (_glSupport.valid || _glSupport.initShaders()) { - Log.v("shaders are ok"); - setOpenglEnabled(); - Log.v("OpenGL is initialized ok"); - return true; + } + // Situation when opposite legacy flag is true and context version is 3.1+ + if (_glSupport.legacyMode) { + int major = to!int(glGetString(GL_VERSION)[0]); + if (major >= 3) { + Log.e("Try to create OpenGL context with <= 3.1 version"); + return false; } } } } - return false; } - if (_glSupport.valid || _glSupport.initShaders()) { + if (_glSupport.valid) { setOpenglEnabled(); + Log.v("OpenGL is initialized ok"); return true; } else { Log.e("Failed to compile shaders"); @@ -742,6 +733,10 @@ final class GLSupport { @property bool legacyMode() { return _legacyMode; } @property queue() { return _queue; } + @property bool valid() { + return _legacyMode || _shadersAreInitialized; + } + this(bool legacy = false) { _queue = new OpenGLQueue; version (Android) { @@ -753,36 +748,40 @@ final class GLSupport { } } _legacyMode = legacy; + if (!_legacyMode) + _shadersAreInitialized = initShaders(); } - OpenGLQueue _queue; - - SolidFillProgram _solidFillProgram; - TextureProgram _textureProgram; - - @property bool valid() { - return _legacyMode || _textureProgram && _solidFillProgram; + ~this() { + uninitShaders(); } - bool initShaders() { - Log.i("initShaders() is called"); + private OpenGLQueue _queue; + + private SolidFillProgram _solidFillProgram; + private TextureProgram _textureProgram; + + private bool _shadersAreInitialized; + private bool initShaders() { if (_solidFillProgram is null) { Log.v("Compiling solid fill program"); _solidFillProgram = new SolidFillProgram(); - if (!_solidFillProgram.compile()) + _solidFillProgram.compile(); + if (!_solidFillProgram.check()) return false; } if (_textureProgram is null) { Log.v("Compiling texture program"); _textureProgram = new TextureProgram(); - if (!_textureProgram.compile()) + _textureProgram.compile(); + if (!_textureProgram.check()) return false; } Log.d("Shaders compiled successfully"); return true; } - bool uninitShaders() { + private void uninitShaders() { Log.d("Uniniting shaders"); if (_solidFillProgram !is null) { destroy(_solidFillProgram); @@ -792,7 +791,6 @@ final class GLSupport { destroy(_textureProgram); _textureProgram = null; } - return true; } void beforeRenderGUI() { @@ -801,10 +799,15 @@ final class GLSupport { checkgl!glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } - VBO vbo; - EBO ebo; + private VBO vbo; + private EBO ebo; + + private void fillBuffers(float[] vertices, float[] colors, float[] texcoords, int[] indices) { + resetBindings(); + + if(_legacyMode) + return; - void fillBuffers(float[] vertices, float[] colors, float[] texcoords, int[] indices) { vbo = new VBO; ebo = new EBO; @@ -823,7 +826,20 @@ final class GLSupport { ebo.bind(); } - void destroyBuffers() { + /// This function is needed to draw custom OpenGL scene correctly (especially on legacy API) + private void resetBindings() { + // TODO: check if there is a very old driver with no such functions + GLProgram.unbind(); + VAO.unbind(); + VBO.unbind(); + } + + private void destroyBuffers() { + resetBindings(); + + if(_legacyMode) + return; + if (_solidFillProgram) _solidFillProgram.destroyBuffers(); if (_textureProgram) @@ -835,26 +851,18 @@ final class GLSupport { ebo = null; } - void drawLines(int length, int start) { - + private void drawLines(int length, int start) { if (_legacyMode) { static if (SUPPORT_LEGACY_OPENGL) { - glColor4f(1,1,1,1); - glDisable(GL_CULL_FACE); - glEnable(GL_BLEND); - glDisable(GL_ALPHA_TEST); - checkgl!glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - checkgl!glEnableClientState(GL_VERTEX_ARRAY); - checkgl!glEnableClientState(GL_COLOR_ARRAY); - checkgl!glVertexPointer(3, GL_FLOAT, 0, cast(void*)_queue._vertices.ptr); - checkgl!glColorPointer(4, GL_FLOAT, 0, cast(void*)_queue._colors.ptr); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, cast(void*)_queue._vertices.ptr); + glColorPointer(4, GL_FLOAT, 0, cast(void*)_queue._colors.ptr); - checkgl!glDrawElements(GL_LINES, cast(int)length, GL_UNSIGNED_INT, cast(void*)(_queue._indices.ptr + start * 4)); + checkgl!glDrawElements(GL_LINES, cast(int)length, GL_UNSIGNED_INT, cast(void*)(_queue._indices[start .. start + length].ptr)); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); - glDisable(GL_ALPHA_TEST); - glDisable(GL_BLEND); } } else { if (_solidFillProgram !is null) { @@ -864,26 +872,18 @@ final class GLSupport { } } - void drawSolidFillTriangles(int length, int start) { - + private void drawSolidFillTriangles(int length, int start) { if (_legacyMode) { static if (SUPPORT_LEGACY_OPENGL) { - glColor4f(1,1,1,1); - glDisable(GL_CULL_FACE); - glEnable(GL_BLEND); - glDisable(GL_ALPHA_TEST); - checkgl!glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - checkgl!glEnableClientState(GL_VERTEX_ARRAY); - checkgl!glEnableClientState(GL_COLOR_ARRAY); - checkgl!glVertexPointer(3, GL_FLOAT, 0, cast(void*)_queue._vertices.ptr); - checkgl!glColorPointer(4, GL_FLOAT, 0, cast(void*)_queue._colors.ptr); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, cast(void*)_queue._vertices.ptr); + glColorPointer(4, GL_FLOAT, 0, cast(void*)_queue._colors.ptr); - checkgl!glDrawElements(GL_TRIANGLES, cast(int)length, GL_UNSIGNED_INT, cast(void*)(_queue._indices.ptr + start * 4)); + checkgl!glDrawElements(GL_TRIANGLES, cast(int)length, GL_UNSIGNED_INT, cast(void*)(_queue._indices[start .. start + length].ptr)); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); - glDisable(GL_ALPHA_TEST); - glDisable(GL_BLEND); } } else { if (_solidFillProgram !is null) { @@ -893,35 +893,25 @@ final class GLSupport { } } - void drawColorAndTextureTriangles(Tex2D texture, bool linear, int length, int start) { - + private void drawColorAndTextureTriangles(Tex2D texture, bool linear, int length, int start) { if (_legacyMode) { static if (SUPPORT_LEGACY_OPENGL) { - glDisable(GL_CULL_FACE); glEnable(GL_TEXTURE_2D); texture.setup(); texture.setSamplerParams(linear); - glColor4f(1,1,1,1); - glDisable(GL_ALPHA_TEST); + glEnableClientState(GL_COLOR_ARRAY); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(3, GL_FLOAT, 0, cast(void*)_queue._vertices.ptr); + glTexCoordPointer(2, GL_FLOAT, 0, cast(void*)_queue._texCoords.ptr); + glColorPointer(4, GL_FLOAT, 0, cast(void*)_queue._colors.ptr); - glEnable(GL_BLEND); - checkgl!glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - checkgl!glEnableClientState(GL_COLOR_ARRAY); - checkgl!glEnableClientState(GL_VERTEX_ARRAY); - checkgl!glEnableClientState(GL_TEXTURE_COORD_ARRAY); - checkgl!glVertexPointer(3, GL_FLOAT, 0, cast(void*)_queue._vertices.ptr); - checkgl!glTexCoordPointer(2, GL_FLOAT, 0, cast(void*)_queue._texCoords.ptr); - checkgl!glColorPointer(4, GL_FLOAT, 0, cast(void*)_queue._colors.ptr); - - checkgl!glDrawElements(GL_TRIANGLES, cast(int)length, GL_UNSIGNED_INT, cast(void*)(_queue._indices.ptr + start * 4)); + checkgl!glDrawElements(GL_TRIANGLES, cast(int)length, GL_UNSIGNED_INT, cast(void*)(_queue._indices[start .. start + length].ptr)); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); - glDisable(GL_BLEND); - glDisable(GL_ALPHA_TEST); glDisable(GL_TEXTURE_2D); } } else { @@ -1459,6 +1449,7 @@ private final class OpenGLQueue { } } //Log.d(batches.length, " ", _vertices.length, " ", _colors.length, " ", _texCoords.length, " ", _indices.length); + glSupport.destroyBuffers(); destroy(batches); destroy(_vertices); destroy(_colors); diff --git a/src/dlangui/graphics/scene/effect.d b/src/dlangui/graphics/scene/effect.d index 039782c5..772bb46a 100644 --- a/src/dlangui/graphics/scene/effect.d +++ b/src/dlangui/graphics/scene/effect.d @@ -18,7 +18,7 @@ class Effect : GLProgram { EffectId _id; string[string] _defs; string _defText; - + @property ref const(EffectId) id() const { return _id; } this(EffectId id) { _id = id; @@ -53,6 +53,7 @@ class Effect : GLProgram { } _defText = buf.dup; // compile shaders + compile(); if (!check()) { Log.e("Failed to compile shaders ", _id.vertexShaderName, " ", _id.fragmentShaderName, " ", _id.definitions); assert(false);