Clarify the line drawing algorithm

This commit is contained in:
Alex Clink 2021-11-29 22:32:55 -05:00
parent db5a1747fa
commit 60f1e39ae9
2 changed files with 54 additions and 44 deletions

View file

@ -12,14 +12,13 @@ class Triangle < PF::Sprite
include PF::VectorSprite include PF::VectorSprite
def update(dt) def update(dt)
# @rotation += 0.5 * dt
end end
def draw(engine) def draw(engine)
frame = project_points(@frame) frame = project_points(@frame)
engine.fill_triangle(frame[0], frame[1], frame[2], PF::Pixel.new(255, 255, 0)) engine.fill_triangle(frame[0], frame[1], frame[2], PF::Pixel.new(255, 255, 0))
# engine.draw_shape(frame, PF::Pixel.new(0, 0, 255)) engine.draw_shape(frame, PF::Pixel.new(0, 255, 255))
# engine.draw_line(@position, frame[0], PF::Pixel.new(255, 255, 0)) engine.draw_line(@position, frame[0], PF::Pixel.new(0, 255, 0))
end end
end end
@ -57,10 +56,8 @@ class TriangleThing < PF::Game
def draw def draw
clear(0, 0, 200) clear(0, 0, 200)
# fill_rect(25, 25, 10, 15)
# draw_rect(15, 15, 30, 30)
@tri.draw(self) @tri.draw(self)
# draw_circle((@width / 2).to_i32, (@height / 2).to_i32, 45) draw_circle((@width / 2).to_i32, (@height / 2).to_i32, (@width / 3).to_i32)
end end
end end

View file

@ -67,29 +67,35 @@ module PF
# Draw a line using Bresenhams Algorithm # Draw a line using Bresenhams Algorithm
def draw_line(x1 : Int, y1 : Int, x2 : Int, y2 : Int, pixel : Pixel = Pixel.new, surface = @screen) def draw_line(x1 : Int, y1 : Int, x2 : Int, y2 : Int, pixel : Pixel = Pixel.new, surface = @screen)
dx = (x2 - x1).abs # The sloap for each axis
dy = -(y2 - y1).abs slope = Point.new((x2 - x1).abs, -(y2 - y1).abs)
sx = x1 < x2 ? 1 : -1 # The step direction in both axis
sy = y1 < y2 ? 1 : -1 step = Point.new(x1 < x2 ? 1 : -1, y1 < y2 ? 1 : -1)
d = dx + dy # The final decision accumulation
x, y = x1, y1 # Initialized to the height of x and y
decision = slope.x + slope.y
point = Point.new(x1, y1)
loop do loop do
draw_point(x, y, pixel, surface) draw_point(point.x, point.y, pixel, surface)
break if x == x2 && y == y2 # Break if we've reached the ending point
break if point.x == x2 && point.y == y2
d2 = d + d # Square the decision to avoid floating point calculations
decision_squared = decision + decision
if d2 >= dy # if decision_squared is greater than
d += dy if decision_squared >= slope.y
x += sx decision += slope.y
point.x += step.x
end end
if d2 <= dx if decision_squared <= slope.x
d += dx decision += slope.x
y += sy point.y += step.y
end end
end end
end end
@ -176,17 +182,17 @@ module PF
# find the lower left and right points # find the lower left and right points
p_left, p_right = p2.x < p3.x ? [p2, p3] : [p3, p2] p_left, p_right = p2.x < p3.x ? [p2, p3] : [p3, p2]
edge_left = get_tri_edge(p_top.x, p_top.y, p_left.x, p_left.y) edge_left = pixel_edge(p_top.x, p_top.y, p_left.x, p_left.y)
edge_right = get_tri_edge(p_top.x, p_top.y, p_right.x, p_right.y) edge_right = pixel_edge(p_top.x, p_top.y, p_right.x, p_right.y)
if edge_left.size < edge_right.size if edge_left.size < edge_right.size
rest = get_tri_edge(p_left.x, p_left.y, p_right.x, p_right.y) rest = pixel_edge(p_left.x, p_left.y, p_right.x, p_right.y)
rest.shift rest.shift
edge_left.concat(rest) edge_left.concat(rest)
end end
if edge_left.size > edge_right.size if edge_left.size > edge_right.size
rest = get_tri_edge(p_right.x, p_right.y, p_left.x, p_left.y) rest = pixel_edge(p_right.x, p_right.y, p_left.x, p_left.y)
rest.shift rest.shift
edge_right.concat(rest) edge_right.concat(rest)
end end
@ -195,39 +201,46 @@ module PF
pl = edge_left[i] pl = edge_left[i]
pr = edge_right[i] pr = edge_right[i]
(pl.x + 1).upto(pr.x - 1) do |x| (pl.x).upto(pr.x) do |x|
draw_point(x, pl.y, pixel, surface) draw_point(x, pl.y, pixel, surface)
end end
end end
end end
private def get_tri_edge(x1 : Int, y1 : Int, x2 : Int, y2 : Int) private def pixel_edge(x1 : Int, y1 : Int, x2 : Int, y2 : Int)
line = [] of Point(Int32) line = [] of Point(Int32)
dx = (x2 - x1).abs
dy = -(y2 - y1).abs
sx = x1 < x2 ? 1 : -1 # The sloap for each axis
sy = y1 < y2 ? 1 : -1 slope = Point.new((x2 - x1).abs, -(y2 - y1).abs)
d = dx + dy # The step direction in both axis
x, y = x1, y1 step = Point.new(x1 < x2 ? 1 : -1, y1 < y2 ? 1 : -1)
xp = x
line << Point.new(x, y) # The final decision accumulation
# Initialized to the height of x and y
decision = slope.x + slope.y
pixel = Point.new(x1, y1)
line << pixel
loop do loop do
break if x == x2 && y == y2 # Break if we've reached the ending point
d2 = d + d break if pixel.x == x2 && pixel.y == y2
if d2 >= dy # Square the decision to avoid floating point calculations
d += dy decision_squared = decision + decision
x += sx
# if decision_squared is greater than
if decision_squared >= slope.y
decision += slope.y
pixel.x += step.x
end end
if d2 <= dx if decision_squared <= slope.x
d += dx decision += slope.x
line << Point.new(x, y) line << pixel
y += sy pixel.y += step.y
end end
end end