85 lines
2 KiB
Go
85 lines
2 KiB
Go
package render
|
|
|
|
import (
|
|
stdmath "math"
|
|
|
|
"github.com/pnx/go-raytracer/math"
|
|
"github.com/pnx/go-raytracer/world"
|
|
)
|
|
|
|
type RayHit struct {
|
|
Cell math.Vec2u8
|
|
Side int
|
|
Distance float64
|
|
Pos math.Vec2f
|
|
}
|
|
|
|
func CastRay(camera math.Transform, level *world.Level, x int, max_rays int) RayHit {
|
|
angle := camera.Direction.Get()
|
|
cameraX := 2*float64(x)/float64(max_rays) - 1
|
|
rayDirX := stdmath.Cos(angle) + cameraX*stdmath.Cos(angle+stdmath.Pi/2)
|
|
rayDirY := stdmath.Sin(angle) + cameraX*stdmath.Sin(angle+stdmath.Pi/2)
|
|
|
|
mapX := int(camera.X) / world.TileSize
|
|
mapY := int(camera.Y) / world.TileSize
|
|
|
|
deltaDistX := stdmath.Abs(1 / rayDirX)
|
|
deltaDistY := stdmath.Abs(1 / rayDirY)
|
|
|
|
var stepX, stepY int
|
|
var sideDistX, sideDistY float64
|
|
|
|
if rayDirX < 0 {
|
|
stepX = -1
|
|
sideDistX = (float64(camera.X)/world.TileSize - float64(mapX)) * deltaDistX
|
|
} else {
|
|
stepX = 1
|
|
sideDistX = (float64(mapX+1) - float64(camera.X)/world.TileSize) * deltaDistX
|
|
}
|
|
if rayDirY < 0 {
|
|
stepY = -1
|
|
sideDistY = (float64(camera.Y)/world.TileSize - float64(mapY)) * deltaDistY
|
|
} else {
|
|
stepY = 1
|
|
sideDistY = (float64(mapY+1) - float64(camera.Y)/world.TileSize) * deltaDistY
|
|
}
|
|
|
|
// DDA loop
|
|
var side int // 0 = x, 1 = y
|
|
for {
|
|
if sideDistX < sideDistY {
|
|
sideDistX += deltaDistX
|
|
mapX += stepX
|
|
side = 0
|
|
} else {
|
|
sideDistY += deltaDistY
|
|
mapY += stepY
|
|
side = 1
|
|
}
|
|
|
|
if mapX < 0 || mapX >= level.W || mapY < 0 || mapY >= level.H {
|
|
break // out of bounds
|
|
}
|
|
if level.Wall(mapX, mapY) {
|
|
break
|
|
}
|
|
}
|
|
|
|
// Calculate distance to wall
|
|
var perpWallDist float64
|
|
if side == 0 {
|
|
perpWallDist = (float64(mapX) - float64(camera.X)/world.TileSize + float64(1-stepX)/2) / rayDirX
|
|
} else {
|
|
perpWallDist = (float64(mapY) - float64(camera.Y)/world.TileSize + float64(1-stepY)/2) / rayDirY
|
|
}
|
|
|
|
return RayHit{
|
|
Cell: math.Vec2u8{X: uint8(mapX), Y: uint8(mapY)},
|
|
Side: side,
|
|
Distance: perpWallDist,
|
|
Pos: math.Vec2f{
|
|
X: rayDirX * perpWallDist,
|
|
Y: rayDirY * perpWallDist,
|
|
},
|
|
}
|
|
}
|