From 8a2544f72e40383844404ebd7c9b222600b5f983 Mon Sep 17 00:00:00 2001 From: BuckarooBanzay Date: Sun, 30 Jun 2024 11:17:54 +0200 Subject: [PATCH] isometric tile renderer --- isotilerenderer.go | 69 +++++++++++++++++++++++++++++++++++++++++ isotilerenderer_test.go | 41 ++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 isotilerenderer.go create mode 100644 isotilerenderer_test.go diff --git a/isotilerenderer.go b/isotilerenderer.go new file mode 100644 index 0000000..ff217e8 --- /dev/null +++ b/isotilerenderer.go @@ -0,0 +1,69 @@ +package maprenderer + +import ( + "fmt" + "image" + "slices" + + "github.com/minetest-go/types" +) + +type IsoTileRenderOpts struct { + CubeLen int +} + +func NewDefaultIsoTileRenderOpts() *IsoTileRenderOpts { + return &IsoTileRenderOpts{ + CubeLen: 8, + } +} + +func RenderIsometricTile(na types.NodeAccessor, cr types.ColorResolver, from, to *types.Pos, opts *IsoTileRenderOpts) (image.Image, error) { + if opts == nil { + opts = NewDefaultIsoTileRenderOpts() + } + + min, max := types.SortPos(from, to) + size := to.Subtract(from).Add(types.NewPos(1, 1, 1)) + top_size := types.NewPos(size.X(), 1, size.Z()) + + width, height := GetIsometricImageSize(top_size, opts.CubeLen) + center_x, center_y := GetIsoCenterCubeOffset(size, opts.CubeLen) + img := image.NewRGBA(image.Rectangle{Min: image.Point{}, Max: image.Point{X: width, Y: height}}) + + ipos := types.NewPos(1, -1, 1) + + nodes := []*NodeWithColor{} + + // top layer + for x := min.X(); x <= max.X(); x++ { + for z := min.Z(); z <= max.Z(); z++ { + pnodes, err := Probe(min, max, types.NewPos(x, max.Y(), z), ipos, na, cr, true) + if err != nil { + return nil, fmt.Errorf("probe error, top layer: %v", err) + } + nodes = append(nodes, pnodes...) + } + } + + slices.SortFunc(nodes, SortNodesWithColor) + + for _, n := range nodes { + rel_pos := n.Pos.Subtract(min) + c1 := ColorAdjust(n.Color, 0) + // disable alpha channel + c1.A = 255 + + // brighter/darker colors for the other sides + c2 := ColorAdjust(c1, -10) + c3 := ColorAdjust(c1, 10) + + x, y := GetIsoCubePosition(center_x, center_y, opts.CubeLen, rel_pos) + err := DrawIsoCube(img, opts.CubeLen, x, y, c1, c2, c3) + if err != nil { + return nil, fmt.Errorf("DrawIsoCube error: %v", err) + } + } + + return img, nil +} diff --git a/isotilerenderer_test.go b/isotilerenderer_test.go new file mode 100644 index 0000000..29adda4 --- /dev/null +++ b/isotilerenderer_test.go @@ -0,0 +1,41 @@ +package maprenderer_test + +import ( + "image/png" + "os" + "testing" + + "github.com/minetest-go/colormapping" + "github.com/minetest-go/maprenderer" + "github.com/minetest-go/types" + "github.com/stretchr/testify/assert" +) + +func TestIsoTileRenderer(t *testing.T) { + m := NewMap() + err := m.Load("testdata/map.csv") + assert.NoError(t, err) + + cm := colormapping.NewColorMapping() + assert.NotNil(t, cm) + + //load defaults + err = cm.LoadDefaults() + assert.NoError(t, err) + + from := types.NewPos(0, 0, 0) + to := types.NewPos(15, 30, 15) + opts := &maprenderer.IsoTileRenderOpts{ + CubeLen: 16, + } + + img, err := maprenderer.RenderIsometricTile(m.GetNode, cm.GetColor, from, to, opts) + assert.NoError(t, err) + assert.NotNil(t, img) + + f, err := os.OpenFile("output/iso-tile-test.png", os.O_CREATE|os.O_RDWR, 0755) + assert.NoError(t, err) + + err = png.Encode(f, img) + assert.NoError(t, err) +}