929 lines
82 KiB
Go
929 lines
82 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"flag"
|
||
|
"image"
|
||
|
"image/color"
|
||
|
"image/draw"
|
||
|
"image/png"
|
||
|
"math"
|
||
|
"time"
|
||
|
|
||
|
"github.com/go-gl/mathgl/mgl32"
|
||
|
|
||
|
"github.com/faiface/pixel"
|
||
|
"github.com/faiface/pixel/pixelgl"
|
||
|
)
|
||
|
|
||
|
const texSize = 64
|
||
|
|
||
|
var (
|
||
|
fullscreen = false
|
||
|
showMap = true
|
||
|
width = 640
|
||
|
height = 400
|
||
|
scale = 1.0
|
||
|
wallDistance = 8.0
|
||
|
|
||
|
as actionSquare
|
||
|
|
||
|
pos, dir, plane pixel.Vec
|
||
|
|
||
|
textures = loadTextures()
|
||
|
)
|
||
|
|
||
|
func setup() {
|
||
|
pos = pixel.V(12.0, 14.5)
|
||
|
dir = pixel.V(-1.0, 0.0)
|
||
|
plane = pixel.V(0.0, 0.66)
|
||
|
}
|
||
|
|
||
|
var world = [24][24]int{
|
||
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
||
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||
|
{1, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 3, 0, 3, 0, 3, 0, 0, 0, 1},
|
||
|
{1, 0, 0, 0, 2, 7, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||
|
{1, 0, 0, 0, 2, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 7, 0, 3, 0, 0, 0, 1},
|
||
|
{1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||
|
{1, 0, 0, 0, 2, 2, 2, 2, 0, 2, 2, 0, 0, 0, 0, 3, 0, 3, 0, 3, 0, 0, 0, 1},
|
||
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||
|
{1, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||
|
{1, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||
|
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||
|
{1, 0, 0, 0, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||
|
{1, 0, 6, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 5, 0, 0, 0, 1},
|
||
|
{1, 0, 6, 0, 4, 0, 7, 0, 4, 0, 0, 0, 0, 0, 5, 0, 0, 0, 5, 0, 0, 0, 0, 1},
|
||
|
{1, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 1},
|
||
|
{1, 4, 4, 4, 4, 4, 4, 0, 4, 0, 0, 0, 5, 5, 0, 5, 5, 5, 0, 5, 5, 0, 0, 1},
|
||
|
{1, 4, 0, 0, 0, 0, 0, 0, 4, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0, 1},
|
||
|
{1, 4, 0, 4, 0, 0, 0, 0, 4, 0, 0, 5, 0, 5, 5, 5, 5, 5, 5, 5, 0, 5, 0, 1},
|
||
|
{1, 4, 0, 4, 4, 4, 4, 4, 4, 0, 0, 5, 0, 5, 0, 0, 0, 0, 0, 5, 0, 5, 0, 1},
|
||
|
{1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 0, 5, 5, 0, 0, 0, 0, 1},
|
||
|
{1, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
|
||
|
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
||
|
}
|
||
|
|
||
|
func loadTextures() *image.RGBA {
|
||
|
p, err := png.Decode(bytes.NewReader(textureData))
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
|
||
|
m := image.NewRGBA(p.Bounds())
|
||
|
|
||
|
draw.Draw(m, m.Bounds(), p, image.ZP, draw.Src)
|
||
|
|
||
|
return m
|
||
|
}
|
||
|
|
||
|
func getTexNum(x, y int) int {
|
||
|
return world[x][y]
|
||
|
}
|
||
|
|
||
|
func getColor(x, y int) color.RGBA {
|
||
|
switch world[x][y] {
|
||
|
case 0:
|
||
|
return color.RGBA{43, 30, 24, 255}
|
||
|
case 1:
|
||
|
return color.RGBA{100, 89, 73, 255}
|
||
|
case 2:
|
||
|
return color.RGBA{110, 23, 0, 255}
|
||
|
case 3:
|
||
|
return color.RGBA{45, 103, 171, 255}
|
||
|
case 4:
|
||
|
return color.RGBA{123, 84, 33, 255}
|
||
|
case 5:
|
||
|
return color.RGBA{158, 148, 130, 255}
|
||
|
case 6:
|
||
|
return color.RGBA{203, 161, 47, 255}
|
||
|
case 7:
|
||
|
return color.RGBA{255, 107, 0, 255}
|
||
|
case 9:
|
||
|
return color.RGBA{0, 0, 0, 0}
|
||
|
default:
|
||
|
return color.RGBA{255, 194, 32, 255}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func frame() *image.RGBA {
|
||
|
m := image.NewRGBA(image.Rect(0, 0, width, height))
|
||
|
|
||
|
for x := 0; x < width; x++ {
|
||
|
var (
|
||
|
step image.Point
|
||
|
sideDist pixel.Vec
|
||
|
perpWallDist float64
|
||
|
hit, side bool
|
||
|
|
||
|
rayPos, worldX, worldY = pos, int(pos.X), int(pos.Y)
|
||
|
|
||
|
cameraX = 2*float64(x)/float64(width) - 1
|
||
|
|
||
|
rayDir = pixel.V(
|
||
|
dir.X+plane.X*cameraX,
|
||
|
dir.Y+plane.Y*cameraX,
|
||
|
)
|
||
|
|
||
|
deltaDist = pixel.V(
|
||
|
math.Sqrt(1.0+(rayDir.Y*rayDir.Y)/(rayDir.X*rayDir.X)),
|
||
|
math.Sqrt(1.0+(rayDir.X*rayDir.X)/(rayDir.Y*rayDir.Y)),
|
||
|
)
|
||
|
)
|
||
|
|
||
|
if rayDir.X < 0 {
|
||
|
step.X = -1
|
||
|
sideDist.X = (rayPos.X - float64(worldX)) * deltaDist.X
|
||
|
} else {
|
||
|
step.X = 1
|
||
|
sideDist.X = (float64(worldX) + 1.0 - rayPos.X) * deltaDist.X
|
||
|
}
|
||
|
|
||
|
if rayDir.Y < 0 {
|
||
|
step.Y = -1
|
||
|
sideDist.Y = (rayPos.Y - float64(worldY)) * deltaDist.Y
|
||
|
} else {
|
||
|
step.Y = 1
|
||
|
sideDist.Y = (float64(worldY) + 1.0 - rayPos.Y) * deltaDist.Y
|
||
|
}
|
||
|
|
||
|
for !hit {
|
||
|
if sideDist.X < sideDist.Y {
|
||
|
sideDist.X += deltaDist.X
|
||
|
worldX += step.X
|
||
|
side = false
|
||
|
} else {
|
||
|
sideDist.Y += deltaDist.Y
|
||
|
worldY += step.Y
|
||
|
side = true
|
||
|
}
|
||
|
|
||
|
if world[worldX][worldY] > 0 {
|
||
|
hit = true
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var wallX float64
|
||
|
|
||
|
if side {
|
||
|
perpWallDist = (float64(worldY) - rayPos.Y + (1-float64(step.Y))/2) / rayDir.Y
|
||
|
wallX = rayPos.X + perpWallDist*rayDir.X
|
||
|
} else {
|
||
|
perpWallDist = (float64(worldX) - rayPos.X + (1-float64(step.X))/2) / rayDir.X
|
||
|
wallX = rayPos.Y + perpWallDist*rayDir.Y
|
||
|
}
|
||
|
|
||
|
if x == width/2 {
|
||
|
wallDistance = perpWallDist
|
||
|
}
|
||
|
|
||
|
wallX -= math.Floor(wallX)
|
||
|
|
||
|
texX := int(wallX * float64(texSize))
|
||
|
|
||
|
lineHeight := int(float64(height) / perpWallDist)
|
||
|
|
||
|
if lineHeight < 1 {
|
||
|
lineHeight = 1
|
||
|
}
|
||
|
|
||
|
drawStart := -lineHeight/2 + height/2
|
||
|
if drawStart < 0 {
|
||
|
drawStart = 0
|
||
|
}
|
||
|
|
||
|
drawEnd := lineHeight/2 + height/2
|
||
|
if drawEnd >= height {
|
||
|
drawEnd = height - 1
|
||
|
}
|
||
|
|
||
|
if !side && rayDir.X > 0 {
|
||
|
texX = texSize - texX - 1
|
||
|
}
|
||
|
|
||
|
if side && rayDir.Y < 0 {
|
||
|
texX = texSize - texX - 1
|
||
|
}
|
||
|
|
||
|
texNum := getTexNum(worldX, worldY)
|
||
|
|
||
|
for y := drawStart; y < drawEnd+1; y++ {
|
||
|
d := y*256 - height*128 + lineHeight*128
|
||
|
texY := ((d * texSize) / lineHeight) / 256
|
||
|
|
||
|
c := textures.RGBAAt(
|
||
|
texX+texSize*(texNum),
|
||
|
texY%texSize,
|
||
|
)
|
||
|
|
||
|
if side {
|
||
|
c.R = c.R / 2
|
||
|
c.G = c.G / 2
|
||
|
c.B = c.B / 2
|
||
|
}
|
||
|
|
||
|
m.Set(x, y, c)
|
||
|
}
|
||
|
|
||
|
var floorWall pixel.Vec
|
||
|
|
||
|
if !side && rayDir.X > 0 {
|
||
|
floorWall.X = float64(worldX)
|
||
|
floorWall.Y = float64(worldY) + wallX
|
||
|
} else if !side && rayDir.X < 0 {
|
||
|
floorWall.X = float64(worldX) + 1.0
|
||
|
floorWall.Y = float64(worldY) + wallX
|
||
|
} else if side && rayDir.Y > 0 {
|
||
|
floorWall.X = float64(worldX) + wallX
|
||
|
floorWall.Y = float64(worldY)
|
||
|
} else {
|
||
|
floorWall.X = float64(worldX) + wallX
|
||
|
floorWall.Y = float64(worldY) + 1.0
|
||
|
}
|
||
|
|
||
|
distWall, distPlayer := perpWallDist, 0.0
|
||
|
|
||
|
for y := drawEnd + 1; y < height; y++ {
|
||
|
currentDist := float64(height) / (2.0*float64(y) - float64(height))
|
||
|
|
||
|
weight := (currentDist - distPlayer) / (distWall - distPlayer)
|
||
|
|
||
|
currentFloor := pixel.V(
|
||
|
weight*floorWall.X+(1.0-weight)*pos.X,
|
||
|
weight*floorWall.Y+(1.0-weight)*pos.Y,
|
||
|
)
|
||
|
|
||
|
fx := int(currentFloor.X*float64(texSize)) % texSize
|
||
|
fy := int(currentFloor.Y*float64(texSize)) % texSize
|
||
|
|
||
|
m.Set(x, y, textures.At(fx, fy))
|
||
|
|
||
|
m.Set(x, height-y-1, textures.At(fx+(4*texSize), fy))
|
||
|
m.Set(x, height-y, textures.At(fx+(4*texSize), fy))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return m
|
||
|
}
|
||
|
|
||
|
func minimap() *image.RGBA {
|
||
|
m := image.NewRGBA(image.Rect(0, 0, 24, 26))
|
||
|
|
||
|
for x, row := range world {
|
||
|
for y := range row {
|
||
|
c := getColor(x, y)
|
||
|
if c.A == 255 {
|
||
|
c.A = 96
|
||
|
}
|
||
|
m.Set(x, y, c)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m.Set(int(pos.X), int(pos.Y), color.RGBA{255, 0, 0, 255})
|
||
|
|
||
|
if as.active {
|
||
|
m.Set(as.X, as.Y, color.RGBA{255, 255, 255, 255})
|
||
|
} else {
|
||
|
m.Set(as.X, as.Y, color.RGBA{64, 64, 64, 255})
|
||
|
}
|
||
|
|
||
|
return m
|
||
|
}
|
||
|
|
||
|
func getActionSquare() actionSquare {
|
||
|
pt := image.Pt(int(pos.X)+1, int(pos.Y))
|
||
|
|
||
|
a := dir.Angle()
|
||
|
|
||
|
switch {
|
||
|
case a > 2.8 || a < -2.8:
|
||
|
pt = image.Pt(int(pos.X)-1, int(pos.Y))
|
||
|
case a > -2.8 && a < -2.2:
|
||
|
pt = image.Pt(int(pos.X)-1, int(pos.Y)-1)
|
||
|
case a > -2.2 && a < -1.4:
|
||
|
pt = image.Pt(int(pos.X), int(pos.Y)-1)
|
||
|
case a > -1.4 && a < -0.7:
|
||
|
pt = image.Pt(int(pos.X)+1, int(pos.Y)-1)
|
||
|
case a > 0.4 && a < 1.0:
|
||
|
pt = image.Pt(int(pos.X)+1, int(pos.Y)+1)
|
||
|
case a > 1.0 && a < 1.7:
|
||
|
pt = image.Pt(int(pos.X), int(pos.Y)+1)
|
||
|
case a > 1.7:
|
||
|
pt = image.Pt(int(pos.X)-1, int(pos.Y)+1)
|
||
|
}
|
||
|
|
||
|
block := -1
|
||
|
active := pt.X > 0 && pt.X < 23 && pt.Y > 0 && pt.Y < 23
|
||
|
|
||
|
if active {
|
||
|
block = world[pt.X][pt.Y]
|
||
|
}
|
||
|
|
||
|
return actionSquare{
|
||
|
X: pt.X,
|
||
|
Y: pt.Y,
|
||
|
active: active,
|
||
|
block: block,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type actionSquare struct {
|
||
|
X int
|
||
|
Y int
|
||
|
block int
|
||
|
active bool
|
||
|
}
|
||
|
|
||
|
func (as actionSquare) toggle(n int) {
|
||
|
if as.active {
|
||
|
if world[as.X][as.Y] == 0 {
|
||
|
world[as.X][as.Y] = n
|
||
|
} else {
|
||
|
world[as.X][as.Y] = 0
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (as actionSquare) set(n int) {
|
||
|
if as.active {
|
||
|
world[as.X][as.Y] = n
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func run() {
|
||
|
cfg := pixelgl.WindowConfig{
|
||
|
Bounds: pixel.R(0, 0, float64(width)*scale, float64(height)*scale),
|
||
|
VSync: true,
|
||
|
Undecorated: false,
|
||
|
}
|
||
|
|
||
|
if fullscreen {
|
||
|
cfg.Monitor = pixelgl.PrimaryMonitor()
|
||
|
}
|
||
|
|
||
|
win, err := pixelgl.NewWindow(cfg)
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
|
||
|
centerScreenPos(win)
|
||
|
|
||
|
c := win.Bounds().Center()
|
||
|
|
||
|
last := time.Now()
|
||
|
|
||
|
mapRot := -1.6683362599999894
|
||
|
|
||
|
canvas := pixelgl.NewCanvas(win.Bounds())
|
||
|
|
||
|
wc := win.GetCanvas()
|
||
|
wc.SetFragmentShader(fxaaFragShader)
|
||
|
|
||
|
var uAmount, uTime float32
|
||
|
var uResolution, uMouse mgl32.Vec2
|
||
|
var uParams mgl32.Vec3
|
||
|
|
||
|
uParams[0] = 10.0
|
||
|
uParams[1] = 0.8
|
||
|
uParams[2] = 0.1
|
||
|
|
||
|
uAmount = 0
|
||
|
|
||
|
wc.BindUniform("u_amount", &uAmount)
|
||
|
wc.BindUniform("u_resolution", &uResolution)
|
||
|
wc.BindUniform("u_mouse", &uMouse)
|
||
|
wc.BindUniform("u_time", &uTime)
|
||
|
wc.BindUniform("u_params", &uParams)
|
||
|
|
||
|
wc.UpdateShader()
|
||
|
|
||
|
uResolution[0] = float32(win.Bounds().W())
|
||
|
uResolution[1] = float32(win.Bounds().H())
|
||
|
|
||
|
start := time.Now()
|
||
|
for !win.Closed() {
|
||
|
if win.JustPressed(pixelgl.KeyEscape) || win.JustPressed(pixelgl.KeyQ) {
|
||
|
return
|
||
|
}
|
||
|
uTime = float32(time.Since(start).Seconds())
|
||
|
uMouse[0] = float32(win.MousePosition().X)
|
||
|
uMouse[1] = float32(win.MousePosition().Y)
|
||
|
|
||
|
win.Clear(color.Black)
|
||
|
canvas.Clear(color.Black)
|
||
|
|
||
|
dt := time.Since(last).Seconds()
|
||
|
last = time.Now()
|
||
|
|
||
|
as = getActionSquare()
|
||
|
if win.Pressed(pixelgl.KeyEqual) {
|
||
|
uAmount++
|
||
|
}
|
||
|
if win.Pressed(pixelgl.KeyMinus) {
|
||
|
uAmount = 0
|
||
|
}
|
||
|
if win.Pressed(pixelgl.KeyUp) || win.Pressed(pixelgl.KeyW) {
|
||
|
moveForward(3.5 * dt)
|
||
|
}
|
||
|
|
||
|
if win.Pressed(pixelgl.KeyA) {
|
||
|
moveLeft(3.5 * dt)
|
||
|
}
|
||
|
|
||
|
if win.Pressed(pixelgl.KeyDown) || win.Pressed(pixelgl.KeyS) {
|
||
|
moveBackwards(3.5 * dt)
|
||
|
}
|
||
|
|
||
|
if win.Pressed(pixelgl.KeyD) {
|
||
|
moveRight(3.5 * dt)
|
||
|
}
|
||
|
|
||
|
if win.Pressed(pixelgl.KeyRight) {
|
||
|
turnRight(1.2 * dt)
|
||
|
}
|
||
|
|
||
|
if win.Pressed(pixelgl.KeyLeft) {
|
||
|
turnLeft(1.2 * dt)
|
||
|
}
|
||
|
|
||
|
if win.JustPressed(pixelgl.KeyM) {
|
||
|
showMap = !showMap
|
||
|
}
|
||
|
|
||
|
if win.JustPressed(pixelgl.Key1) {
|
||
|
as.set(1)
|
||
|
}
|
||
|
|
||
|
if win.JustPressed(pixelgl.Key2) {
|
||
|
as.set(2)
|
||
|
}
|
||
|
|
||
|
if win.JustPressed(pixelgl.Key3) {
|
||
|
as.set(3)
|
||
|
}
|
||
|
|
||
|
if win.JustPressed(pixelgl.Key4) {
|
||
|
as.set(4)
|
||
|
}
|
||
|
|
||
|
if win.JustPressed(pixelgl.Key5) {
|
||
|
as.set(5)
|
||
|
}
|
||
|
|
||
|
if win.JustPressed(pixelgl.Key6) {
|
||
|
as.set(6)
|
||
|
}
|
||
|
|
||
|
if win.JustPressed(pixelgl.Key7) {
|
||
|
as.set(7)
|
||
|
}
|
||
|
|
||
|
if win.JustPressed(pixelgl.Key0) {
|
||
|
as.set(0)
|
||
|
}
|
||
|
|
||
|
if win.JustPressed(pixelgl.KeySpace) {
|
||
|
as.toggle(3)
|
||
|
}
|
||
|
|
||
|
p := pixel.PictureDataFromImage(frame())
|
||
|
|
||
|
pixel.NewSprite(p, p.Bounds()).
|
||
|
Draw(canvas, pixel.IM.Moved(c).Scaled(c, scale))
|
||
|
|
||
|
if showMap {
|
||
|
m := pixel.PictureDataFromImage(minimap())
|
||
|
|
||
|
mc := m.Bounds().Min.Add(pixel.V(-m.Rect.W(), m.Rect.H()))
|
||
|
|
||
|
pixel.NewSprite(m, m.Bounds()).
|
||
|
Draw(canvas, pixel.IM.
|
||
|
Moved(mc).
|
||
|
Rotated(mc, mapRot).
|
||
|
ScaledXY(pixel.ZV, pixel.V(-scale*2, scale*2)))
|
||
|
}
|
||
|
|
||
|
canvas.Draw(win, pixel.IM.Moved(win.Bounds().Center()))
|
||
|
|
||
|
win.Update()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func moveForward(s float64) {
|
||
|
if wallDistance > 0.3 {
|
||
|
if world[int(pos.X+dir.X*s)][int(pos.Y)] == 0 {
|
||
|
pos.X += dir.X * s
|
||
|
}
|
||
|
|
||
|
if world[int(pos.X)][int(pos.Y+dir.Y*s)] == 0 {
|
||
|
pos.Y += dir.Y * s
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func moveLeft(s float64) {
|
||
|
if world[int(pos.X-plane.X*s)][int(pos.Y)] == 0 {
|
||
|
pos.X -= plane.X * s
|
||
|
}
|
||
|
|
||
|
if world[int(pos.X)][int(pos.Y-plane.Y*s)] == 0 {
|
||
|
pos.Y -= plane.Y * s
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func moveBackwards(s float64) {
|
||
|
if world[int(pos.X-dir.X*s)][int(pos.Y)] == 0 {
|
||
|
pos.X -= dir.X * s
|
||
|
}
|
||
|
|
||
|
if world[int(pos.X)][int(pos.Y-dir.Y*s)] == 0 {
|
||
|
pos.Y -= dir.Y * s
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func moveRight(s float64) {
|
||
|
if world[int(pos.X+plane.X*s)][int(pos.Y)] == 0 {
|
||
|
pos.X += plane.X * s
|
||
|
}
|
||
|
|
||
|
if world[int(pos.X)][int(pos.Y+plane.Y*s)] == 0 {
|
||
|
pos.Y += plane.Y * s
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func turnRight(s float64) {
|
||
|
oldDirX := dir.X
|
||
|
|
||
|
dir.X = dir.X*math.Cos(-s) - dir.Y*math.Sin(-s)
|
||
|
dir.Y = oldDirX*math.Sin(-s) + dir.Y*math.Cos(-s)
|
||
|
|
||
|
oldPlaneX := plane.X
|
||
|
|
||
|
plane.X = plane.X*math.Cos(-s) - plane.Y*math.Sin(-s)
|
||
|
plane.Y = oldPlaneX*math.Sin(-s) + plane.Y*math.Cos(-s)
|
||
|
}
|
||
|
|
||
|
func turnLeft(s float64) {
|
||
|
oldDirX := dir.X
|
||
|
|
||
|
dir.X = dir.X*math.Cos(s) - dir.Y*math.Sin(s)
|
||
|
dir.Y = oldDirX*math.Sin(s) + dir.Y*math.Cos(s)
|
||
|
|
||
|
oldPlaneX := plane.X
|
||
|
|
||
|
plane.X = plane.X*math.Cos(s) - plane.Y*math.Sin(s)
|
||
|
plane.Y = oldPlaneX*math.Sin(s) + plane.Y*math.Cos(s)
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
flag.BoolVar(&fullscreen, "f", fullscreen, "fullscreen")
|
||
|
flag.IntVar(&width, "w", width, "width")
|
||
|
flag.IntVar(&height, "h", height, "height")
|
||
|
flag.Float64Var(&scale, "s", scale, "scale")
|
||
|
flag.Parse()
|
||
|
|
||
|
setup()
|
||
|
|
||
|
pixelgl.Run(run)
|
||
|
}
|
||
|
|
||
|
func centerScreenPos(window *pixelgl.Window) {
|
||
|
width, height := pixelgl.PrimaryMonitor().Size()
|
||
|
window.SetPos(
|
||
|
pixel.V(
|
||
|
width/2-(window.Bounds().W()/2),
|
||
|
height/2-(window.Bounds().H()/2),
|
||
|
))
|
||
|
}
|
||
|
|
||
|
var shockwaveFragShader = `
|
||
|
#version 330 core
|
||
|
|
||
|
in vec2 texcoords;
|
||
|
|
||
|
uniform vec4 u_texbounds;
|
||
|
uniform sampler2D u_texture;
|
||
|
uniform vec2 u_resolution;
|
||
|
uniform float u_amount;
|
||
|
uniform float u_time;
|
||
|
uniform vec2 u_mouse;
|
||
|
uniform vec3 u_params; // 10.0, 0.8, 0.1
|
||
|
|
||
|
out vec4 fragColor;
|
||
|
|
||
|
vec2 getMx() {
|
||
|
vec2 mx = u_mouse / u_resolution.xy;
|
||
|
// correct aspect ratio
|
||
|
mx.y *= u_resolution.y / u_resolution.x;
|
||
|
mx.y += (u_resolution.x - u_resolution.y) / u_resolution.x / 2.0;
|
||
|
// centering
|
||
|
// mx -= 0.5;
|
||
|
// mx *= vec2(1.0, -1.0);
|
||
|
return mx;
|
||
|
}
|
||
|
|
||
|
void main()
|
||
|
{
|
||
|
vec2 uv = (texcoords - u_texbounds.xy) / u_texbounds.zw;
|
||
|
vec2 texCoord = uv;
|
||
|
vec2 um = getMx();
|
||
|
float distance = distance(uv, um);
|
||
|
if ( (distance <= (u_time + u_params.z)) &&
|
||
|
(distance >= (u_time - u_params.z)) )
|
||
|
{
|
||
|
float diff = (distance - u_time);
|
||
|
float powDiff = 1.0 - pow(abs(diff*u_params.x),
|
||
|
u_params.y);
|
||
|
float diffu_time = diff * powDiff;
|
||
|
vec2 diffUV = normalize(uv - um);
|
||
|
texCoord = uv + (diffUV * diffu_time);
|
||
|
}
|
||
|
fragColor = texture(u_texture, texCoord);
|
||
|
}
|
||
|
`
|
||
|
|
||
|
var fxaaFragShader = `
|
||
|
#version 330 core
|
||
|
|
||
|
in vec2 texcoords;
|
||
|
|
||
|
uniform vec4 u_texbounds;
|
||
|
uniform sampler2D u_texture;
|
||
|
uniform vec2 u_resolution;
|
||
|
uniform float u_amount;
|
||
|
uniform float u_time;
|
||
|
uniform vec2 u_mouse;
|
||
|
|
||
|
out vec4 fragColor;
|
||
|
|
||
|
#define FXAA_REDUCE_MIN (1.0/128.0)
|
||
|
#define FXAA_REDUCE_MUL (1.0/8.0)
|
||
|
#define FXAA_SPAN_MAX 8.0
|
||
|
|
||
|
void main() {
|
||
|
vec2 uv = (texcoords - u_texbounds.xy) / u_texbounds.zw;
|
||
|
vec2 res = 1. / u_resolution;
|
||
|
|
||
|
if (u_amount < 1 ) {
|
||
|
fragColor = texture(u_texture, uv);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
vec3 rgbNW = texture( u_texture, ( uv.xy + vec2( -1.0, -1.0 ) * res ) ).xyz;
|
||
|
vec3 rgbNE = texture( u_texture, ( uv.xy + vec2( 1.0, -1.0 ) * res ) ).xyz;
|
||
|
vec3 rgbSW = texture( u_texture, ( uv.xy + vec2( -1.0, 1.0 ) * res ) ).xyz;
|
||
|
vec3 rgbSE = texture( u_texture, ( uv.xy + vec2( 1.0, 1.0 ) * res ) ).xyz;
|
||
|
vec4 rgbaM = texture( u_texture, uv.xy * res );
|
||
|
vec3 rgbM = rgbaM.xyz;
|
||
|
vec3 luma = vec3( 0.299, 0.587, 0.114 );
|
||
|
|
||
|
float lumaNW = dot( rgbNW, luma );
|
||
|
float lumaNE = dot( rgbNE, luma );
|
||
|
float lumaSW = dot( rgbSW, luma );
|
||
|
float lumaSE = dot( rgbSE, luma );
|
||
|
float lumaM = dot( rgbM, luma );
|
||
|
float lumaMin = min( lumaM, min( min( lumaNW, lumaNE ), min( lumaSW, lumaSE ) ) );
|
||
|
float lumaMax = max( lumaM, max( max( lumaNW, lumaNE) , max( lumaSW, lumaSE ) ) );
|
||
|
|
||
|
vec2 dir;
|
||
|
dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
|
||
|
dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));
|
||
|
|
||
|
float dirReduce = max( ( lumaNW + lumaNE + lumaSW + lumaSE ) * ( 0.25 * FXAA_REDUCE_MUL ), FXAA_REDUCE_MIN );
|
||
|
|
||
|
float rcpDirMin = 1.0 / ( min( abs( dir.x ), abs( dir.y ) ) + dirReduce );
|
||
|
dir = min( vec2( FXAA_SPAN_MAX, FXAA_SPAN_MAX),
|
||
|
max( vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
|
||
|
dir * rcpDirMin)) * res;
|
||
|
vec4 rgbA = (1.0/2.0) * (
|
||
|
texture(u_texture, uv.xy + dir * (1.0/3.0 - 0.5)) +
|
||
|
texture(u_texture, uv.xy + dir * (2.0/3.0 - 0.5)));
|
||
|
vec4 rgbB = rgbA * (1.0/2.0) + (1.0/4.0) * (
|
||
|
texture(u_texture, uv.xy + dir * (0.0/3.0 - 0.5)) +
|
||
|
texture(u_texture, uv.xy + dir * (3.0/3.0 - 0.5)));
|
||
|
float lumaB = dot(rgbB, vec4(luma, 0.0));
|
||
|
|
||
|
if ( ( lumaB < lumaMin ) || ( lumaB > lumaMax ) ) {
|
||
|
fragColor = rgbA;
|
||
|
} else {
|
||
|
fragColor = rgbB;
|
||
|
}
|
||
|
|
||
|
//fragColor = vec4( texture( u_texture,uv ).xyz, 1. );
|
||
|
}
|
||
|
`
|
||
|
|
||
|
var toonFragShader = `
|
||
|
#version 330 core
|
||
|
|
||
|
in vec4 Color;
|
||
|
in vec2 texcoords;
|
||
|
|
||
|
out vec4 fragColor;
|
||
|
|
||
|
uniform vec4 u_colormask;
|
||
|
uniform vec4 u_texbounds;
|
||
|
uniform sampler2D u_texture;
|
||
|
uniform float u_amount;
|
||
|
uniform float u_time;
|
||
|
uniform vec2 u_mouse;
|
||
|
uniform vec2 u_resolution;
|
||
|
|
||
|
#define HueLevCount 6
|
||
|
#define SatLevCount 7
|
||
|
#define ValLevCount 4
|
||
|
|
||
|
float HueLevels[HueLevCount];
|
||
|
float SatLevels[SatLevCount];
|
||
|
float ValLevels[ValLevCount];
|
||
|
|
||
|
vec3 RGBtoHSV( float r, float g, float b) {
|
||
|
float minv, maxv, delta;
|
||
|
vec3 res;
|
||
|
|
||
|
minv = min(min(r, g), b);
|
||
|
maxv = max(max(r, g), b);
|
||
|
res.z = maxv; // v
|
||
|
|
||
|
delta = maxv - minv;
|
||
|
|
||
|
if( maxv != 0.0 )
|
||
|
res.y = delta / maxv; // s
|
||
|
else {
|
||
|
// r = g = b = 0 // s = 0, v is undefined
|
||
|
res.y = 0.0;
|
||
|
res.x = -1.0;
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
if( r == maxv )
|
||
|
res.x = ( g - b ) / delta; // between yellow & magenta
|
||
|
else if( g == maxv )
|
||
|
res.x = 2.0 + ( b - r ) / delta; // between cyan & yellow
|
||
|
else
|
||
|
res.x = 4.0 + ( r - g ) / delta; // between magenta & cyan
|
||
|
|
||
|
res.x = res.x * 60.0; // degrees
|
||
|
if( res.x < 0.0 )
|
||
|
res.x = res.x + 360.0;
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
vec3 HSVtoRGB(float h, float s, float v ) {
|
||
|
int i;
|
||
|
float f, p, q, t;
|
||
|
vec3 res;
|
||
|
|
||
|
if( s == 0.0 ) {
|
||
|
// achromatic (grey)
|
||
|
res.x = v;
|
||
|
res.y = v;
|
||
|
res.z = v;
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
h /= 60.0; // sector 0 to 5
|
||
|
i = int(floor( h ));
|
||
|
f = h - float(i); // factorial part of h
|
||
|
p = v * ( 1.0 - s );
|
||
|
q = v * ( 1.0 - s * f );
|
||
|
t = v * ( 1.0 - s * ( 1.0 - f ) );
|
||
|
|
||
|
if (i==0) {
|
||
|
res.x = v;
|
||
|
res.y = t;
|
||
|
res.z = p;
|
||
|
} else if (i==1) {
|
||
|
res.x = q;
|
||
|
res.y = v;
|
||
|
res.z = p;
|
||
|
} else if (i==2) {
|
||
|
res.x = p;
|
||
|
res.y = v;
|
||
|
res.z = t;
|
||
|
} else if (i==3) {
|
||
|
res.x = p;
|
||
|
res.y = q;
|
||
|
res.z = v;
|
||
|
} else if (i==4) {
|
||
|
res.x = t;
|
||
|
res.y = p;
|
||
|
res.z = v;
|
||
|
} else if (i==5) {
|
||
|
res.x = v;
|
||
|
res.y = p;
|
||
|
res.z = q;
|
||
|
}
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
float nearestLevel(float col, int mode) {
|
||
|
|
||
|
if (mode==0) {
|
||
|
for (int i =0; i<HueLevCount-1; i++ ) {
|
||
|
if (col >= HueLevels[i] && col <= HueLevels[i+1]) {
|
||
|
return HueLevels[i+1];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (mode==1) {
|
||
|
for (int i =0; i<SatLevCount-1; i++ ) {
|
||
|
if (col >= SatLevels[i] && col <= SatLevels[i+1]) {
|
||
|
return SatLevels[i+1];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if (mode==2) {
|
||
|
for (int i =0; i<ValLevCount-1; i++ ) {
|
||
|
if (col >= ValLevels[i] && col <= ValLevels[i+1]) {
|
||
|
return ValLevels[i+1];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
// averaged pixel intensity from 3 color channels
|
||
|
float avg_intensity(vec4 pix) {
|
||
|
return (pix.r + pix.g + pix.b)/3.;
|
||
|
}
|
||
|
|
||
|
vec4 get_pixel(vec2 coords, float dx, float dy) {
|
||
|
return texture(u_texture, coords + vec2(dx, dy));
|
||
|
}
|
||
|
|
||
|
// returns pixel color
|
||
|
float IsEdge(in vec2 coords){
|
||
|
float dxtex = 1.0 / u_resolution.x ;
|
||
|
float dytex = 1.0 / u_resolution.y ;
|
||
|
|
||
|
float pix[9];
|
||
|
|
||
|
int k = -1;
|
||
|
float delta;
|
||
|
|
||
|
// read neighboring pixel intensities
|
||
|
float pix0 = avg_intensity(get_pixel(coords,-1.0*dxtex, -1.0*dytex));
|
||
|
float pix1 = avg_intensity(get_pixel(coords,-1.0*dxtex, 0.0*dytex));
|
||
|
float pix2 = avg_intensity(get_pixel(coords,-1.0*dxtex, 1.0*dytex));
|
||
|
float pix3 = avg_intensity(get_pixel(coords,0.0*dxtex, -1.0*dytex));
|
||
|
float pix4 = avg_intensity(get_pixel(coords,0.0*dxtex, 0.0*dytex));
|
||
|
float pix5 = avg_intensity(get_pixel(coords,0.0*dxtex, 1.0*dytex));
|
||
|
float pix6 = avg_intensity(get_pixel(coords,1.0*dxtex, -1.0*dytex));
|
||
|
float pix7 = avg_intensity(get_pixel(coords,1.0*dxtex, 0.0*dytex));
|
||
|
float pix8 = avg_intensity(get_pixel(coords,1.0*dxtex, 1.0*dytex));
|
||
|
// average color differences around neighboring pixels
|
||
|
delta = (abs(pix1-pix7)+
|
||
|
abs(pix5-pix3) +
|
||
|
abs(pix0-pix8)+
|
||
|
abs(pix2-pix6)
|
||
|
)/4.;
|
||
|
|
||
|
return clamp(5.5*delta,0.0,1.0);
|
||
|
}
|
||
|
|
||
|
void main(void)
|
||
|
{
|
||
|
vec2 uv = (texcoords - u_texbounds.xy) / u_texbounds.zw;
|
||
|
|
||
|
HueLevels[0] = 0.0;
|
||
|
HueLevels[1] = 80.0;
|
||
|
HueLevels[2] = 160.0;
|
||
|
HueLevels[3] = 240.0;
|
||
|
HueLevels[4] = 320.0;
|
||
|
HueLevels[5] = 360.0;
|
||
|
|
||
|
SatLevels[0] = 0.0;
|
||
|
SatLevels[1] = 0.1;
|
||
|
SatLevels[2] = 0.3;
|
||
|
SatLevels[3] = 0.5;
|
||
|
SatLevels[4] = 0.6;
|
||
|
SatLevels[5] = 0.8;
|
||
|
SatLevels[6] = 1.0;
|
||
|
|
||
|
ValLevels[0] = 0.0;
|
||
|
ValLevels[1] = 0.3;
|
||
|
ValLevels[2] = 0.6;
|
||
|
ValLevels[3] = 1.0;
|
||
|
|
||
|
vec4 colorOrg = texture( u_texture, uv );
|
||
|
vec3 vHSV = RGBtoHSV(colorOrg.r,colorOrg.g,colorOrg.b);
|
||
|
vHSV.x = nearestLevel(vHSV.x, 0);
|
||
|
vHSV.y = nearestLevel(vHSV.y, 1);
|
||
|
vHSV.z = nearestLevel(vHSV.z, 2);
|
||
|
float edg = IsEdge(uv);
|
||
|
vec3 vRGB = (edg >= 0.3)? vec3(0.0,0.0,0.0):HSVtoRGB(vHSV.x,vHSV.y,vHSV.z);
|
||
|
fragColor = vec4(vRGB.x,vRGB.y,vRGB.z,1.0);
|
||
|
}
|
||
|
`
|
||
|
|
||
|
var textureData = []byte{137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 2, 0, 0, 0, 0, 64, 8, 3, 0, 0, 0, 91, 97, 63, 141, 0, 0, 2, 100, 80, 76, 84, 69, 182, 182, 182, 48, 38, 29, 33, 23, 15, 191, 146, 37, 7, 3, 1, 72, 64, 49, 40, 28, 20, 37, 26, 19, 42, 31, 22, 110, 100, 84, 64, 54, 40, 55, 46, 32, 142, 131, 114, 74, 40, 10, 22, 14, 7, 97, 86, 69, 66, 35, 6, 99, 60, 20, 102, 91, 75, 16, 9, 3, 120, 27, 1, 27, 18, 11, 184, 140, 33, 83, 72, 57, 131, 119, 103, 114, 73, 27, 128, 87, 34, 48, 23, 2, 159, 149, 134, 185, 185, 185, 6, 37, 82, 68, 59, 45, 130, 188, 209, 111, 72, 8, 129, 32, 4, 134, 93, 38, 150, 139, 123, 46, 33, 27, 80, 68, 54, 199, 156, 43, 87, 75, 61, 43, 43, 43, 123, 111, 95, 60, 50, 38, 92, 55, 17, 119, 79, 31, 170, 159, 142, 82, 46, 14, 170, 125, 23, 146, 135, 118, 164, 119, 20, 189, 189, 189, 31, 80, 138, 115, 104, 89, 203, 162, 47, 1, 0, 0, 127, 115, 99, 87, 49, 15, 193, 193, 193, 1, 27, 64, 40, 96, 165, 83, 83, 83, 54, 42, 36, 42, 100, 171, 154, 143, 128, 118, 108, 92, 57, 57, 56, 109, 69, 25, 137, 127, 108, 206, 167, 50, 89, 80, 63, 224, 211, 196, 0, 9, 27, 255, 255, 255, 79, 44, 1, 3, 31, 71, 92, 82, 66, 71, 71, 71, 22, 61, 110, 19, 54, 100, 198, 198, 198, 189, 176, 161, 1, 22, 57, 117, 78, 9, 93, 19, 0, 29, 76, 132, 99, 22, 1, 111, 26, 2, 35, 87, 150, 27, 71, 126, 78, 69, 57, 127, 127, 127, 160, 114, 18, 0, 5, 16, 1, 18, 49, 0, 12, 38, 134, 124, 105, 178, 133, 28, 34, 33, 33, 105, 25, 2, 139, 123, 109, 135, 38, 7, 27, 67, 116, 105, 66, 24, 37, 91, 157, 72, 58, 46, 174, 129, 26, 59, 30, 5, 33, 83, 144, 132, 125, 112, 124, 83, 32, 148, 130, 114, 45, 104, 178, 78, 62, 51, 195, 152, 40, 23, 54, 90, 153, 137, 123, 81, 20, 2, 38, 15, 1, 184, 173, 157, 175, 163, 148, 9, 44, 95, 172, 119, 47, 28, 63, 102, 210, 171, 54, 95, 56, 3, 94, 84, 72, 83, 73, 66, 207, 195, 180, 201, 189, 173, 179, 168, 152, 28, 10, 0, 155, 155, 155, 97, 87, 80, 139, 100, 42, 152, 55, 18, 144, 46, 11, 164, 155, 138, 123, 123, 123, 55, 27, 4, 203, 203, 203, 214, 203, 187, 87, 86, 86, 164, 112, 46, 155, 103, 39, 50, 116, 197, 106, 106, 106, 57, 133, 225, 44, 107, 183, 52, 121, 205, 86, 49, 3, 54, 126, 214, 147, 103, 16, 147, 95, 36, 68, 16, 1, 140, 98, 16, 153, 109, 18, 145, 102, 45, 169, 150, 136, 194, 181, 166, 48, 112, 190, 169, 73, 36, 84, 7, 0, 19, 47, 78, 169, 120, 61, 114, 114, 114, 131, 91, 14, 123, 84, 13, 169, 170, 170, 64, 63, 62, 137, 137, 137, 100, 64, 7, 56, 11, 0, 100, 100, 100, 209, 209, 209, 178, 130, 76, 50, 50, 50, 43, 87, 171, 95, 95, 95, 9, 51, 110, 87, 79, 70, 110, 159, 225, 105, 146, 167, 15, 39, 62, 13, 31, 46, 174, 175, 175, 213, 144, 111, 95, 143, 212, 189, 90, 48, 164, 164, 163, 66, 148, 245, 70, 114, 191, 116, 160, 179, 141, 143, 144, 220, 155, 122, 222, 224, 225, 154, 198, 214, 60, 139, 234, 125, 53, 24, 237, 242, 244, 140, 175, 189, 188, 217, 227, 191, 150, 127, 218, 172, 148, 46, 0, 54, 145, 0, 0, 51, 110, 73, 68, 65, 84, 120, 218, 164, 89, 251, 83, 27, 85, 20, 206, 46, 44, 201, 238, 38, 89, 8, 132, 141, 36, 146, 9, 133, 52, 36, 72, 0, 27, 11, 104, 90, 94, 166, 140, 6, 104, 10, 82, 26, 106, 11, 229, 209, 2, 125, 88, 30, 133, 14, 211, 240, 40, 200, 163, 128, 14, 227, 116, 176, 160, 72, 145, 74, 45, 48, 90, 113, 208, 81, 199, 225, 23, 255, 46, 191, 187, 187, 233, 110, 124, 160, 213, 143, 189, 143, 239, 158, 123, 218, 41, 223, 185, 231, 62, 170, 243, 165, 228, 229, 81, 255, 21, 167, 242, 104, 49, 192, 222, 200, 189, 113, 195, 27, 53, 68, 121, 171, 143, 97, 246, 99, 99, 226, 24, 195, 39, 235, 157, 252, 254, 244, 244, 62, 195, 241, 62, 234, 20, 179, 63, 54, 54, 166, 181, 171, 94, 86, 43, 173, 167, 173, 86, 243, 149, 83, 85, 81, 96, 63, 202, 36, 96, 76, 237, 70, 85, 251, 55, 249, 87, 136, 159, 222, 106, 77, 206, 126, 73, 188, 171, 224, 174, 140, 236, 251, 5, 5, 5, 254, 50, 2, 211, 253, 234, 172, 99, 159, 2, 31, 43, 64, 55, 1, 202, 208, 177, 172, 106, 141, 143, 115, 194, 49, 60, 62, 49, 190, 120, 102, 113, 124, 124, 98, 113, 157, 61, 179, 56, 49, 49, 62, 129, 114, 102, 241, 204, 153, 51, 109, 158, 197, 197, 241, 137, 245, 8, 161, 139, 139, 145, 145, 54, 46, 178, 56, 62, 57, 82, 56, 17, 89, 95, 9
|