From e715c52d0b56d5d22ff7b28b22afcfc8ea1bd353 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Mon, 7 Nov 2016 10:01:19 +0300 Subject: [PATCH] line, polyLine with width - implementation for OpenGL --- examples/example1/src/example1.d | 24 +++++++++++ src/dlangui/core/math3d.d | 5 ++- src/dlangui/graphics/drawbuf.d | 49 ++++++++++++++++++++++ src/dlangui/graphics/gldrawbuf.d | 29 +++++++++++++ src/dlangui/graphics/glsupport.d | 71 ++++++++++++++++++++++++++++++++ 5 files changed, 177 insertions(+), 1 deletion(-) diff --git a/examples/example1/src/example1.d b/examples/example1/src/example1.d index b511c042..9aaf7799 100644 --- a/examples/example1/src/example1.d +++ b/examples/example1/src/example1.d @@ -189,9 +189,31 @@ enum : int { ACTION_FILE_EXIT, } +debug(SDLSettings) { + import dlangui.core.settings; + void testSDL(string fn) { + Log.d("Loading SDL from ", fn); + Setting s = new Setting(); + if (s.load(fn)) { + Log.d("JSON:\n", s.toJSON(true)); + } else { + Log.e("failed to read SDL from ", fn); + } + } + void testSDLSettings() { + testSDL(`C:\Users\vlopatin\AppData\Roaming\.dlangide\settings.json`); + testSDL("dub.json"); + testSDL("test1.sdl"); + } +} + /// entry point for dlangui based application extern (C) int UIAppMain(string[] args) { + debug(SDLSettings) { + testSDLSettings(); + } + // always use trace, even for release builds //Log.setLogLevel(LogLevel.Trace); //Log.setFileLogger(new std.stdio.File("ui.log", "w")); @@ -1069,6 +1091,8 @@ void main() canvas.font.drawText(buf, x + 200, y + 250, "drawLine()"d, 0x800020); for (int i = 0; i < 40; i+=3) buf.drawLine(Point(x+200 + i * 4, y+290), Point(x+150 + i * 7, y+420 + i * 2), 0x008000 + i * 5); + PointF[] poly = [vec2(130, 150), vec2(240, 110), vec2(270, 170), vec2(300, 290), vec2(220, 400), vec2(180, 330)]; + buf.polyLineF(poly, 3.5f, 0x804020, true); }; tabs.addTab(canvas, "TAB_CANVAS"c); diff --git a/src/dlangui/core/math3d.d b/src/dlangui/core/math3d.d index 2c979231..820b9a45 100644 --- a/src/dlangui/core/math3d.d +++ b/src/dlangui/core/math3d.d @@ -189,7 +189,7 @@ struct vec2 { return res; } /// subtract value from all components of vector - vec3 opBinary(string op : "-")(const vec2 v) const { + vec2 opBinary(string op : "-")(const vec2 v) const { vec2 res = this; res.vec[0] -= v.vec[0]; res.vec[1] -= v.vec[1]; @@ -1723,3 +1723,6 @@ vec3 triangleNormal(vec3 p1, vec3 p2, vec3 p3) { vec3 triangleNormal(float[3] p1, float[3] p2, float[3] p3) { return vec3.crossProduct(vec3(p2) - vec3(p1), vec3(p3) - vec3(p2)).normalized(); } + +/// Alias for 2d float point +alias PointF = vec2; diff --git a/src/dlangui/graphics/drawbuf.d b/src/dlangui/graphics/drawbuf.d index 00bc399f..423d552c 100644 --- a/src/dlangui/graphics/drawbuf.d +++ b/src/dlangui/graphics/drawbuf.d @@ -19,6 +19,7 @@ module dlangui.graphics.drawbuf; public import dlangui.core.config; public import dlangui.core.types; +public import dlangui.core.math3d; import dlangui.core.logger; import dlangui.graphics.colors; @@ -370,6 +371,54 @@ class DrawBuf : RefCountedObject { } } + /// draw filled triangle in float coordinates + void fillTriangleF(PointF p1, PointF p2, PointF p3, uint colour) { + // override and implement it + } + + /// draw filled quad in float coordinates + void fillQuadF(PointF p1, PointF p2, PointF p3, PointF p4, uint colour) { + fillTriangleF(p1, p2, p3, colour); + fillTriangleF(p3, p4, p1, colour); + } + + /// draw line of arbitrary width in float coordinates + void drawLineF(PointF p1, PointF p2, float width, uint colour) { + // direction vector + PointF v = (p2 - p1).normalized; + // calculate normal vector + PointF n; + // rotate CCW 90 degrees + n.y = v.x; + n.x = -v.y; + // offset by normal * half_width + n *= width / 2; + // draw line using quad + fillQuadF(p1 - n, p2 - n, p2 + n, p1 + n, colour); + } + + /// draw poly line of arbitrary width in float coordinates; when cycled is true, connect first and last point + void polyLineF(PointF[] points, float width, uint colour, bool cycled) { + if (points.length < 2) + return; + for(int i = 0; i + 1 < points.length; i++) { + drawLineF(points[i], points[i + 1], width, colour); + } + if (cycled && points.length > 2) + drawLineF(points[$ - 1], points[0], width, colour); + } + + /// draw poly line of width == 1px; when cycled is true, connect first and last point + void polyLine(Point[] points, uint colour, bool cycled) { + if (points.length < 2) + return; + for(int i = 0; i + 1 < points.length; i++) { + drawLine(points[i], points[i + 1], colour); + } + if (cycled && points.length > 2) + drawLine(points[$ - 1], points[0], colour); + } + /// draw line from point p1 to p2 with specified color void drawLine(Point p1, Point p2, uint colour) { if (!clipLine(_clipRect, p1, p2)) diff --git a/src/dlangui/graphics/gldrawbuf.d b/src/dlangui/graphics/gldrawbuf.d index bf64c701..43d73d27 100644 --- a/src/dlangui/graphics/gldrawbuf.d +++ b/src/dlangui/graphics/gldrawbuf.d @@ -180,6 +180,16 @@ class GLDrawBuf : DrawBuf, GLConfigCallback { _scene.add(new LineSceneItem(p1, p2, colour)); } + /// draw filled triangle in float coordinates + override void fillTriangleF(PointF p1, PointF p2, PointF p3, uint colour) { + assert(_scene !is null); + //if (!clipLine(_clipRect, p1, p2)) + // return; + // TODO: clipping + _scene.add(new TriangleSceneItem(p1, p2, p3, colour)); + } + + /// cleanup resources override void clear() { if (_framebuffer) { @@ -722,6 +732,25 @@ public: } } +private class TriangleSceneItem : SceneItem { +private: + PointF _p1; + PointF _p2; + PointF _p3; + uint _color; + +public: + this(PointF p1, PointF p2, PointF p3, uint color) { + _p1 = p1; + _p2 = p2; + _p3 = p3; + _color = color; + } + override void draw() { + glSupport.batch.addTriangle(_p1, _p2, _p3, _color, _color, _color); + } +} + private class SolidRectSceneItem : SceneItem { private: Rect _rc; diff --git a/src/dlangui/graphics/glsupport.d b/src/dlangui/graphics/glsupport.d index 90268537..def452b1 100644 --- a/src/dlangui/graphics/glsupport.d +++ b/src/dlangui/graphics/glsupport.d @@ -26,6 +26,7 @@ public import dlangui.core.math3d; import dlangui.core.logger; import dlangui.core.types; +import dlangui.core.math3d; import std.conv; import std.string; @@ -965,6 +966,18 @@ final class GLSupport { 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; @@ -1035,6 +1048,58 @@ final class GLSupport { } } + 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(); @@ -1691,6 +1756,12 @@ class OpenGLBatch { _colors ~= color4; } + 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]); + } + /// add gradient rect void addLine(Rect dstRect, uint color1, uint color2) { flush();