Added clipping to terrain renderer.
This commit is contained in:
parent
0a73529306
commit
b32017f18a
7
math.go
Normal file
7
math.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package tins2020
|
||||||
|
|
||||||
|
import "math"
|
||||||
|
|
||||||
|
func Ceil32(x float32) float32 { return float32(math.Ceil(float64(x))) }
|
||||||
|
|
||||||
|
func Floor32(x float32) float32 { return float32(math.Floor(float64(x))) }
|
90
projection.go
Normal file
90
projection.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
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(65, 32), tileScreenDeltaInv: PtF(1./65, 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)*65*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*256), int32(p.zoomInv*300))
|
||||||
|
p.tileScreenSize = Pt(int32(p.zoomInv*512), int32(p.zoomInv*512))
|
||||||
|
p.tileFitScreenSize = Pt(int32(p.zoomInv*65), 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: 200, Y: 200, W: windowW - 400, H: windowH - 400}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,11 +2,9 @@ package tins2020
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
|
|
||||||
"opslag.de/schobers/geom"
|
|
||||||
|
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
|
"opslag.de/schobers/geom"
|
||||||
)
|
)
|
||||||
|
|
||||||
type terrainRenderer struct {
|
type terrainRenderer struct {
|
||||||
@ -23,59 +21,6 @@ type interaction struct {
|
|||||||
mouseDrag *Point
|
mouseDrag *Point
|
||||||
}
|
}
|
||||||
|
|
||||||
type projection struct {
|
|
||||||
center PointF
|
|
||||||
zoom float32
|
|
||||||
zoomInv float32
|
|
||||||
|
|
||||||
tileScreenDelta PointF
|
|
||||||
tileScreenDeltaInv PointF
|
|
||||||
tileScreenOffset Point
|
|
||||||
tileScreenSize Point
|
|
||||||
windowCenter Point
|
|
||||||
}
|
|
||||||
|
|
||||||
func newProjection() projection {
|
|
||||||
return projection{zoom: 1, tileScreenDelta: PtF(65, 32), tileScreenDeltaInv: PtF(1./65, 1./32)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *projection) update(renderer *sdl.Renderer) {
|
|
||||||
p.zoomInv = 1 / p.zoom
|
|
||||||
|
|
||||||
p.tileScreenOffset = Pt(int32(p.zoomInv*256), int32(p.zoomInv*300))
|
|
||||||
p.tileScreenSize = Pt(int32(p.zoomInv*512), int32(p.zoomInv*512))
|
|
||||||
|
|
||||||
windowW, windowH, err := renderer.GetOutputSize()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
p.windowCenter = Pt(windowW/2, windowH/2)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)*65*p.zoomInv), p.windowCenter.Y+int32((translated.X+translated.Y)*32*p.zoomInv))
|
|
||||||
}
|
|
||||||
|
|
||||||
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) screenToMap(x, y int32) PointF {
|
|
||||||
pos := p.screenToMapRel(x-p.windowCenter.X, y-p.windowCenter.Y)
|
|
||||||
return p.center.Add(pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 NewTerrainRenderer(terrain *Map) Control {
|
func NewTerrainRenderer(terrain *Map) Control {
|
||||||
return &terrainRenderer{terrain: terrain, project: newProjection()}
|
return &terrainRenderer{terrain: terrain, project: newProjection()}
|
||||||
}
|
}
|
||||||
@ -186,37 +131,40 @@ func (r *terrainRenderer) Render(ctx *Context) {
|
|||||||
// vertical: [267,332) = 65
|
// vertical: [267,332) = 65
|
||||||
|
|
||||||
hover := Pt(int32(geom.Round32(r.hover.X)), int32(geom.Round32(r.hover.Y)))
|
hover := Pt(int32(geom.Round32(r.hover.X)), int32(geom.Round32(r.hover.Y)))
|
||||||
for y := int32(-100); y < 100; y++ {
|
r.project.visibleTiles(func(x, y int32, pos Point) {
|
||||||
for x := int32(-100); x < 100; x++ {
|
|
||||||
if x == hover.X && y == hover.Y {
|
if x == hover.X && y == hover.Y {
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
temp := r.terrain.Temp.Value(x, y)
|
temp := r.terrain.Temp.Value(x, y)
|
||||||
humid := r.terrain.Humid.Value(x, y)
|
humid := r.terrain.Humid.Value(x, y)
|
||||||
text := toTileTexture(temp, humid)
|
text := toTileTexture(temp, humid)
|
||||||
pos := r.project.mapToScreen(x, y)
|
rect := r.project.screenToTileRect(pos)
|
||||||
text.Copy(ctx.Renderer, r.project.screenToTileRect(pos))
|
text.Copy(ctx.Renderer, rect)
|
||||||
}
|
})
|
||||||
}
|
|
||||||
|
|
||||||
for y := int32(-100); y < 100; y++ {
|
r.project.visibleTiles(func(x, y int32, pos Point) {
|
||||||
for x := int32(-100); x < 100; x++ {
|
|
||||||
variant := r.terrain.Variant.Value(x, y)
|
variant := r.terrain.Variant.Value(x, y)
|
||||||
if variant < -1 || variant > 1 {
|
if variant < -1 || variant > 1 {
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
temp := r.terrain.Temp.Value(x, y)
|
temp := r.terrain.Temp.Value(x, y)
|
||||||
humid := r.terrain.Humid.Value(x, y)
|
humid := r.terrain.Humid.Value(x, y)
|
||||||
text := toPropTexture(temp, humid, variant)
|
text := toPropTexture(temp, humid, variant)
|
||||||
if text == nil {
|
if text == nil {
|
||||||
continue
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
placeX, placeY := r.terrain.PlaceX.Value(x, y), r.terrain.PlaceY.Value(x, y)
|
placeX, placeY := r.terrain.PlaceX.Value(x, y), r.terrain.PlaceY.Value(x, y)
|
||||||
pos := r.project.mapToScreenF(float32(x)-.2+float32(.8*placeX-.4), float32(y)-.2+float32(.8*placeY-.4))
|
pos = r.project.mapToScreenF(float32(x)-.2+float32(.8*placeX-.4), float32(y)-.2+float32(.8*placeY-.4))
|
||||||
|
|
||||||
text.Copy(ctx.Renderer, r.project.screenToTileRect(pos))
|
text.Copy(ctx.Renderer, r.project.screenToTileRect(pos))
|
||||||
}
|
})
|
||||||
}
|
|
||||||
|
// gfx.RectangleColor(ctx.Renderer, r.project.windowRect.X, r.project.windowRect.Y, r.project.windowRect.X+r.project.windowRect.W, r.project.windowRect.Y+r.project.windowRect.H, sdl.Color{R: 255, A: 255})
|
||||||
|
// for y := int32(-40); y < 40; y++ {
|
||||||
|
// for x := int32(-40); x < 40; x++ {
|
||||||
|
// pos := r.project.mapToScreen(x, y)
|
||||||
|
// ctx.Fonts.Font("debug").RenderCopy(ctx.Renderer, fmt.Sprintf("(%d, %d)", x, y), pos, sdl.Color{R: 255, A: 255})
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user