From 0778b77531c84b0fc84c9f7a5c507fc1a309ce79 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Tue, 3 Nov 2015 15:51:49 +0300 Subject: [PATCH] OpenGL: drawLine - use line shader instead of drawing line by points --- dlanguilib.visualdproj | 2 +- examples/d3d/d3d.visualdproj | 6 +- examples/d3d/src/d3d.d | 26 +++++++- src/dlangui/graphics/gldrawbuf.d | 28 +++++++++ src/dlangui/graphics/glsupport.d | 101 ++++++++++++++++++++++++++++++- src/dlangui/widgets/controls.d | 2 +- 6 files changed, 159 insertions(+), 6 deletions(-) diff --git a/dlanguilib.visualdproj b/dlanguilib.visualdproj index db4f5a74..79447cfe 100644 --- a/dlanguilib.visualdproj +++ b/dlanguilib.visualdproj @@ -72,7 +72,7 @@ 0 DebugFocus FontResources 0 - EmbedStandardResources Unicode USE_FREETYPE + Unicode USE_OPENGL USE_FREETYPE EmbedStandardResources 0 0 1 diff --git a/examples/d3d/d3d.visualdproj b/examples/d3d/d3d.visualdproj index 05d50817..e5920820 100644 --- a/examples/d3d/d3d.visualdproj +++ b/examples/d3d/d3d.visualdproj @@ -54,7 +54,7 @@ 1 $(DMDInstallDir)windows\bin\dmd.exe $(SolutionDir)/src $(SolutionDir)/3rdparty $(SolutionDir)/3rdparty/libpng/source $(SolutionDir)/../DerelictGL3/source $(SolutionDir)/../DerelictUtil/source $(SolutionDir)/../DerelictFT/source $(SolutionDir)/../DerelictSDL2/source $(SolutionDir)/../de_image/source/interfaces $(SolutionDir)/../de_image/source/png $(SolutionDir)/../dlib - views views/res views/res/i18n views/res/mdpi + views views/res views/res/i18n views/res/mdpi views/res/hdpi $(ConfigurationName) $(OutDir) @@ -72,7 +72,7 @@ 0 0 - Unicode USE_OPENGL USE_FREETYPE USE_SDL EmbedStandardResources + Unicode USE_OPENGL USE_FREETYPE EmbedStandardResources 0 0 0 @@ -96,6 +96,7 @@ $(OutDir)\$(ProjectName).exe 1 2 + 0 @@ -197,6 +198,7 @@ $(OutDir)\$(ProjectName).exe 1 1 + 0 diff --git a/examples/d3d/src/d3d.d b/examples/d3d/src/d3d.d index 4d3f96a2..9c5ce3d5 100644 --- a/examples/d3d/src/d3d.d +++ b/examples/d3d/src/d3d.d @@ -7,7 +7,7 @@ mixin APP_ENTRY_POINT; /// entry point for dlangui based application extern (C) int UIAppMain(string[] args) { // create window - Window window = Platform.instance.createWindow("DlangUI example - 3D Application", null); + Window window = Platform.instance.createWindow("DlangUI example - 3D Application", null, WindowFlag.Resizable, 600, 500); // create some widget to show in window //window.mainWidget = (new Button()).text("Hello, world!"d).margins(Rect(20,20,20,20)); @@ -43,9 +43,33 @@ extern (C) int UIAppMain(string[] args) { Button { id: btnOk; text: "Ok" } Button { id: btnCancel; text: "Cancel" } } + CanvasWidget { + id: canvas + minWidth: 500 + minHeight: 300 + } } }); + auto canvas = window.mainWidget.childById!CanvasWidget("canvas"); + canvas.onDrawListener = delegate(CanvasWidget canvas, DrawBuf buf, Rect rc) { + Log.w("canvas.onDrawListener clipRect=" ~ to!string(buf.clipRect)); + buf.fill(0xFFFFFF); + int x = rc.left; + int y = rc.top; + buf.fillRect(Rect(x+20, y+20, x+150, y+200), 0x80FF80); + buf.fillRect(Rect(x+90, y+80, x+250, y+250), 0x80FF80FF); + canvas.font.drawText(buf, x + 40, y + 50, "fillRect()"d, 0xC080C0); + buf.drawFrame(Rect(x + 400, y + 30, x + 550, y + 150), 0x204060, Rect(2,3,4,5), 0x80704020); + canvas.font.drawText(buf, x + 400, y + 5, "drawFrame()"d, 0x208020); + canvas.font.drawText(buf, x + 300, y + 100, "drawPixel()"d, 0x000080); + for (int i = 0; i < 80; i++) + buf.drawPixel(x+300 + i * 4, y+140 + i * 3 % 100, 0xFF0000 + i * 2); + canvas.font.drawText(buf, x + 200, y + 150, "drawLine()"d, 0x800020); + for (int i = 0; i < 40; i+=3) + buf.drawLine(Point(x+200 + i * 4, y+190), Point(x+150 + i * 7, y+320 + i * 2), 0x008000 + i * 5); + }; + // show window window.show(); diff --git a/src/dlangui/graphics/gldrawbuf.d b/src/dlangui/graphics/gldrawbuf.d index d2580705..bc173c8e 100644 --- a/src/dlangui/graphics/gldrawbuf.d +++ b/src/dlangui/graphics/gldrawbuf.d @@ -149,6 +149,20 @@ class GLDrawBuf : DrawBuf, GLConfigCallback { } } + /// draw line from point p1 to p2 with specified color + override void drawLine(Point p1, Point p2, uint colour) { + assert(_scene !is null); + if (p1.x < _clipRect.left && p2.x < _clipRect.left) + return; + if (p1.y < _clipRect.top && p2.y < _clipRect.top) + return; + if (p1.x >= _clipRect.right && p2.x >= _clipRect.right) + return; + if (p1.y >= _clipRect.bottom && p2.y >= _clipRect.bottom) + return; + _scene.add(new LineSceneItem(p1, p2, colour)); + } + /// cleanup resources override void clear() { if (_framebuffer) { @@ -856,6 +870,20 @@ private class GLGlyphCache { +class LineSceneItem : SceneItem { + Point _p1; + Point _p2; + uint _color; + this(Point p1, Point p2, uint color) { + _p1 = p1; + _p2 = p2; + _color = color; + } + override void draw() { + glSupport.drawLine(_p1, _p2, _color, _color); + } +} + class SolidRectSceneItem : SceneItem { Rect _rc; diff --git a/src/dlangui/graphics/glsupport.d b/src/dlangui/graphics/glsupport.d index 110da6ae..3c6137a7 100644 --- a/src/dlangui/graphics/glsupport.d +++ b/src/dlangui/graphics/glsupport.d @@ -343,6 +343,67 @@ class SolidFillProgram : GLProgram { } } +class LineProgram : SolidFillProgram { + override bool execute(float[] vertices, float[] colors) { + if (error) + return false; + if (!initialized) + if (!compile()) + return false; + beforeExecute(); + + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + GLuint vbo; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData( + GL_ARRAY_BUFFER, + vertices.length * vertices[0].sizeof + colors.length * colors[0].sizeof, + null, + GL_STREAM_DRAW); + glBufferSubData( + GL_ARRAY_BUFFER, + 0, + vertices.length * vertices[0].sizeof, + vertices.ptr); + glBufferSubData( + GL_ARRAY_BUFFER, + vertices.length * vertices[0].sizeof, + colors.length * colors[0].sizeof, + colors.ptr); + + glEnableVertexAttribArray(vertexLocation); + checkError("glEnableVertexAttribArray"); + glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, cast(void*) 0); + checkError("glVertexAttribPointer"); + + glEnableVertexAttribArray(colAttrLocation); + checkError("glEnableVertexAttribArray"); + glVertexAttribPointer(colAttrLocation, 4, GL_FLOAT, GL_FALSE, 0, cast(void*) (float.sizeof*3*2)); + checkError("glVertexAttribPointer"); + + glDrawArrays(GL_LINES, 0, 2); + checkError("glDrawArrays"); + + glDisableVertexAttribArray(vertexLocation); + checkError("glDisableVertexAttribArray"); + glDisableVertexAttribArray(colAttrLocation); + checkError("glDisableVertexAttribArray"); + + afterExecute(); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glDeleteBuffers(1, &vbo); + + glBindVertexArray(0); + glDeleteVertexArrays(1, &vao); + return true; + } +} + class TextureProgram : SolidFillProgram { @property override string vertexSource() { return q{ @@ -605,10 +666,11 @@ class GLSupport { TextureProgram _textureProgram; SolidFillProgram _solidFillProgram; + LineProgram _lineProgram; FontProgram _fontProgram; @property bool valid() { - return _textureProgram && _solidFillProgram && _fontProgram; + return _textureProgram && _solidFillProgram && _fontProgram && _lineProgram; } bool initShaders() { @@ -618,6 +680,12 @@ class GLSupport { if (!_solidFillProgram.compile()) return false; } + if (_lineProgram is null) { + Log.v("Compiling line program"); + _lineProgram = new LineProgram(); + if (!_lineProgram.compile()) + return false; + } if (_textureProgram is null) { Log.v("Compiling texture program"); _textureProgram = new TextureProgram(); @@ -640,6 +708,10 @@ class GLSupport { destroy(_solidFillProgram); _solidFillProgram = null; } + if (_lineProgram !is null) { + destroy(_lineProgram); + _lineProgram = null; + } if (_textureProgram !is null) { destroy(_textureProgram); _textureProgram = null; @@ -674,6 +746,33 @@ class GLSupport { matrix2.copyDataTo(m); */ } + + void drawLine(Point p1, Point p2, uint color1, uint color2) { + float[2 * 4] colors; + LVGLFillColor(color1, colors.ptr + 4*0, 1); + LVGLFillColor(color2, colors.ptr + 4*1, 1); + float x0 = cast(float)(p1.x); + float y0 = cast(float)(bufferDy-p1.y); + float x1 = cast(float)(p2.x); + float y1 = cast(float)(bufferDy-p2.y); + + // don't flip for framebuffer + if (currentFramebufferId) { + y0 = cast(float)(p1.y); + y1 = cast(float)(p2.y); + } + + float[3 * 2] vertices = [ + x0,y0,Z_2D, + x1,y1,Z_2D + ]; + if (_lineProgram !is null) { + //Log.d("solid fill: vertices ", vertices, " colors ", colors); + _lineProgram.execute(vertices, colors); + } else + Log.e("No program"); + } + static immutable float Z_2D = -2.0f; void drawSolidFillRect(Rect rc, uint color1, uint color2, uint color3, uint color4) { float[6 * 4] colors; diff --git a/src/dlangui/widgets/controls.d b/src/dlangui/widgets/controls.d index f5fd51b4..629c8869 100644 --- a/src/dlangui/widgets/controls.d +++ b/src/dlangui/widgets/controls.d @@ -1057,4 +1057,4 @@ class CanvasWidget : Widget { } import dlangui.widgets.metadata; -mixin(registerWidgets!(Widget, TextWidget, MultilineTextWidget, Button, ImageWidget, ImageButton, ImageTextButton, RadioButton, CheckBox, ScrollBar, HSpacer, VSpacer)()); +mixin(registerWidgets!(Widget, TextWidget, MultilineTextWidget, Button, ImageWidget, ImageButton, ImageTextButton, RadioButton, CheckBox, ScrollBar, HSpacer, VSpacer, CanvasWidget)());