Mask.hx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package h2d;
  2. /**
  3. Restricts rendering area within the `[width, height]` rectangle.
  4. For more advanced masking, see `h2d.filter.AbstractMask`.
  5. Rotation of the mask does not rotate the masked area and instead causes it to cover the bounding box of the mask.
  6. The `Mask.maskWidth` and `Mask.unmask` can be used to mask out rendering area without direct usage of Mask instance in-between.
  7. **/
  8. class Mask extends Object {
  9. /**
  10. Masks render zone based off object position and given dimensions.
  11. Should call `Mask.unmask()` afterwards.
  12. @param ctx The render context to mask.
  13. @param object An Object which transform will be used as mask origin.
  14. @param width The width of the mask in scene coordinate space.
  15. @param height The height of the mask in scene coordinate space.
  16. @param scrollX Additional horizontal offset of the masked area.
  17. @param scrollY Additional vertical offset of the masked area.
  18. **/
  19. @:access(h2d.RenderContext)
  20. public static function maskWith( ctx : RenderContext, object : Object, width : Int, height : Int, scrollX : Float = 0, scrollY : Float = 0) {
  21. var x1 = object.absX + scrollX;
  22. var y1 = object.absY + scrollY;
  23. var x2 = width * object.matA + height * object.matC + x1;
  24. var y2 = width * object.matB + height * object.matD + y1;
  25. var tmp;
  26. if (x1 > x2) {
  27. tmp = x1;
  28. x1 = x2;
  29. x2 = tmp;
  30. }
  31. if (y1 > y2) {
  32. tmp = y1;
  33. y1 = y2;
  34. y2 = tmp;
  35. }
  36. ctx.flush();
  37. ctx.clipRenderZone(x1, y1, x2-x1, y2-y1);
  38. }
  39. /**
  40. Unmasks the previously masked area from `Mask.maskWith`.
  41. @param ctx The render context to unmask.
  42. **/
  43. public static function unmask( ctx : RenderContext ) {
  44. ctx.flush();
  45. ctx.popRenderZone();
  46. }
  47. /**
  48. The width of the masked area.
  49. **/
  50. public var width : Int;
  51. /**
  52. The height of the masked area.
  53. **/
  54. public var height : Int;
  55. /**
  56. Horizontal scroll offset of the Mask content in pixels. Can be clamped by `Mask.scrollBounds`.
  57. **/
  58. public var scrollX(default, set) : Float = 0;
  59. /**
  60. Vertical scroll offset of the Mask content in pixels. Can be clamped by `Mask.scrollBounds`.
  61. **/
  62. public var scrollY(default, set) : Float = 0;
  63. /**
  64. Optional scroll boundaries that prevent content from overscroll.
  65. **/
  66. public var scrollBounds : h2d.col.Bounds;
  67. /**
  68. Create a new Mask instance.
  69. @param width The width of the masked area.
  70. @param height The height of the masked area.
  71. @param parent An optional parent `h2d.Object` instance to which Mask adds itself if set.
  72. **/
  73. public function new(width, height, ?parent) {
  74. super(parent);
  75. this.width = width;
  76. this.height = height;
  77. }
  78. /**
  79. Scroll the Mask content to the specified offset.
  80. **/
  81. public function scrollTo( x : Float, y : Float ) {
  82. scrollX = x;
  83. scrollY = y;
  84. }
  85. /**
  86. Scroll the Mask content by the specified offset relative to the current scroll offset.
  87. **/
  88. public function scrollBy( x : Float, y : Float ) {
  89. scrollX += x;
  90. scrollY += y;
  91. }
  92. function set_scrollX( v : Float ) : Float {
  93. if ( scrollBounds != null ) v = hxd.Math.clamp(v, scrollBounds.xMin, scrollBounds.xMax - width);
  94. posChanged = true;
  95. return scrollX = v;
  96. }
  97. function set_scrollY( v : Float ) : Float {
  98. if ( scrollBounds != null ) v = hxd.Math.clamp(v, scrollBounds.yMin, scrollBounds.yMax - height);
  99. posChanged = true;
  100. return scrollY = v;
  101. }
  102. override function calcAbsPos() {
  103. super.calcAbsPos();
  104. absX -= scrollX;
  105. absY -= scrollY;
  106. }
  107. override function getBoundsRec( relativeTo, out:h2d.col.Bounds, forSize ) {
  108. var xMin = out.xMin, yMin = out.yMin, xMax = out.xMax, yMax = out.yMax;
  109. out.empty();
  110. if( posChanged ) {
  111. calcAbsPos();
  112. for( c in children )
  113. c.posChanged = true;
  114. posChanged = false;
  115. }
  116. addBounds(relativeTo, out, scrollX, scrollY, width, height);
  117. var bxMin = out.xMin, byMin = out.yMin, bxMax = out.xMax, byMax = out.yMax;
  118. out.xMin = xMin;
  119. out.xMax = xMax;
  120. out.yMin = yMin;
  121. out.yMax = yMax;
  122. super.getBoundsRec(relativeTo, out, forSize);
  123. if( out.xMin < bxMin ) out.xMin = hxd.Math.min(xMin, bxMin);
  124. if( out.yMin < byMin ) out.yMin = hxd.Math.min(yMin, byMin);
  125. if( out.xMax > bxMax ) out.xMax = hxd.Math.max(xMax, bxMax);
  126. if( out.yMax > byMax ) out.yMax = hxd.Math.max(yMax, byMax);
  127. }
  128. override function drawRec( ctx : h2d.RenderContext ) @:privateAccess {
  129. maskWith(ctx, this, width, height, scrollX, scrollY);
  130. super.drawRec(ctx);
  131. unmask(ctx);
  132. }
  133. }