Sander Schobers
44aef25d34
Inversed zoom on projection (previously how much smaller the content would be, now it is the magnification).
91 lines
2.9 KiB
Go
91 lines
2.9 KiB
Go
package tins2020
|
|
|
|
import (
|
|
"log"
|
|
|
|
"github.com/veandco/go-sdl2/sdl"
|
|
)
|
|
|
|
type projection struct {
|
|
center PointF
|
|
zoom float32
|
|
zoomInv float32
|
|
|
|
windowRect Rectangle
|
|
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.zoom), p.windowCenter.Y+int32((translated.X+translated.Y)*32*p.zoom))
|
|
}
|
|
|
|
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.zoomInv * float32(x)
|
|
normY := p.zoomInv * 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.zoom*64), int32(p.zoom*112))
|
|
p.tileScreenSize = Pt(int32(p.zoom*128), int32(p.zoom*160))
|
|
p.tileFitScreenSize = Pt(int32(p.zoom*64), int32(p.zoom*32))
|
|
|
|
windowW, windowH, err := renderer.GetOutputSize()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
p.windowCenter = Pt(windowW/2, windowH/2)
|
|
p.windowRect = RectSize(buttonBarWidth, 0, windowW-2*buttonBarWidth, windowH)
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
}
|