3dtrial/tinyrender1/render.go
2024-07-23 23:01:31 -04:00

236 lines
5.8 KiB
Go

package main
import (
"math"
)
// Draw a line using dumb
func LineDumb(fb *Framebuffer, color uint, x0 uint, y0 uint, x1 uint, y1 uint) {
var t float32
for t = 0; t < 1; t += 0.01 {
// Very simple interpolation between x and y
x := x0 + uint(float32(x1-x0)*t)
y := y0 + uint(float32(y1-y0)*t)
fb.Set(x, y, color)
}
}
func LineDumb2(fb *Framebuffer, color uint, x0 uint, y0 uint, x1 uint, y1 uint) {
for x := x0; x < x1; x++ {
// For each pixel across, compute how far across we are and interpolate y
t := float32(x-x0) / float32(x1-x0)
y := uint(float32(y0)*(1-t) + float32(y1)*t)
fb.Set(x, y, color)
}
}
func LineDumb3(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(x0-x1)) < math.Abs(float64(y0-y1)) {
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...
}
// 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++ {
t := float32(x-x0) / float32(x1-x0)
y := uint(float32(y0)*(1-t) + float32(y1)*t)
if steep {
fb.Set(y, uint(x), color)
} else {
fb.Set(uint(x), y, color)
}
}
}
func LineDumb4(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
// Delta error or something? Basically, as we move in one direction, we get farther
// and farther off course if we never move in the OTHER direction. This is the amount
// of that per x direction.
derror := math.Abs(float64(dy) / float64(dx))
y := uint(y0)
var err float64
// 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(y, uint(x), color)
} else {
fb.Set(uint(x), y, color)
}
err += derror
if err > 0.5 {
if y1 > y0 {
y += 1
} else {
y = y - 1
}
err -= 1
}
}
}
// 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.SetSafe(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
}
}
}