package tins2020 import ( "fmt" "github.com/veandco/go-sdl2/sdl" "opslag.de/schobers/geom" ) type terrainRenderer struct { terrain *Map hover PointF 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: r.hover = r.project.screenToMap(e.X, e.Y) 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 (r *terrainRenderer) Render(ctx *Context) { toTileTexture := func(temp, humid float64) *Texture { 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) } // horizontal: [191, 321) = 130 // vertical: [267,332) = 65 hover := Pt(int32(geom.Round32(r.hover.X)), int32(geom.Round32(r.hover.Y))) r.project.visibleTiles(func(x, y int32, pos Point) { if x == hover.X && y == hover.Y { return } temp := r.terrain.Temp.Value(x, y) humid := r.terrain.Humid.Value(x, y) text := toTileTexture(temp, humid) rect := r.project.screenToTileRect(pos) text.Copy(ctx.Renderer, rect) }) r.project.visibleTiles(func(x, y int32, pos Point) { variant := r.terrain.Variant.Value(x, y) if variant < -1 || variant > 1 { return } temp := r.terrain.Temp.Value(x, y) humid := r.terrain.Humid.Value(x, y) text := toPropTexture(temp, humid, variant) 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(.8*placeX-.4), float32(y)-.2+float32(.8*placeY-.4)) 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}) // } // } }