// Copyright 2014 by Sascha L. Teichmann // Use of this source code is governed by the MIT license // that can be found in the LICENSE file. package main import ( "image" "image/color" "math" "bitbucket.org/s_l_teichmann/mtredisalize/common" ) type Renderer struct { width int height int xOfs int16 zOfs int16 yBuffer []int32 cBuffer []int32 filled []uint16 minYs []int16 RejectedBlocks int } 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) for i := 0; i < pixSize; i++ { yBuffer[i] = math.MinInt32 cBuffer[i] = -1 } renderer = &Renderer{ width: width, height: height, xOfs: xOfs, zOfs: zOfs, yBuffer: yBuffer, cBuffer: cBuffer} return } func (r *Renderer) minY(x, z int16) (minY int32) { x -= r.xOfs z -= r.zOfs w := r.width << 4 ofs := int(z)*w<<4 + int(x)<<4 minY = int32(math.MaxInt32) for yEnd := ofs + w<<4; ofs < yEnd; { for xEnd := ofs + 16; ofs < xEnd; ofs++ { y := r.yBuffer[ofs] if y < minY { minY = y } } ofs += w - 16 } return } func (r *Renderer) RenderBlock(block *common.Block, nameIndex map[string]int32) (err error) { 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. blockY := int32(block.Coord.Y) << 4 if blockY < r.minY(block.Coord.X, block.Coord.Z) { r.RejectedBlocks++ return } // Decoding is pretty expensive so it that late. var db *DecodedBlock if db, err = NewDecodedBlock(block.Data, nameIndex); err != nil { return } w := r.width << 4 ofs := int(bz)*w<<4 + int(bx)<<4 for z := 0; z < 16; z++ { for x := 0; x < 16; x++ { if currentY := r.yBuffer[ofs]; currentY < blockY { for y := 15; y >= 0; y-- { if c, ok := db.Content(x, y, z); ok { r.cBuffer[ofs] = c r.yBuffer[ofs] = blockY + int32(y) break } } } ofs++ } ofs += w - 16 } return } func (r *Renderer) CreateImage(colors []color.RGBA, background color.RGBA) *image.RGBA { pw, ph := r.width<<4, r.height<<4 image := image.NewRGBA(image.Rect(0, 0, pw, ph)) ofs, numCols := 0, int32(len(colors)) for z := ph - 1; z >= 0; z-- { for x := 0; x < pw; x++ { colIdx := r.cBuffer[ofs] if colIdx >= 0 && colIdx < numCols { image.Set(x, z, colors[colIdx]) } else { image.Set(x, z, background) } ofs++ } } return image }