Skip to content

Commit

Permalink
iso render overhaul
Browse files Browse the repository at this point in the history
  • Loading branch information
BuckarooBanzay committed Feb 3, 2023
1 parent 88108eb commit 1134080
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 87 deletions.
33 changes: 14 additions & 19 deletions iso_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import "math"

var tan30 = math.Tan(30 * math.Pi / 180)
var sqrt3div2 = 2 / math.Sqrt(3)
var sqrt3 = math.Sqrt(3)
var sin30 = math.Sin(30 * math.Pi / 180)

// returns the outer cube dimensions (of the surrounding rectangle)
// "cubesize" is the length from the center to the right or left side (2*cubesize is the width)
// "cubesize" is the true sidelength (https://en.wikipedia.org/wiki/Isometric_projection#/media/File:3D_shapes_in_isometric_projection.svg)
func GetIsoCubeSize(cubesize float64) (float64, float64) {
return cubesize * 2, cubesize * sqrt3div2 * 2
return cubesize * sqrt3, cubesize * 2
}

func GetIsometricImageSize(size *Pos, cubesize float64) (int, int) {
Expand All @@ -20,30 +22,23 @@ func GetIsometricImageSize(size *Pos, cubesize float64) (int, int) {
max_xz = size.Z()
}

size_x := math.Floor(cube_x * float64(size.X()+size.Z()) / 2)
size_y := math.Floor(cube_y * float64(size.Y()+max_xz) / 2)
size_x := math.Ceil(cube_x * float64(size.X()+size.Z()) / 2)
size_y := math.Ceil(cube_y * float64(size.Y()+max_xz) / 2)

return int(size_x), int(size_y)
}

// returns the left/top aligned image position for the cube at given position
func GetImagePos(rel_pos *Pos, size_x, size_y int, cubesize float64) (float64, float64) {
func GetImagePos(rel_pos, size *Pos, size_x, size_y int, cubesize float64) (float64, float64) {
// floating point coords
x := float64(rel_pos.X())
y := float64(rel_pos.Y())
z := float64(rel_pos.Z())
cube_x, cube_y := GetIsoCubeSize(cubesize)

// max size of z or x axis
max_xz := x
if z > max_xz {
max_xz = z
}
x_pos := (float64(rel_pos.X()) * cube_x / 2) +
(float64(rel_pos.Z()) * cube_x / 2)

xpos := ((cubesize * x) - (cubesize * z)) + (float64(size_x) / 2) - cubesize
ypos := float64(size_y) - (cubesize * sqrt3div2 * 2) -
(cubesize * tan30 * x) -
(cubesize * tan30 * z) -
(cubesize * sqrt3div2 * y)
y_pos := (float64(size.Y()-rel_pos.Y()-1) * cube_y / 2) +
(float64(size.X()-rel_pos.X()-1) * cube_y / 2) +
(float64(size.Z()-rel_pos.Z()-1) * cube_y / 2)

return xpos, ypos
return x_pos, y_pos
}
39 changes: 10 additions & 29 deletions iso_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import (
)

func TestGetIsoCubeSize(t *testing.T) {
size_x, size_y := maprenderer.GetIsoCubeSize(5.0)
assert.InDelta(t, 10, size_x, 0.1)
assert.InDelta(t, 11.54, size_y, 0.1)
size_x, size_y := maprenderer.GetIsoCubeSize(1.0)
assert.InDelta(t, 1.732, size_x, 0.1)
assert.InDelta(t, 2.0, size_y, 0.1)
}

func TestGetIsometricImageSize(t *testing.T) {
Expand All @@ -19,50 +19,31 @@ func TestGetIsometricImageSize(t *testing.T) {
// event side length
size := maprenderer.NewPos(16, 16, 16)
size_x, size_y := maprenderer.GetIsometricImageSize(size, cubesize)
assert.Equal(t, 160, size_x)
assert.Equal(t, 184, size_y)
assert.Equal(t, 139, size_x)
assert.Equal(t, 160, size_y)

// uneven side length
size = maprenderer.NewPos(16, 16, 32)
size_x, size_y = maprenderer.GetIsometricImageSize(size, cubesize)
assert.Equal(t, 240, size_x)
assert.Equal(t, 277, size_y)
assert.Equal(t, 208, size_x)
assert.Equal(t, 240, size_y)
}

func TestGetImagePosEvenSides(t *testing.T) {
cubesize := 5.0
size := maprenderer.NewPos(16, 16, 16)
// 160x184px
size_x, size_y := maprenderer.GetIsometricImageSize(size, cubesize)

// top/center node
// TODO
rel_pos := maprenderer.NewPos(15, 15, 15)
x, y := maprenderer.GetImagePos(rel_pos, size_x, size_y, cubesize)
x, y := maprenderer.GetImagePos(rel_pos, size, size_x, size_y, cubesize)
assert.InDelta(t, 75, x, 0.1) // (size_x/2)-cubesize
assert.InDelta(t, 0, y, 1)

// bottom/center node
rel_pos = maprenderer.NewPos(0, 0, 0)
x, y = maprenderer.GetImagePos(rel_pos, size_x, size_y, cubesize)
assert.InDelta(t, 75, x, 0.1)
assert.InDelta(t, 172.5, y, 1) // size_y - cubesize_y
}

func TestGetImagePosUnevenSides(t *testing.T) {
cubesize := 5.0
size := maprenderer.NewPos(16, 16, 32)
// 160x184px
size_x, size_y := maprenderer.GetIsometricImageSize(size, cubesize)

// top/center node
rel_pos := maprenderer.NewPos(15, 15, 31)
x, y := maprenderer.GetImagePos(rel_pos, size_x, size_y, cubesize)
assert.InDelta(t, 75, x, 0.1) // (size_x/2)-cubesize
assert.InDelta(t, 0, y, 1)

// bottom/center node
rel_pos = maprenderer.NewPos(0, 0, 0)
x, y = maprenderer.GetImagePos(rel_pos, size_x, size_y, cubesize)
x, y = maprenderer.GetImagePos(rel_pos, size, size_x, size_y, cubesize)
assert.InDelta(t, 75, x, 0.1)
assert.InDelta(t, 172.5, y, 1) // size_y - cubesize_y
}
35 changes: 21 additions & 14 deletions isocache.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,18 +36,25 @@ func (rc *IsoRenderCache) GetCachedIsoCubeImage(c *color.RGBA, size float64) ima
if img == nil {
// create image
size_x, size_y := GetIsoCubeSize(size)
// round up
size_x = math.Ceil(size_x)
size_y = math.Ceil(size_y)

// center position
x := size_x / 2
y := size_y / 2
center_x := size_x / 2
center_y := size_y / 2

// proportional size
sin30_proportional := sin30 * size

dc := gg.NewContext(int(math.Ceil(size_x)), int(math.Ceil(size_y)))

// right side
dc.SetRGBA255(int(c.R), int(c.G), int(c.B), int(c.A))
dc.MoveTo(size+x, (size*tan30)+y)
dc.LineTo(x, (size*sqrt3div2)+y)
dc.LineTo(x, y)
dc.LineTo(size+x, -(size*tan30)+y)
dc.MoveTo(center_x, center_y)
dc.LineTo(size_x, center_y-sin30_proportional)
dc.LineTo(size_x, size_y-sin30_proportional)
dc.LineTo(center_x, size_y)
dc.ClosePath()
dc.Fill()

Expand All @@ -58,10 +65,10 @@ func (rc *IsoRenderCache) GetCachedIsoCubeImage(c *color.RGBA, size float64) ima
AdjustColorComponent(c.B, -20),
int(c.A),
)
dc.MoveTo(x, (size*sqrt3div2)+y)
dc.LineTo(-size+x, (size*tan30)+y)
dc.LineTo(-size+x, -(size*tan30)+y)
dc.LineTo(x, y)
dc.MoveTo(center_x, center_y)
dc.LineTo(center_x, size_y)
dc.LineTo(0, size_y-sin30_proportional)
dc.LineTo(0, center_y-sin30_proportional)
dc.ClosePath()
dc.Fill()

Expand All @@ -72,10 +79,10 @@ func (rc *IsoRenderCache) GetCachedIsoCubeImage(c *color.RGBA, size float64) ima
AdjustColorComponent(c.B, 20),
int(c.A),
)
dc.MoveTo(-size+x, -(size*tan30)+y)
dc.LineTo(x, -(size*sqrt3div2)+y)
dc.LineTo(size+x, -(size*tan30)+y)
dc.LineTo(x, y)
dc.MoveTo(center_x, center_y)
dc.LineTo(0, center_y-sin30_proportional)
dc.LineTo(center_x, 0)
dc.LineTo(size_x, center_y-sin30_proportional)
dc.ClosePath()
dc.Fill()

Expand Down
11 changes: 3 additions & 8 deletions isocache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,13 @@ import (
"os"
"testing"

"github.com/fogleman/gg"
"github.com/minetest-go/maprenderer"
"github.com/stretchr/testify/assert"
)

func TestGetCachedIsoCubeImage(t *testing.T) {

size := 7.0
size := 20.0

size_x, size_y := maprenderer.GetIsoCubeSize(size)

Expand All @@ -25,16 +24,12 @@ func TestGetCachedIsoCubeImage(t *testing.T) {

img := image.NewRGBA(image.Rect(0, 0, int(size_x), int(size_y)))

p1 := image.Point{X: 10, Y: 10}

p1 := image.Point{X: 0, Y: 0}
draw.Draw(img, image.Rectangle{p1, p1.Add(cube.Bounds().Size())}, cube, image.Point{0, 0}, draw.Src)

dc := gg.NewContext(int(size_x), int(size_y))
dc.DrawImage(cube, 0, 0)

f, err := os.OpenFile("output/isocache-test.png", os.O_CREATE|os.O_RDWR, 0755)
assert.NoError(t, err)

err = png.Encode(f, dc.Image())
err = png.Encode(f, img)
assert.NoError(t, err)
}
18 changes: 1 addition & 17 deletions isorenderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func (r *IsoRenderer) Render(from, to *Pos) (image.Image, error) {

for _, node := range nodes {
rel_pos := node.Pos.Subtract(from)
x, y := r.getImagePos(float64(rel_pos.X()), float64(rel_pos.Y()), float64(rel_pos.Z()), size_x, size_y)
x, y := GetImagePos(rel_pos, size, size_x, size_y, r.cubesize)

cube_img := r.rc.GetCachedIsoCubeImage(node.RGBA, r.cubesize)
p1 := image.Point{X: int(x), Y: int(y)}
Expand Down Expand Up @@ -125,19 +125,3 @@ func (r *IsoRenderer) searchNode(pos, direction, base_pos *Pos, bounds [2]*Pos)

return nil, nil
}

func (r *IsoRenderer) getImagePos(x, y, z float64, size_x, size_y int) (float64, float64) {
// max size of z or x axis
max_xz := x
if z > max_xz {
max_xz = z
}

xpos := ((r.cubesize * x) - (r.cubesize * z)) + (float64(size_x) / 2) - r.cubesize
ypos := float64(size_y) - (r.cubesize * sqrt3div2 * 2) -
(r.cubesize * tan30 * x) -
(r.cubesize * tan30 * z) -
(r.cubesize * sqrt3div2 * y)

return xpos, ypos
}

0 comments on commit 1134080

Please sign in to comment.