Module: Tea::Primitive
Overview
The PrimitiveDrawing mixin enables primitive shapes to be drawn to classes with an internal SDL::Surface.
To use this mixin, include it and implement/alias a primitive_buffer
method that gets the object’s SDL::Surface.
include 'Primitive'
def primitive_buffer
@internal_sdl_buffer
end
Constant Summary collapse
- BLEND_MIXER =
lambda do |src_r, src_g, src_b, src_a, dest_r, dest_g, dest_b, dest_a, intensity| ai = src_a * intensity ratio = dest_a > 0 ? ai / dest_a.to_f : 1 ratio = 1 if ratio > 1 final_r = dest_r + (src_r - dest_r) * ratio final_g = dest_g + (src_g - dest_g) * ratio final_b = dest_b + (src_b - dest_b) * ratio final_a = (dest_a + ai < 255) ? (dest_a + ai) : 255 [final_r, final_g, final_b, final_a] end
- REPLACE_MIXER =
lambda do |src_r, src_g, src_b, src_a, dest_r, dest_g, dest_b, dest_a, intensity| [src_r, src_g, src_b, src_a * intensity] end
Instance Method Summary collapse
-
#[](x, y) ⇒ Object
Get the color (0xRRGGBBAA) at the point (x, y) on the Bitmap.
-
#[]=(x, y, color) ⇒ Object
Plot a point at (x, y) with the given color (0xRRGGBBAA) on the Bitmap.
-
#circle(x, y, radius, color, options = nil) ⇒ Object
Draw a circle centred at (x, y) with the given radius and color (0xRRGGBBAA).
-
#clear ⇒ Object
Clear the drawing buffer.
-
#line(x1, y1, x2, y2, color, options = nil) ⇒ Object
Draw a line from (x1, y1) to (x2, y2) with the given color (0xRRGGBBAA).
-
#rect(x, y, w, h, color, options = nil) ⇒ Object
Draw a rectangle of size w * h with the top-left corner at (x, y) with the given color (0xRRGGBBAA).
Instance Method Details
#[](x, y) ⇒ Object
Get the color (0xRRGGBBAA) at the point (x, y) on the Bitmap.
Raises Tea::Error if (x, y) is outside of the Bitmap’s area.
32 33 34 35 36 37 38 39 40 |
# File 'lib/tea/mix_primitive.rb', line 32 def [](x, y) buffer = primitive_buffer w = buffer.w h = buffer.h if x < 0 || x >= w || y < 0 || y >= h raise Tea::Error, "can't get color at (#{x}, #{y}), not within #{w}x#{h}", caller end Color.mix(*buffer.get_rgba(buffer[x, y])) end |
#[]=(x, y, color) ⇒ Object
Plot a point at (x, y) with the given color (0xRRGGBBAA) on the Bitmap.
Raises Tea::Error if (x, y) is outside of the Bitmap’s area.
45 46 47 48 49 50 51 52 53 |
# File 'lib/tea/mix_primitive.rb', line 45 def []=(x, y, color) buffer = primitive_buffer w = buffer.w h = buffer.h if x < 0 || x >= w || y < 0 || y >= h raise Tea::Error, "can't plot point (#{x}, #{y}), not within #{w}x#{h}", caller end buffer[x, y] = primitive_color(color) end |
#circle(x, y, radius, color, options = nil) ⇒ Object
Draw a circle centred at (x, y) with the given radius and color (0xRRGGBBAA). Optional hash arguments:
:outline
-
If true, do not fill the circle, just draw an outline.
:antialias
-
If true, smooth the edges of the circle with antialiasing.
:mix
-
:blend
averages the RGB parts of the circle and destination colours by the colour’s alpha (default).:replace
writes over the RGBA parts of the circle’s destination pixels.
Raises Tea::Error if the radius is less than 0, or :mix is given an unrecognised symbol.
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/tea/mix_primitive.rb', line 161 def circle(x, y, radius, color, =nil) if radius < 0 raise Tea::Error, "can't draw circle with radius #{radius}", caller end r, g, b, a = Color.split(color) if == nil outline = false antialias = false mix = (a < 0xff) ? :blend : :replace else if [:mix] && [:blend, :replace].include?([:mix]) == false raise Tea::Error, "invalid mix option \"#{mix}\"", caller end outline = [:outline] || false antialias = [:antialias] || false mix = (a < 0xff) ? ([:mix] ? [:mix] : :blend) : :replace end if primitive_buffer.class == SDL::Screen case mix when :blend if !outline && antialias # rubysdl can't draw filled antialiased alpha circles for some reason. # Big endian because the SGE-powered circle antialiasing apparently # doesn't like it any other way. ts = SDL::Surface.new(SDL::SWSURFACE, (radius + 1) * 2, (radius + 1) * 2, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff) ts.draw_circle radius + 1, radius + 1, radius, ts.map_rgba(r, g, b, a), true, true SDL::Surface.blit ts, 0, 0, ts.w, ts.h, primitive_buffer, x - radius - 1, y - radius - 1 else primitive_buffer.draw_circle x, y, radius, primitive_rgba_to_color(r, g, b, 255), !outline, antialias, (a == 255 ? nil : a) end when :replace primitive_buffer.draw_circle x, y, radius, primitive_color(color), !outline, antialias end else # SGE and alpha mixing don't... mix. Gotta do it ourselves. mixer = (mix == :blend) ? BLEND_MIXER : REPLACE_MIXER primitive_circle x, y, radius, !outline, antialias, r, g, b, a, mixer end end |
#clear ⇒ Object
Clear the drawing buffer. This is the same as drawing a completely black rectangle over the whole buffer.
24 25 26 27 |
# File 'lib/tea/mix_primitive.rb', line 24 def clear primitive_buffer.fill_rect 0, 0, primitive_buffer.w, primitive_buffer.h, primitive_color(0x000000ff) end |
#line(x1, y1, x2, y2, color, options = nil) ⇒ Object
Draw a line from (x1, y1) to (x2, y2) with the given color (0xRRGGBBAA). Optional hash arguments:
:antialias
-
If true, smooth the line with antialiasing.
:mix
-
:blend
averages the RGB parts of the line and destination colours by the line alpha (default).:replace
writes over the RGBA parts of the line destination pixels.
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/tea/mix_primitive.rb', line 121 def line(x1, y1, x2, y2, color, =nil) r, g, b, a = Color.split(color) if == nil antialias = false mix = (a < 0xff) ? :blend : :replace else if [:mix] && [:blend, :replace].include?([:mix]) == false raise Tea::Error, "invalid mix option \"#{mix}\"", caller end antialias = [:antialias] || false mix = ([:mix] && a < 0xff) ? [:mix] : :replace mix = (a < 0xff) ? ([:mix] ? [:mix] : :blend) : :replace end if primitive_buffer.class == SDL::Screen primitive_buffer.draw_line x1, y1, x2, y2, primitive_rgba_to_color(r, g, b, (mix == :replace ? a : 255)), antialias, (mix == :blend ? a : nil) else if antialias primitive_aa_line x1, y1, x2, y2, r, g, b, a, (mix == :blend ? BLEND_MIXER : REPLACE_MIXER) else primitive_line x1, y1, x2, y2, r, g, b, a, (mix == :blend ? BLEND_MIXER : REPLACE_MIXER) end end end |
#rect(x, y, w, h, color, options = nil) ⇒ Object
Draw a rectangle of size w * h with the top-left corner at (x, y) with the given color (0xRRGGBBAA). Hash arguments that can be used:
:mix
-
:blend
averages the RGB parts the rectangle and destination colours according to the colour’s alpha (default).:replace
writes over the full RGBA parts of the rectangle area’s pixels.
Raises Tea::Error if w or h are less than 0, or if :mix
is given an unrecognised symbol.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/tea/mix_primitive.rb', line 80 def rect(x, y, w, h, color, =nil) if w < 0 || h < 0 || ( && [:mix] == :blend && (w < 1 || h < 1)) raise Tea::Error, "can't draw rectangle of size #{w}x#{h}", caller end r, g, b, a = Color.split(color) if == nil || [:mix] == nil mix = (a < 0xff) ? :blend : :replace else unless [:blend, :replace].include?([:mix]) raise Tea::Error, "invalid mix option \"#{[:mix]}\"", caller end mix = (a < 0xff) ? [:mix] : :replace end case mix when :blend if primitive_buffer.class == SDL::Screen # SGE's broken alpha blending doesn't matter on the screen, so # optimise for it. rubysdl's draw_rect is off-by-one for width and # height, so compensate for that. primitive_buffer.draw_rect x, y, w - 1, h - 1, primitive_rgba_to_color(r, g, b, 255), true, a else # CAUTION: This is _really_ slow, almost unusably so. Perhaps I # should consider not making :blend the default mix mode. primitive_rect x, y, w, h, r, g, b, a, BLEND_MIXER end when :replace primitive_buffer.fill_rect x, y, w, h, primitive_rgba_to_color(r, g, b, a) end end |