func (g *generator) buildTerrain(mpath minecraft.Path, level *level, terrain, biomes, plants *image.Paletted, height, water *image.Gray, c chan paint) error { b := terrain.Bounds() proceed := make(chan uint8, 10) errChan := make(chan error, 1) go func() { defer close(proceed) cc := newCache(g.Terrain.Blocks) for j := 0; j < b.Max.Y; j += 16 { chunkZ := int32(j >> 4) for i := 0; i < b.Max.X; i += 16 { chunkX := int32(i >> 4) h := int32(meanHeight(height.SubImage(image.Rect(i, j, i+16, j+16)).(*image.Gray))) wh := int32(meanHeight(water.SubImage(image.Rect(i, j, i+16, j+16)).(*image.Gray))) var t uint8 if wh >= h<<1 { // more water than land... c <- paint{ color.RGBA{0, 0, 255, 255}, chunkX, chunkZ, } t = uint8(len(g.Terrain.Blocks) - 1) h = wh } else { t = modeTerrain(terrain.SubImage(image.Rect(i, j, i+16, j+16)).(*image.Paletted), len(g.Terrain.Palette)) c <- paint{ g.Terrain.Palette[t], chunkX, chunkZ, } } if err := mpath.SetChunk(cc.getFromCache(chunkX, chunkZ, t, h)); err != nil { errChan <- err return } proceed <- t } } }() ts := make([]uint8, 0, 1024) for i := 0; i < (b.Max.X>>4)+2; i++ { ts = append(ts, <-proceed) // get far enough ahead so all chunks are surrounded before shaping, to get correct lighting } select { case err := <-errChan: return err default: } for j := int32(0); j < int32(b.Max.Y); j += 16 { chunkZ := j >> 4 for i := int32(0); i < int32(b.Max.X); i += 16 { chunkX := i >> 4 var totalHeight int32 ot := ts[0] ts = ts[1:] oy, _ := level.GetHeight(i, j) for x := i; x < i+16; x++ { for z := j; z < j+16; z++ { if biomes != nil { level.SetBiome(x, z, g.Biomes.Values[biomes.ColorIndexAt(int(x), int(z))]) } h := int32(height.GrayAt(int(x), int(z)).Y) totalHeight += h wl := int32(water.GrayAt(int(x), int(z)).Y) y := oy if h > y { y = h } if wl > y { y = wl } for ; y > h && y > wl; y-- { level.SetBlock(x, y, z, minecraft.Block{}) } if plants != nil { p := g.Plants.Blocks[plants.ColorIndexAt(int(x), int(z))] py := int32(1) for ; py <= int32(p.Level); py++ { level.SetBlock(x, y+py, z, p.Base) } level.SetBlock(x, y+py, z, p.Top) } for ; y > h; y-- { level.SetBlock(x, y, z, minecraft.Block{ID: 9}) } t := terrain.ColorIndexAt(int(x), int(z)) tb := g.Terrain.Blocks[t] for ; y > h-int32(tb.Level); y-- { level.SetBlock(x, y, z, tb.Top) } if t != ot { h = 0 } else { h = oy } for ; y >= h; y-- { level.SetBlock(x, y, z, tb.Base) } } } c <- paint{ color.Alpha{uint8(totalHeight >> 8)}, chunkX, chunkZ, } select { case p, ok := <-proceed: if ok { ts = append(ts, p) } case err := <-errChan: return err } } } return nil }