diff --git a/src/dlangui/graphics/gldrawbuf.d b/src/dlangui/graphics/gldrawbuf.d index 50533728..5f38e70c 100644 --- a/src/dlangui/graphics/gldrawbuf.d +++ b/src/dlangui/graphics/gldrawbuf.d @@ -65,7 +65,7 @@ class GLDrawBuf : DrawBuf, GLConfigCallback { glSupport.setOrthoProjection(Rect(0, 0, _dx, _dy), Rect(0, 0, _dx, _dy)); } - /// reserved for hardware-accelerated drawing - begins drawing batch + /// reserved for hardware-accelerated drawing - begins drawing queue override void beforeDrawing() { _alpha = 0; if (_scene !is null) { @@ -74,11 +74,12 @@ class GLDrawBuf : DrawBuf, GLConfigCallback { _scene = new Scene(this); } - /// reserved for hardware-accelerated drawing - ends drawing batch + /// reserved for hardware-accelerated drawing - ends drawing queue override void afterDrawing() { glSupport.setOrthoProjection(Rect(0, 0, _dx, _dy), Rect(0, 0, _dx, _dy)); + glSupport.beforeRenderGUI(); _scene.draw(); - glSupport.batch.flush(); + glSupport.queue.flush(); GLProgram.unbind(); glSupport.destroyBuffers(); glSupport.flushGL(); @@ -142,7 +143,6 @@ class GLDrawBuf : DrawBuf, GLConfigCallback { assert(_scene !is null); Rect dstrect = Rect(x,y, x + glyph.correctedBlackBoxX, y + glyph.blackBoxY); Rect srcrect = Rect(0, 0, glyph.correctedBlackBoxX, glyph.blackBoxY); - //Log.v("GLDrawBuf.drawGlyph dst=", dstrect, " src=", srcrect, " color=", color); color = applyAlpha(color); if (!isFullyTransparentColor(color) && applyClipping(dstrect, srcrect)) { if (!glGlyphCache.isInCache(glyph.id)) @@ -158,7 +158,7 @@ class GLDrawBuf : DrawBuf, GLConfigCallback { if (applyClipping(dstrect, srcrect)) { if (!glImageCache.isInCache(src.id)) glImageCache.put(src); - _scene.add(new TextureSceneItem(src.id, dstrect, srcrect, applyAlpha(0xFFFFFF), 0, null, 0)); + _scene.add(new TextureSceneItem(src.id, dstrect, srcrect, applyAlpha(0xFFFFFF), 0, null)); } } /// draw source buffer rectangle contents to destination buffer rectangle applying rescaling @@ -168,7 +168,7 @@ class GLDrawBuf : DrawBuf, GLConfigCallback { if (applyClipping(dstrect, srcrect)) { if (!glImageCache.isInCache(src.id)) glImageCache.put(src); - _scene.add(new TextureSceneItem(src.id, dstrect, srcrect, applyAlpha(0xFFFFFF), 0, null, 0)); + _scene.add(new TextureSceneItem(src.id, dstrect, srcrect, applyAlpha(0xFFFFFF), 0, null)); } } @@ -545,17 +545,12 @@ private class GLImageCache : GLCache _needUpdateTexture = true; return cacheItem; } - void drawItem(GLCacheItem item, Rect dstrc, Rect srcrc, uint color, uint options, Rect * clip, int rotationAngle) { + void drawItem(GLCacheItem item, Rect dstrc, Rect srcrc, uint color, uint options, Rect * clip) { if (_needUpdateTexture) updateTexture(); if (_texture && _texture.ID != 0) { - //rotationAngle = 0; int rx = dstrc.middlex; int ry = dstrc.middley; - if (rotationAngle) { - //rotationAngle = 0; - //setRotation(rx, ry, rotationAngle); - } // convert coordinates to cached texture srcrc.offset(item._rc.left, item._rc.top); if (clip) { @@ -577,17 +572,7 @@ private class GLImageCache : GLCache dstrc.bottom -= clip.bottom; } if (!dstrc.empty) - glSupport.batch.addTexturedRect(_texture, _tdx, _tdy, color, color, color, color, srcrc, dstrc, srcrc.width() != dstrc.width() || srcrc.height() != dstrc.height()); - //glSupport.drawColorAndTextureRects(_texture, _tdx, _tdy, [srcrc], [dstrc], [color, color, color, color], srcrc.width() != dstrc.width() || srcrc.height() != dstrc.height()); - //drawColorAndTextureRect(vertices, texcoords, color, _texture); - - if (rotationAngle) { - // unset rotation - glSupport.setRotation(rx, ry, 0); - // glMatrixMode(GL_PROJECTION); - // checkgl!glPopMatrix(); - } - + glSupport.queue.addTexturedRect(_texture, _tdx, _tdy, color, color, color, color, srcrc, dstrc, srcrc.width() != dstrc.width() || srcrc.height() != dstrc.height()); } } } @@ -619,11 +604,11 @@ private class GLImageCache : GLCache _map[img.id] = res; } /// draw cached item - void drawItem(uint objectId, Rect dstrc, Rect srcrc, uint color, int options, Rect * clip, int rotationAngle) { + void drawItem(uint objectId, Rect dstrc, Rect srcrc, uint color, int options, Rect * clip) { GLCacheItem* item = objectId in _map; if (item) { auto page = (cast(GLImageCachePage)item.page); - page.drawItem(*item, dstrc, srcrc, color, options, clip, rotationAngle); + page.drawItem(*item, dstrc, srcrc, color, options, clip); } } } @@ -673,9 +658,7 @@ private class GLGlyphCache : GLCache } if (!dstrc.empty) { //Log.d("drawing glyph with color ", color); - //glSupport.drawColorAndTextureRect(_texture, _tdx, _tdy, srcrc, dstrc, color, false); - //glSupport.drawColorAndTextureRects(_texture, _tdx, _tdy, [srcrc], [dstrc], [color, color, color, color], false); - glSupport.batch.addTexturedRect(_texture, _tdx, _tdy, color, color, color, color, srcrc, dstrc, false); + glSupport.queue.addTexturedRect(_texture, _tdx, _tdy, color, color, color, color, srcrc, dstrc, false); } } } @@ -723,8 +706,7 @@ public: _color = color; } override void draw() { - //glSupport.drawLines([Rect(_p1, _p2)], [_color, _color]); - glSupport.batch.addLine(Rect(_p1, _p2), _color, _color); + glSupport.queue.addLine(Rect(_p1, _p2), _color, _color); } } @@ -743,7 +725,7 @@ public: _color = color; } override void draw() { - glSupport.batch.addTriangle(_p1, _p2, _p3, _color, _color, _color); + glSupport.queue.addTriangle(_p1, _p2, _p3, _color, _color, _color); } } @@ -758,8 +740,7 @@ public: _color = color; } override void draw() { - glSupport.batch.addSolidRect(_rc, _color); - //glSupport.drawSolidFillRects([_rc], [_color, _color, _color, _color]); + glSupport.queue.addSolidRect(_rc, _color); } } @@ -781,9 +762,7 @@ public: for (int y = _rc.top; y < _rc.bottom; y++) { for (int x = _rc.left; x < _rc.right; x++) if ((x ^ y) & 1) { - //glSupport.drawSolidFillRect(Rect(x, y, x + 1, y + 1), _color, _color, _color, _color); - //glSupport.drawSolidFillRects([Rect(x, y, x + 1, y + 1)], [_color, _color, _color, _color]); - glSupport.batch.addSolidRect(Rect(x, y, x + 1, y + 1), _color); + glSupport.queue.addSolidRect(Rect(x, y, x + 1, y + 1), _color); } } } @@ -798,15 +777,14 @@ private: uint color; uint options; Rect * clip; - int rotationAngle; public: override void draw() { if (glImageCache) - glImageCache.drawItem(objectId, dstrc, srcrc, color, options, clip, rotationAngle); + glImageCache.drawItem(objectId, dstrc, srcrc, color, options, clip); } - this(uint _objectId, Rect _dstrc, Rect _srcrc, uint _color, uint _options, Rect * _clip, int _rotationAngle) + this(uint _objectId, Rect _dstrc, Rect _srcrc, uint _color, uint _options, Rect * _clip) { objectId = _objectId; dstrc = _dstrc; @@ -814,7 +792,6 @@ public: color = _color; options = _options; clip = _clip; - rotationAngle = _rotationAngle; } } @@ -856,13 +833,12 @@ public: } override void draw() { if (_handler) { - glSupport.batch.flush(); + 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.batch.flush(); glSupport.setOrthoProjection(_windowRect, _windowRect); } } diff --git a/src/dlangui/graphics/glsupport.d b/src/dlangui/graphics/glsupport.d index def452b1..24b089d3 100644 --- a/src/dlangui/graphics/glsupport.d +++ b/src/dlangui/graphics/glsupport.d @@ -38,7 +38,7 @@ version (Android) { public import EGL.egl; //public import GLES2.gl2; public import GLES3.gl3; - + static if (SUPPORT_LEGACY_OPENGL) { public import GLES.gl : glEnableClientState, glLightfv, glColor4f, GL_ALPHA_TEST, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, glVertexPointer, glColorPointer, glDisableClientState, @@ -268,7 +268,7 @@ class GLProgram : dlangui.graphics.scene.mesh.GraphicsEffect { /// override to init shader code locations abstract bool initLocations(); - + ~this() { // TODO: cleanup if (program) @@ -499,88 +499,50 @@ class SolidFillProgram : GLProgram { } VAO vao; - VBO vbo; - EBO ebo; - protected void createVAO(float[] vertices, float[] colors) { - if (!vao) { - vao = new VAO; - vbo = new VBO; - ebo = new EBO; - } - vbo.bind(); - ebo.bind(); - vao.bind(); + protected void beforeExecute() { + bind(); + setUniform(DefaultUniform.u_worldViewProjectionMatrix, glSupport.projectionMatrix); + } + + protected void createVAO(size_t verticesBufferLength) { + 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 * float.sizeof)); + glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, cast(void*) (verticesBufferLength * float.sizeof)); glEnableVertexAttribArray(vertexLocation); glEnableVertexAttribArray(colAttrLocation); } - protected void beforeExecute() { - glEnable(GL_BLEND); - checkgl!glDisable(GL_CULL_FACE); - checkgl!glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - bind(); - setUniform(DefaultUniform.u_worldViewProjectionMatrix, glSupport.projectionMatrix); - //checkgl!glUniformMatrix4fv(matrixLocation, 1, false, glSupport.projectionMatrix.m.ptr); - } - - bool execute(float[] vertices, float[] colors, int[] indexes) { + bool drawBatch(int length, int start) { if(!check()) return false; beforeExecute(); - createVAO(vertices, colors); - - vbo.bind(); - vbo.fill([vertices, colors]); - - ebo.bind(); - ebo.fill(indexes); - vao.bind(); - checkgl!glDrawElements(GL_TRIANGLES, cast(int)indexes.length, GL_UNSIGNED_INT, cast(void*)null); - vao.unbind(); - vbo.unbind(); - ebo.unbind(); + checkgl!glDrawElements(GL_TRIANGLES, cast(int)length, GL_UNSIGNED_INT, cast(void*)(start * 4)); return true; } void destroyBuffers() { destroy(vao); - destroy(vbo); - destroy(ebo); vao = null; - vbo = null; - ebo = null; } } class LineProgram : SolidFillProgram { - override bool execute(float[] vertices, float[] colors, int[] indexes) { + override bool drawBatch(int length, int start) { if(!check()) return false; beforeExecute(); - createVAO(vertices, colors); - - vbo.bind(); - vbo.fill([vertices, colors]); - - ebo.bind(); - ebo.fill(indexes); - vao.bind(); - checkgl!glDrawElements(GL_LINES, cast(int)indexes.length, GL_UNSIGNED_INT, cast(void*)null); - vao.unbind(); - vbo.unbind(); - ebo.unbind(); + checkgl!glDrawElements(GL_LINES, cast(int)length, GL_UNSIGNED_INT, cast(void*)(start * 4)); + return true; } } @@ -624,33 +586,26 @@ class TextureProgram : SolidFillProgram { /// get location for vertex attribute override int getVertexElementLocation(VertexElementType type) { switch(type) with(VertexElementType) { - case TEXCOORD0: + case TEXCOORD0: return texCoordLocation; default: return super.getVertexElementLocation(type); } } - protected void createVAO(float[] vertices, float[] colors, float[] texcoords) { - if (!vao) { - vao = new VAO; - vbo = new VBO; - ebo = new EBO; - } - vbo.bind(); - ebo.bind(); - vao.bind(); + protected void createVAO(size_t verticesBufferLength, size_t colorsBufferLength) { + 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 * float.sizeof)); - glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, cast(void*) ((vertices.length + colors.length) * float.sizeof)); + glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, cast(void*) (verticesBufferLength * float.sizeof)); + glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, cast(void*) ((verticesBufferLength + colorsBufferLength) * float.sizeof)); glEnableVertexAttribArray(vertexLocation); glEnableVertexAttribArray(colAttrLocation); glEnableVertexAttribArray(texCoordLocation); } - bool execute(float[] vertices, float[] colors, float[] texcoords, Tex2D texture, bool linear, int[] indexes) { + bool drawBatch(Tex2D texture, bool linear, int length, int start) { if(!check()) return false; beforeExecute(); @@ -658,21 +613,9 @@ class TextureProgram : SolidFillProgram { texture.setup(); texture.setSamplerParams(linear); - createVAO(vertices, colors, texcoords); - - vbo.bind(); - vbo.fill([vertices, colors, texcoords]); - - ebo.bind(); - ebo.fill(indexes); - vao.bind(); - checkgl!glDrawElements(GL_TRIANGLES, cast(int)indexes.length, GL_UNSIGNED_INT, cast(void*)null); - - vao.unbind(); - vbo.unbind(); - ebo.unbind(); + checkgl!glDrawElements(GL_TRIANGLES, cast(int)length, GL_UNSIGNED_INT, cast(void*)(start * 4)); texture.unbind(); return true; @@ -699,6 +642,24 @@ private void FillColor(uint color, Color[] buf_slice) { } } +private float[] convertColors(uint[] cols) { + float[] colors; + colors.assumeSafeAppend(); + colors.length = cols.length * 4; + for (uint i = 0; i < cols.length; i++) { + uint color = cols[i]; + float r = ((color >> 16) & 255) / 255.0; + float g = ((color >> 8) & 255) / 255.0; + float b = ((color >> 0) & 255) / 255.0; + float a = (((color >> 24) & 255) ^ 255) / 255.0; + colors[i * 4 + 0] = r; + colors[i * 4 + 1] = g; + colors[i * 4 + 2] = b; + colors[i * 4 + 3] = a; + } + return colors; +} + __gshared GLSupport _glSupport; @property GLSupport glSupport() { if (!_glSupport) { @@ -794,10 +755,10 @@ final class GLSupport { private bool _legacyMode; @property bool legacyMode() { return _legacyMode; } - @property batch() { return _batch; } + @property queue() { return _queue; } this(bool legacy = false) { - _batch = new OpenGLBatch(); + _queue = new OpenGLQueue; version (Android) { Log.d("creating GLSupport"); } else { @@ -809,7 +770,7 @@ final class GLSupport { _legacyMode = legacy; } - OpenGLBatch _batch; + OpenGLQueue _queue; SolidFillProgram _solidFillProgram; LineProgram _lineProgram; @@ -860,67 +821,48 @@ final class GLSupport { return true; } + void beforeRenderGUI() { + glEnable(GL_BLEND); + checkgl!glDisable(GL_CULL_FACE); + checkgl!glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + VBO vbo; + EBO ebo; + + void fillBuffers(float[] vertices, float[] colors, float[] texcoords, int[] indices) { + vbo = new VBO; + ebo = new EBO; + + vbo.bind(); + vbo.fill([vertices, colors, texcoords]); + + ebo.bind(); + ebo.fill(indices); + + // create vertex array objects and bind vertex buffers to them + _solidFillProgram.createVAO(vertices.length); + vbo.bind(); + ebo.bind(); + _lineProgram.vao = _solidFillProgram.vao; + _textureProgram.createVAO(vertices.length, colors.length); + vbo.bind(); + ebo.bind(); + } + void destroyBuffers() { if (_solidFillProgram) _solidFillProgram.destroyBuffers(); - if (_lineProgram) - _lineProgram.destroyBuffers(); if (_textureProgram) _textureProgram.destroyBuffers(); + + destroy(vbo); + destroy(ebo); + vbo = null; + ebo = null; } - void setRotation(int x, int y, int rotationAngle) { - /* - this->rotationAngle = rotationAngle; - rotationX = x; - rotationY = y; - if (!currentFramebufferId) { - rotationY = bufferDy - rotationY; - } - - QMatrix4x4 matrix2; - matrix2.ortho(0, bufferDx, 0, bufferDy, 0.5f, 5.0f); - if (rotationAngle) { - matrix2.translate(rotationX, rotationY, 0); - matrix2.rotate(rotationAngle, 0, 0, 1); - matrix2.translate(-rotationX, -rotationY, 0); - } - matrix2.copyDataTo(m); - */ - } - - /// one rect is one line (left, top) - (right, bottom); for one line there are two color items - void drawLines(Rect[] lines, uint[] vertexColors) { - Color[] colors; - colors.length = vertexColors.length; - for (uint i = 0; i < vertexColors.length; i++) - FillColor(vertexColors[i], colors[i .. i + 1]); - - float[] vertexArray; - vertexArray.assumeSafeAppend(); - for (uint i = 0; i < lines.length; i++) { - Rect rc = lines[i]; - - float x0 = cast(float)(rc.left); - float y0 = cast(float)(bufferDy-rc.top); - float x1 = cast(float)(rc.right); - float y1 = cast(float)(bufferDy-rc.bottom); - - // don't flip for framebuffer - if (currentFBO) { - y0 = cast(float)(rc.top); - y1 = cast(float)(rc.bottom); - } - - vertexArray ~= x0; - vertexArray ~= y0; - vertexArray ~= Z_2D; - vertexArray ~= x1; - vertexArray ~= y1; - vertexArray ~= Z_2D; - } - - int[] indexes = makeLineIndexesArray(lines.length); + void drawLines(int length, int start) { if (_legacyMode) { static if (SUPPORT_LEGACY_OPENGL) { @@ -931,10 +873,10 @@ final class GLSupport { 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*)vertexArray.ptr); - checkgl!glColorPointer(4, GL_FLOAT, 0, cast(void*)colors.ptr); + checkgl!glVertexPointer(3, GL_FLOAT, 0, cast(void*)_queue._vertices.ptr); + checkgl!glColorPointer(4, GL_FLOAT, 0, cast(void*)_queue._colors.ptr); - checkgl!glDrawElements(GL_LINES, cast(int)indexes.length, GL_UNSIGNED_INT, cast(void*)indexes.ptr); + checkgl!glDrawElements(GL_LINES, cast(int)length, GL_UNSIGNED_INT, cast(void*)(_queue._indices.ptr + start * 4)); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); @@ -943,83 +885,13 @@ final class GLSupport { } } else { if (_lineProgram !is null) { - _lineProgram.execute(vertexArray, cast(float[])colors, indexes); + _lineProgram.drawBatch(length, start); } else Log.e("No program"); } } - static immutable float Z_2D = -2.0f; - - /// make indexes for rectangle TRIANGLES (2 triangles == 6 vertexes per rect) - protected int[] makeRectangleIndexesArray(size_t rectCount) { - int[] indexes; - indexes.assumeSafeAppend(); - for (uint i = 0; i < rectCount; i++) { - indexes ~= i * 4 + 0; - indexes ~= i * 4 + 1; - indexes ~= i * 4 + 2; - indexes ~= i * 4 + 1; - indexes ~= i * 4 + 2; - indexes ~= i * 4 + 3; - } - return indexes; - } - - /// make indexes for rectangle TRIANGLES (2 triangles == 6 vertexes per rect) - protected int[] makeTriangleIndexesArray(size_t pointCount) { - int[] indexes; - indexes.assumeSafeAppend(); - for (uint i = 0; i + 2 < pointCount; i += 3) { - indexes ~= i + 0; - indexes ~= i + 1; - indexes ~= i + 2; - } - return indexes; - } - - /// make indexes for LINES - protected int[] makeLineIndexesArray(size_t lineCount) { - int[] indexes; - indexes.assumeSafeAppend(); - for (uint i = 0; i < lineCount; i++) { - indexes ~= i * 2 + 0; - indexes ~= i * 2 + 1; - } - return indexes; - } - - void drawSolidFillRects(Rect[] rects, uint[] vertexColors) { - //Log.v("drawSolidFillRects rects:", rects.length, " colors:", vertexColors.length); - float[] colors = convertColors(vertexColors); - - float[] vertexArray; - vertexArray.assumeSafeAppend(); - - for (uint i = 0; i < rects.length; i++) { - Rect rc = rects[i]; - - float x0 = cast(float)(rc.left); - float y0 = cast(float)(bufferDy-rc.top); - float x1 = cast(float)(rc.right); - float y1 = cast(float)(bufferDy-rc.bottom); - - // don't flip for framebuffer - if (currentFBO) { - y0 = cast(float)(rc.top); - y1 = cast(float)(rc.bottom); - } - - float[3 * 4] vertices = [ - x0,y0,Z_2D, - x0,y1,Z_2D, - x1,y0,Z_2D, - x1,y1,Z_2D]; - - vertexArray ~= vertices; - } - - int[] indexes = makeRectangleIndexesArray(rects.length); + void drawSolidFillTriangles(int length, int start) { if (_legacyMode) { static if (SUPPORT_LEGACY_OPENGL) { @@ -1030,10 +902,10 @@ final class GLSupport { 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*)vertexArray.ptr); - checkgl!glColorPointer(4, GL_FLOAT, 0, cast(void*)colors.ptr); + checkgl!glVertexPointer(3, GL_FLOAT, 0, cast(void*)_queue._vertices.ptr); + checkgl!glColorPointer(4, GL_FLOAT, 0, cast(void*)_queue._colors.ptr); - checkgl!glDrawElements(GL_TRIANGLES, cast(int)indexes.length, GL_UNSIGNED_INT, cast(void*)indexes.ptr); + checkgl!glDrawElements(GL_TRIANGLES, cast(int)length, GL_UNSIGNED_INT, cast(void*)(_queue._indices.ptr + start * 4)); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); @@ -1042,121 +914,13 @@ final class GLSupport { } } else { if (_solidFillProgram !is null) { - _solidFillProgram.execute(vertexArray, colors, indexes); + _solidFillProgram.drawBatch(length, start); } else Log.e("No program"); } } - void drawSolidFillTriangles(PointF[] points, uint[] vertexColors) { - //Log.v("drawSolidFillRects rects:", rects.length, " colors:", vertexColors.length); - float[] colors = convertColors(vertexColors); - - float[] vertexArray; - vertexArray.assumeSafeAppend(); - - for (uint i = 0; i + 2 < points.length; i += 3) { - float x0 = points[i+0].x; - float y0 = currentFBO ? points[i+0].y : (bufferDy - points[i+0].y); - float x1 = points[i+1].x; - float y1 = currentFBO ? points[i+1].y : (bufferDy - points[i+1].y); - float x2 = points[i+2].x; - float y2 = currentFBO ? points[i+2].y : (bufferDy - points[i+2].y); - - float[3 * 3] vertices = [ - x0,y0,Z_2D, - x1,y1,Z_2D, - x2,y2,Z_2D]; - - vertexArray ~= vertices; - } - - int[] indexes = makeTriangleIndexesArray(points.length); - - 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*)vertexArray.ptr); - checkgl!glColorPointer(4, GL_FLOAT, 0, cast(void*)colors.ptr); - - checkgl!glDrawElements(GL_TRIANGLES, cast(int)indexes.length, GL_UNSIGNED_INT, cast(void*)indexes.ptr); - - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - glDisable(GL_ALPHA_TEST); - glDisable(GL_BLEND); - } - } else { - if (_solidFillProgram !is null) { - _solidFillProgram.execute(vertexArray, colors, indexes); - } else - Log.e("No program"); - } - } - - float[] convertColors(uint[] cols) { - float[] colors; - colors.assumeSafeAppend(); - colors.length = cols.length * 4; - for (uint i = 0; i < cols.length; i++) { - uint color = cols[i]; - float r = ((color >> 16) & 255) / 255.0; - float g = ((color >> 8) & 255) / 255.0; - float b = ((color >> 0) & 255) / 255.0; - float a = (((color >> 24) & 255) ^ 255) / 255.0; - colors[i * 4 + 0] = r; - colors[i * 4 + 1] = g; - colors[i * 4 + 2] = b; - colors[i * 4 + 3] = a; - } - return colors; - } - - void drawColorAndTextureRects(Tex2D texture, int tdx, int tdy, Rect[] srcRects, Rect[] dstRects, uint[] vertexColors, bool linear) { - float[] colors = convertColors(vertexColors); - - float[] vertexArray; - vertexArray.assumeSafeAppend(); - float[] txcoordArray; - txcoordArray.assumeSafeAppend(); - - for (uint i = 0; i < srcRects.length; i++) { - Rect srcrc = srcRects[i]; - Rect dstrc = dstRects[i]; - - float dstx0 = cast(float)dstrc.left; - float dsty0 = cast(float)(bufferDy - (dstrc.top)); - float dstx1 = cast(float)dstrc.right; - float dsty1 = cast(float)(bufferDy - (dstrc.bottom)); - - // don't flip for framebuffer - if (currentFBO) { - dsty0 = cast(float)(dstrc.top); - dsty1 = cast(float)(dstrc.bottom); - } - - float srcx0 = srcrc.left / cast(float)tdx; - float srcy0 = srcrc.top / cast(float)tdy; - float srcx1 = srcrc.right / cast(float)tdx; - float srcy1 = srcrc.bottom / cast(float)tdy; - float[3 * 4] vertices = [ - dstx0,dsty0,Z_2D, - dstx0,dsty1,Z_2D, - dstx1,dsty0,Z_2D, - dstx1,dsty1,Z_2D]; - float[2 * 4] texcoords = [srcx0,srcy0, srcx0,srcy1, srcx1,srcy0, srcx1,srcy1]; - vertexArray ~= vertices; - txcoordArray ~= texcoords; - } - - int[] indexes = makeRectangleIndexesArray(srcRects.length); - //Log.v("drawColorAndTextureRects srcrects:", srcRects.length, " dstrects:", dstRects.length, " colors:", vertexColors.length, " indexes: ", indexes); + void drawColorAndTextureTriangles(Tex2D texture, bool linear, int length, int start) { if (_legacyMode) { static if (SUPPORT_LEGACY_OPENGL) { @@ -1174,11 +938,11 @@ final class GLSupport { checkgl!glEnableClientState(GL_COLOR_ARRAY); checkgl!glEnableClientState(GL_VERTEX_ARRAY); checkgl!glEnableClientState(GL_TEXTURE_COORD_ARRAY); - checkgl!glVertexPointer(3, GL_FLOAT, 0, cast(void*)vertexArray.ptr); - checkgl!glTexCoordPointer(2, GL_FLOAT, 0, cast(void*)txcoordArray.ptr); - checkgl!glColorPointer(4, GL_FLOAT, 0, cast(void*)colors.ptr); + 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)indexes.length, GL_UNSIGNED_INT, cast(void*)indexes.ptr); + checkgl!glDrawElements(GL_TRIANGLES, cast(int)length, GL_UNSIGNED_INT, cast(void*)(_queue._indices.ptr + start * 4)); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); @@ -1188,7 +952,7 @@ final class GLSupport { glDisable(GL_TEXTURE_2D); } } else { - _textureProgram.execute(vertexArray, colors, txcoordArray, texture, linear, indexes); + _textureProgram.drawBatch(texture, linear, length, start); } } @@ -1412,7 +1176,7 @@ class GLObject(GLObjectTypes type, GLuint target = 0) { else mixin("checkgl!glBind" ~ to!string(type) ~ "(0);"); } - + static if(type == GLObjectTypes.Buffer) { void fill(float[][] buffs) { @@ -1422,7 +1186,7 @@ class GLObject(GLObjectTypes type, GLuint target = 0) { checkgl!glBufferData(target, length * float.sizeof, null, - GL_STREAM_DRAW); + GL_STATIC_DRAW); int offset; foreach(b; buffs) { checkgl!glBufferSubData(target, @@ -1435,7 +1199,7 @@ class GLObject(GLObjectTypes type, GLuint target = 0) { static if (target == GL_ELEMENT_ARRAY_BUFFER) { void fill(int[] indexes) { - checkgl!glBufferData(target, cast(int)(indexes.length * int.sizeof), indexes.ptr, GL_STREAM_DRAW); + checkgl!glBufferData(target, cast(int)(indexes.length * int.sizeof), indexes.ptr, GL_STATIC_DRAW); } } } @@ -1678,95 +1442,234 @@ GLenum primitiveTypeToGL(PrimitiveType type) { } -/// OpenGL batch buffer - to draw several triangles in single OpenGL call -class OpenGLBatch { - private Tex2D _currentTexture; - private int _currentTextureDx; - private int _currentTextureDy; - private bool _currentTextureLinear; - private Rect[] _srcRects; - private Rect[] _dstRects; - private uint[] _colors; - /// clear buffers - void reset() { - _colors.length = 0; - _colors.assumeSafeAppend(); - _srcRects.length = 0; - _srcRects.assumeSafeAppend(); - _dstRects.length = 0; - _dstRects.assumeSafeAppend(); - _currentTexture = null; - _currentTextureDx = 0; - _currentTextureDy = 0; - _currentTextureLinear = false; + +/// OpenGL GUI rendering queue. It collects gui draw calls, fills a big buffer for vertex data and draws everything +private final class OpenGLQueue { + + OpenGLBatch[] batches; + + /// OpenGL batch structure - to draw several triangles in single OpenGL call + private struct OpenGLBatch { + + enum BatchType { Line = 0, Rect, Triangle, TexturedRect } + BatchType type; + Tex2D texture; + int textureDx; + int textureDy; + bool textureLinear; + + // length of batch in indices + int length; + // offset in index buffer + int start; } - /// draw buffered items + + // a big buffer + float[] _vertices; + float[] _colors; + float[] _texCoords; + int[] _indices; + + + /// draw all void flush() { - if (_dstRects.length == 0) - return; // nothing to draw - if (_currentTexture) { - // draw with texture - //Log.v("flush ", _dstRects.length, " texture rectangles"); - glSupport.drawColorAndTextureRects(_currentTexture, _currentTextureDx, _currentTextureDy, _srcRects, _dstRects, _colors, _currentTextureLinear); - } else { - // draw solid fill - //Log.v("flush ", _dstRects.length, " solid rectangles"); - glSupport.drawSolidFillRects(_dstRects, _colors); + glSupport.fillBuffers(_vertices, _colors, _texCoords, _indices); + foreach(b; batches) { + switch(b.type) with(OpenGLBatch.BatchType) + { + case Line: glSupport.drawLines(b.length, b.start); break; + case Rect: glSupport.drawSolidFillTriangles(b.length, b.start); break; + case Triangle: glSupport.drawSolidFillTriangles(b.length, b.start); break; + case TexturedRect: glSupport.drawColorAndTextureTriangles(b.texture, b.textureLinear, b.length, b.start); break; + default: break; + } } - reset(); + //Log.d(batches.length, " ", _vertices.length, " ", _colors.length, " ", _texCoords.length, " ", _indices.length); + destroy(batches); + destroy(_vertices); + destroy(_colors); + destroy(_texCoords); + destroy(_indices); + batches = null; + _vertices = null; + _colors = null; + _texCoords = null; + _indices = null; } - /// add textured rect - void addTexturedRect(Tex2D texture, int textureDx, int textureDy, uint color1, uint color2, uint color3, uint color4, Rect srcRect, Rect dstRect, bool linear) { - if (!_currentTexture - || _currentTexture.ID != texture.ID - || _currentTextureLinear != linear - //|| (textureDx != _currentTextureDx) - //|| (textureDy != _currentTextureDy) - //|| true - ) + + static immutable float Z_2D = -2.0f; + + /// add textured rectangle to queue + void addTexturedRect(Tex2D texture, int textureDx, int textureDy, uint color1, uint color2, uint color3, uint color4, Rect srcrc, Rect dstrc, bool linear) { + if (batches is null + || batches[$-1].type != OpenGLBatch.BatchType.TexturedRect + || batches[$-1].texture.ID != texture.ID + || batches[$-1].textureLinear != linear) { - flush(); - _currentTexture = texture; - _currentTextureDx = textureDx; - _currentTextureDy = textureDy; - _currentTextureLinear = linear; + batches ~= OpenGLBatch(); + batches[$-1].type = OpenGLBatch.BatchType.TexturedRect; + batches[$-1].texture = texture; + batches[$-1].textureDx = textureDx; + batches[$-1].textureDy = textureDy; + batches[$-1].textureLinear = linear; + if(batches.length > 1) + batches[$-1].start = batches[$-2].start + batches[$-2].length; } - if (_currentTexture) { - _srcRects ~= srcRect; - } - _dstRects ~= dstRect; - _colors ~= color1; - _colors ~= color2; - _colors ~= color3; - _colors ~= color4; + + float[] colors = convertColors([color1, color2, color3, color4]); + + float dstx0 = cast(float)dstrc.left; + float dsty0 = cast(float)(glSupport.currentFBO ? dstrc.top : (glSupport.bufferDy - dstrc.top)); + float dstx1 = cast(float)dstrc.right; + float dsty1 = cast(float)(glSupport.currentFBO ? dstrc.bottom : (glSupport.bufferDy - dstrc.bottom)); + + float srcx0 = srcrc.left / cast(float)textureDx; + float srcy0 = srcrc.top / cast(float)textureDy; + float srcx1 = srcrc.right / cast(float)textureDx; + float srcy1 = srcrc.bottom / cast(float)textureDy; + + float[3 * 4] vertices = [ + dstx0,dsty0,Z_2D, + dstx0,dsty1,Z_2D, + dstx1,dsty0,Z_2D, + dstx1,dsty1,Z_2D ]; + + float[2 * 4] texCoords = [srcx0,srcy0, srcx0,srcy1, srcx1,srcy0, srcx1,srcy1]; + + int[] indices = makeRectangleIndicesArray(cast(int)_vertices.length / 3); + + mixin(calcLengthAndAppendAllToBuffer); } - /// add solid rect + + /// add solid rectangle to queue void addSolidRect(Rect dstRect, uint color) { addGradientRect(dstRect, color, color, color, color); } - /// add gradient rect - void addGradientRect(Rect dstRect, uint color1, uint color2, uint color3, uint color4) { - if (_currentTexture) - flush(); - _dstRects ~= dstRect; - _colors ~= color1; - _colors ~= color2; - _colors ~= color3; - _colors ~= color4; + /// add gradient rectangle to queue + void addGradientRect(Rect rc, uint color1, uint color2, uint color3, uint color4) { + if (batches is null || batches[$-1].type != OpenGLBatch.BatchType.Rect) { + batches ~= OpenGLBatch(); + batches[$-1].type = OpenGLBatch.BatchType.Rect; + if(batches.length > 1) + batches[$-1].start = batches[$-2].start + batches[$-2].length; + } + + float[] colors = convertColors([color1, color2, color3, color4]); + + float x0 = cast(float)(rc.left); + float y0 = cast(float)(glSupport.currentFBO ? rc.top : (glSupport.bufferDy - rc.top)); + float x1 = cast(float)(rc.right); + float y1 = cast(float)(glSupport.currentFBO ? rc.bottom : (glSupport.bufferDy - rc.bottom)); + + float[3 * 4] vertices = [ + x0,y0,Z_2D, + x0,y1,Z_2D, + x1,y0,Z_2D, + x1,y1,Z_2D ]; + // fill texture coords buffer with zeros + float[2 * 4] texCoords = 0; + + int[] indices = makeRectangleIndicesArray(cast(int)_vertices.length / 3); + + mixin(calcLengthAndAppendAllToBuffer); } + /// add triangle to queue void addTriangle(PointF p1, PointF p2, PointF p3, uint color1, uint color2, uint color3) { - flush(); - // TODO: batch triangles - glSupport.drawSolidFillTriangles([p1, p2, p3], [color1, color2, color3]); + if (batches is null || batches[$-1].type != OpenGLBatch.BatchType.Triangle) { + batches ~= OpenGLBatch(); + batches[$-1].type = OpenGLBatch.BatchType.Triangle; + if(batches.length > 1) + batches[$-1].start = batches[$-2].start + batches[$-2].length; + } + + float[] colors = convertColors([color1, color2, color3]); + + float x0 = p1.x; + float y0 = glSupport.currentFBO ? p1.y : (glSupport.bufferDy - p1.y); + float x1 = p2.x; + float y1 = glSupport.currentFBO ? p2.y : (glSupport.bufferDy - p2.y); + float x2 = p3.x; + float y2 = glSupport.currentFBO ? p3.y : (glSupport.bufferDy - p3.y); + + float[3 * 3] vertices = [ + x0,y0,Z_2D, + x1,y1,Z_2D, + x2,y2,Z_2D ]; + // fill texture coords buffer with zeros + float[2 * 3] texCoords = 0; + + int[] indices = makeTriangleIndicesArray(cast(int)_vertices.length / 3); + + mixin(calcLengthAndAppendAllToBuffer); } - /// add gradient rect - void addLine(Rect dstRect, uint color1, uint color2) { - flush(); - // TODO: batch lines, too - glSupport.drawLines([dstRect], [color1, color2]); + /// add line to queue + /// rc is a line (left, top) - (right, bottom) + void addLine(Rect rc, uint color1, uint color2) { + if (batches is null || batches[$-1].type != OpenGLBatch.BatchType.Line) { + batches ~= OpenGLBatch(); + batches[$-1].type = OpenGLBatch.BatchType.Line; + if(batches.length > 1) + batches[$-1].start = batches[$-2].start + batches[$-2].length; + } + + float[] colors = convertColors([color1, color2]); + + float x0 = cast(float)(rc.left); + float y0 = cast(float)(glSupport.currentFBO ? rc.top : (glSupport.bufferDy - rc.top)); + float x1 = cast(float)(rc.right); + float y1 = cast(float)(glSupport.currentFBO ? rc.bottom : (glSupport.bufferDy - rc.bottom)); + + float[3 * 2] vertices = [ + x0, y0, Z_2D, + x1, y1, Z_2D ]; + // fill texture coords buffer with zeros + float[2 * 2] texCoords = 0; + + int[] indices = makeLineIndicesArray(cast(int)_vertices.length / 3); + + mixin(calcLengthAndAppendAllToBuffer); + } + + enum calcLengthAndAppendAllToBuffer = q{ + batches[$-1].length += cast(int)indices.length; + + _vertices ~= vertices; + _colors ~= colors; + _texCoords ~= texCoords; + _indices ~= indices; + }; + + /// make indices for rectangle (2 triangles == 6 vertexes per rect) + int[6] makeRectangleIndicesArray(int offset) { + int[6] indices; + indices[0] = offset + 0; + indices[1] = offset + 1; + indices[2] = offset + 2; + indices[3] = offset + 1; + indices[4] = offset + 2; + indices[5] = offset + 3; + + return indices; + } + + /// make indices for triangles + int[3] makeTriangleIndicesArray(int offset) { + int[3] indices; + indices[0] = offset + 0; + indices[1] = offset + 1; + indices[2] = offset + 2; + return indices; + } + + /// make indices for lines + int[2] makeLineIndicesArray(int offset) { + int[2] indices; + indices[0] = offset + 0; + indices[1] = offset + 1; + + return indices; } } -