123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- package h2d;
- /**
- A simple 9-slice bitmap renderer.
- Enables rendering of the Tile as a stretchable surface with unscaled corners, stretched center and either stretched or tiled borders.
- Set `ScaleGrid.width` and `ScaleGrid.height` to resize the ScaleGrid.
- **/
- class ScaleGrid extends h2d.TileGroup {
- /**
- The width of the left border in pixels.
- **/
- public var borderLeft(default, set) : Int;
- /**
- The width of the right border in pixels.
- **/
- public var borderRight(default, set) : Int;
- /**
- The height of the top border in pixels.
- **/
- public var borderTop(default, set) : Int;
- /**
- The height of the bottom border in pixels.
- **/
- public var borderBottom(default, set) : Int;
- /**
- Set the width of left and right borders altogether.
- **/
- public var borderWidth(never,set) : Int;
- /**
- Set the height of top and bottom borders altogether.
- **/
- public var borderHeight(never,set) : Int;
- /**
- The width of the bitmap. Setting to values less than `borderLeft + borderRight` leads to undefined results.
- **/
- public var width(default,set) : Float;
- /**
- The height of the bitmap. Setting to values less than `borderTop + borderBottom` leads to undefined results.
- **/
- public var height(default,set) : Float;
- /**
- When enabled, borders will be repeated along the edges instead of stretching to match the desired dimensions.
- **/
- public var tileBorders(default, set) : Bool;
- /**
- When enabled, center will be repeated along the edges instead of stretching to match the desired dimensions.
- **/
- public var tileCenter(default, set) : Bool;
- /**
- When enabled, the borders will ignore the final scale of the `h2d.ScaleGrid` to be rendered pixel perfect.
- This does not change the values of `borderLeft`, `borderRight`, `borderTop` or `borderBottom`.
- Center tile is always stretched.
- **/
- public var ignoreScale(default, set) : Bool;
- /**
- Scale factor applied to borders only. If combined with `ignoreScale`, becomes an absolute scale independent from the scene scale.
- **/
- public var borderScale(default, set) : Float = 1.0;
- var contentTile : h2d.Tile;
- var currentScaleX = 1.;
- var currentScaleY = 1.;
- /**
- Create a new ScaleGrid with specified parameters.
- @param tile The source tile which will be sliced.
- @param borderW The width of the left and right borders in pixels.
- @param borderH The height of the top and bottom borders in pixels.
- @param parent An optional parent `h2d.Object` instance to which ScaleGrid adds itself if set.
- **/
- public function new( tile, borderL, borderT, ?borderR, ?borderB, ?parent ) {
- super(tile,parent);
- borderLeft = borderL;
- borderRight = (borderR != null)? borderR : borderL;
- borderTop = borderT;
- borderBottom = (borderB != null)? borderB : borderT;
- width = tile.width;
- height = tile.height;
- }
- function set_tileBorders(b) {
- if( tileBorders == b ) return b;
- this.tileBorders = b;
- clear();
- return b;
- }
- function set_tileCenter(b) {
- if( tileCenter == b ) return b;
- this.tileCenter = b;
- clear();
- return b;
- }
- function set_ignoreScale(b) {
- if(ignoreScale == b) return b;
- this.ignoreScale = b;
- clear();
- return b;
- }
- function set_borderScale(s) {
- if(borderScale == s) return s;
- this.borderScale = s;
- clear();
- return s;
- }
- function set_width(w) {
- if( width == w ) return w;
- this.width = w;
- clear();
- return w;
- }
- function set_height(h) {
- if( height == h ) return h;
- this.height = h;
- clear();
- return h;
- }
- function set_borderWidth(w) {
- if( borderLeft == w && borderRight == w ) return w;
- @:bypassAccessor borderLeft = w;
- @:bypassAccessor borderRight = w;
- clear();
- return w;
- }
- function set_borderHeight(h) {
- if( borderTop == h && borderBottom == h ) return h;
- @:bypassAccessor borderTop = h;
- @:bypassAccessor borderBottom = h;
- clear();
- return h;
- }
- function set_borderTop(top) {
- if( borderTop == top ) return top;
- this.borderTop = top;
- clear();
- return top;
- }
- function set_borderBottom(bot) {
- if( borderBottom == bot ) return bot;
- this.borderBottom = bot;
- clear();
- return bot;
- }
- function set_borderLeft(left) {
- if( borderLeft == left ) return left;
- this.borderLeft = left;
- clear();
- return left;
- }
- function set_borderRight(right) {
- if( borderRight == right ) return right;
- this.borderRight = right;
- clear();
- return right;
- }
- override function getBoundsRec(relativeTo, out, forSize) {
- checkUpdate();
- super.getBoundsRec(relativeTo, out, forSize);
- if( tile != null && tile.width == 1 && tile.height == 1 )
- addBounds(relativeTo, out, 0, 0, width, height);
- }
- function checkUpdate() {
- var needUpdate = false;
- if(ignoreScale){
- var s = getAbsPos().getScale();
- if(currentScaleX != s.x || currentScaleY != s.y){
- needUpdate = true;
- currentScaleX = s.x;
- currentScaleY = s.y;
- }
- }
- if( content.isEmpty() || tile != contentTile ) {
- contentTile = tile;
- needUpdate = true;
- }
- if(needUpdate){
- clear();
- updateContent();
- }
- }
- function updateContent() {
- if( tile != null && tile.width == 1 && tile.height == 1 )
- return;
- var bt = borderTop, bb = borderBottom, bl = borderLeft, br = borderRight;
- var unscaledBl : Float = bl * borderScale,
- unscaledBr : Float = br * borderScale,
- unscaledBt : Float = bt * borderScale,
- unscaledBb : Float = bb * borderScale;
- var invScaleX = 1.;
- var invScaleY = 1.;
- if(ignoreScale){
- var s = getAbsPos().getScale();
- if(s.x == 0. || s.y == 0.)
- return;
- invScaleX /= s.x;
- invScaleY /= s.y;
- unscaledBl *= invScaleX;
- unscaledBr *= invScaleX;
- unscaledBt *= invScaleY;
- unscaledBb *= invScaleY;
- }
- // 4 corners
- var t = tile.sub(0, 0, bl, bt);
- t.scaleToSize(unscaledBl, unscaledBt);
- content.addColor(0, 0, curColor, t);
- t = tile.sub(tile.width - br, 0, br, bt);
- t.scaleToSize(unscaledBr, unscaledBt);
- content.addColor(width - unscaledBr, 0, curColor, t);
- t = tile.sub(0, tile.height - bb, bl, bb);
- t.scaleToSize(unscaledBl, unscaledBb);
- content.addColor(0, height-unscaledBb, curColor, t);
- t = tile.sub(tile.width - br, tile.height - bb, br, bb);
- t.scaleToSize(unscaledBr, unscaledBb);
- content.addColor(width - unscaledBr, height - unscaledBb, curColor, t);
- var innerTileWidth = tile.width - (br + bl);
- var innerTileHeight = tile.height - (bb + bt);
- var innerWidth = width - (unscaledBl + unscaledBr);
- var innerHeight = height - (unscaledBt + unscaledBb);
- if( !tileBorders ) {
- // top
- var t = tile.sub(bl, 0, innerTileWidth, bt);
- t.scaleToSize(innerWidth, unscaledBt);
- content.addColor(unscaledBl, 0, curColor, t);
- // bottom
- var t = tile.sub(bl, tile.height - bb, innerTileWidth, bb);
- t.scaleToSize(innerWidth, unscaledBb);
- content.addColor(unscaledBl, innerHeight + unscaledBt, curColor, t);
- // left
- var t = tile.sub(0, bt, bl, innerTileHeight);
- t.scaleToSize(unscaledBl, innerHeight);
- content.addColor(0, unscaledBt, curColor, t);
- // right
- var t = tile.sub(tile.width - br, bt, br, innerTileHeight);
- t.scaleToSize(unscaledBr, innerHeight);
- content.addColor(innerWidth + unscaledBl, unscaledBt, curColor, t);
- } else {
- var unscaledInnerTileWidth = innerTileWidth * invScaleX;
- var unscaledInnerTileHeight = innerTileHeight * invScaleY;
- var rw = Std.int(innerWidth / unscaledInnerTileWidth);
- for( x in 0...rw ) {
- // top
- var t = tile.sub(bl, 0, innerTileWidth, bt);
- t.scaleToSize(unscaledInnerTileWidth, unscaledBt);
- content.addColor(unscaledBl + x * unscaledInnerTileWidth, 0, curColor, t);
- // bottom
- t = tile.sub(bl, tile.height - bb, innerTileWidth, bb);
- t.scaleToSize(unscaledInnerTileWidth, unscaledBb);
- content.addColor(unscaledBl + x * unscaledInnerTileWidth, height - unscaledBb, curColor, t);
- }
- var dx = innerWidth - rw * unscaledInnerTileWidth;
- if( dx > 0 ) {
- // top
- var t = tile.sub(bl, 0, dx / invScaleX, bt);
- t.scaleToSize(dx, unscaledBt);
- content.addColor(unscaledBl + rw * unscaledInnerTileWidth, 0, curColor, t);
- // bottom
- t = tile.sub(bl, tile.height - bb, dx / invScaleX, bb);
- t.scaleToSize(dx, unscaledBb);
- content.addColor(unscaledBl + rw * unscaledInnerTileWidth, height - unscaledBb, curColor, t);
- }
- var rh = Std.int(innerHeight / unscaledInnerTileHeight);
- for( y in 0...rh ) {
- // left
- var t = tile.sub(0, bt, bl, innerTileHeight);
- t.scaleToSize(unscaledBl, unscaledInnerTileHeight);
- content.addColor(0, unscaledBt + y * unscaledInnerTileHeight, curColor, t);
- // right
- t = tile.sub(tile.width - br, bt, br, innerTileHeight);
- t.scaleToSize(unscaledBr, unscaledInnerTileHeight);
- content.addColor(width - unscaledBr, unscaledBt + y * unscaledInnerTileHeight, curColor, t);
- }
- var dy = innerHeight - rh * unscaledInnerTileHeight;
- if( dy > 0 ) {
- // left
- var t = tile.sub(0, bt, bl, dy / invScaleY);
- t.scaleToSize(unscaledBl, dy);
- content.addColor(0, bt + rh * unscaledInnerTileHeight, curColor, t);
- // right
- t = tile.sub(tile.width - br, bt, br, dy / invScaleY);
- t.scaleToSize(unscaledBr, dy);
- content.addColor(width - unscaledBr, unscaledBt + rh * unscaledInnerTileHeight, curColor, t);
- }
- }
- if( !tileCenter ) {
- var t = tile.sub(bl, bt, innerTileWidth, innerTileHeight);
- t.scaleToSize(width - (unscaledBr + unscaledBl), height - (unscaledBt + unscaledBb));
- content.addColor(unscaledBl, unscaledBt, curColor, t);
- }
- else {
- var unscaledInnerTileWidth = innerTileWidth * invScaleX;
- var unscaledInnerTileHeight = innerTileHeight * invScaleY;
- var rw = Std.int( ( width - (unscaledBr + unscaledBl) ) / unscaledInnerTileWidth );
- var rh = Std.int(innerHeight / unscaledInnerTileHeight);
- for( y in 0...rh )
- for( x in 0...rw ) {
- var t = tile.sub(bl, bt, unscaledInnerTileWidth, unscaledInnerTileHeight);
- content.addColor(unscaledBl + x * unscaledInnerTileWidth, unscaledBt + y * unscaledInnerTileHeight, curColor, t);
- }
- var dx = innerWidth - rw * unscaledInnerTileWidth;
- if( dx > 0 ) {
- for( y in 0...rh ) {
- var t = tile.sub(bl, bt, dx, unscaledInnerTileHeight);
- content.addColor(unscaledBl + rw * unscaledInnerTileWidth, unscaledBt + y * unscaledInnerTileHeight, curColor, t);
- }
- }
- var dy = innerHeight - rh * unscaledInnerTileHeight;
- if( dy > 0 ) {
- for( x in 0...rw ) {
- var t = tile.sub(bl, bt, unscaledInnerTileWidth, dy);
- content.addColor(unscaledBl + x * unscaledInnerTileWidth, unscaledBt + rh * unscaledInnerTileHeight, curColor, t);
- }
- }
- if( dx > 0 && dy > 0 ) {
- var t = tile.sub(bl, bt, dx, dy);
- content.addColor(unscaledBl + rw * unscaledInnerTileWidth, unscaledBt + rh * unscaledInnerTileHeight, curColor, t);
- }
- }
- }
- override function draw(ctx:RenderContext) {
- if( tile != null && tile.width == 1 && tile.height == 1 ) @:privateAccess {
- var ow = tile.width;
- var oh = tile.height;
- tile.width = width;
- tile.height = height;
- emitTile(ctx,tile);
- tile.width = ow;
- tile.height = oh;
- return;
- }
- super.draw(ctx);
- }
- override function sync( ctx : RenderContext ) {
- checkUpdate();
- super.sync(ctx);
- }
- }
|