From ab767a97bb198a3eb0f6aa25f83aa7b9b5767dc7 Mon Sep 17 00:00:00 2001 From: "Sascha L. Teichmann" Date: Wed, 10 Sep 2014 23:49:27 +0200 Subject: [PATCH] Made tilerender finally work. Needs performance tweaks. --- tilemapper/blockdecoder.go | 22 +++++------ tilemapper/colors.go | 6 +-- tilemapper/main.go | 2 + tilemapper/renderer.go | 81 +++++++++++++++++++++++--------------- 4 files changed, 65 insertions(+), 46 deletions(-) diff --git a/tilemapper/blockdecoder.go b/tilemapper/blockdecoder.go index 3e6ffe2..bfc13b1 100644 --- a/tilemapper/blockdecoder.go +++ b/tilemapper/blockdecoder.go @@ -25,9 +25,9 @@ const ( type DecodedBlock struct { Version byte MapContent []byte - AirId int - IgnoreId int - IndexMap map[int]int + AirId int32 + IgnoreId int32 + IndexMap map[int32]int32 } // The content of the map and the meta data are compressed with zlib. @@ -41,7 +41,7 @@ type PosBuf struct { Pos int } -func NewDecodedBlock(data []byte, nameIndex map[string]int) (db *DecodedBlock, err error) { +func NewDecodedBlock(data []byte, nameIndex map[string]int32) (db *DecodedBlock, err error) { version := data[0] contentWidth := int(data[2]) @@ -113,14 +113,14 @@ func NewDecodedBlock(data []byte, nameIndex map[string]int) (db *DecodedBlock, e } offset += 4 - airId, ignoreId := -1, -1 - indexMap := make(map[int]int) + airId, ignoreId := int32(-1), int32(-1) + indexMap := make(map[int32]int32) if version >= 22 { offset++ numMappings := int(binary.BigEndian.Uint16(data[offset:])) offset += 2 for i := 0; i < numMappings; i++ { - nodeId := int(binary.BigEndian.Uint16(data[offset:])) + nodeId := int32(binary.BigEndian.Uint16(data[offset:])) offset += 2 nameLen := int(binary.BigEndian.Uint16(data[offset:])) offset += 2 @@ -151,18 +151,18 @@ func NewDecodedBlock(data []byte, nameIndex map[string]int) (db *DecodedBlock, e return } -func (db *DecodedBlock) Content(x, y, z int) (content int, found bool) { +func (db *DecodedBlock) Content(x, y, z int) (content int32, found bool) { pos := z<<8 + y<<4 + x switch { case db.Version >= 24: pos <<= 1 - content = int(db.MapContent[pos])<<8 | int(db.MapContent[pos+1]) + content = int32(db.MapContent[pos])<<8 | int32(db.MapContent[pos+1]) case db.Version >= 20: if db.MapContent[pos] <= 0x80 { - content = int(db.MapContent[pos]) + content = int32(db.MapContent[pos]) } else { - content = int(db.MapContent[pos])<<4 | int(db.MapContent[pos+0x2000])>>4 + content = int32(db.MapContent[pos])<<4 | int32(db.MapContent[pos+0x2000])>>4 } default: return diff --git a/tilemapper/colors.go b/tilemapper/colors.go index 536d467..90f3a9d 100644 --- a/tilemapper/colors.go +++ b/tilemapper/colors.go @@ -14,7 +14,7 @@ import ( type Colors struct { Colors []color.RGBA - NameIndex map[string]int + NameIndex map[string]int32 } func ParseColors(filename string) (colors *Colors, err error) { @@ -25,7 +25,7 @@ func ParseColors(filename string) (colors *Colors, err error) { } defer file.Close() - nameIndex := make(map[string]int) + nameIndex := make(map[string]int32) cols := make([]color.RGBA, 0, 2200) scanner := bufio.NewScanner(file) @@ -38,7 +38,7 @@ func ParseColors(filename string) (colors *Colors, err error) { var name string if n, _ := fmt.Sscanf( line, "%s %d %d %d %d", &name, &c.R, &c.G, &c.B, &c.A); n > 0 { - idx := len(cols) + idx := int32(len(cols)) cols = append(cols, c) nameIndex[name] = idx } diff --git a/tilemapper/main.go b/tilemapper/main.go index 237082b..d1d79e1 100644 --- a/tilemapper/main.go +++ b/tilemapper/main.go @@ -81,4 +81,6 @@ func main() { if err = SaveAsPNG(outfile, image); err != nil { log.Fatalf("writing image failed: %s", err) } + + fmt.Printf("Rejected blocks: %d\n", renderer.RejectedBlocks) } diff --git a/tilemapper/renderer.go b/tilemapper/renderer.go index 296e5cc..3bf8bb0 100644 --- a/tilemapper/renderer.go +++ b/tilemapper/renderer.go @@ -13,14 +13,15 @@ import ( ) type Renderer struct { - width int - height int - xOfs int16 - zOfs int16 - yBuffer []int32 - cBuffer []int32 - filled []byte - minYs []int16 + 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) { @@ -28,59 +29,75 @@ func NewRenderer(xOfs, zOfs int16, width, height int) (renderer *Renderer) { pixSize := dim * 16 * 16 yBuffer := make([]int32, pixSize) cBuffer := make([]int32, pixSize) - filled := make([]byte, dim) - minYs := make([]int16, dim) for i := 0; i < pixSize; i++ { yBuffer[i] = math.MinInt32 cBuffer[i] = -1 } - for i := 0; i < dim; i++ { - minYs[i] = math.MinInt16 - } - renderer = &Renderer{ width: width, height: height, xOfs: xOfs, zOfs: zOfs, yBuffer: yBuffer, - cBuffer: cBuffer, - filled: filled, - minYs: minYs} + cBuffer: cBuffer} return } -func (r *Renderer) RenderBlock(block *common.Block, nameIndex map[string]int) (err error) { - // fmt.Printf("%d %d\n", r.xOfs, r.zOfs) - // fmt.Printf("%d %d\n", block.Coord.X, block.Coord.Z) +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 - dimIndex := (bx << 4) + bz // We do not need to render the block if the whole 16x16 area // is already filled and the block is strictly below. - if r.filled[dimIndex] == 0xff && r.minYs[dimIndex] > block.Coord.Y { + 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 } - _ = db + w := r.width << 4 - ay := int32(block.Coord.Y) << 4 - - _ = ay - - for x := 0; x < 16; x++ { - for z := 0; z < 16; z++ { - for y := 15; y >= 0; y-- { - _, _, _ = x, y, z + 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 @@ -90,7 +107,7 @@ func (r *Renderer) CreateImage(colors []color.RGBA, background color.RGBA) *imag 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 := 0; z < ph; z++ { + for z := ph - 1; z >= 0; z-- { for x := 0; x < pw; x++ { colIdx := r.cBuffer[ofs] if colIdx >= 0 && colIdx < numCols {