Created
October 11, 2020 16:07
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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