Class: Ruby2D::Canvas

Inherits:
Object
  • Object
show all
Includes:
Renderable
Defined in:
lib/ruby2d/canvas.rb

Constant Summary

Constants included from Interactive

Interactive::OBJECT_EVENTS, Interactive::OBJECT_EVENT_FILTER_PREDICATES

Instance Attribute Summary collapse

Attributes included from Renderable

#color, #padding_bottom, #padding_left, #padding_right, #padding_top, #visible, #x_align, #y_align, #z

Instance Method Summary collapse

Methods included from Renderable

#_alignment_anchor_dx, #_alignment_anchor_dy, #_apply_padding, #_extract_alignment, #_point_in_polygon?, #_point_on_segment?, #_require_numeric_position, #_resolve_alignment, #_unrotate, #_validate_dimensions, #add, #colour=, #contains?, flatten_color, flatten_per_vertex, flatten_points, flatten_resolved_color, #hide, #padding=, #remove, resolve_color_or_default, resolve_single_color, #show

Methods included from Interactive

#_fire_event, #interactive?, #off, #on

Constructor Details

#initialize(width:, height:, x: 0, y: 0, z: 0, rotate: 0, fill: [0, 0, 0, 0], tint: nil, opacity: nil, add: true, visible: true) ⇒ Canvas

Create a canvas with the given dimensions



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/ruby2d/canvas.rb', line 17

def initialize(width:, height:, x: 0, y: 0, z: 0, rotate: 0,
               fill: [0, 0, 0, 0], tint: nil, opacity: nil,
               add: true, visible: true)
  self.x = x
  self.y = y
  @z = z
  @width = width
  @height = height
  @rotate = rotate
  @_user_rx = nil
  @_user_ry = nil
  @fill = Color.new(fill)
  self.tint = tint || 'white'
  self.opacity = opacity unless opacity.nil?

  @fill_r = @fill.r
  @fill_g = @fill.g
  @fill_b = @fill.b
  @fill_a = @fill.a

  Ext.canvas_create(self)
  @visible = visible
  self.add if add
end

Instance Attribute Details

#fillObject (readonly)

Returns the value of attribute fill.



14
15
16
# File 'lib/ruby2d/canvas.rb', line 14

def fill
  @fill
end

#heightObject

Returns the value of attribute height.



13
14
15
# File 'lib/ruby2d/canvas.rb', line 13

def height
  @height
end

#rotateObject

Returns the value of attribute rotate.



13
14
15
# File 'lib/ruby2d/canvas.rb', line 13

def rotate
  @rotate
end

#widthObject

Returns the value of attribute width.



13
14
15
# File 'lib/ruby2d/canvas.rb', line 13

def width
  @width
end

#xObject

Returns the value of attribute x.



14
15
16
# File 'lib/ruby2d/canvas.rb', line 14

def x
  @x
end

#yObject

Returns the value of attribute y.



14
15
16
# File 'lib/ruby2d/canvas.rb', line 14

def y
  @y
end

Instance Method Details

#_render_sceneObject

Scene-graph draw hook (see Renderable#_render_scene): render with no overrides, minus its keyword handling — a zero-arg call into a keyword-heavy render still pays microseconds of keyword setup on wasm mruby.



518
519
520
# File 'lib/ruby2d/canvas.rb', line 518

def _render_scene
  Ext.canvas_draw(self, rx, ry)
end

#clear(fill_color = nil, color: nil, colour: nil, x: 0, y: 0, width: @width, height: @height) ⇒ Object

Clear the canvas, resetting all pixels to the fill color (or the given color). The color may be passed positionally or via color:/colour:, matching the rest of the draw API. Optionally clear only a rectangular region.



466
467
468
469
470
471
# File 'lib/ruby2d/canvas.rb', line 466

def clear(fill_color = nil, color: nil, colour: nil, x: 0, y: 0, width: @width, height: @height)
  return unless validate4(:clear, x, y, width, height)
  input = fill_color || color || colour
  c = input ? Color.new(input) : @fill
  Ext.canvas_clear(self, [c.r, c.g, c.b, c.a, x, y, width, height])
end

#draw_image(image, x: 0, y: 0, width: nil, height: nil) ⇒ Object

Draw an Image onto this canvas at the given position and size



445
446
447
448
449
450
# File 'lib/ruby2d/canvas.rb', line 445

def draw_image(image, x: 0, y: 0, width: nil, height: nil)
  w = width || image.width
  h = height || image.height
  return unless validate4(:draw_image, x, y, w, h)
  Ext.canvas_draw_image(self, image, [x, y, w, h])
end

#draw_line(x1: nil, y1: nil, x2: nil, y2: nil, points: nil, stroke_width: 1, dash: 0, gap: 5, color: nil, colour: nil, opacity: nil) ⇒ Object

Draw a line. Specify endpoints via points: or via numbered kwargs. Pass dash: (and optionally gap:) to draw a dashed line. color: accepts a single color or a Color::Set of 2 (start, end) for a gradient along the length.



364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
# File 'lib/ruby2d/canvas.rb', line 364

def draw_line(x1: nil, y1: nil, x2: nil, y2: nil,
              points: nil, stroke_width: 1, dash: 0, gap: 5,
              color: nil, colour: nil, opacity: nil)
  if points
    validate_points(points, 2, :draw_line)
    x1, y1 = points[0]
    x2, y2 = points[1]
  end
  return unless validate_vertex4(:draw_line, x1, y1, x2, y2)
  opacity = clamp_opacity(opacity) if opacity
  c = resolve_color_or_set(color || colour)
  if c.is_a?(Color::Set)
    raise ArgumentError, 'Color::Set for draw_line must have 2 colors (start, end)' unless c.length == 2
    Ext.canvas_draw_line_lerp(self, [
      x1, y1, x2, y2, stroke_width,
      c[0].r, c[0].g, c[0].b, opacity || c[0].a,
      c[0].r, c[0].g, c[0].b, opacity || c[0].a,
      c[1].r, c[1].g, c[1].b, opacity || c[1].a,
      c[1].r, c[1].g, c[1].b, opacity || c[1].a,
      dash, gap
    ])
  else
    # `c` is already a drawable Color (or the canvas tint); read it directly
    # instead of allocating a second Color via resolve_draw_color.
    Ext.canvas_draw_line(self, x1, y1, x2, y2, stroke_width, c.r, c.g, c.b, opacity || c.a, dash, gap)
  end
end

#draw_lines(segments:, stroke_width: 1, color: nil, colour: nil, opacity: nil) ⇒ Object

Draw many line segments with a single shared color and stroke width in one call. segments is an array of [[x, y], [x, y]] endpoint pairs.



394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
# File 'lib/ruby2d/canvas.rb', line 394

def draw_lines(segments:, stroke_width: 1, color: nil, colour: nil, opacity: nil)
  return if segments.empty?

  n = segments.length
  # Fused validate-and-build pass (`while`, not blocks) — per draw call
  # over N segments; see fill_rectangles.
  payload = [n]
  i = 0
  while i < n
    s = segments[i]
    unless s.is_a?(Array) && s.length == 2
      raise ArgumentError, 'segments must be an array of [[x, y], [x, y]] endpoint pairs'
    end
    a = s[0]
    b = s[1]
    unless a.is_a?(Array) && a.length == 2 && b.is_a?(Array) && b.length == 2
      raise ArgumentError, 'segments must be an array of [[x, y], [x, y]] endpoint pairs'
    end
    payload.push(a[0], a[1], b[0], b[1])
    i += 1
  end
  opacity = clamp_opacity(opacity) if opacity
  c = resolve_draw_color(color || colour)
  payload.push(stroke_width, c.r, c.g, c.b, opacity || c.a)
  Ext.canvas_draw_lines(self, payload)
end

#draw_polyline(points:, stroke_width: 1, color: nil, colour: nil, closed: false, opacity: nil) ⇒ Object

Draw a polyline from an array of [x, y] pairs. Set closed: true to connect the last point back to the first. color: accepts a single color or a Color::Set of N (one per vertex) interpolated along the path.



425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
# File 'lib/ruby2d/canvas.rb', line 425

def draw_polyline(points:, stroke_width: 1, color: nil, colour: nil, closed: false, opacity: nil)
  validate_point_pairs(points)
  n = points.length
  return if n < 2
  return unless validate_pair_coords(points, :draw_polyline)

  colors = expand_stroke_colors(color || colour, n, opacity, label: :draw_polyline)
  payload = [closed ? 1 : 0, n]
  i = 0
  while i < n
    p = points[i]
    payload.push(p[0], p[1])
    i += 1
  end
  payload.push(stroke_width)
  payload.concat(colors)
  Ext.canvas_stroke_polyline(self, payload)
end

#draw_text(text, x: 0, y: 0, width: nil, height: nil, color: nil, colour: nil, opacity: nil) ⇒ Object

Draw a Text onto this canvas at the given position and size, with optional color



453
454
455
456
457
458
459
460
# File 'lib/ruby2d/canvas.rb', line 453

def draw_text(text, x: 0, y: 0, width: nil, height: nil, color: nil, colour: nil, opacity: nil)
  w = width || text.width
  h = height || text.height
  return unless validate4(:draw_text, x, y, w, h)
  opacity = clamp_opacity(opacity) if opacity
  c = resolve_draw_color(color || colour)
  Ext.canvas_draw_text(self, text, [x, y, w, h, c.r, c.g, c.b, opacity || c.a])
end

#fill_circle(x:, y:, radius:, color: nil, colour: nil, opacity: nil) ⇒ Object

Fill a circle centered at (x,y) with the given radius



238
239
240
# File 'lib/ruby2d/canvas.rb', line 238

def fill_circle(x:, y:, radius:, color: nil, colour: nil, opacity: nil)
  fill_ellipse(x: x, y: y, xradius: radius, yradius: radius, color: color, colour: colour, opacity: opacity)
end

#fill_ellipse(x:, y:, xradius:, yradius:, color: nil, colour: nil, opacity: nil) ⇒ Object

Fill an ellipse centered at (x,y) with the given x and y radii



243
244
245
246
247
248
249
250
251
# File 'lib/ruby2d/canvas.rb', line 243

def fill_ellipse(x:, y:, xradius:, yradius:, color: nil, colour: nil, opacity: nil)
  if opacity.is_a?(Array)
    raise ArgumentError, 'fill_ellipse/fill_circle is rasterized, not vertex-based, so it does not support a per-vertex opacity array'
  end
  return unless validate4(:fill_ellipse, x, y, xradius, yradius)
  opacity = clamp_opacity(opacity) if opacity
  c = resolve_draw_color(color || colour)
  Ext.canvas_fill_ellipse(self, x, y, xradius, yradius, c.r, c.g, c.b, opacity || c.a)
end

#fill_pixel_grid(cols:, rows:, cell_w:, cell_h:, colors:, x: 0, y: 0) ⇒ Object

Fill a regular grid of equal-size rectangles, each with its own color, in one call. The cell at column c, row r covers (x + c*cell_w, y + r*cell_h, cell_w, cell_h) and is colored by colors[(r*cols + c)*4 .. +3]. colors is a flat array of cols*rows*4 floats in 0..1: r0, g0, b0, a0, r1, g1, b1, a1, .... Cells with alpha 0 are skipped. Designed for grid renderings (fluid sims, heatmaps, tile fields) where per-rect FFI overhead dominates over the actual pixel work.



221
222
223
224
225
226
227
228
229
230
# File 'lib/ruby2d/canvas.rb', line 221

def fill_pixel_grid(cols:, rows:, cell_w:, cell_h:, colors:, x: 0, y: 0)
  return if cols < 1 || rows < 1
  return unless validate4(:fill_pixel_grid, cell_w, cell_h, x, y)
  expected = cols * rows * 4
  unless colors.length == expected
    raise ArgumentError,
          "colors must have #{expected} elements (cols*rows*4), got #{colors.length}"
  end
  Ext.canvas_fill_pixel_grid(self, [cols, rows, cell_w, cell_h, x, y], colors)
end

#fill_polygon(points:, color: nil, colour: nil, opacity: nil) ⇒ Object

Fill a polygon defined by an array of [x, y] pairs. Concave polygons fill correctly: triangulation happens in C via ear clipping (R2D_TriangulatePolygon), shared with Polygon.new.



256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# File 'lib/ruby2d/canvas.rb', line 256

def fill_polygon(points:, color: nil, colour: nil, opacity: nil)
  validate_point_pairs(points)
  n = points.length
  return if n < 3
  return unless validate_pair_coords(points, :fill_polygon)

  opacity = clamp_opacity(opacity) if opacity
  c = resolve_color_or_set(color || colour)
  # `while` loops, not blocks — this is a per-draw-call path over N points
  # and block calls dominate on wasm mruby.
  if c.is_a?(Color::Set) || opacity.is_a?(Array)
    colors = per_vertex_fill_tuples(c, opacity, n, :fill_polygon)
    payload = [n]
    i = 0
    while i < n
      p = points[i]
      col = colors[i]
      payload.push(p[0], p[1], col[0], col[1], col[2], col[3])
      i += 1
    end
    Ext.canvas_fill_polygon_lerp(self, payload)
  else
    payload = [n]
    i = 0
    while i < n
      p = points[i]
      payload.push(p[0], p[1])
      i += 1
    end
    payload.push(c.r, c.g, c.b, opacity || c.a)
    Ext.canvas_fill_polygon(self, payload)
  end
end

#fill_quad(x1: nil, y1: nil, x2: nil, y2: nil, x3: nil, y3: nil, x4: nil, y4: nil, points: nil, color: nil, colour: nil, opacity: nil) ⇒ Object

Fill a quadrilateral. Specify vertices via points: or via numbered kwargs.



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/ruby2d/canvas.rb', line 119

def fill_quad(x1: nil, y1: nil, x2: nil, y2: nil, x3: nil, y3: nil, x4: nil, y4: nil,
              points: nil, color: nil, colour: nil, opacity: nil)
  if points
    validate_points(points, 4, :fill_quad)
    x1, y1 = points[0]
    x2, y2 = points[1]
    x3, y3 = points[2]
    x4, y4 = points[3]
  end
  return unless validate_vertex8(:fill_quad, x1, y1, x2, y2, x3, y3, x4, y4)
  opacity = clamp_opacity(opacity) if opacity
  c = resolve_color_or_set(color || colour)
  if c.is_a?(Color::Set) || opacity.is_a?(Array)
    colors = per_vertex_fill_tuples(c, opacity, 4, :fill_quad)
    # Split into triangles (0,1,2) and (0,2,3), each carrying its vertices'
    # colors so the per-vertex gradient interpolates across the quad.
    Ext.canvas_fill_triangle_lerp(self,
      [x1, y1, *colors[0], x2, y2, *colors[1], x3, y3, *colors[2]])
    Ext.canvas_fill_triangle_lerp(self,
      [x1, y1, *colors[0], x3, y3, *colors[2], x4, y4, *colors[3]])
  else
    a = opacity || c.a
    Ext.canvas_fill_triangle(self, x1, y1, x2, y2, x3, y3, c.r, c.g, c.b, a)
    Ext.canvas_fill_triangle(self, x1, y1, x3, y3, x4, y4, c.r, c.g, c.b, a)
  end
end

#fill_rectangle(x:, y:, width:, height:, color: nil, colour: nil, opacity: nil) ⇒ Object

Fill a rectangle at position (x,y) with the given width and height



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/ruby2d/canvas.rb', line 147

def fill_rectangle(x:, y:, width:, height:, color: nil, colour: nil, opacity: nil)
  return unless validate4(:fill_rectangle, x, y, width, height)
  opacity = clamp_opacity(opacity) if opacity
  c = resolve_color_or_set(color || colour)
  # Per-vertex (corner) coloring or opacity needs the quad path; a single
  # flat color uses the dedicated rectangle rasterizer.
  if c.is_a?(Color::Set) || opacity.is_a?(Array)
    fill_quad(
      x1: x, y1: y, x2: x + width, y2: y,
      x3: x + width, y3: y + height, x4: x, y4: y + height,
      color: c, opacity: opacity
    )
  else
    # `c` is already a drawable Color (or the canvas tint) from
    # resolve_color_or_set; read it directly instead of allocating a second
    # Color via resolve_draw_color.
    Ext.canvas_fill_rectangle(self, x, y, width, height, c.r, c.g, c.b, opacity || c.a)
  end
end

#fill_rectangles(rectangles:, color: nil, colour: nil, opacity: nil) ⇒ Object

Fill many rectangles with a single shared color in one call. rectangles is an array of [x, y, width, height] tuples.



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
209
210
211
# File 'lib/ruby2d/canvas.rb', line 169

def fill_rectangles(rectangles:, color: nil, colour: nil, opacity: nil)
  return if rectangles.empty?
  if opacity.is_a?(Array)
    raise ArgumentError, 'fill_rectangles uses a single shared color and does not support a per-vertex opacity array'
  end
  opacity = clamp_opacity(opacity) if opacity

  # One fused validate-and-build pass (`while`, not blocks — this runs per
  # draw call on N tuples, and block calls dominate on wasm mruby). A
  # malformed tuple or non-Numeric coordinate is a programming mistake —
  # raise, as the vertex-based methods do. A rect carrying a non-finite
  # (NaN/Inf) coordinate or size is instead dropped rather than forwarded
  # to C; the finite-only payload keeps the draw a clean no-op for the bad
  # rects while still drawing the good ones.
  payload = [0]
  count = 0
  i = 0
  size = rectangles.size
  while i < size
    r = rectangles[i]
    unless r.is_a?(Array) && r.length == 4
      raise ArgumentError, 'rectangles must be an array of [x, y, width, height] tuples'
    end
    x = r[0]
    y = r[1]
    w = r[2]
    h = r[3]
    unless x.is_a?(Numeric) && y.is_a?(Numeric) && w.is_a?(Numeric) && h.is_a?(Numeric)
      raise ArgumentError, 'fill_rectangles: every coordinate must be a number'
    end
    if finite4?(x, y, w, h)
      count += 1
      payload.push(x, y, w, h)
    end
    i += 1
  end
  return if count.zero?

  payload[0] = count
  c = resolve_draw_color(color || colour)
  payload.push(c.r, c.g, c.b, opacity || c.a)
  Ext.canvas_fill_rectangles(self, payload)
end

#fill_square(x:, y:, size:, color: nil, colour: nil, opacity: nil) ⇒ Object

Fill a square at position (x,y) with the given size



233
234
235
# File 'lib/ruby2d/canvas.rb', line 233

def fill_square(x:, y:, size:, color: nil, colour: nil, opacity: nil)
  fill_rectangle(x: x, y: y, width: size, height: size, color: color, colour: colour, opacity: opacity)
end

#fill_triangle(x1: nil, y1: nil, x2: nil, y2: nil, x3: nil, y3: nil, points: nil, color: nil, colour: nil, opacity: nil) ⇒ Object

Fill a triangle. Specify vertices via points: or via numbered kwargs.



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/ruby2d/canvas.rb', line 95

def fill_triangle(x1: nil, y1: nil, x2: nil, y2: nil, x3: nil, y3: nil,
                  points: nil, color: nil, colour: nil, opacity: nil)
  if points
    validate_points(points, 3, :fill_triangle)
    x1, y1 = points[0]
    x2, y2 = points[1]
    x3, y3 = points[2]
  end
  return unless validate_vertex6(:fill_triangle, x1, y1, x2, y2, x3, y3)
  opacity = clamp_opacity(opacity) if opacity
  c = resolve_color_or_set(color || colour)
  # A single flat color reads its channels straight into the C call; only
  # a `Color::Set` or per-vertex opacity array builds the tuple array.
  if c.is_a?(Color::Set) || opacity.is_a?(Array)
    colors = per_vertex_fill_tuples(c, opacity, 3, :fill_triangle)
    Ext.canvas_fill_triangle_lerp(self,
      [x1, y1, *colors[0], x2, y2, *colors[1], x3, y3, *colors[2]])
  else
    Ext.canvas_fill_triangle(self, x1, y1, x2, y2, x3, y3,
                             c.r, c.g, c.b, opacity || c.a)
  end
end

#opacityObject

Get the tint's opacity. Canvas overrides Renderable#opacity because its modulating color is @tint, not @color.



54
55
56
# File 'lib/ruby2d/canvas.rb', line 54

def opacity
  @tint&.opacity
end

#opacity=(value) ⇒ Object



58
59
60
# File 'lib/ruby2d/canvas.rb', line 58

def opacity=(value)
  @tint.opacity = value
end

#render(x: nil, y: nil, width: nil, height: nil, rotate: nil, tint: nil, opacity: nil) ⇒ Object

Render the canvas. Called with overrides for one-shot rendering inside a render block; with no arguments it draws the same frame the scene graph does (delegating to _render_scene). width:/height: scale the displayed output — the underlying pixel buffer is fixed at construction.



477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
# File 'lib/ruby2d/canvas.rb', line 477

def render(x: nil, y: nil, width: nil, height: nil, rotate: nil,
           tint: nil, opacity: nil)
  if x.nil? && y.nil? && width.nil? && height.nil? && rotate.nil? &&
     tint.nil? && opacity.nil?
    return _render_scene
  end

  Window.render_ready_check

  saved_x, saved_y = @x, @y
  saved_width, saved_height = @width, @height
  saved_rotate = @rotate
  saved_tint = @tint

  @x = x if x
  @y = y if y
  @width = width if width
  @height = height if height
  @rotate = rotate if rotate

  if tint || opacity
    @tint = tint ? Color.new(tint) : Color.new(saved_tint)
    @tint.opacity = opacity if opacity
  end

  begin
    Ext.canvas_draw(self, rx, ry)
  ensure
    @x, @y = saved_x, saved_y
    @width, @height = saved_width, saved_height
    @rotate = saved_rotate
    @tint = saved_tint
  end
end

#rxObject

Get the rotation center x coordinate



75
76
77
# File 'lib/ruby2d/canvas.rb', line 75

def rx
  @_user_rx.nil? ? @x + @width / 2.0 : @_user_rx
end

#rx=(val) ⇒ Object

Set the rotation center x coordinate



85
86
87
# File 'lib/ruby2d/canvas.rb', line 85

def rx=(val)
  @_user_rx = val
end

#ryObject

Get the rotation center y coordinate



80
81
82
# File 'lib/ruby2d/canvas.rb', line 80

def ry
  @_user_ry.nil? ? @y + @height / 2.0 : @_user_ry
end

#ry=(val) ⇒ Object

Set the rotation center y coordinate



90
91
92
# File 'lib/ruby2d/canvas.rb', line 90

def ry=(val)
  @_user_ry = val
end

#stroke_circle(x:, y:, radius:, sectors: 30, stroke_width: 1, color: nil, colour: nil, opacity: nil) ⇒ Object

Stroke a circle outline centered at (x,y) with the given radius. Single color only — sectors have no natural vertex identity.



339
340
341
342
# File 'lib/ruby2d/canvas.rb', line 339

def stroke_circle(x:, y:, radius:, sectors: 30, stroke_width: 1, color: nil, colour: nil, opacity: nil)
  stroke_ellipse(x: x, y: y, xradius: radius, yradius: radius, sectors: sectors,
                 stroke_width: stroke_width, color: color, colour: colour, opacity: opacity)
end

#stroke_ellipse(x:, y:, xradius:, yradius:, sectors: 30, stroke_width: 1, color: nil, colour: nil, opacity: nil) ⇒ Object

Stroke an ellipse outline centered at (x,y) with the given x and y radii. Single color only — sectors have no natural vertex identity.



346
347
348
349
350
351
352
353
354
355
356
357
358
# File 'lib/ruby2d/canvas.rb', line 346

def stroke_ellipse(x:, y:, xradius:, yradius:, sectors: 30, stroke_width: 1, color: nil, colour: nil, opacity: nil)
  c = resolve_draw_color(color || colour)
  a = (clamp_opacity(opacity) if opacity) || c.a
  verts = []
  colors = []
  sectors.times do |i|
    angle = 2.0 * Math::PI * i / sectors
    verts << x + xradius * Math.cos(angle)
    verts << y + yradius * Math.sin(angle)
    colors << c.r << c.g << c.b << a
  end
  Ext.canvas_stroke_polygon(self, [sectors, *verts, stroke_width, *colors])
end

#stroke_quad(x1: nil, y1: nil, x2: nil, y2: nil, x3: nil, y3: nil, x4: nil, y4: nil, points: nil, stroke_width: 1, color: nil, colour: nil, opacity: nil) ⇒ Object

Stroke a quadrilateral outline. Specify vertices via points: or via numbered kwargs. color: accepts a single color or a Color::Set of 4 (one per vertex) interpolated around the perimeter.



309
310
311
312
313
314
315
316
317
318
319
320
321
# File 'lib/ruby2d/canvas.rb', line 309

def stroke_quad(x1: nil, y1: nil, x2: nil, y2: nil, x3: nil, y3: nil, x4: nil, y4: nil,
                points: nil, stroke_width: 1, color: nil, colour: nil, opacity: nil)
  if points
    validate_points(points, 4, :stroke_quad)
    x1, y1 = points[0]
    x2, y2 = points[1]
    x3, y3 = points[2]
    x4, y4 = points[3]
  end
  return unless validate_vertex8(:stroke_quad, x1, y1, x2, y2, x3, y3, x4, y4)
  colors = expand_stroke_colors(color || colour, 4, opacity, label: :stroke_quad)
  Ext.canvas_stroke_polygon(self, [4, x1, y1, x2, y2, x3, y3, x4, y4, stroke_width, *colors])
end

#stroke_rectangle(x:, y:, width:, height:, stroke_width: 1, color: nil, colour: nil, opacity: nil) ⇒ Object

Stroke a rectangle outline at position (x,y) with the given width and height



324
325
326
327
328
329
330
# File 'lib/ruby2d/canvas.rb', line 324

def stroke_rectangle(x:, y:, width:, height:, stroke_width: 1, color: nil, colour: nil, opacity: nil)
  stroke_quad(
    x1: x, y1: y, x2: x + width, y2: y,
    x3: x + width, y3: y + height, x4: x, y4: y + height,
    stroke_width: stroke_width, color: color, colour: colour, opacity: opacity
  )
end

#stroke_square(x:, y:, size:, stroke_width: 1, color: nil, colour: nil, opacity: nil) ⇒ Object

Stroke a square outline at position (x,y) with the given size



333
334
335
# File 'lib/ruby2d/canvas.rb', line 333

def stroke_square(x:, y:, size:, stroke_width: 1, color: nil, colour: nil, opacity: nil)
  stroke_rectangle(x: x, y: y, width: size, height: size, stroke_width: stroke_width, color: color, colour: colour, opacity: opacity)
end

#stroke_triangle(x1: nil, y1: nil, x2: nil, y2: nil, x3: nil, y3: nil, points: nil, stroke_width: 1, color: nil, colour: nil, opacity: nil) ⇒ Object

Stroke a triangle outline. Specify vertices via points: or via numbered kwargs. color: accepts a single color or a Color::Set of 3 (one per vertex) interpolated around the perimeter.



293
294
295
296
297
298
299
300
301
302
303
304
# File 'lib/ruby2d/canvas.rb', line 293

def stroke_triangle(x1: nil, y1: nil, x2: nil, y2: nil, x3: nil, y3: nil,
                    points: nil, stroke_width: 1, color: nil, colour: nil, opacity: nil)
  if points
    validate_points(points, 3, :stroke_triangle)
    x1, y1 = points[0]
    x2, y2 = points[1]
    x3, y3 = points[2]
  end
  return unless validate_vertex6(:stroke_triangle, x1, y1, x2, y2, x3, y3)
  colors = expand_stroke_colors(color || colour, 3, opacity, label: :stroke_triangle)
  Ext.canvas_stroke_polygon(self, [3, x1, y1, x2, y2, x3, y3, stroke_width, *colors])
end

#tintObject

The canvas's tint color. The canvas's own pixel buffer is multiplied by this — tint: 'red' makes the canvas redder, not solid red.



44
45
46
# File 'lib/ruby2d/canvas.rb', line 44

def tint
  @tint
end

#tint=(c) ⇒ Object



48
49
50
# File 'lib/ruby2d/canvas.rb', line 48

def tint=(c)
  @tint = Color.new(c)
end