From ff7ea1cf25c530aa07bbdd3d5596f297a02348fb Mon Sep 17 00:00:00 2001 From: Carlos Sanchez Date: Tue, 23 Jul 2024 21:42:26 -0400 Subject: [PATCH] Lots of line algos --- tinyrender1/main.go | 9 ++- tinyrender1/render.go | 141 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+), 3 deletions(-) diff --git a/tinyrender1/main.go b/tinyrender1/main.go index ef64e7c..8a70669 100644 --- a/tinyrender1/main.go +++ b/tinyrender1/main.go @@ -44,9 +44,12 @@ func main() { // Just draw a simple line (a million times or something) for range LineRepeat { - LineDumb4(&fb, 0xFFFFFF, 100, 100, 350, 200) - LineDumb4(&fb, 0xFF0000, 120, 100, 200, 350) - LineDumb4(&fb, 0xFF0000, 350, 200, 100, 100) // backward first line + // LineDumb5(&fb, 0xFFFFFF, 100, 100, 350, 200) + // LineDumb5(&fb, 0xFF0000, 120, 100, 200, 350) + // LineDumb5(&fb, 0xFF0000, 350, 200, 100, 100) // backward first line + Bresenham2(&fb, 0xFFFFFF, 100, 100, 350, 200) + Bresenham2(&fb, 0xFF0000, 120, 100, 200, 350) + Bresenham2(&fb, 0xFF0000, 350, 200, 100, 100) // backward first line } log.Printf("Exporting ppm to stdout") diff --git a/tinyrender1/render.go b/tinyrender1/render.go index 791961f..d5b0026 100644 --- a/tinyrender1/render.go +++ b/tinyrender1/render.go @@ -92,3 +92,144 @@ func LineDumb4(fb *Framebuffer, color uint, x0 int, y0 int, x1 int, y1 int) { } } } + +// For not-steep lines +func BresenhamLow(fb *Framebuffer, color uint, x0 int, y0 int, x1 int, y1 int) { + dx := x1 - x0 + dy := y1 - y0 + yi := 1 // This is the increment + if dy < 0 { // Line moves in opposite vertical direction + yi = -1 + dy = -dy + } + d := 2*dy - dx + // Why minus dx? if slope is 0 then d is -dx. If slope is 1 then d = dy. + // I don't know... + y := y0 + x1u := uint(x1) + for x := uint(x0); x <= x1u; x++ { + fb.Set(x, uint(y), color) + if d > 0 { + y = y + yi + d = d + 2*(dy-dx) + } else { + d = d + 2*dy + } + } +} + +// For steep lines +func BresenhamHigh(fb *Framebuffer, color uint, x0 int, y0 int, x1 int, y1 int) { + dx := x1 - x0 + dy := y1 - y0 + xi := 1 // This is the increment + if dx < 0 { // Line moves in opposite vertical direction + xi = -1 + dx = -dx + } + d := 2*dx - dy + // Why minus dx? if slope is 0 then d is -dx. If slope is 1 then d = dy. + // I don't know... + x := x0 + y1u := uint(y1) + for y := uint(y0); y <= y1u; y++ { + fb.Set(uint(x), y, color) + if d > 0 { + x = x + xi + d = d + 2*(dx-dy) + } else { + d = d + 2*dx + } + } +} + +func Bresenham(fb *Framebuffer, color uint, x0 int, y0 int, x1 int, y1 int) { + if math.Abs(float64(y1-y0)) < math.Abs(float64(x1-x0)) { // This is a flatter line + if x0 > x1 { // This line is backwards + BresenhamLow(fb, color, x1, y1, x0, y0) + } else { + BresenhamLow(fb, color, x0, y0, x1, y1) + } + } else { // This is a steep line + if y0 > y1 { // This line is backwards + BresenhamHigh(fb, color, x1, y1, x0, y0) + } else { + BresenhamHigh(fb, color, x0, y0, x1, y1) + } + } +} + +func Bresenham2(fb *Framebuffer, color uint, x0 int, y0 int, x1 int, y1 int) { + dx := int(math.Abs(float64(x1 - x0))) + sx := -1 + if x0 < x1 { + sx = 1 + } + dy := -int(math.Abs(float64(y1 - y0))) + sy := -1 + if y0 < y1 { + sy = 1 + } + err := dx + dy + + for { + fb.Set(uint(x0), uint(y0), color) + if x0 == x1 && y0 == y1 { + break + } + e2 := 2 * err + if e2 >= dy { + if x0 == x1 { + break + } + err += dy + x0 += sx + } + if e2 <= dx { + if y0 == y1 { + break + } + err += dx + y0 += sy + } + } +} + +func LineDumb5(fb *Framebuffer, color uint, x0 int, y0 int, x1 int, y1 int) { + steep := false + // This one makes sure that going pixel by pixel will not make holes in the + // other direction by always moving in the less steep direction. + if math.Abs(float64(x1-x0)) < math.Abs(float64(y1-y0)) { + x0, y0 = y0, x0 + x1, y1 = y1, x1 + steep = true + } + // Don't let lines be invisible, always go left to right + if x0 > x1 { // need to be left to right + x0, x1 = x1, x0 + y0, y1 = y1, y0 // Why are we swapping these? I guess because we're swapping the points... + } + dx := x1 - x0 // These MUST be POST calcs + dy := y1 - y0 + derror2 := int(math.Abs(float64(dy))) * 2 + error2 := 0 + y := y0 + sy := 1 + if y1 <= y0 { + sy = -1 + } + // Same as dumb2, going across pixel by pixel. But "x" here might actually be y + // because of the inverted direction + for x := x0; x <= x1; x++ { + if steep { + fb.Set(uint(y), uint(x), color) + } else { + fb.Set(uint(x), uint(y), color) + } + error2 += derror2 + if error2 > dx { + y = y + sy + error2 -= dx * 2 + } + } +}