Class: RGame::Core::NineSlice
- Inherits:
-
Object
- Object
- RGame::Core::NineSlice
- Defined in:
- lib/rgame/core/nine_slice.rb
Overview
A bordered texture drawn at any size, by cutting it into nine pieces and treating each differently.
panel = RGame::Core::NineSlice.new(image, x: 0, y: 0, w: 26, h: 28,
border: 7, scale: 3)
panel.draw(renderer, x, y, width, height, z: 0)
The four corners keep their size, the four edges stretch along one axis and the centre along both — so one small piece of art fills a button, a dialog or a health bar without the corners smearing.
┌──┬────────┬──┐ corners: fixed
│tl│ top │tr│ top / bottom: tiled across
├──┼────────┼──┤ left / right: tiled down
│l │ centre │ r│ centre: tiled both ways
├──┼────────┼──┤
│bl│ bottom │br│
└──┴────────┴──┘
Edges and the centre are tiled, not stretched. Repeating a 7-pixel motif keeps pixel art crisp at any widget size; stretching it would blur exactly the detail the art was drawn for. Each band is clipped to itself, so the last tile in a row is cropped cleanly rather than spilling over the corner next to it.
scale is an integer pixel scale for the chrome itself. Source art is
small — corners are often 7 pixels — so a scale of 2 or 3 gives legible
borders on a 640x480 screen without any blurring, because every source
pixel becomes a whole square of screen pixels.
The nine pieces are cut once at construction, so #draw allocates
nothing. It is called once per widget per frame.
Instance Method Summary collapse
-
#draw(renderer, dx, dy, dw, dh, z: 0, color: nil) ⇒ Object
Fills the rectangle (dx, dy, dw, dh).
-
#initialize(image, x:, y:, w:, h:, border:, scale: 1) ⇒ NineSlice
constructor
borderis a uniform integer or a hash ofleft/right/top/bottom.
Constructor Details
#initialize(image, x:, y:, w:, h:, border:, scale: 1) ⇒ NineSlice
border is a uniform integer or a hash of left/right/top/bottom.
(x, y, w, h) is the source rectangle inside image, so one sheet can
hold many of these — which is what UiAtlas does with it.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/rgame/core/nine_slice.rb', line 43 def initialize(image, x:, y:, w:, h:, border:, scale: 1) # A zero or negative scale would give every tile a step of zero pixels, # and `#draw`'s tiling loops would never advance. Refusing it here costs # nothing; a guard inside the loop would cost a branch per tile, per # widget, per frame. raise ArgumentError, "nine-slice scale must be positive, got #{scale}" unless scale.positive? @scale = scale border = normalize_border(border) @l = border.fetch(:left) @r = border.fetch(:right) @t = border.fetch(:top) @b = border.fetch(:bottom) cut_pieces(image, x, y, w, h) end |
Instance Method Details
#draw(renderer, dx, dy, dw, dh, z: 0, color: nil) ⇒ Object
Fills the rectangle (dx, dy, dw, dh).
color tints every piece — a focus highlight, a disabled grey. A
rectangle smaller than its own borders draws its corners and nothing
else, which is the least misleading thing a widget too small for its own
chrome can look like.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/rgame/core/nine_slice.rb', line 66 def draw(renderer, dx, dy, dw, dh, z: 0, color: nil) s = @scale l = @l * s r = @r * s t = @t * s b = @b * s # These go negative for a rectangle narrower than its own borders, and # are not clamped: #band refuses a non-positive size anyway, so clamping # here would be a second guard that cannot change any outcome — and # would read as if the case were handled in two places. inner_w = dw - l - r inner_h = dh - t - b band(renderer, @centre, dx + l, dy + t, inner_w, inner_h, z, color) band(renderer, @top, dx + l, dy, inner_w, t, z, color) band(renderer, @bottom, dx + l, dy + dh - b, inner_w, b, z, color) band(renderer, @left, dx, dy + t, l, inner_h, z, color) band(renderer, @right, dx + dw - r, dy + t, r, inner_h, z, color) # Last, so a tile that reached the edge of its band is covered rather # than showing through a corner's transparent pixels. piece(renderer, @tl, dx, dy, z, color) piece(renderer, @tr, dx + dw - r, dy, z, color) piece(renderer, @bl, dx, dy + dh - b, z, color) piece(renderer, @br, dx + dw - r, dy + dh - b, z, color) end |