2020-05-09 14:48:39 +00:00
package tins2020
import (
"log"
"github.com/veandco/go-sdl2/sdl"
)
2020-05-11 01:09:01 +00:00
func mapToTile ( q PointF ) Point {
return Pt ( int32 ( Round32 ( q . X ) ) , int32 ( Round32 ( q . Y ) ) )
}
2020-05-09 14:48:39 +00:00
type projection struct {
center PointF
zoom float32
zoomInv float32
2020-05-10 15:16:18 +00:00
windowInteractRect Rectangle
windowVisibleRect Rectangle
2020-05-09 14:48:39 +00:00
tileScreenDelta PointF
tileScreenDeltaInv PointF
tileScreenOffset Point
tileScreenSize Point
tileFitScreenSize Point
windowCenter Point
}
func newProjection ( ) projection {
2020-05-10 08:56:20 +00:00
return projection { zoom : 1 , tileScreenDelta : PtF ( 64 , 32 ) , tileScreenDeltaInv : PtF ( 1. / 64 , 1. / 32 ) }
2020-05-09 14:48:39 +00:00
}
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 )
2020-05-10 10:40:44 +00:00
return Pt ( p . windowCenter . X + int32 ( ( translated . X - translated . Y ) * 64 * p . zoom ) , p . windowCenter . Y + int32 ( ( translated . X + translated . Y ) * 32 * p . zoom ) )
2020-05-09 14:48:39 +00:00
}
func ( p * projection ) screenToMap ( x , y int32 ) PointF {
pos := p . screenToMapRel ( x - p . windowCenter . X , y - p . windowCenter . Y )
return p . center . Add ( pos )
}
2020-05-10 18:44:20 +00:00
func ( p * projection ) screenToMapInt ( x , y int32 ) Point {
pos := p . screenToMap ( x , y )
2020-05-11 01:09:01 +00:00
return mapToTile ( pos )
2020-05-10 18:44:20 +00:00
}
2020-05-09 14:48:39 +00:00
func ( p * projection ) screenToMapRel ( x , y int32 ) PointF {
2020-05-10 10:40:44 +00:00
normX := p . zoomInv * float32 ( x )
normY := p . zoomInv * float32 ( y )
2020-05-09 14:48:39 +00:00
return PtF ( .5 * ( p . tileScreenDeltaInv . X * normX + p . tileScreenDeltaInv . Y * normY ) , .5 * ( - p . tileScreenDeltaInv . X * normX + p . tileScreenDeltaInv . Y * normY ) )
}
2020-05-10 15:16:18 +00:00
func ( p * projection ) screenToTileFitRect ( pos Point ) Rectangle {
return RectSize ( pos . X - p . tileFitScreenSize . X , pos . Y - p . tileFitScreenSize . Y , 2 * p . tileFitScreenSize . X , 2 * p . tileFitScreenSize . Y )
2020-05-09 14:48:39 +00:00
}
2020-05-10 15:16:18 +00:00
func ( p * projection ) screenToTileRect ( pos Point ) Rectangle {
return RectSize ( pos . X - p . tileScreenOffset . X , pos . Y - p . tileScreenOffset . Y , p . tileScreenSize . X , p . tileScreenSize . Y )
2020-05-09 14:48:39 +00:00
}
func ( p * projection ) update ( renderer * sdl . Renderer ) {
p . zoomInv = 1 / p . zoom
2020-05-10 10:40:44 +00:00
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 ) )
2020-05-09 14:48:39 +00:00
windowW , windowH , err := renderer . GetOutputSize ( )
if err != nil {
log . Fatal ( err )
}
p . windowCenter = Pt ( windowW / 2 , windowH / 2 )
2020-05-10 15:16:18 +00:00
p . windowInteractRect = Rect ( buttonBarWidth , 64 , windowW - buttonBarWidth , windowH )
p . windowVisibleRect = Rect ( buttonBarWidth , 0 , windowW - buttonBarWidth , windowH + p . tileScreenSize . Y ) // Adding a tile height to the bottom for trees that stick out from the cells below.
2020-05-09 14:48:39 +00:00
}
func ( p * projection ) visibleTiles ( action func ( int32 , int32 , Point ) ) {
2020-05-10 15:16:18 +00:00
visible := p . windowVisibleRect
topLeft := p . screenToMap ( visible . X , visible . Y )
topRight := p . screenToMap ( visible . X + visible . W , visible . Y )
bottomLeft := p . screenToMap ( visible . X , visible . Y + visible . H )
bottomRight := p . screenToMap ( visible . X + visible . W , visible . Y + visible . H )
2020-05-09 14:48:39 +00:00
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 )
2020-05-10 15:16:18 +00:00
if rectFit . X + rectFit . W < visible . X || rectFit . Y + rectFit . H < visible . Y {
2020-05-09 14:48:39 +00:00
continue
}
2020-05-10 15:16:18 +00:00
if rectFit . X > visible . X + visible . W || rectFit . Y > visible . Y + visible . H {
2020-05-09 14:48:39 +00:00
break
}
action ( x , y , pos )
}
}
}
2020-05-11 10:05:54 +00:00
func ( p * projection ) ZoomOut ( ctx * Context , center PointF ) {
if p . zoom <= .25 {
return
}
p . SetZoom ( ctx , center , .5 * p . zoom )
}
func ( p * projection ) ZoomIn ( ctx * Context , center PointF ) {
if p . zoom >= 2 {
return
}
p . SetZoom ( ctx , center , 2 * p . zoom )
}
func ( p * projection ) SetZoom ( ctx * Context , center PointF , zoom float32 ) {
if p . zoom == zoom {
return
}
p . center = center . Sub ( center . Sub ( p . center ) . Mul ( p . zoom / zoom ) )
p . zoom = zoom
p . update ( ctx . Renderer )
}