tins2020/terrainrenderer.go

185 lines
5.0 KiB
Go
Raw Normal View History

package tins2020
import (
"fmt"
"github.com/veandco/go-sdl2/sdl"
)
type terrainRenderer struct {
terrain *Map
hover *Point
project projection
interact interaction
}
type interaction struct {
mousePos Point
mouseLeftDown bool
mouseDrag *Point
}
func NewTerrainRenderer(terrain *Map) Control {
return &terrainRenderer{terrain: terrain, project: newProjection()}
}
func (r *terrainRenderer) Init(ctx *Context) error {
r.project.update(ctx.Renderer)
return nil
}
func (r *terrainRenderer) Handle(ctx *Context, event sdl.Event) {
switch e := event.(type) {
case *sdl.MouseButtonEvent:
if e.Button == sdl.BUTTON_LEFT {
r.interact.mouseLeftDown = e.Type == sdl.MOUSEBUTTONDOWN
if r.interact.mouseLeftDown && r.interact.mouseDrag == nil {
r.interact.mouseDrag = &Point{e.X, e.Y}
} else if !r.interact.mouseLeftDown && r.interact.mouseDrag != nil {
r.interact.mouseDrag = nil
}
}
case *sdl.MouseMotionEvent:
if insideRect(e.X, e.Y, &r.project.windowRect) {
hover := r.project.screenToMap(e.X, e.Y)
r.hover = &Point{X: int32(Round32(hover.X)), Y: int32(Round32(hover.Y))}
} else {
r.hover = nil
}
if r.interact.mouseDrag != nil {
r.project.center = r.project.center.Sub(r.project.screenToMapRel(e.X-r.interact.mouseDrag.X, e.Y-r.interact.mouseDrag.Y))
r.project.update(ctx.Renderer)
r.interact.mouseDrag = &Point{e.X, e.Y}
}
case *sdl.MouseWheelEvent:
2020-05-09 12:02:00 +00:00
if e.Y > 0 && r.project.zoom > .5 {
r.project.zoom *= .5
r.project.update(ctx.Renderer)
2020-05-09 12:02:00 +00:00
} else if e.Y < 0 && r.project.zoom < 4 {
r.project.zoom *= 2
r.project.update(ctx.Renderer)
}
case *sdl.WindowEvent:
if e.Event == sdl.WINDOWEVENT_RESIZED {
r.project.update(ctx.Renderer)
}
}
}
func insideRect(x, y int32, rect *sdl.Rect) bool {
return x >= rect.X && x < rect.X+rect.W && y >= rect.Y && y < rect.Y+rect.H
}
func insideRectPt(p Point, rect *sdl.Rect) bool { return insideRect(p.X, p.Y, rect) }
func (r *terrainRenderer) Render(ctx *Context) {
2020-05-09 20:50:11 +00:00
toTileTexture := func(x, y int32) *Texture {
temp := r.terrain.Temp.Value(x, y)
if temp < .35 {
return ctx.Textures.Texture("tile-snow")
}
if temp > .65 {
return ctx.Textures.Texture("tile-dirt")
}
return ctx.Textures.Texture("tile-grass")
}
variantToInt := func(variant float64) int {
if variant < .25 {
return 1
}
if variant < .5 {
return 2
}
if variant < .75 {
return 3
}
if variant < 1 {
return 4
}
return -1
}
variantToTexture := func(format string, variant float64) *Texture {
textName := fmt.Sprintf(format, variantToInt(variant))
return ctx.Textures.Texture(textName)
}
stretch := func(x, from, to float64) float64 { return (x - from) * 1 / (to - from) }
toPropTexture := func(temp, humid, variant float64) *Texture {
if temp < .35 {
if humid < .2 {
return nil
} else if humid < .7 {
return variantToTexture("bush-small-%d", variant*5)
}
return variantToTexture("tree-pine-%d", variant*5)
}
if temp > .65 {
if humid < .2 {
return nil
}
if humid < .7 {
return variantToTexture("cactus-short-%d", variant*7)
}
return variantToTexture("cactus-tall-%d", variant*2)
}
if humid < .2 {
return nil
}
multiplier := 1 - stretch(humid, 0.2, 1)
if variant < .5 {
return variantToTexture("tree-fat-%d", stretch(variant, 0, .5)*multiplier*3)
} else if variant < .8 {
return variantToTexture("grass-small-%d", stretch(variant, .5, .8)*multiplier*2)
}
return variantToTexture("bush-large-%d", stretch(variant, .8, 1)*multiplier)
}
toItemTexture := func(x, y int32) *Texture {
variant := r.terrain.Variant.Value(x, y)
_, ok := r.terrain.Flowers[Pt(x, y)]
if ok {
return variantToTexture("flower-poppy-%d", variant)
}
temp := r.terrain.Temp.Value(x, y)
humid := r.terrain.Humid.Value(x, y)
return toPropTexture(temp, humid, variant)
}
// horizontal: [0, 128) = 128
// vertical (tile): [96,160) = 64
// vertical (total): [0,160) = 160
2020-05-09 14:48:39 +00:00
r.project.visibleTiles(func(x, y int32, pos Point) {
2020-05-09 20:50:11 +00:00
text := toTileTexture(x, y)
2020-05-09 14:48:39 +00:00
rect := r.project.screenToTileRect(pos)
text.Copy(ctx.Renderer, rect)
2020-05-09 20:50:11 +00:00
if r.hover != nil && x == r.hover.X && y == r.hover.Y {
ctx.Textures.Texture("tile-hover").Copy(ctx.Renderer, rect)
2020-05-09 20:50:11 +00:00
}
2020-05-09 14:48:39 +00:00
})
r.project.visibleTiles(func(x, y int32, pos Point) {
text := toItemTexture(x, y)
2020-05-09 14:48:39 +00:00
if text == nil {
return
}
placeX, placeY := r.terrain.PlaceX.Value(x, y), r.terrain.PlaceY.Value(x, y)
2020-05-09 20:50:11 +00:00
pos = r.project.mapToScreenF(float32(x)-.2+float32(.9*placeX-.45), float32(y)-.2+float32(.9*placeY-.45))
2020-05-09 14:48:39 +00:00
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})
// }
// }
}