From 38dbaea4af6d426a1b40abe4fba16fad28e00015 Mon Sep 17 00:00:00 2001 From: Alex Clink Date: Mon, 24 Jan 2022 22:03:49 -0500 Subject: [PATCH] Add fill_circle drawing method --- src/game.cr | 4 ++-- src/sprite.cr | 25 +++++++++++++++++++++++++ src/sprite/draw_line.cr | 7 +++++++ src/sprite/fill_circle.cr | 34 ++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 src/sprite/fill_circle.cr diff --git a/src/game.cr b/src/game.cr index 86c1c93..15e2024 100644 --- a/src/game.cr +++ b/src/game.cr @@ -17,8 +17,8 @@ module PF @viewport : Vector2(Int32)? = nil - delegate :draw_point, :draw_line, :draw_circle, :draw_triangle, :draw_rect, :draw_shape, - :fill_triangle, :fill_rect, :fill_shape, to: @screen + delegate :draw_point, :draw_line, :scan_line, :draw_circle, :draw_triangle, :draw_rect, :draw_shape, + :fill_triangle, :fill_rect, :fill_circle, :fill_shape, to: @screen @fps_lasttime : Float64 = Time.monotonic.total_milliseconds # the last recorded time. @fps_current : UInt32 = 0 # the current FPS. diff --git a/src/sprite.cr b/src/sprite.cr index e58a97a..76b3d68 100644 --- a/src/sprite.cr +++ b/src/sprite.cr @@ -4,6 +4,26 @@ require "./sprite/*" module PF class Sprite + def self.load_tiles(path, tile_width, tile_height) + sheet = Sprite.new(path) + sprites = [] of Sprite + + tiles_x = sheet.width // tile_width + tiles_y = sheet.height // tile_height + + 0.upto(tiles_x - 1) do |tx| + 0.upto(tiles_y - 1) do |ty| + sx = tx * tile_width + sy = ty * tile_height + sprite = Sprite.new(tile_width, tile_height) + sheet.draw_to(sprite, Vector[sx, sy], Vector[tile_width, tile_height], Vector[0, 0]) + sprites << sprite + end + end + + sprites + end + property surface : SDL::Surface delegate :fill, :lock, :format, to: @surface @@ -59,6 +79,11 @@ module PF draw_to(dest, at.x, at.y) end + # Draw this sprite to another given a source rect and destination + def draw_to(sprite : Sprite, source : Vector2(Int), size : Vector2(Int), dest : Vector2(Int)) + @surface.blit(sprite.surface, SDL::Rect.new(source.x, source.y, size.x, size.y), SDL::Rect.new(dest.x, dest.y, size.x, size.y)) + end + # Raw access to the pixels as a Slice def pixels Slice.new(@surface.pixels.as(Pointer(UInt32)), width * height) diff --git a/src/sprite/draw_line.cr b/src/sprite/draw_line.cr index a38e493..a6f9a98 100644 --- a/src/sprite/draw_line.cr +++ b/src/sprite/draw_line.cr @@ -54,5 +54,12 @@ module PF def draw_line(line : Line, pixel : Pixel = Pixel.new) draw_line(line.p1.to_i32, line.p2.to_i32, pixel) end + + # Draw a horizontal line to a certain *width* + def scan_line(x : Int, y : Int, width : Int, pixel : Pixel = Pixel.new) + 0.upto(width) do |n| + draw_point(x + n, y, pixel) + end + end end end diff --git a/src/sprite/fill_circle.cr b/src/sprite/fill_circle.cr new file mode 100644 index 0000000..0c13e1b --- /dev/null +++ b/src/sprite/fill_circle.cr @@ -0,0 +1,34 @@ +module PF + class Sprite + # Fill a circle using Bresenham’s Algorithm + def fill_circle(cx : Int, cy : Int, r : Int, pixel : Pixel = Pixel.new) + x, y = 0, r + balance = 0 - r + + while x <= y + p0 = cx - x + p1 = cx - y + + w0 = x + x + w1 = y + y + + scan_line(p0, cy + y, w0, pixel) + scan_line(p0, cy - y, w0, pixel) + scan_line(p1, cy + x, w1, pixel) + scan_line(p1, cy - x, w1, pixel) + + x += 1 + balance += x + x + + if balance >= 0 + y -= 1 + balance -= (y + y) + end + end + end + + def fill_circle(c : Vector2(Int), r : Int, pixel : Pixel = Pixel.new) + fill_circle(c.x, c.y, r, pixel) + end + end +end