Render transparent tiles if command line flag is set.

This commit is contained in:
Sascha L. Teichmann 2014-10-26 18:36:47 +01:00
parent 2aa9ee0e24
commit 8452a26fcd
8 changed files with 198 additions and 77 deletions

View File

@ -48,6 +48,7 @@ func order(a, b int) (int, int) {
func createBaseLevel(
address string,
xMin, zMin, xMax, zMax int,
transparent bool,
colorsFile, outDir string,
numWorkers int) (err error) {
@ -71,7 +72,7 @@ func createBaseLevel(
return
}
done.Add(1)
btc := common.NewBaseTileCreator(client, colors, baseDir, false)
btc := common.NewBaseTileCreator(client, colors, transparent, baseDir, false)
go createTiles(btc, jobs, &done)
}

View File

@ -21,6 +21,7 @@ func main() {
numWorkers int
skipBaseLevel bool
skipPyramid bool
transparent bool
)
flag.IntVar(&port, "port", 6379, "port to of mtredisalize server")
@ -39,6 +40,8 @@ func main() {
flag.BoolVar(&skipBaseLevel, "sb", false, "Do not generate base level tiles (shorthand)")
flag.BoolVar(&skipPyramid, "skip-pyramid", false, "Do not generate pyramid tiles")
flag.BoolVar(&skipPyramid, "sp", false, "Do not generate pyramid tiles (shorthand)")
flag.BoolVar(&transparent, "transparent", false, "Render transparent blocks.")
flag.BoolVar(&transparent, "t", false, "Render transparent blocks (shorthand).")
flag.Parse()
@ -46,7 +49,12 @@ func main() {
if !skipBaseLevel {
address := fmt.Sprintf("%s:%d", host, port)
if err = createBaseLevel(
address, xMin, zMin, xMax, zMax, colorsFile, outDir, numWorkers); err != nil {
address,
xMin, zMin, xMax, zMax,
transparent,
colorsFile,
outDir,
numWorkers); err != nil {
log.Fatalf("Creating base level tiles failed: %s", err)
}
}

View File

@ -23,6 +23,7 @@ func main() {
colorsfile string
outfile string
shaded bool
transparent bool
)
flag.IntVar(&port, "port", 6379, "port to of mtredisalize server")
@ -41,6 +42,7 @@ func main() {
flag.StringVar(&outfile, "output", "out.png", "image file of result")
flag.StringVar(&outfile, "o", "out.png", "image file of result (shorthand)")
flag.BoolVar(&shaded, "shaded", true, "draw relief")
flag.BoolVar(&transparent, "transparent", false, "render transparent blocks")
flag.Parse()
@ -70,7 +72,7 @@ func main() {
q1x, q1y, q1z := int16(x), int16(y), int16(z)
q2x, q2y, q2z := q1x+int16(width)-1, q1y+int16(depth)-1, q1z+int16(height)-1
renderer := common.NewRenderer(width, height)
renderer := common.NewRenderer(width, height, transparent)
renderer.SetPos(q1x, q1z)
yOrder := common.NewYOrder(renderer, 512)
@ -106,7 +108,7 @@ func main() {
if shaded {
image = renderer.CreateShadedImage(
16, 16, (width-2)*16, (height-2)*16,
colors.Colors, color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff})
colors, color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff})
} else {
image = renderer.CreateImage(
colors.Colors, color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff})

View File

@ -17,14 +17,15 @@ import (
func main() {
var (
webPort int
webHost string
webDir string
mapDir string
redisPort int
redisHost string
colorsFile string
workers int
webPort int
webHost string
webDir string
mapDir string
redisPort int
redisHost string
colorsFile string
workers int
transparent bool
)
flag.IntVar(&webPort, "web-port", 8808, "port of the web server")
flag.IntVar(&webPort, "p", 8808, "port of the web server (shorthand)")
@ -41,6 +42,8 @@ func main() {
flag.IntVar(&workers, "workers", 1, "number of workers to render tiles")
flag.StringVar(&colorsFile, "colors", "colors.txt", "colors used to render map tiles.")
flag.StringVar(&colorsFile, "c", "colors.txt", "colors used to render map tiles (shorthand).")
flag.BoolVar(&transparent, "transparent", false, "Render transparent blocks.")
flag.BoolVar(&transparent, "t", false, "Render transparent blocks (shorthand).")
flag.Parse()
@ -56,7 +59,7 @@ func main() {
log.Fatalf("ERROR: problem loading colors: %s", err)
}
redisAddress := fmt.Sprintf("%s:%d", redisHost, redisPort)
tu := newTileUpdater(mapDir, redisAddress, colors, workers)
tu := newTileUpdater(mapDir, redisAddress, colors, transparent, workers)
go tu.doUpdates()
router.Path("/update").Methods("POST").Handler(tu)
}

View File

@ -26,6 +26,7 @@ type tileUpdater struct {
redisAddress string
colors *common.Colors
workers int
transparent bool
cond *sync.Cond
mu sync.Mutex
}
@ -56,12 +57,18 @@ func (c xz) parent() xzm {
Mask: 1 << (zr<<1 | xr)}
}
func newTileUpdater(mapDir, redisAddress string, colors *common.Colors, workers int) *tileUpdater {
func newTileUpdater(
mapDir, redisAddress string,
colors *common.Colors,
transparent bool,
workers int) *tileUpdater {
tu := tileUpdater{
mapDir: mapDir,
redisAddress: redisAddress,
changes: map[xz]bool{},
colors: colors,
transparent: transparent,
workers: workers}
tu.cond = sync.NewCond(&tu.mu)
return &tu
@ -113,7 +120,7 @@ func (tu *tileUpdater) doUpdates() {
log.Printf("WARN: Cannot connect to redis server: %s", err)
continue
}
btc := common.NewBaseTileCreator(client, tu.colors, baseDir, true)
btc := common.NewBaseTileCreator(client, tu.colors, tu.transparent, baseDir, true)
done.Add(1)
go updateBaseTiles(jobs, btc, &done)
}

View File

@ -54,9 +54,10 @@ type BaseTileCreator struct {
func NewBaseTileCreator(
client *RedisClient,
colors *Colors,
transparent bool,
baseDir string,
update bool) *BaseTileCreator {
renderer := NewRenderer(tileWidth, tileHeight)
renderer := NewRenderer(tileWidth, tileHeight, transparent)
return &BaseTileCreator{
client: client,
colors: colors,
@ -118,7 +119,7 @@ func (btc *BaseTileCreator) CreateTile(x, z int16, i, j int) error {
image := btc.renderer.CreateShadedImage(
16, 16, (tileWidth-2)*16, (tileHeight-2)*16,
btc.colors.Colors, color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff})
btc.colors, color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff})
path := filepath.Join(btc.baseDir, strconv.Itoa(i), fmt.Sprintf("%d.png", j))

View File

@ -115,8 +115,8 @@ func (colors *Colors) BlendColors(span *Span, col color.RGBA, pos int32) color.R
}
const scale = float32(1) / float32(100)
for ; curr != nil; curr = curr.Next {
// At least 20% attenuation + 5% extra for each depth meter.
factor := float32(min(100, 20+(curr.To-curr.From)*5)) * scale
// At least 35% attenuation + 5% extra for each depth meter.
factor := float32(min(100, 35+(curr.To-curr.From)*5)) * scale
col = BlendColor(colors.Colors[curr.Value], col, factor)
}
return col

View File

@ -27,6 +27,8 @@ type Renderer struct {
RejectedBlocks int
SolidBlocks int
TransparentBlocks int
spans *SpanPool
tBuffer []*Span
}
type YOrder struct {
@ -122,19 +124,29 @@ func (yo *YOrder) Pop() (x interface{}) {
return x
}
func NewRenderer(width, height int) (renderer *Renderer) {
func NewRenderer(width, height int, transparent bool) (renderer *Renderer) {
dim := width * height
pixSize := dim * 16 * 16
yBuffer := make([]int32, pixSize)
cBuffer := make([]int32, pixSize)
yMin := make([]int32, dim)
var tBuffer []*Span
var spans *SpanPool
if transparent {
tBuffer = make([]*Span, pixSize)
spans = NewSpanPool()
}
renderer = &Renderer{
width: width,
height: height,
yBuffer: yBuffer,
cBuffer: cBuffer,
yMin: yMin}
yMin: yMin,
tBuffer: tBuffer,
spans: spans}
renderer.Reset()
return
@ -153,6 +165,15 @@ func (r *Renderer) Reset() {
for i, n := 0, len(r.yMin); i < n; i++ {
r.yMin[i] = math.MinInt32
}
if r.tBuffer != nil {
for i, t := range r.tBuffer {
if t != nil {
r.spans.FreeAll(t)
r.tBuffer[i] = nil
}
}
}
}
func (r *Renderer) IsFilled() bool {
@ -189,37 +210,64 @@ func (r *Renderer) RenderBlock(block *Block, colors *Colors) (err error) {
return
}
if db.Transparent {
r.TransparentBlocks++
} else {
r.SolidBlocks++
}
w := r.width << 4
ofs := int(bz)*w<<4 + int(bx)<<4
yB := r.yBuffer
yMin := int32(math.MaxInt32)
for z := 0; z < 16; z++ {
for x := 0; x < 16; x++ {
currentY := yB[ofs]
if currentY < blockY {
for y := 15; y >= 0; y-- {
if c, ok := db.Content(x, y, z); ok {
r.cBuffer[ofs] = c
currentY = blockY + int32(y)
yB[ofs] = currentY
break
if db.Transparent && r.tBuffer != nil {
r.TransparentBlocks++
for z := 0; z < 16; z++ {
for x := 0; x < 16; x++ {
currentY := yB[ofs]
if currentY < blockY {
for y := 15; y >= 0; y-- {
if c, ok := db.Content(x, y, z); ok {
currentY = blockY + int32(y)
if colors.IsTransparent(c) {
r.tBuffer[ofs] = r.spans.Insert(r.tBuffer[ofs], currentY, c)
} else {
r.cBuffer[ofs] = c
yB[ofs] = currentY
break
}
}
}
}
if currentY < yMin {
yMin = currentY
}
ofs++
}
if currentY < yMin {
yMin = currentY
}
ofs++
ofs += w - 16
}
} else {
r.SolidBlocks++
for z := 0; z < 16; z++ {
for x := 0; x < 16; x++ {
currentY := yB[ofs]
if currentY < blockY {
for y := 15; y >= 0; y-- {
if c, ok := db.Content(x, y, z); ok {
r.cBuffer[ofs] = c
currentY = blockY + int32(y)
yB[ofs] = currentY
break
}
}
}
if currentY < yMin {
yMin = currentY
}
ofs++
}
ofs += w - 16
}
ofs += w - 16
}
r.yMin[pos] = yMin
return
@ -349,13 +397,15 @@ func safeColor(x int32) uint8 {
func (r *Renderer) CreateShadedImage(
xOfs, zOfs, width, height int,
colors []color.RGBA, background color.RGBA) *image.RGBA {
cols *Colors, background color.RGBA) *image.RGBA {
image := image.NewRGBA(image.Rect(0, 0, width, height))
pw := r.width << 4
ofs, numCols := zOfs*pw+xOfs, int32(len(colors))
cs := cols.Colors
ofs, numCols := zOfs*pw+xOfs, int32(len(cs))
stride := pw - width
@ -365,42 +415,91 @@ func (r *Renderer) CreateShadedImage(
pix := image.Pix
for z := height - 1; z >= 0; z-- {
for x := 0; x < width; x++ {
colIdx := r.cBuffer[ofs]
if colIdx < 0 || colIdx >= numCols {
pix[iofs] = background.R
pix[iofs+1] = background.G
pix[iofs+2] = background.B
pix[iofs+3] = 0xff
} else {
var y, y1, y2 int32
y = r.yBuffer[ofs]
if x == 0 {
y1 = y
if r.tBuffer != nil { // Fast path for transparent images.
for z := height - 1; z >= 0; z-- {
for x := 0; x < width; x++ {
colIdx := r.cBuffer[ofs]
if colIdx < 0 || colIdx >= numCols {
pix[iofs] = background.R
pix[iofs+1] = background.G
pix[iofs+2] = background.B
pix[iofs+3] = 0xff
} else {
y1 = r.yBuffer[ofs-1]
var y, y1, y2 int32
y = r.yBuffer[ofs]
if x == 0 {
y1 = y
} else {
y1 = r.yBuffer[ofs-1]
}
if z == 0 {
y2 = y
} else {
y2 = r.yBuffer[ofs+pw]
}
d := ((y - y1) + (y - y2)) * 12
if d > 36 {
d = 36
}
col := cs[colIdx]
col = color.RGBA{
R: safeColor(int32(col.R) + d),
G: safeColor(int32(col.G) + d),
B: safeColor(int32(col.B) + d),
A: 0xff}
if r.tBuffer[ofs] != nil {
col = cols.BlendColors(r.tBuffer[ofs], col, y)
}
pix[iofs] = col.R
pix[iofs+1] = col.G
pix[iofs+2] = col.B
pix[iofs+3] = col.A
}
if z == 0 {
y2 = y
} else {
y2 = r.yBuffer[ofs+pw]
}
d := ((y - y1) + (y - y2)) * 12
if d > 36 {
d = 36
}
col := colors[colIdx]
pix[iofs] = safeColor(int32(col.R) + d)
pix[iofs+1] = safeColor(int32(col.G) + d)
pix[iofs+2] = safeColor(int32(col.B) + d)
pix[iofs+3] = 0xff
iofs += 4
ofs++
}
iofs += 4
ofs++
ofs += stride
iofs -= istride
}
} else { // Solid images.
for z := height - 1; z >= 0; z-- {
for x := 0; x < width; x++ {
colIdx := r.cBuffer[ofs]
if colIdx < 0 || colIdx >= numCols {
pix[iofs] = background.R
pix[iofs+1] = background.G
pix[iofs+2] = background.B
pix[iofs+3] = 0xff
} else {
var y, y1, y2 int32
y = r.yBuffer[ofs]
if x == 0 {
y1 = y
} else {
y1 = r.yBuffer[ofs-1]
}
if z == 0 {
y2 = y
} else {
y2 = r.yBuffer[ofs+pw]
}
d := ((y - y1) + (y - y2)) * 12
if d > 36 {
d = 36
}
col := cs[colIdx]
pix[iofs] = safeColor(int32(col.R) + d)
pix[iofs+1] = safeColor(int32(col.G) + d)
pix[iofs+2] = safeColor(int32(col.B) + d)
pix[iofs+3] = 0xff
}
iofs += 4
ofs++
}
ofs += stride
iofs -= istride
}
ofs += stride
iofs -= istride
}
return image
}