tins2020/projection.go
Sander Schobers 69c8ae72f3 Updated textures (cropped & slightly resized).
Textures used to be 512x512px, cropped them to 128x160px. The width of the texture was first cropped to 130px and then resized to 128px (height was not resized).
2020-05-10 10:56:20 +02:00

91 lines
3.0 KiB
Go

package tins2020
import (
"log"
"github.com/veandco/go-sdl2/sdl"
)
type projection struct {
center PointF
zoom float32
zoomInv float32
windowRect sdl.Rect
tileScreenDelta PointF
tileScreenDeltaInv PointF
tileScreenOffset Point
tileScreenSize Point
tileFitScreenSize Point
windowCenter Point
}
func newProjection() projection {
return projection{zoom: 1, tileScreenDelta: PtF(64, 32), tileScreenDeltaInv: PtF(1./64, 1./32)}
}
func (p *projection) mapToScreen(x, y int32) Point {
return p.mapToScreenF(float32(x), float32(y))
}
func (p *projection) mapToScreenF(x, y float32) Point {
translated := PtF(x-p.center.X, y-p.center.Y)
return Pt(p.windowCenter.X+int32((translated.X-translated.Y)*64*p.zoomInv), p.windowCenter.Y+int32((translated.X+translated.Y)*32*p.zoomInv))
}
func (p *projection) screenToMap(x, y int32) PointF {
pos := p.screenToMapRel(x-p.windowCenter.X, y-p.windowCenter.Y)
return p.center.Add(pos)
}
func (p *projection) screenToMapRel(x, y int32) PointF {
normX := p.zoom * float32(x)
normY := p.zoom * float32(y)
return PtF(.5*(p.tileScreenDeltaInv.X*normX+p.tileScreenDeltaInv.Y*normY), .5*(-p.tileScreenDeltaInv.X*normX+p.tileScreenDeltaInv.Y*normY))
}
func (p *projection) screenToTileFitRect(pos Point) *sdl.Rect {
return &sdl.Rect{X: pos.X - p.tileFitScreenSize.X, Y: pos.Y - p.tileFitScreenSize.Y, W: 2 * p.tileFitScreenSize.X, H: 2 * p.tileFitScreenSize.Y}
}
func (p *projection) screenToTileRect(pos Point) *sdl.Rect {
return &sdl.Rect{X: pos.X - p.tileScreenOffset.X, Y: pos.Y - p.tileScreenOffset.Y, W: p.tileScreenSize.X, H: p.tileScreenSize.Y}
}
func (p *projection) update(renderer *sdl.Renderer) {
p.zoomInv = 1 / p.zoom
p.tileScreenOffset = Pt(int32(p.zoomInv*64), int32(p.zoomInv*112))
p.tileScreenSize = Pt(int32(p.zoomInv*128), int32(p.zoomInv*160))
p.tileFitScreenSize = Pt(int32(p.zoomInv*64), int32(p.zoomInv*32))
windowW, windowH, err := renderer.GetOutputSize()
if err != nil {
log.Fatal(err)
}
p.windowCenter = Pt(windowW/2, windowH/2)
p.windowRect = sdl.Rect{X: buttonBarWidth, Y: 0, W: windowW - 2*buttonBarWidth, H: windowH - 0}
}
func (p *projection) visibleTiles(action func(int32, int32, Point)) {
topLeft := p.screenToMap(p.windowRect.X, p.windowRect.Y)
topRight := p.screenToMap(p.windowRect.X+p.windowRect.W, p.windowRect.Y)
bottomLeft := p.screenToMap(p.windowRect.X, p.windowRect.Y+p.windowRect.H)
bottomRight := p.screenToMap(p.windowRect.X+p.windowRect.W, p.windowRect.Y+p.windowRect.H)
minY, maxY := int32(Floor32(topRight.Y)), int32(Ceil32(bottomLeft.Y))
minX, maxX := int32(Floor32(topLeft.X)), int32(Ceil32(bottomRight.X))
for y := minY; y <= maxY; y++ {
for x := minX; x <= maxX; x++ {
pos := p.mapToScreen(x, y)
rectFit := p.screenToTileFitRect(pos)
if rectFit.X+rectFit.W < p.windowRect.X || rectFit.Y+rectFit.H < p.windowRect.Y {
continue
}
if rectFit.X > p.windowRect.X+p.windowRect.W || rectFit.Y > p.windowRect.Y+p.windowRect.H {
break
}
action(x, y, pos)
}
}
}