123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866 |
- package h2d;
- import h2d.impl.BatchDrawState;
- import hxd.Math;
- import hxd.impl.Allocator;
- private typedef GraphicsPoint = hxd.poly2tri.Point;
- @:dox(hide)
- class GPoint {
- public var x : Float;
- public var y : Float;
- public var r : Float;
- public var g : Float;
- public var b : Float;
- public var a : Float;
- public function new() {
- }
- public function load(x, y, r, g, b, a ){
- this.x = x;
- this.y = y;
- this.r = r;
- this.g = g;
- this.b = b;
- this.a = a;
- }
- }
- private class GraphicsContent extends h3d.prim.Primitive {
- var tmp : hxd.FloatBuffer;
- var index : hxd.IndexBuffer;
- var state : BatchDrawState;
- var buffers : Array<{ buf : hxd.FloatBuffer, vbuf : h3d.Buffer, idx : hxd.IndexBuffer, ibuf : h3d.Indexes, state : BatchDrawState }>;
- var bufferDirty : Bool;
- var indexDirty : Bool;
- var allocPos : hxd.impl.AllocPos;
- public function new() {
- buffers = [];
- state = new BatchDrawState();
- this.allocPos = hxd.impl.AllocPos.make();
- }
- public inline function addIndex(i) {
- index.push(i);
- state.add(1);
- indexDirty = true;
- }
- public inline function add( x : Float, y : Float, u : Float, v : Float, r : Float, g : Float, b : Float, a : Float ) {
- tmp.push(x);
- tmp.push(y);
- tmp.push(u);
- tmp.push(v);
- tmp.push(r);
- tmp.push(g);
- tmp.push(b);
- tmp.push(a);
- bufferDirty = true;
- }
- public function setTile( tile : h2d.Tile ) {
- state.setTile(tile);
- }
- public function next() {
- var nvect = tmp.length >> 3;
- if( nvect < 1 << 15 )
- return false;
- buffers.push( { buf : tmp, idx : index, vbuf : null, ibuf : null, state: state } );
- tmp = new hxd.FloatBuffer();
- index = new hxd.IndexBuffer();
- var tex = state.currentTexture;
- state = new BatchDrawState();
- state.setTexture(tex);
- super.dispose();
- return true;
- }
- override function alloc( engine : h3d.Engine ) {
- if (index.length <= 0) return ;
- var alloc = Allocator.get();
- buffer = alloc.ofFloats(tmp, hxd.BufferFormat.H2D);
- @:privateAccess buffer.allocPos = allocPos;
- indexes = alloc.ofIndexes(index);
- for( b in buffers ) {
- if( b.vbuf == null || b.vbuf.isDisposed() ) b.vbuf = alloc.ofFloats(b.buf, hxd.BufferFormat.H2D);
- if( b.ibuf == null || b.ibuf.isDisposed() ) b.ibuf = alloc.ofIndexes(b.idx);
- }
- bufferDirty = false;
- indexDirty = false;
- }
- public function doRender( ctx : h2d.RenderContext ) {
- if ( index.length == 0 ) return;
- flush();
- for ( b in buffers ) b.state.drawIndexed(ctx, b.vbuf, b.ibuf);
- state.drawIndexed(ctx, buffer, indexes);
- }
- public function flush() {
- if( buffer == null || buffer.isDisposed() ) {
- alloc(h3d.Engine.getCurrent());
- } else {
- var allocator = Allocator.get();
- if ( bufferDirty ) {
- allocator.disposeBuffer(buffer);
- buffer = allocator.ofFloats(tmp, hxd.BufferFormat.H2D);
- bufferDirty = false;
- }
- if ( indexDirty ) {
- allocator.disposeIndexBuffer(indexes);
- indexes = allocator.ofIndexes(index);
- indexDirty = false;
- }
- }
- }
- override function dispose() {
- for( b in buffers ) {
- if( b.vbuf != null ) Allocator.get().disposeBuffer(b.vbuf);
- if( b.ibuf != null ) Allocator.get().disposeIndexBuffer(b.ibuf);
- b.vbuf = null;
- b.ibuf = null;
- b.state.clear();
- }
- if( buffer != null ) {
- Allocator.get().disposeBuffer(buffer);
- buffer = null;
- }
- if( indexes != null ) {
- Allocator.get().disposeIndexBuffer(indexes);
- indexes = null;
- }
- state.clear();
- super.dispose();
- }
- public function clear() {
- dispose();
- tmp = new hxd.FloatBuffer();
- index = new hxd.IndexBuffer();
- buffers = [];
- }
- }
- /**
- A simple interface to draw arbitrary 2D geometry.
- Usage notes:
- * While Graphics allows for multiple unique textures, each texture swap causes a new drawcall,
- and due to that it's recommended to minimize the amount of used textures per Graphics instance,
- ideally limiting to only one texture.
- * Due to how Graphics operate, removing them from the active `h2d.Scene` will cause a loss of all data.
- **/
- class Graphics extends Drawable {
- var content : GraphicsContent;
- var tmpPoints : Array<GPoint>;
- var pindex : Int;
- var curR : Float;
- var curG : Float;
- var curB : Float;
- var curA : Float;
- var lineSize : Float;
- var lineR : Float;
- var lineG : Float;
- var lineB : Float;
- var lineA : Float;
- var doFill : Bool;
- var xMin : Float;
- var yMin : Float;
- var xMax : Float;
- var yMax : Float;
- var xMinSize : Float;
- var yMinSize : Float;
- var xMaxSize : Float;
- var yMaxSize : Float;
- var ma : Float = 1.;
- var mb : Float = 0.;
- var mc : Float = 0.;
- var md : Float = 1.;
- var mx : Float = 0.;
- var my : Float = 0.;
- /**
- The Tile used as source of Texture to render.
- **/
- public var tile : h2d.Tile;
- /**
- Adds bevel cut-off at line corners.
- The value is a percentile in range of 0...1, dictating at which point edges get beveled based on their angle.
- Value of 0 being not beveled and 1 being always beveled.
- **/
- public var bevel = 0.25; //0 = not beveled, 1 = always beveled
- /**
- Create a new Graphics instance.
- @param parent An optional parent `h2d.Object` instance to which Graphics adds itself if set.
- **/
- public function new(?parent) {
- super(parent);
- content = new GraphicsContent();
- tile = h2d.Tile.fromColor(0xFFFFFF);
- clear();
- }
- override function onRemove() {
- super.onRemove();
- clear();
- }
- /**
- Clears the Graphics contents.
- **/
- public function clear() {
- content.clear();
- tmpPoints = [];
- pindex = 0;
- lineSize = 0;
- xMin = Math.POSITIVE_INFINITY;
- yMin = Math.POSITIVE_INFINITY;
- yMax = Math.NEGATIVE_INFINITY;
- xMax = Math.NEGATIVE_INFINITY;
- xMinSize = Math.POSITIVE_INFINITY;
- yMinSize = Math.POSITIVE_INFINITY;
- yMaxSize = Math.NEGATIVE_INFINITY;
- xMaxSize = Math.NEGATIVE_INFINITY;
- }
- override function getBoundsRec( relativeTo, out, forSize ) {
- super.getBoundsRec(relativeTo, out, forSize);
- if( tile != null ) {
- if( forSize ) addBounds(relativeTo, out, xMinSize, yMinSize, xMaxSize - xMinSize, yMaxSize - yMinSize);
- else addBounds(relativeTo, out, xMin, yMin, xMax - xMin, yMax - yMin);
- }
- }
- function isConvex( points : Array<GPoint> ) {
- var first = true, sign = false;
- for( i in 0...points.length ) {
- var p1 = points[i];
- var p2 = points[(i + 1) % points.length];
- var p3 = points[(i + 2) % points.length];
- var s = (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x) > 0;
- if( first ) {
- first = false;
- sign = s;
- } else if( sign != s )
- return false;
- }
- return true;
- }
- function flushLine( start ) {
- var pts = tmpPoints;
- var last = pts.length - 1;
- var prev = pts[last];
- var p = pts[0];
- content.setTile(h2d.Tile.fromColor(0xFFFFFF));
- var closed = p.x == prev.x && p.y == prev.y;
- var count = pts.length;
- if( !closed ) {
- var prevLast = pts[last - 1];
- if( prevLast == null ) prevLast = p;
- var gp = new GPoint();
- gp.load(prev.x * 2 - prevLast.x, prev.y * 2 - prevLast.y, 0, 0, 0, 0);
- pts.push(gp);
- var pNext = pts[1];
- if( pNext == null ) pNext = p;
- var gp = new GPoint();
- gp.load(p.x * 2 - pNext.x, p.y * 2 - pNext.y, 0, 0, 0, 0);
- prev = gp;
- } else if( p != prev ) {
- count--;
- last--;
- prev = pts[last];
- }
- for( i in 0...count ) {
- var next = pts[(i + 1) % pts.length];
- var nx1 = prev.y - p.y;
- var ny1 = p.x - prev.x;
- var ns1 = Math.invSqrt(nx1 * nx1 + ny1 * ny1);
- var nx2 = p.y - next.y;
- var ny2 = next.x - p.x;
- var ns2 = Math.invSqrt(nx2 * nx2 + ny2 * ny2);
- var nx = nx1 * ns1 + nx2 * ns2;
- var ny = ny1 * ns1 + ny2 * ns2;
- var ns = Math.invSqrt(nx * nx + ny * ny);
- nx *= ns;
- ny *= ns;
- var size = nx * nx1 * ns1 + ny * ny1 * ns1; // N.N1
- // *HACK* we should instead properly detect limits when the angle is too small
- if(size < 0.1) size = 0.1;
- var d = lineSize * 0.5 / size;
- nx *= d;
- ny *= d;
- if(size > bevel) {
- content.add(p.x + nx, p.y + ny, 0, 0, p.r, p.g, p.b, p.a);
- content.add(p.x - nx, p.y - ny, 0, 0, p.r, p.g, p.b, p.a);
- var pnext = i == last ? start : pindex + 2;
- if( i < count - 1 || closed ) {
- content.addIndex(pindex);
- content.addIndex(pindex + 1);
- content.addIndex(pnext);
- content.addIndex(pindex + 1);
- content.addIndex(pnext);
- content.addIndex(pnext + 1);
- }
- pindex += 2;
- }
- else {
- //bevel
- var n0x = next.x - p.x;
- var n0y = next.y - p.y;
- var sign = n0x * nx + n0y * ny;
- var nnx = -ny;
- var nny = nx;
- var size = nnx * nx1 * ns1 + nny * ny1 * ns1;
- var d = lineSize * 0.5 / size;
- nnx *= d;
- nny *= d;
- var pnext = i == last ? start : pindex + 3;
- if(sign > 0) {
- content.add(p.x + nx, p.y + ny, 0, 0, p.r, p.g, p.b, p.a);
- content.add(p.x - nnx, p.y - nny, 0, 0, p.r, p.g, p.b, p.a);
- content.add(p.x + nnx, p.y + nny, 0, 0, p.r, p.g, p.b, p.a);
- content.addIndex(pindex);
- content.addIndex(pnext);
- content.addIndex(pindex + 2);
- content.addIndex(pindex + 2);
- content.addIndex(pnext);
- content.addIndex(pnext + 1);
- }
- else {
- content.add(p.x + nnx, p.y + nny, 0, 0, p.r, p.g, p.b, p.a);
- content.add(p.x - nx, p.y - ny, 0, 0, p.r, p.g, p.b, p.a);
- content.add(p.x - nnx, p.y - nny, 0, 0, p.r, p.g, p.b, p.a);
- content.addIndex(pindex + 1);
- content.addIndex(pnext);
- content.addIndex(pindex + 2);
- content.addIndex(pindex + 1);
- content.addIndex(pnext);
- content.addIndex(pnext + 1);
- }
- content.addIndex(pindex);
- content.addIndex(pindex + 1);
- content.addIndex(pindex + 2);
- pindex += 3;
- }
- prev = p;
- p = next;
- }
- content.setTile(tile);
- }
- static var EARCUT = null;
- function flushFill( i0 ) {
- if( tmpPoints.length < 3 )
- return;
- var pts = tmpPoints;
- var p0 = pts[0];
- var p1 = pts[pts.length - 1];
- var last = null;
- // closed poly
- if( hxd.Math.abs(p0.x - p1.x) < 1e-9 && hxd.Math.abs(p0.y - p1.y) < 1e-9 )
- last = pts.pop();
- if( isConvex(pts) ) {
- for( i in 1...pts.length - 1 ) {
- content.addIndex(i0);
- content.addIndex(i0 + i);
- content.addIndex(i0 + i + 1);
- }
- } else {
- var ear = EARCUT;
- if( ear == null )
- EARCUT = ear = new hxd.earcut.Earcut();
- for( i in ear.triangulate(pts) )
- content.addIndex(i + i0);
- }
- if( last != null )
- pts.push(last);
- }
- function flush() {
- if( tmpPoints.length == 0 )
- return;
- if( doFill ) {
- flushFill(pindex);
- pindex += tmpPoints.length;
- if( content.next() )
- pindex = 0;
- }
- if( lineSize > 0 ) {
- flushLine(pindex);
- if( content.next() )
- pindex = 0;
- }
- tmpPoints = [];
- }
- /**
- Begins a solid color fill.
- Beginning new fill will finish previous fill operation without need to call `Graphics.endFill`.
- @param color An RGB color with which to fill the drawn shapes.
- @param alpha A transparency of the fill color.
- **/
- public function beginFill( color : Int = 0, alpha = 1. ) {
- flush();
- tile = h2d.Tile.fromColor(0xFFFFFF);
- content.setTile(tile);
- setColor(color,alpha);
- doFill = true;
- }
- /**
- Position a virtual tile at the given position and scale. Every draw will display a part of this tile relative
- to these coordinates.
- Note that in by default, Tile is not wrapped, and in order to render a tiling texture, `Drawable.tileWrap` has to be set.
- Additionally, both `Tile.dx` and `Tile.dy` are ignored (use `dx`/`dy` arguments instead)
- as well as tile defined size of the tile through `Tile.width` and `Tile.height` (use `scaleX`/`scaleY` relative to texture size).
- Beginning new fill will finish previous fill operation without need to call `Graphics.endFill`.
- @param dx An X offset of the Tile relative to Graphics.
- @param dy An Y offset of the Tile relative to Graphics.
- @param scaleX A horizontal scale factor applied to the Tile texture.
- @param scaleY A vertical scale factor applied to the Tile texture.
- @param tile The tile to fill with. If null, uses previously used Tile with `beginTileFill` or throws an error.
- Previous tile is remembered across `Graphics.clear` calls.
- **/
- public function beginTileFill( ?dx : Float, ?dy : Float, ?scaleX : Float, ?scaleY : Float, ?tile : h2d.Tile ) {
- if ( tile == null )
- tile = this.tile;
- if ( tile == null )
- throw "Tile not specified";
- flush();
- this.tile = tile;
- content.setTile(tile);
- setColor(0xFFFFFF);
- doFill = true;
- if( dx == null ) dx = 0;
- if( dy == null ) dy = 0;
- if( scaleX == null ) scaleX = 1;
- if( scaleY == null ) scaleY = 1;
- dx -= tile.x;
- dy -= tile.y;
- var tex = tile.getTexture();
- var pixWidth = 1 / tex.width;
- var pixHeight = 1 / tex.height;
- ma = pixWidth / scaleX;
- mb = 0;
- mc = 0;
- md = pixHeight / scaleY;
- mx = -dx * ma;
- my = -dy * md;
- }
- /**
- Draws a Tile at given position.
- See `Graphics.beginTileFill` for limitations.
- This methods ends current fill operation.
- @param x The X position of the tile.
- @param y The Y position of the tile.
- @param tile The tile to draw.
- **/
- public function drawTile( x : Float, y : Float, tile : h2d.Tile ) {
- beginTileFill(x, y, tile);
- drawRect(x, y, tile.width, tile.height);
- endFill();
- }
- /**
- Sets an outline style. Changing the line style ends the currently drawn line.
- @param size Width of the outline. Setting size to 0 will remove the outline.
- @param color An outline RGB color.
- @param alpha An outline transparency.
- **/
- public function lineStyle( size : Float = 0, color = 0, alpha = 1. ) {
- flush();
- this.lineSize = size;
- lineA = alpha;
- lineR = ((color >> 16) & 0xFF) / 255.;
- lineG = ((color >> 8) & 0xFF) / 255.;
- lineB = (color & 0xFF) / 255.;
- }
- /**
- Ends the current line and starts new one at given position.
- **/
- public inline function moveTo(x,y) {
- flush();
- lineTo(x, y);
- }
- /**
- Ends the current fill operation.
- **/
- public function endFill() {
- flush();
- doFill = false;
- }
- /**
- Changes current fill color.
- Does not interrupt current fill operation and can be utilized to customize color per vertex.
- During tile fill operation, color serves as a tile color multiplier.
- @param color The new fill color.
- @param alpha The new fill transparency.
- **/
- public inline function setColor( color : Int, alpha : Float = 1. ) {
- curA = alpha;
- curR = ((color >> 16) & 0xFF) / 255.;
- curG = ((color >> 8) & 0xFF) / 255.;
- curB = (color & 0xFF) / 255.;
- }
- /**
- Draws a rectangle with given parameters.
- @param x The rectangle top-left corner X position.
- @param y The rectangle top-left corner Y position.
- @param w The rectangle width.
- @param h The rectangle height.
- **/
- public function drawRect( x : Float, y : Float, w : Float, h : Float ) {
- flush();
- lineTo(x, y);
- lineTo(x + w, y);
- lineTo(x + w, y + h);
- lineTo(x, y + h);
- lineTo(x, y);
- var e = 0.01; // see #776
- tmpPoints[0].x += e;
- tmpPoints[0].y += e;
- tmpPoints[1].y += e;
- tmpPoints[3].x += e;
- tmpPoints[4].x += e;
- tmpPoints[4].y += e;
- flush();
- }
- /**
- Draws a rounded rectangle with given parameters.
- @param x The rectangle top-left corner X position.
- @param y The rectangle top-left corner Y position.
- @param w The rectangle width.
- @param h The rectangle height.
- @param radius Radius of the rectangle corners.
- @param nsegments Amount of segments used for corners. When `0` segment count calculated automatically.
- **/
- public function drawRoundedRect( x : Float, y : Float, w : Float, h : Float, radius : Float, nsegments = 0 ) {
- if (radius <= 0) {
- return drawRect(x, y, w, h);
- }
- x += radius;
- y += radius;
- w -= radius * 2;
- h -= radius * 2;
- flush();
- if( nsegments == 0 )
- nsegments = Math.ceil(Math.abs(radius * hxd.Math.degToRad(90) / 4));
- if( nsegments < 3 ) nsegments = 3;
- var angle = hxd.Math.degToRad(90) / (nsegments - 1);
- inline function corner(x, y, angleStart) {
- for ( i in 0...nsegments) {
- var a = i * angle + hxd.Math.degToRad(angleStart);
- lineTo(x + Math.cos(a) * radius, y + Math.sin(a) * radius);
- }
- }
- lineTo(x, y - radius);
- lineTo(x + w, y - radius);
- corner(x + w, y, 270);
- lineTo(x + w + radius, y + h);
- corner(x + w, y + h, 0);
- lineTo(x, y + h + radius);
- corner(x, y + h, 90);
- lineTo(x - radius, y);
- corner(x, y, 180);
- flush();
- }
- /**
- Draws a circle centered at given position.
- @param cx X center position of the circle.
- @param cy Y center position of the circle.
- @param radius Radius of the circle.
- @param nsegments Amount of segments used to draw the circle. When `0`, amount of segments calculated automatically.
- **/
- public function drawCircle( cx : Float, cy : Float, radius : Float, nsegments = 0 ) {
- flush();
- if( nsegments == 0 )
- nsegments = Math.ceil(Math.abs(radius * 3.14 * 2 / 4));
- if( nsegments < 3 ) nsegments = 3;
- var angle = Math.PI * 2 / nsegments;
- for( i in 0...nsegments + 1 ) {
- var a = i * angle;
- lineTo(cx + Math.cos(a) * radius, cy + Math.sin(a) * radius);
- }
- flush();
- }
- /**
- Draws an ellipse centered at given position.
- @param cx X center position of the ellipse.
- @param cy Y center position of the ellipse.
- @param radiusX Horizontal radius of an ellipse.
- @param radiusY Vertical radius of an ellipse.
- @param rotationAngle Ellipse rotation in radians.
- @param nsegments Amount of segments used to draw an ellipse. When `0`, amount of segments calculated automatically.
- **/
- public function drawEllipse( cx : Float, cy : Float, radiusX : Float, radiusY : Float, rotationAngle : Float = 0, nsegments = 0 ) {
- flush();
- if( nsegments == 0 )
- nsegments = Math.ceil(Math.abs(radiusY * 3.14 * 2 / 4));
- if( nsegments < 3 ) nsegments = 3;
- var angle = Math.PI * 2 / nsegments;
- var x1, y1;
- for( i in 0...nsegments + 1 ) {
- var a = i * angle;
- x1 = Math.cos(a) * Math.cos(rotationAngle) * radiusX - Math.sin(a) * Math.sin(rotationAngle) * radiusY;
- y1 = Math.cos(rotationAngle) * Math.sin(a) * radiusY + Math.cos(a) * Math.sin(rotationAngle) * radiusX;
- lineTo(cx + x1, cy + y1);
- }
- flush();
- }
- /**
- Draws a pie centered at given position.
- @param cx X center position of the pie.
- @param cy Y center position of the pie.
- @param radius Radius of the pie.
- @param angleStart Starting angle of the pie in radians.
- @param angleLength The pie size in clockwise direction with `2*PI` being full circle.
- @param nsegments Amount of segments used to draw the pie. When `0`, amount of segments calculated automatically.
- **/
- public function drawPie( cx : Float, cy : Float, radius : Float, angleStart:Float, angleLength:Float, nsegments = 0 ) {
- if(Math.abs(angleLength) >= Math.PI * 2) {
- return drawCircle(cx, cy, radius, nsegments);
- }
- flush();
- lineTo(cx, cy);
- if( nsegments == 0 )
- nsegments = Math.ceil(Math.abs(radius * angleLength / 4));
- if( nsegments < 3 ) nsegments = 3;
- var angle = angleLength / (nsegments - 1);
- for( i in 0...nsegments ) {
- var a = i * angle + angleStart;
- lineTo(cx + Math.cos(a) * radius, cy + Math.sin(a) * radius);
- }
- lineTo(cx, cy);
- flush();
- }
- /**
- Draws a double-edged pie centered at given position.
- @param cx X center position of the pie.
- @param cy Y center position of the pie.
- @param radius The outer radius of the pie.
- @param innerRadius The inner radius of the pie.
- @param angleStart Starting angle of the pie in radians.
- @param angleLength The pie size in clockwise direction with `2*PI` being full circle.
- @param nsegments Amount of segments used to draw the pie. When `0`, amount of segments calculated automatically.
- **/
- public function drawPieInner( cx : Float, cy : Float, radius : Float, innerRadius : Float, angleStart:Float, angleLength:Float, nsegments = 0 ) {
- flush();
- if( Math.abs(angleLength) >= Math.PI * 2 + 1e-3 ) angleLength = Math.PI*2+1e-3;
- var cs = Math.cos(angleStart);
- var ss = Math.sin(angleStart);
- var ce = Math.cos(angleStart + angleLength);
- var se = Math.sin(angleStart + angleLength);
- lineTo(cx + cs * innerRadius, cy + ss * innerRadius);
- if( nsegments == 0 )
- nsegments = Math.ceil(Math.abs(radius * angleLength / 4));
- if( nsegments < 3 ) nsegments = 3;
- var angle = angleLength / (nsegments - 1);
- for( i in 0...nsegments ) {
- var a = i * angle + angleStart;
- lineTo(cx + Math.cos(a) * radius, cy + Math.sin(a) * radius);
- }
- lineTo(cx + ce * innerRadius, cy + se * innerRadius);
- for( i in 0...nsegments ) {
- var a = (nsegments - 1 - i) * angle + angleStart;
- lineTo(cx + Math.cos(a) * innerRadius, cy + Math.sin(a) * innerRadius);
- }
- flush();
- }
- /**
- Draws a rectangular pie centered at given position.
- @param cx X center position of the pie.
- @param cy Y center position of the pie.
- @param width Width of the pie.
- @param height Height of the pie.
- @param angleStart Starting angle of the pie in radians.
- @param angleLength The pie size in clockwise direction with `2*PI` being solid rectangle.
- @param nsegments Amount of segments used to draw the pie. When `0`, amount of segments calculated automatically.
- **/
- public function drawRectanglePie( cx : Float, cy : Float, width : Float, height : Float, angleStart:Float, angleLength:Float, nsegments = 0 ) {
- if(Math.abs(angleLength) >= Math.PI*2) {
- return drawRect(cx-(width/2), cy-(height/2), width, height);
- }
- flush();
- lineTo(cx, cy);
- if( nsegments == 0 )
- nsegments = Math.ceil(Math.abs(Math.max(width, height) * angleLength / 4));
- if( nsegments < 3 ) nsegments = 3;
- var angle = angleLength / (nsegments - 1);
- var square2 = Math.sqrt(2);
- for( i in 0...nsegments ) {
- var a = i * angle + angleStart;
- var _width = Math.cos(a) * (width/2+1) * square2;
- var _height = Math.sin(a) * (height/2+1) * square2;
- _width = Math.abs(_width) >= width/2 ? (Math.cos(a) < 0 ? width/2*-1 : width/2) : _width;
- _height = Math.abs(_height) >= height/2 ? (Math.sin(a) < 0 ? height/2*-1 : height/2) : _height;
- lineTo(cx + _width, cy + _height);
- }
- lineTo(cx, cy);
- flush();
- }
- /**
- * Draws a quadratic Bezier curve using the current line style from the current drawing position to (cx, cy) and using the control point that (bx, by) specifies.
- * IvanK Lib port ( http://lib.ivank.net )
- */
- public function curveTo( bx : Float, by : Float, cx : Float, cy : Float) {
- var ax = tmpPoints.length == 0 ? 0 :tmpPoints[ tmpPoints.length - 1 ].x;
- var ay = tmpPoints.length == 0 ? 0 :tmpPoints[ tmpPoints.length - 1 ].y;
- var t = 2 / 3;
- cubicCurveTo(ax + t * (bx - ax), ay + t * (by - ay), cx + t * (bx - cx), cy + t * (by - cy), cx, cy);
- }
- /**
- * Draws a cubic Bezier curve from the current drawing position to the specified anchor point.
- * IvanK Lib port ( http://lib.ivank.net )
- * @param bx control X for start point
- * @param by control Y for start point
- * @param cx control X for end point
- * @param cy control Y for end point
- * @param dx end X
- * @param dy end Y
- * @param nsegments = 40
- */
- public function cubicCurveTo( bx : Float, by : Float, cx : Float, cy : Float, dx : Float, dy : Float, nsegments = 40) {
- var ax = tmpPoints.length == 0 ? 0 : tmpPoints[tmpPoints.length - 1].x;
- var ay = tmpPoints.length == 0 ? 0 : tmpPoints[tmpPoints.length - 1].y;
- var tobx = bx - ax, toby = by - ay;
- var tocx = cx - bx, tocy = cy - by;
- var todx = dx - cx, tody = dy - cy;
- var step = 1 / nsegments;
- for (i in 1...nsegments) {
- var d = i * step;
- var px = ax + d * tobx, py = ay + d * toby;
- var qx = bx + d * tocx, qy = by + d * tocy;
- var rx = cx + d * todx, ry = cy + d * tody;
- var toqx = qx - px, toqy = qy - py;
- var torx = rx - qx, tory = ry - qy;
- var sx = px + d * toqx, sy = py + d * toqy;
- var tx = qx + d * torx, ty = qy + d * tory;
- var totx = tx - sx, toty = ty - sy;
- lineTo(sx + d * totx, sy + d * toty);
- }
- lineTo(dx, dy);
- }
- /**
- Draws a straight line from the current drawing position to the given position.
- **/
- public inline function lineTo( x : Float, y : Float ) {
- addVertex(x, y, curR, curG, curB, curA, x * ma + y * mc + mx, x * mb + y * md + my);
- }
- /**
- Advanced usage. Adds new vertex to the current polygon with given parameters and current line style.
- @param x Vertex X position
- @param y Vertex Y position
- @param r Red tint value of the vertex when performing fill operation.
- @param g Green tint value of the vertex when performing fill operation.
- @param b Blue tint value of the vertex when performing fill operation.
- @param a Alpha of the vertex when performing fill operation.
- @param u Normalized horizontal Texture position from the current Tile fill operation.
- @param v Normalized vertical Texture position from the current Tile fill operation.
- **/
- public function addVertex( x : Float, y : Float, r : Float, g : Float, b : Float, a : Float, u : Float = 0., v : Float = 0. ) {
- var half = lineSize / 2.0;
- if( x - half < xMin ) xMin = x - half;
- if( y - half < yMin ) yMin = y - half;
- if( x + half > xMax ) xMax = x + half;
- if( y + half > yMax ) yMax = y + half;
- if( x < xMinSize ) xMinSize = x;
- if( y < yMinSize ) yMinSize = y;
- if( x > xMaxSize ) xMaxSize = x;
- if( y > yMaxSize ) yMaxSize = y;
- if( doFill )
- content.add(x, y, u, v, r, g, b, a);
- var gp = new GPoint();
- gp.load(x, y, lineR, lineG, lineB, lineA);
- tmpPoints.push(gp);
- }
- override function draw(ctx:RenderContext) {
- if( !ctx.beginDrawBatchState(this) ) return;
- content.doRender(ctx);
- }
- override function sync(ctx:RenderContext) {
- super.sync(ctx);
- flush();
- content.flush();
- }
- }
|