tins2020/terrainrenderer.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

185 lines
5.0 KiB
Go

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:
if e.Y > 0 && r.project.zoom > .5 {
r.project.zoom *= .5
r.project.update(ctx.Renderer)
} 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) {
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
r.project.visibleTiles(func(x, y int32, pos Point) {
text := toTileTexture(x, y)
rect := r.project.screenToTileRect(pos)
text.Copy(ctx.Renderer, rect)
if r.hover != nil && x == r.hover.X && y == r.hover.Y {
ctx.Textures.Texture("tile-hover").Copy(ctx.Renderer, rect)
}
})
r.project.visibleTiles(func(x, y int32, pos Point) {
text := toItemTexture(x, y)
if text == nil {
return
}
placeX, placeY := r.terrain.PlaceX.Value(x, y), r.terrain.PlaceY.Value(x, y)
pos = r.project.mapToScreenF(float32(x)-.2+float32(.9*placeX-.45), float32(y)-.2+float32(.9*placeY-.45))
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})
// }
// }
}