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 = PtPtr(e.X, e.Y) } else if !r.interact.mouseLeftDown && r.interact.mouseDrag != nil { r.interact.mouseDrag = nil } } case *sdl.MouseMotionEvent: if r.project.windowRect.IsPointInside(e.X, e.Y) { hover := r.project.screenToMap(e.X, e.Y) r.hover = PtPtr(int32(Round32(hover.X)), 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 = PtPtr(e.X, e.Y) } case *sdl.MouseWheelEvent: if r.hover != nil { zoom := r.project.zoom if e.Y < 0 && r.project.zoom > .25 { zoom *= .5 } else if e.Y > 0 && r.project.zoom < 2 { zoom *= 2 } if zoom != r.project.zoom { hover := r.hover.ToPtF() r.project.center = hover.Sub(hover.Sub(r.project.center).Mul(r.project.zoom / zoom)) r.project.zoom = zoom 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(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}) // } // } }