Skip to content

Instantly share code, notes, and snippets.

@mdudzinski
Created October 11, 2020 16:07
Show Gist options
  • Save mdudzinski/7960d0c6d3b1b5d93da813688446a09b to your computer and use it in GitHub Desktop.
Save mdudzinski/7960d0c6d3b1b5d93da813688446a09b to your computer and use it in GitHub Desktop.
a proof of concept of a programmatic rounded rectangle created with DRGTK draw API
def tick args
args.outputs.background_color = [33, 33, 33]
args.state.rr1 ||= RoundedRectangle.create({id: :rect_1, x: 100, y: 100, w: 350, h: 400, radius: 16, color: [248, 160, 85], border: {width: 4, color: [116, 134, 148]} })
args.state.rr2 ||= RoundedRectangle.create({id: :rect_2, x: 90, y: 110, w: 350, h: 400, radius: 16, color: [255, 219, 92], border: {width: 4, color: [116, 134, 148]} })
args.outputs.sprites << args.state.rr1
args.outputs.sprites << args.state.rr2
end
class RoundedRectangle
attr_sprite
def initialize options
@path = options[:id]
@x = options[:x]
@y = options[:y]
@w = options[:w]
@h = options[:h]
@radius = options[:radius]
@color = options[:color] || [200, 200, 200]
@border_width = options.dig(:border, :width) || 1
@border_color = options.dig(:border, :color) || [200, 200, 200]
@steps = 50 + @radius
@source_x = 0
@source_y = 0
@source_w = @w
@source_h = @h
end
def self.create options
instance = new options
instance.to_sprite
end
def to_sprite
create_rounded_corner
$gtk.args.state.shapes ||= { }
$gtk.args.state.shapes[@path] = true
#corners
$gtk.args.render_target(@path).sprites << {x: 0, y: 0, w: @radius, h: @radius, path: corner_sprite_path, source_x: 0, source_y: 0, source_w: @radius, source_h: @radius }
$gtk.args.render_target(@path).sprites << {x: 0, y: @h - @radius, w: @radius, h: @radius, path: corner_sprite_path, source_x: 0, source_y: 0, source_w: @radius, source_h: @radius, flip_vertically: true }
$gtk.args.render_target(@path).sprites << {x: @w - @radius, y: 0, w: @radius, h: @radius, path: corner_sprite_path, source_x: 0, source_y: 0, source_w: @radius, source_h: @radius, flip_horizontally: true }
$gtk.args.render_target(@path).sprites << {x: @w - @radius, y: @h - @radius, w: @radius, h: @radius, path: corner_sprite_path, source_x: 0, source_y: 0, source_w: @radius, source_h: @radius, flip_vertically: true, flip_horizontally: true }
#borders
@border_width.times do |i|
# left
$gtk.args.render_target(@path).lines << {x: i, y: @radius, x2: i, y2: @h - @radius + 1, r: @border_color[0], g: @border_color[1], b: @border_color[2] }
# top
$gtk.args.render_target(@path).lines << {x: @radius, y: @h - i, x2: @w - @radius, y2: @h - i, r: @border_color[0], g: @border_color[1], b: @border_color[2] }
# right
$gtk.args.render_target(@path).lines << {x: @w - 1 - i, y: @radius, x2: @w - 1 - i, y2: @h - @radius + 1, r: @border_color[0], g: @border_color[1], b: @border_color[2] }
# bottom
$gtk.args.render_target(@path).lines << {x: @radius, y: 1 + i, x2: @w - @radius, y2: 1 + i, r: @border_color[0], g: @border_color[1], b: @border_color[2] }
end
#fill
# left
$gtk.args.render_target(@path).solids << {x: 0, y: @radius, w: @radius, h: @h - 2 * @radius, r: @color[0], g: @color[1], b: @color[2] }
# right
$gtk.args.render_target(@path).solids << {x: @w - @radius, y: @radius, w: @radius, h: @h - 2 * @radius, r: @color[0], g: @color[1], b: @color[2] }
# top
$gtk.args.render_target(@path).solids << {x: @radius, y: @h - @radius, w: @w - 2 * @radius, h: @radius, r: @color[0], g: @color[1], b: @color[2] }
# bottom
$gtk.args.render_target(@path).solids << {x: @radius, y: 0, w: @w - 2 * @radius, h: @radius, r: @color[0], g: @color[1], b: @color[2] }
# the middle
$gtk.args.render_target(@path).solids << {x: @radius, y: @radius, w: @w - 2 * @radius, h: @h - 2 * @radius, r: @color[0], g: @color[1], b: @color[2] }
self
end
def create_rounded_corner
points = []
@border_width.times do |i|
points << bezier(
i, @radius,
i, @radius/2,
@radius/2, i,
@radius, i,
@steps, @border_color
)
end
# color the rest of the corner
points.last.each do |inner_points|
$gtk.args.render_target(corner_sprite_path).lines << [inner_points[1][0], inner_points[1][1], inner_points[1][0], @radius + 1, @color]
end
$gtk.args.render_target(corner_sprite_path).lines << points
end
def corner_sprite_path
"#{@path.to_s}_corner".to_sym
end
end
def bezier x1, y1, x2, y2, x3, y3, x4, y4, step, color
step ||= 0
points = points_for_bezier [x1, y1], [x2, y2], [x3, y3], [x4, y4], step
points.each_cons(2).map do |p1, p2|
[p1, p2, color]
end
end
def points_for_bezier p1, p2, p3, p4, step
points = []
if step == 0
[p1, p2, p3, p4]
else
t_step = 1.fdiv(step + 1)
t = 0
t += t_step
points = []
while t < 1
points << [
b_for_t(p1.x, p2.x, p3.x, p4.x, t),
b_for_t(p1.y, p2.y, p3.y, p4.y, t),
]
t += t_step
end
[
p1,
*points,
p4
]
end
end
def b_for_t v0, v1, v2, v3, t
pow(1 - t, 3) * v0 +
3 * pow(1 - t, 2) * t * v1 +
3 * (1 - t) * pow(t, 2) * v2 +
pow(t, 3) * v3
end
def pow n, to
n ** to
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment