diff --git a/examples/example1/src/example1.d b/examples/example1/src/example1.d index 9aaf7799..b90b0677 100644 --- a/examples/example1/src/example1.d +++ b/examples/example1/src/example1.d @@ -1088,11 +1088,22 @@ void main() 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 + 250, "drawLine()"d, 0x800020); + canvas.font.drawText(buf, x + 300, y + 420, "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); + // poly line test + Rect newClipRect = Rect(x + 110, y + 100, x + 350, y + 320); + buf.fillRect(newClipRect, 0xC08080FF); + Rect oldClip = buf.clipRect; + buf.clipRect = newClipRect; + PointF[] poly = [vec2(x+130, y+150), vec2(x+240, y+80), vec2(x+170, y+170), vec2(x+380, y+270), vec2(x+220, y+400), vec2(x+180, y+330)]; + buf.polyLineF(poly, 8.0f, 0x804020, true); + buf.fillTriangleF(vec2(x+230, y+50), vec2(x+400, y+250), vec2(x+130, y+200), 0xC0FF0000); + buf.fillTriangleF(vec2(x+230, y+250), vec2(x+200, y+350), vec2(x+80, y+200), 0xC000FF00); + buf.fillTriangleF(vec2(x+430, y+250), vec2(x+280, y+150), vec2(x+200, y+300), 0xC00000FF); + buf.fillTriangleF(vec2(x+80, y+150), vec2(x+280, y+250), vec2(x+80, y+200), 0xC0008080); + buf.clipRect = oldClip; + canvas.font.drawText(buf, x + 190, y + 260, "polyLineF()"d, 0x603010); }; tabs.addTab(canvas, "TAB_CANVAS"c); diff --git a/src/dlangui/graphics/drawbuf.d b/src/dlangui/graphics/drawbuf.d index 423d552c..5c0b8756 100644 --- a/src/dlangui/graphics/drawbuf.d +++ b/src/dlangui/graphics/drawbuf.d @@ -371,9 +371,170 @@ class DrawBuf : RefCountedObject { } } + /// draw filled triangle in float coordinates; clipping is already applied + protected void fillTriangleFClipped(PointF p1, PointF p2, PointF p3, uint colour) { + // override and implement it + } + + /// find intersection of line p1..p2 with clip rectangle + protected bool intersectClipF(ref PointF p1, ref PointF p2, ref bool p1moved, ref bool p2moved) { + if (p1.x < _clipRect.left && p2.x < _clipRect.left) + return true; + if (p1.x >= _clipRect.right && p2.x >= _clipRect.right) + return true; + if (p1.y < _clipRect.top && p2.y < _clipRect.top) + return true; + if (p1.y >= _clipRect.bottom && p2.y >= _clipRect.bottom) + return true; + // horizontal clip + if (p1.x < _clipRect.left && p2.x >= _clipRect.left) { + // move p1 to clip left + p1 += (p2 - p1) * ((_clipRect.left - p1.x) / (p2.x - p1.x)); + p1moved = true; + } + if (p2.x < _clipRect.left && p1.x >= _clipRect.left) { + // move p2 to clip left + p2 += (p1 - p2) * ((_clipRect.left - p2.x) / (p1.x - p2.x)); + p2moved = true; + } + if (p1.x > _clipRect.right && p2.x < _clipRect.right) { + // move p1 to clip right + p1 += (p2 - p1) * ((_clipRect.right - p1.x) / (p2.x - p1.x)); + p1moved = true; + } + if (p2.x > _clipRect.right && p1.x < _clipRect.right) { + // move p1 to clip right + p2 += (p1 - p2) * ((_clipRect.right - p2.x) / (p1.x - p2.x)); + p2moved = true; + } + // vertical clip + if (p1.y < _clipRect.top && p2.y >= _clipRect.top) { + // move p1 to clip left + p1 += (p2 - p1) * ((_clipRect.top - p1.y) / (p2.y - p1.y)); + p1moved = true; + } + if (p2.y < _clipRect.top && p1.y >= _clipRect.top) { + // move p2 to clip left + p2 += (p1 - p2) * ((_clipRect.top - p2.y) / (p1.y - p2.y)); + p2moved = true; + } + if (p1.y > _clipRect.bottom && p2.y < _clipRect.bottom) { + // move p1 to clip right <0 <0 + p1 += (p2 - p1) * ((_clipRect.bottom - p1.y) / (p2.y - p1.y)); + p1moved = true; + } + if (p2.y > _clipRect.bottom && p1.y < _clipRect.bottom) { + // move p1 to clip right + p2 += (p1 - p2) * ((_clipRect.bottom - p2.y) / (p1.y - p2.y)); + p2moved = true; + } + return false; + } + /// draw filled triangle in float coordinates void fillTriangleF(PointF p1, PointF p2, PointF p3, uint colour) { - // override and implement it + if (_clipRect.empty) // clip rectangle is empty - all drawables are clipped out + return; + // apply clipping + bool p1insideClip = (p1.x >= _clipRect.left && p1.x < _clipRect.right && p1.y >= _clipRect.top && p1.y < _clipRect.bottom); + bool p2insideClip = (p2.x >= _clipRect.left && p2.x < _clipRect.right && p2.y >= _clipRect.top && p2.y < _clipRect.bottom); + bool p3insideClip = (p3.x >= _clipRect.left && p3.x < _clipRect.right && p3.y >= _clipRect.top && p3.y < _clipRect.bottom); + if (p1insideClip && p2insideClip && p3insideClip) { + // all points inside clipping area - no clipping required + fillTriangleFClipped(p1, p2, p3, colour); + return; + } + // do triangle clipping + // check if all points outside the same bound + if ((p1.x < _clipRect.left && p2.x < _clipRect.left && p3.x < _clipRect.left) + || (p1.x >= _clipRect.right && p2.x >= _clipRect.right && p3.x >= _clipRect.bottom) + || (p1.y < _clipRect.top && p2.y < _clipRect.top && p3.y < _clipRect.top) + || (p1.y >= _clipRect.bottom && p2.y >= _clipRect.bottom && p3.y >= _clipRect.bottom)) + return; + /++ + + side 1 + + p1-------p11------------p21--------------p2 + + \ / + + \ / + + \ / + + \ / + + p13\ /p22 + + \ / + + \ / + + \ / + + \ / side 2 + + side 3 \ / + + \ / + + \ / + + \ /p32 + + p33\ / + + \ / + + \ / + + \ / + + \ / + + \ / + + \ / + + p3 + +/ + PointF p11 = p1; + PointF p13 = p1; + PointF p21 = p2; + PointF p22 = p2; + PointF p32 = p3; + PointF p33 = p3; + bool p1moved = false; + bool p2moved = false; + bool p3moved = false; + bool side1clipped = intersectClipF(p11, p21, p1moved, p2moved); + bool side2clipped = intersectClipF(p22, p32, p2moved, p3moved); + bool side3clipped = intersectClipF(p33, p13, p3moved, p1moved); + if (!p1moved && !p2moved && !p3moved) { + // no moved - no clipping + fillTriangleFClipped(p1, p2, p3, colour); + } else if (p1moved && !p2moved && !p3moved) { + fillTriangleFClipped(p11, p2, p3, colour); + fillTriangleFClipped(p3, p13, p11, colour); + } else if (!p1moved && p2moved && !p3moved) { + fillTriangleFClipped(p22, p3, p1, colour); + fillTriangleFClipped(p1, p21, p22, colour); + } else if (!p1moved && !p2moved && p3moved) { + fillTriangleFClipped(p33, p1, p2, colour); + fillTriangleFClipped(p2, p32, p33, colour); + } else if (p1moved && p2moved && !p3moved) { + if (!side1clipped) { + fillTriangleFClipped(p13, p11, p21, colour); + fillTriangleFClipped(p21, p22, p13, colour); + } + fillTriangleFClipped(p22, p3, p13, colour); + } else if (!p1moved && p2moved && p3moved) { + if (!side2clipped) { + fillTriangleFClipped(p21, p22, p32, colour); + fillTriangleFClipped(p32, p33, p21, colour); + } + fillTriangleFClipped(p21, p33, p1, colour); + } else if (p1moved && !p2moved && p3moved) { + if (!side3clipped) { + fillTriangleFClipped(p13, p11, p32, colour); + fillTriangleFClipped(p32, p33, p13, colour); + } + fillTriangleFClipped(p11, p2, p32, colour); + } else if (p1moved && p2moved && p3moved) { + if (side1clipped) { + fillTriangleFClipped(p13, p22, p32, colour); + fillTriangleFClipped(p32, p33, p13, colour); + } else if (side2clipped) { + fillTriangleFClipped(p11, p21, p33, colour); + fillTriangleFClipped(p33, p13, p11, colour); + } else if (side3clipped) { + fillTriangleFClipped(p11, p21, p22, colour); + fillTriangleFClipped(p22, p32, p11, colour); + } else { + fillTriangleFClipped(p13, p11, p21, colour); + fillTriangleFClipped(p21, p22, p13, colour); + fillTriangleFClipped(p22, p32, p33, colour); + fillTriangleFClipped(p33, p13, p22, colour); + } + } } /// draw filled quad in float coordinates diff --git a/src/dlangui/graphics/gldrawbuf.d b/src/dlangui/graphics/gldrawbuf.d index 43d73d27..50533728 100644 --- a/src/dlangui/graphics/gldrawbuf.d +++ b/src/dlangui/graphics/gldrawbuf.d @@ -180,16 +180,12 @@ 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) { + /// draw filled triangle in float coordinates; clipping is already applied + override protected void fillTriangleFClipped(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) {