diff --git a/tilemapper/renderer.go b/tilemapper/renderer.go index 3ccfc32..9c2d6f5 100644 --- a/tilemapper/renderer.go +++ b/tilemapper/renderer.go @@ -18,22 +18,32 @@ type Renderer struct { xOfs int16 zOfs int16 yBuffer []int32 + yMin []int32 cBuffer []int32 filled int Rejected int } +const ( + invalid = math.MinInt32 + 1 +) + func NewRenderer(xOfs, zOfs int16, width, height int) (renderer *Renderer) { dim := width * height pixSize := dim * 16 * 16 yBuffer := make([]int32, pixSize) cBuffer := make([]int32, pixSize) + yMin := make([]int32, dim) for i := 0; i < pixSize; i++ { yBuffer[i] = math.MinInt32 cBuffer[i] = -1 } + for i := 0; i < dim; i++ { + yMin[i] = math.MinInt32 + } + renderer = &Renderer{ width: width, height: height, @@ -44,24 +54,6 @@ func NewRenderer(xOfs, zOfs int16, width, height int) (renderer *Renderer) { return } -func (r *Renderer) minY(ofs, w int) (minY int32, filled bool) { - minY = int32(math.MaxInt32) - for yEnd := ofs + w<<4; ofs < yEnd; { - for xEnd := ofs + 16; ofs < xEnd; ofs++ { - y := r.yBuffer[ofs] - switch { - case y == math.MaxInt32: - return - case y < minY: - minY = y - } - } - ofs += w - 16 - } - filled = true - return -} - func (r *Renderer) IsFilled() bool { return r.filled == r.width<<4*r.height<<4 } @@ -70,40 +62,50 @@ func (r *Renderer) RenderBlock(block *common.Block, nameIndex map[string]int32) bx := block.Coord.X - r.xOfs bz := block.Coord.Z - r.zOfs + // We do not need to render the block if the whole 16x16 area // is already filled and the block is strictly below. w := r.width << 4 ofs := int(bz)*w<<4 + int(bx)<<4 + blockY := int32(block.Coord.Y) << 4 - if minY, filled := r.minY(ofs, w); filled && blockY < minY { + pos := int(bz)*r.width + int(bx) + if blockY < r.yMin[pos] { r.Rejected++ return } - // Decoding is pretty expensive so it that late. + // Decoding is pretty expensive so do it that late. var db *DecodedBlock if db, err = NewDecodedBlock(block.Data, nameIndex); err != nil { return } + yMin := int32(math.MaxInt32) for z := 0; z < 16; z++ { for x := 0; x < 16; x++ { - if currentY := r.yBuffer[ofs]; currentY < blockY { + currentY := r.yBuffer[ofs] + if currentY < blockY { for y := 15; y >= 0; y-- { if c, ok := db.Content(x, y, z); ok { if r.cBuffer[ofs] == -1 { r.filled++ } r.cBuffer[ofs] = c - r.yBuffer[ofs] = blockY + int32(y) + currentY = blockY + int32(y) + r.yBuffer[ofs] = currentY break } } } + if currentY < yMin { + yMin = currentY + } ofs++ } ofs += w - 16 } + r.yMin[pos] = yMin return }