From df9cc6fe519369cec1f2fbc0bbdc57755cb9b4ef Mon Sep 17 00:00:00 2001 From: OvertureGames Date: Wed, 5 Mar 2014 13:15:15 -0500 Subject: [PATCH 1/3] Added a 'Shape' class to the 'display' package Added a Shape display class that is assembled by adding various primitives together and can be transformed like any Sprite object. Currently it only supports line segments (with rounded caps), but can be easily enhanced to do other shapes like rectangles and circles. --- src/flambe/display/Graphics.hx | 3 + src/flambe/display/Shape.hx | 94 ++++++++++ src/flambe/platform/OverdrawGraphics.hx | 5 + src/flambe/platform/flash/Stage3DGraphics.hx | 178 +++++++++++++++++++ src/flambe/platform/html/CanvasGraphics.hx | 17 ++ src/flambe/platform/html/WebGLGraphics.hx | 173 ++++++++++++++++++ 6 files changed, 470 insertions(+) create mode 100644 src/flambe/display/Shape.hx diff --git a/src/flambe/display/Graphics.hx b/src/flambe/display/Graphics.hx index 3ec63287..abb27214 100644 --- a/src/flambe/display/Graphics.hx +++ b/src/flambe/display/Graphics.hx @@ -57,4 +57,7 @@ interface Graphics /** Draws a colored rectangle at the given region. */ function fillRect (color :Int, x :Float, y :Float, width :Float, height :Float) :Void; + + /** Draws a line using the given specifications. */ + function drawLine (color :Int, xStart :Float, yStart :Float, xEnd :Float, yEnd :Float, width :Float, roundedCap :Bool) :Void; } diff --git a/src/flambe/display/Shape.hx b/src/flambe/display/Shape.hx new file mode 100644 index 00000000..990c1cb1 --- /dev/null +++ b/src/flambe/display/Shape.hx @@ -0,0 +1,94 @@ +// +// Flambe - Rapid game development +// https://github.com/aduros/flambe/blob/master/LICENSE.txt + +package flambe.display; + +import flambe.display.Sprite; +import flambe.math.Point; +import flambe.util.Assert; + +/** + * A user defined shape (line, rectangle, polygon) that is assembled by adding + * various primitives together. Can be transformed like any Sprite object. + */ +class Shape extends Sprite +{ + public var color(default, default) :Int; + private var segments :Array; + + public function new() + { + super(); + + color = 0x000000; + segments = new Array(); + } + + /** + * Adds a line segment to this shape. The coordinates specified are local to the Shape's origin. + * @returns This instance, for chaining. + */ + public function addLineSegmentF(xStart :Float, yStart :Float, xEnd :Float, yEnd :Float, width :Float, ?roundedCap :Bool = false) :Shape + { + var index = segments.length; + segments[index] = new Segment(xStart, yStart, xEnd, yEnd, width, roundedCap); + + return this; + } + + /** + * Adds a line segment to this shape. The coordinates specified are local to the Shape's origin. + * @returns This instance, for chaining. + */ + public function addLineSegment(ptStart :Point, ptEnd :Point, width :Float, ?roundedCap :Bool = false) :Shape + { + var index = segments.length; + segments[index] = new Segment(ptStart.x, ptStart.y, ptEnd.x, ptEnd.y, width, roundedCap); + + return this; + } + + /** + * Adds a contiguous line strip to this shape. The coordinates specified are local to the Shape's origin. + * @returns This instance, for chaining. + */ + public function addLineStrip(ptArray :Array, width :Float, ?roundedCap :Bool = false) + { + Assert.that(ptArray.length >= 2, "addLineStrip() must have at least '2' Points"); + + for(i in 1...ptArray.length) { + addLineSegment(ptArray[i - 1], ptArray[i], width, roundedCap); + } + + return this; + } + + override public function draw (g :Graphics) + { + for (seg in segments) { + seg.draw(g, color); + } + } +} + +private class Segment +{ + public var ptStart :Point; + public var ptEnd :Point; + public var width :Float; + public var roundedCap :Bool; + + public function new(xStart :Float, yStart :Float, xEnd :Float, yEnd :Float, width :Float, roundedCap :Bool) + { + ptStart = new Point(xStart, yStart); + ptEnd = new Point(xEnd, yEnd); + this.width = width; + this.roundedCap = roundedCap; + } + + public function draw (g :Graphics, color :Int) + { + g.drawLine(color, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y, width, roundedCap); + } +} \ No newline at end of file diff --git a/src/flambe/platform/OverdrawGraphics.hx b/src/flambe/platform/OverdrawGraphics.hx index d32c487e..3085d9ad 100644 --- a/src/flambe/platform/OverdrawGraphics.hx +++ b/src/flambe/platform/OverdrawGraphics.hx @@ -86,6 +86,11 @@ class OverdrawGraphics drawRegion(x, y, width, height); } + public function drawLine (color :Int, xStart :Float, yStart :Float, xEnd :Float, yEnd :Float, width :Float, roundedCap :Bool) + { + _impl.drawLine(color, xStart, yStart, xEnd, yEnd, width, roundedCap); + } + public function willRender () { _impl.willRender(); diff --git a/src/flambe/platform/flash/Stage3DGraphics.hx b/src/flambe/platform/flash/Stage3DGraphics.hx index f00f4947..65c3fa42 100644 --- a/src/flambe/platform/flash/Stage3DGraphics.hx +++ b/src/flambe/platform/flash/Stage3DGraphics.hx @@ -233,6 +233,54 @@ class Stage3DGraphics data[++offset] = a; } + public function drawLine (color :Int, xStart :Float, yStart :Float, xEnd :Float, yEnd :Float, width :Float, roundedCap :Bool) :Void + { + var state = getTopState(); + + var pos = transformQuadForLine(xStart, yStart, xEnd, yEnd, width); + var r = (color & 0xff0000) / 0xff0000; + var g = (color & 0x00ff00) / 0x00ff00; + var b = (color & 0x0000ff) / 0x0000ff; + var a = state.alpha; + + var offset = _batcher.prepareFillRect(_renderTarget, state.blendMode, state.scissor); + var data = _batcher.data; + + data[ offset] = pos[0]; + data[++offset] = pos[1]; + data[++offset] = r; + data[++offset] = g; + data[++offset] = b; + data[++offset] = a; + + data[++offset] = pos[3]; + data[++offset] = pos[4]; + data[++offset] = r; + data[++offset] = g; + data[++offset] = b; + data[++offset] = a; + + data[++offset] = pos[6]; + data[++offset] = pos[7]; + data[++offset] = r; + data[++offset] = g; + data[++offset] = b; + data[++offset] = a; + + data[++offset] = pos[9]; + data[++offset] = pos[10]; + data[++offset] = r; + data[++offset] = g; + data[++offset] = b; + data[++offset] = a; + + if (roundedCap) + { + drawLineCap(true, xStart, yStart, width, r, g, b, a); + drawLineCap(false, xEnd, yEnd, width, r, g, b, a); + } + } + public function multiplyAlpha (factor :Float) { getTopState().alpha *= factor; @@ -339,6 +387,134 @@ class Stage3DGraphics return pos; } + private function transformQuadForLine(xStart :Float, yStart :Float, xEnd :Float, yEnd :Float, width :Float) :Vector + { + var halfWidth = width * 0.5; + var pos = _scratchQuadVector; + + pos[2] = 0; + pos[5] = 0; + pos[8] = 0; + pos[11] = 0; + + // Case for vertical line + if(xStart == xEnd) { + pos[0] = xStart - halfWidth; + pos[1] = yStart; + pos[3] = xStart + halfWidth; + pos[4] = yStart; + + pos[6] = xEnd + halfWidth; + pos[7] = yEnd; + pos[9] = xEnd - halfWidth; + pos[10] = yEnd; + + _startTheta = (yStart > yEnd) ? Math.PI : 0.0; + } + // Case for horizontal line + else if(yStart == yEnd) { + pos[0] = xStart; + pos[1] = yStart - halfWidth; + pos[3] = xStart; + pos[4] = yStart + halfWidth; + + pos[6] = xEnd; + pos[7] = yEnd + halfWidth; + pos[9] = xEnd; + pos[10] = yEnd - halfWidth; + + _startTheta = (xStart > xEnd) ? 0.5*Math.PI : -0.5*Math.PI; + } + // Final case for any line with slope + else { + var slopePerp = (xStart - xEnd) / (yEnd - yStart); + var xOffset = Math.sqrt((halfWidth * halfWidth) / (1.0 + (slopePerp * slopePerp))); + + pos[0] = xStart - xOffset; + pos[1] = slopePerp * (pos[0] - xStart) + yStart; + pos[3] = xStart + xOffset; + pos[4] = slopePerp * (pos[3] - xStart) + yStart; + + pos[6] = xEnd + xOffset; + pos[7] = slopePerp * (pos[6] - xEnd) + yEnd; + pos[9] = xEnd - xOffset; + pos[10] = slopePerp * (pos[9] - xEnd) + yEnd; + + _startTheta = Math.atan(slopePerp); + if(yStart > yEnd) { + _startTheta += Math.PI; + } + } + + getTopState().matrix.transformVectors(pos, pos); + return pos; + } + + private function drawLineCap(startCap :Bool, xCtr :Float, yCtr :Float, width :Float, red :Float, green :Float, blue :Float, alpha :Float) + { + var halfWidth = width * 0.5; + var numWedgeForCap :Int = Std.int(width / 4); + if (numWedgeForCap < 6) numWedgeForCap = 6; + + var wedgeAngle = (2.0 * Math.PI) / (numWedgeForCap * 2); + wedgeAngle *= (startCap ? -1.0 : 1.0); + + for (i in 0...numWedgeForCap) + { + var pos = _scratchQuadVector; + pos[0] = xCtr; + pos[1] = yCtr; + + var theta = _startTheta; + theta += i * wedgeAngle; + + pos[3] = xCtr + halfWidth*Math.cos(theta); + pos[4] = yCtr + halfWidth*Math.sin(theta); + + theta += wedgeAngle; + + pos[6] = xCtr + halfWidth*Math.cos(theta); + pos[7] = yCtr + halfWidth*Math.sin(theta); + + pos[9] = xCtr; + pos[10] = yCtr; + + var state = getTopState(); + state.matrix.transformVectors(pos, pos); + + var offset = _batcher.prepareFillRect(_renderTarget, state.blendMode, state.scissor); + var data = _batcher.data; + + data[ offset] = pos[0]; + data[++offset] = pos[1]; + data[++offset] = red; + data[++offset] = green; + data[++offset] = blue; + data[++offset] = alpha; + + data[++offset] = pos[3]; + data[++offset] = pos[4]; + data[++offset] = red; + data[++offset] = green; + data[++offset] = blue; + data[++offset] = alpha; + + data[++offset] = pos[6]; + data[++offset] = pos[7]; + data[++offset] = red; + data[++offset] = green; + data[++offset] = blue; + data[++offset] = alpha; + + data[++offset] = pos[9]; + data[++offset] = pos[10]; + data[++offset] = red; + data[++offset] = green; + data[++offset] = blue; + data[++offset] = alpha; + } + } + private static var _scratchMatrix3D = new Matrix3D(); private static var _scratchClipVector = new Vector(2*3, true); private static var _scratchQuadVector = new Vector(4*3, true); @@ -348,6 +524,8 @@ class Stage3DGraphics return v; })(); + private var _startTheta :Float; // Used for drawing rounded line caps + private var _batcher :Stage3DBatcher; private var _renderTarget :Stage3DTextureRoot; diff --git a/src/flambe/platform/html/CanvasGraphics.hx b/src/flambe/platform/html/CanvasGraphics.hx index 62a56094..9f0ae1ad 100644 --- a/src/flambe/platform/html/CanvasGraphics.hx +++ b/src/flambe/platform/html/CanvasGraphics.hx @@ -114,6 +114,23 @@ class CanvasGraphics _canvasCtx.fillRect(Std.int(x), Std.int(y), Std.int(width), Std.int(height)); } + public function drawLine (color :Int, xStart :Float, yStart :Float, xEnd :Float, yEnd :Float, width :Float, roundedCap :Bool) + { + _canvasCtx.beginPath(); + _canvasCtx.moveTo(xStart, yStart); + _canvasCtx.lineTo(xEnd, yEnd); + _canvasCtx.lineWidth = width; + _canvasCtx.lineCap = roundedCap ? "round" : "butt"; + + // Convert color into a hex string in the form of #RRGGBB + var hex = untyped (0xffffff & color).toString(16); + while (hex.length < 6) { + hex = "0"+hex; + } + _canvasCtx.strokeStyle = hex; + _canvasCtx.stroke(); + } + public function multiplyAlpha (factor :Float) { _canvasCtx.globalAlpha *= factor; diff --git a/src/flambe/platform/html/WebGLGraphics.hx b/src/flambe/platform/html/WebGLGraphics.hx index b0dd9c3e..627dde89 100644 --- a/src/flambe/platform/html/WebGLGraphics.hx +++ b/src/flambe/platform/html/WebGLGraphics.hx @@ -227,6 +227,54 @@ class WebGLGraphics data[++offset] = a; } + public function drawLine (color :Int, xStart :Float, yStart :Float, xEnd :Float, yEnd :Float, width :Float, roundedCap :Bool) + { + var state = getTopState(); + + var pos = transformQuadForLine(xStart, yStart, xEnd, yEnd, width); + var r = (color & 0xff0000) / 0xff0000; + var g = (color & 0x00ff00) / 0x00ff00; + var b = (color & 0x0000ff) / 0x0000ff; + var a = state.alpha; + + var offset = _batcher.prepareFillRect(_renderTarget, state.blendMode, state.scissor); + var data = _batcher.data; + + data[ offset] = pos[0]; + data[++offset] = pos[1]; + data[++offset] = r; + data[++offset] = g; + data[++offset] = b; + data[++offset] = a; + + data[++offset] = pos[2]; + data[++offset] = pos[3]; + data[++offset] = r; + data[++offset] = g; + data[++offset] = b; + data[++offset] = a; + + data[++offset] = pos[4]; + data[++offset] = pos[5]; + data[++offset] = r; + data[++offset] = g; + data[++offset] = b; + data[++offset] = a; + + data[++offset] = pos[6]; + data[++offset] = pos[7]; + data[++offset] = r; + data[++offset] = g; + data[++offset] = b; + data[++offset] = a; + + if (roundedCap) + { + drawLineCap(true, xStart, yStart, width, r, g, b, a); + drawLineCap(false, xEnd, yEnd, width, r, g, b, a); + } + } + public function multiplyAlpha (factor :Float) { getTopState().alpha *= factor; @@ -323,9 +371,134 @@ class WebGLGraphics return pos; } + private function transformQuadForLine(xStart :Float, yStart :Float, xEnd :Float, yEnd :Float, width :Float) :Float32Array + { + var halfWidth = width * 0.5; + var pos = _scratchQuadArray; + + // Edge case for vertical line + if(xStart == xEnd) { + pos[0] = xStart - halfWidth; + pos[1] = yStart; + pos[2] = xStart + halfWidth; + pos[3] = yStart; + + pos[4] = xEnd + halfWidth; + pos[5] = yEnd; + pos[6] = xEnd - halfWidth; + pos[7] = yEnd; + + _startTheta = (yStart > yEnd) ? Math.PI : 0.0; + } + // Edge case for horizontal line + else if(yStart == yEnd) { + pos[0] = xStart; + pos[1] = yStart - halfWidth; + pos[2] = xStart; + pos[3] = yStart + halfWidth; + + pos[4] = xEnd; + pos[5] = yEnd + halfWidth; + pos[6] = xEnd; + pos[7] = yEnd - halfWidth; + + _startTheta = (xStart > xEnd) ? 0.5*Math.PI : -0.5*Math.PI; + } + // Final Edge case for any line with slope + else { + var slopePerp = (xStart - xEnd) / (yEnd - yStart); + var xOffset = Math.sqrt((halfWidth * halfWidth) / (1.0 + (slopePerp * slopePerp))); + + pos[0] = xStart - xOffset; + pos[1] = slopePerp * (pos[0] - xStart) + yStart; + pos[2] = xStart + xOffset; + pos[3] = slopePerp * (pos[2] - xStart) + yStart; + + pos[4] = xEnd + xOffset; + pos[5] = slopePerp * (pos[4] - xEnd) + yEnd; + pos[6] = xEnd - xOffset; + pos[7] = slopePerp * (pos[6] - xEnd) + yEnd; + + _startTheta = Math.atan(slopePerp); + if(yStart > yEnd) { + _startTheta += Math.PI; + } + } + + getTopState().matrix.transformArray(cast pos, 8, cast pos); + return pos; + } + + private function drawLineCap(startCap :Bool, xCtr :Float, yCtr :Float, width :Float, red :Float, green :Float, blue :Float, alpha :Float) + { + var halfWidth = width * 0.5; + var numWedgeForCap :Int = Std.int(width / 4); + if (numWedgeForCap < 6) numWedgeForCap = 6; + + var wedgeAngle = (2.0 * Math.PI) / (numWedgeForCap * 2); + wedgeAngle *= (startCap ? -1.0 : 1.0); + + for (i in 0...numWedgeForCap) + { + var pos = _scratchQuadArray; + pos[0] = xCtr; + pos[1] = yCtr; + + var theta = _startTheta; + theta += i * wedgeAngle; + + pos[2] = xCtr + halfWidth*Math.cos(theta); + pos[3] = yCtr + halfWidth*Math.sin(theta); + + theta += wedgeAngle; + + pos[4] = xCtr + halfWidth*Math.cos(theta); + pos[5] = yCtr + halfWidth*Math.sin(theta); + + pos[6] = xCtr; + pos[7] = yCtr; + + var state = getTopState(); + state.matrix.transformArray(cast pos, 8, cast pos); + + var offset = _batcher.prepareFillRect(_renderTarget, state.blendMode, state.scissor); + var data = _batcher.data; + + data[ offset] = pos[0]; + data[++offset] = pos[1]; + data[++offset] = red; + data[++offset] = green; + data[++offset] = blue; + data[++offset] = alpha; + + data[++offset] = pos[2]; + data[++offset] = pos[3]; + data[++offset] = red; + data[++offset] = green; + data[++offset] = blue; + data[++offset] = alpha; + + data[++offset] = pos[4]; + data[++offset] = pos[5]; + data[++offset] = red; + data[++offset] = green; + data[++offset] = blue; + data[++offset] = alpha; + + data[++offset] = pos[6]; + data[++offset] = pos[7]; + data[++offset] = red; + data[++offset] = green; + data[++offset] = blue; + data[++offset] = alpha; + } + } + private static var _scratchMatrix = new Matrix(); private static var _scratchQuadArray :Float32Array = null; + private var _startTheta :Float; // Used for drawing rounded line caps + private var _batcher :WebGLBatcher; private var _renderTarget :WebGLTextureRoot; From e332114ba96188c3b448a20206fe751a9d29e496 Mon Sep 17 00:00:00 2001 From: OvertureGames Date: Wed, 5 Mar 2014 17:08:25 -0500 Subject: [PATCH 2/3] Fixed a scissor issue with Shapes on Stage3D --- src/flambe/platform/flash/Stage3DGraphics.hx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/flambe/platform/flash/Stage3DGraphics.hx b/src/flambe/platform/flash/Stage3DGraphics.hx index 65c3fa42..f4f2615a 100644 --- a/src/flambe/platform/flash/Stage3DGraphics.hx +++ b/src/flambe/platform/flash/Stage3DGraphics.hx @@ -236,6 +236,9 @@ class Stage3DGraphics public function drawLine (color :Int, xStart :Float, yStart :Float, xEnd :Float, yEnd :Float, width :Float, roundedCap :Bool) :Void { var state = getTopState(); + if (state.emptyScissor()) { + return; + } var pos = transformQuadForLine(xStart, yStart, xEnd, yEnd, width); var r = (color & 0xff0000) / 0xff0000; @@ -243,7 +246,7 @@ class Stage3DGraphics var b = (color & 0x0000ff) / 0x0000ff; var a = state.alpha; - var offset = _batcher.prepareFillRect(_renderTarget, state.blendMode, state.scissor); + var offset = _batcher.prepareFillRect(_renderTarget, state.blendMode, state.getScissor()); var data = _batcher.data; data[ offset] = pos[0]; @@ -482,7 +485,7 @@ class Stage3DGraphics var state = getTopState(); state.matrix.transformVectors(pos, pos); - var offset = _batcher.prepareFillRect(_renderTarget, state.blendMode, state.scissor); + var offset = _batcher.prepareFillRect(_renderTarget, state.blendMode, state.getScissor()); var data = _batcher.data; data[ offset] = pos[0]; From 651ac97858839e6e5cef4b70909ebaa5dfdf4e24 Mon Sep 17 00:00:00 2001 From: Jason Knobler Date: Thu, 3 Apr 2014 23:11:31 -0400 Subject: [PATCH 3/3] New drawing API, (WIP) --- src/flambe/display/Shape.hx | 166 +++++++++++++++++++++++++----------- src/flambe/math/FMath.hx | 5 ++ 2 files changed, 119 insertions(+), 52 deletions(-) diff --git a/src/flambe/display/Shape.hx b/src/flambe/display/Shape.hx index 990c1cb1..9a40d2e5 100644 --- a/src/flambe/display/Shape.hx +++ b/src/flambe/display/Shape.hx @@ -4,91 +4,153 @@ package flambe.display; +import flambe.display.Shape.LineCaps; import flambe.display.Sprite; import flambe.math.Point; +import flambe.math.FMath; import flambe.util.Assert; +enum LineCaps +{ + None; + Rounded; +} + /** * A user defined shape (line, rectangle, polygon) that is assembled by adding * various primitives together. Can be transformed like any Sprite object. */ class Shape extends Sprite { - public var color(default, default) :Int; - private var segments :Array; + public var lineWidth(default, default) :Float; + public var lineCap(default, default) :LineCaps; + public var strokeColor(default, default) :Int; + public var fillColor(default, default) :Int; + public var penCoordinate(default, null) :Point; + + private var _segments :Array; + public function new() { super(); - - color = 0x000000; - segments = new Array(); + + lineWidth = 1.0; + lineCap = None; + strokeColor = 0x000000; + fillColor = 0xFFFFFF; + penCoordinate = new Point(); + + _segments = new Array(); } - /** - * Adds a line segment to this shape. The coordinates specified are local to the Shape's origin. - * @returns This instance, for chaining. - */ - public function addLineSegmentF(xStart :Float, yStart :Float, xEnd :Float, yEnd :Float, width :Float, ?roundedCap :Bool = false) :Shape + public function lineStyle(width :Float, color :Int, cap :LineCaps) : Void { - var index = segments.length; - segments[index] = new Segment(xStart, yStart, xEnd, yEnd, width, roundedCap); - - return this; + lineWidth = width; + strokeColor = color; + lineCap = cap; } - - /** - * Adds a line segment to this shape. The coordinates specified are local to the Shape's origin. - * @returns This instance, for chaining. - */ - public function addLineSegment(ptStart :Point, ptEnd :Point, width :Float, ?roundedCap :Bool = false) :Shape + + public function fillStyle(color :Int) : Void { - var index = segments.length; - segments[index] = new Segment(ptStart.x, ptStart.y, ptEnd.x, ptEnd.y, width, roundedCap); - - return this; + fillColor = color; } - - /** - * Adds a contiguous line strip to this shape. The coordinates specified are local to the Shape's origin. - * @returns This instance, for chaining. - */ - public function addLineStrip(ptArray :Array, width :Float, ?roundedCap :Bool = false) + + public function moveTo(x :Float, y :Float) : Void { - Assert.that(ptArray.length >= 2, "addLineStrip() must have at least '2' Points"); - - for(i in 1...ptArray.length) { - addLineSegment(ptArray[i - 1], ptArray[i], width, roundedCap); + penCoordinate.set(x, y); + } + + public function lineTo(x :Float, y :Float) : Void + { + var startPoint :Point = new Point(penCoordinate.x, penCoordinate.y); + penCoordinate.set(x, y); + + trace(startPoint); + + var index = _segments.length; + _segments[index] = new Segment(startPoint, penCoordinate, lineWidth, lineCap, strokeColor); + } + + public function curveTo(anchorX :Float, anchorY :Float, x :Float, y :Float) : Void + { + // Determine how much percision + var iPercInterval = 0.1; // 0.1 == 10 vertices + + var i :Float = 0.0; + var xa, ya, xb, yb; + while (i < 1.0) { + // Compute anchor/path + xa = FMath.lerp(penCoordinate.x, anchorX, i); + ya = FMath.lerp(penCoordinate.y, anchorY, i); + xb = FMath.lerp(anchorX, x, i ); + yb = FMath.lerp(anchorY, y, i ); + + // Find position along the anchor/path + lineTo(FMath.lerp(xa, xb, i), FMath.lerp(ya, yb, i)); + + i += iPercInterval; + } + } + + public function drawCircle(x :Float, y :Float, radius :Float) : Void + { + var numWedges :Int = Std.int(radius / 2); + if (numWedges < 12) numWedges = 12; + + var wedgeAngle :Float = (2.0 * Math.PI) / numWedges; + + moveTo(x + radius, y); + var theta :Float = 0.0; + for (i in 0...numWedges) + { + theta = i * wedgeAngle; + lineTo(x + radius * Math.cos(theta), y + radius * Math.sin(theta)); } - - return this; + } + + public function drawEllipse(x :Float, y :Float, width :Float, height :Float, ?rotation :Float) : Void + { + } + + public function drawRect(x :Float, y :Float, width :Float, height :Float) : Void + { + moveTo(x, y); + lineTo(x + width, y); + lineTo(x + width, y + height); + lineTo(x, y + height); + lineTo(x, y); + } + + public function clear() : Void + { + _segments = new Array(); } override public function draw (g :Graphics) { - for (seg in segments) { - seg.draw(g, color); + for (seg in _segments) { + g.drawLine(seg.color, seg.startPt.x, seg.startPt.y, seg.endPt.x, seg.endPt.y, seg.width, seg.cap == Rounded); } } } private class Segment { - public var ptStart :Point; - public var ptEnd :Point; - public var width :Float; - public var roundedCap :Bool; - - public function new(xStart :Float, yStart :Float, xEnd :Float, yEnd :Float, width :Float, roundedCap :Bool) - { - ptStart = new Point(xStart, yStart); - ptEnd = new Point(xEnd, yEnd); - this.width = width; - this.roundedCap = roundedCap; - } + public var startPt(default, null) :Point; + public var endPt(default, null) :Point; + public var width(default, null) :Float; + public var cap(default, null) :LineCaps; + public var color(default, null) :Int; - public function draw (g :Graphics, color :Int) + public function new(startPoint :Point, endPoint :Point, lineWidth :Float, lineCap :LineCaps, clr :Int) { - g.drawLine(color, ptStart.x, ptStart.y, ptEnd.x, ptEnd.y, width, roundedCap); + startPt = new Point(startPoint.x, startPoint.y); + endPt = new Point(endPoint.x, endPoint.y); + + width = lineWidth; + cap = lineCap; + + color = clr; } } \ No newline at end of file diff --git a/src/flambe/math/FMath.hx b/src/flambe/math/FMath.hx index b61bd913..86759df3 100644 --- a/src/flambe/math/FMath.hx +++ b/src/flambe/math/FMath.hx @@ -66,4 +66,9 @@ class FMath else if (value > 0) 1 else 0; } + + public static function lerp (n1 :Float, n2 :Float, percent :Float) :Float + { + return n1 + ((n2 - n1) * percent); + } }