Moved generation of base level tiles to separate file and made the base level generation optional.

This commit is contained in:
Sascha L. Teichmann 2014-09-14 17:12:28 +02:00
parent dddb9c0a6b
commit bbd96172a3
2 changed files with 219 additions and 189 deletions

203
cmd/mtseeder/baselevel.go Normal file
View File

@ -0,0 +1,203 @@
// 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 (
"fmt"
"image/color"
"log"
"os"
"path/filepath"
"sync"
"bitbucket.org/s_l_teichmann/mtredisalize/common"
)
const (
width = 18
height = 18
baseLevelDir = "8"
yOrderCapacity = 512
)
// To scan the whole height in terms of the y coordinate
// the database is queried in height units defined in the yRanges table.
var yRanges = [][]int16{
{1024, 1934},
{256, 1023},
{128, 255},
{64, 127},
{32, 63},
{16, 31},
{8, 15},
{4, 7},
{2, 3},
{0, 1},
{-1, 0},
{-4, -2},
{-8, -5},
{-16, -9},
{-32, -17},
{-64, -33},
{-128, -65},
{-256, -129},
{-1024, -257},
{-1936, -1025}}
type blockPos struct {
x, z int16
j, i int
}
type baseLevelWorker struct {
client *common.RedisClient
colors *common.Colors
renderer *common.Renderer
yOrder *common.YOrder
baseDir string
}
func newBaseLevelWorker(client *common.RedisClient,
colors *common.Colors, baseDir string) *baseLevelWorker {
renderer := common.NewRenderer(width, height)
return &baseLevelWorker{
client: client,
colors: colors,
baseDir: baseDir,
renderer: renderer,
yOrder: common.NewYOrder(renderer, yOrderCapacity)}
}
func (blw *baseLevelWorker) close() error {
return blw.client.Close()
}
func (blw *baseLevelWorker) createTile(x, z int16, i, j int) {
blw.renderer.Reset()
blw.renderer.SetPos(x, z)
blw.yOrder.Reset()
drawBlock := func(block *common.Block) {
if err := blw.yOrder.RenderBlock(block, blw.colors.NameIndex); err != nil {
log.Printf("WARN: rendering block failed: %s", err)
}
}
var c1, c2 common.Coord
nareas := make([]common.Area, 0, width*height/2)
oareas := make([]common.Area, 1, width*height/2)
oareas[0] = common.Area{
X1: 0, Z1: 0,
X2: int16(width) - 1, Z2: int16(height) - 1}
var err error
for _, yRange := range yRanges {
c1.Y = yRange[0]
c2.Y = yRange[1]
nareas = blw.renderer.UncoveredAreas(nareas, oareas)
if len(nareas) == 0 {
break
}
for _, area := range nareas {
c1.X = area.X1 + x
c1.Z = area.Z1 + z
c2.X = area.X2 + x
c2.Z = area.Z2 + z
query := common.Cuboid{P1: c1, P2: c2}
if err = blw.client.QueryCuboid(query, drawBlock); err != nil {
log.Printf("WARN: query failed: %s", err)
return
}
if err = blw.yOrder.Drain(blw.colors.NameIndex); err != nil {
log.Printf("WARN: rendering block failed: %s", err)
}
}
oareas, nareas = nareas, oareas[0:0]
}
image := blw.renderer.CreateShadedImage(
16, 16, (width-2)*16, (height-2)*16,
blw.colors.Colors, color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff})
path := filepath.Join(blw.baseDir, fmt.Sprintf("%d", i), fmt.Sprintf("%d.png", j))
log.Printf("Writing (%d, %d) (%d, %d)", i, j, x, z)
if err = common.SaveAsPNG(path, image); err != nil {
log.Fatalf("writing image failed: %s", err)
}
}
func (blw *baseLevelWorker) run(jobs chan blockPos, done *sync.WaitGroup) {
defer done.Done()
for job := range jobs {
blw.createTile(job.x-1, job.z-1, job.i, job.j)
}
}
func order(a, b int) (int, int) {
if a < b {
return a, b
}
return b, a
}
func createBaseLevel(
address string,
xMin, zMin, xMax, zMax int,
colorsFile, outDir string,
numWorkers int) (err error) {
var colors *common.Colors
if colors, err = common.ParseColors(colorsFile); err != nil {
return
}
baseDir := filepath.Join(outDir, baseLevelDir)
if err = os.MkdirAll(baseDir, os.ModePerm); err != nil {
return
}
jobs := make(chan blockPos)
var done sync.WaitGroup
for i := 0; i < numWorkers; i++ {
var client *common.RedisClient
if client, err = common.NewRedisClient("tcp", address); err != nil {
return
}
done.Add(1)
blw := newBaseLevelWorker(client, colors, baseDir)
defer blw.close()
go blw.run(jobs, &done)
}
zMin, zMax = order(zMin, zMax)
for x, i := int16(xMin), 0; x <= int16(xMax); x += 16 {
xDir := filepath.Join(baseDir, fmt.Sprintf("%d", i))
log.Printf("creating dir: %s", xDir)
if err = os.MkdirAll(xDir, os.ModePerm); err != nil {
log.Fatalf("Cannot create directory '%s': %s", xDir, err)
}
for z, j := int16(zMin), 0; z <= int16(zMax); z += 16 {
jobs <- blockPos{x: x, z: z, i: i, j: j}
j++
}
i++
}
close(jobs)
done.Wait()
return
}

View File

@ -7,157 +7,19 @@ package main
import ( import (
"flag" "flag"
"fmt" "fmt"
"image/color"
"log" "log"
"os"
"path/filepath"
"sync"
"bitbucket.org/s_l_teichmann/mtredisalize/common"
) )
const (
width = 18
height = 18
baseLevelDir = "8"
yOrderCapacity = 512
)
var yRanges = [][]int16{
{1024, 1934},
{256, 1023},
{128, 255},
{64, 127},
{32, 63},
{16, 31},
{8, 15},
{4, 7},
{2, 3},
{0, 1},
{-1, 0},
{-4, -2},
{-8, -5},
{-16, -9},
{-32, -17},
{-64, -33},
{-128, -65},
{-256, -129},
{-1024, -257},
{-1936, -1025}}
type blockPos struct {
x, z int16
j, i int
}
type baseLevelWorker struct {
client *common.RedisClient
colors *common.Colors
renderer *common.Renderer
yOrder *common.YOrder
baseDir string
}
func newBaseLevelWorker(client *common.RedisClient,
colors *common.Colors, baseDir string) *baseLevelWorker {
renderer := common.NewRenderer(width, height)
return &baseLevelWorker{
client: client,
colors: colors,
baseDir: baseDir,
renderer: renderer,
yOrder: common.NewYOrder(renderer, yOrderCapacity)}
}
func (blw *baseLevelWorker) close() error {
return blw.client.Close()
}
func (blw *baseLevelWorker) createTile(x, z int16, i, j int) {
blw.renderer.Reset()
blw.renderer.SetPos(x, z)
blw.yOrder.Reset()
drawBlock := func(block *common.Block) {
if err := blw.yOrder.RenderBlock(block, blw.colors.NameIndex); err != nil {
log.Printf("WARN: rendering block failed: %s", err)
}
}
var c1, c2 common.Coord
nareas := make([]common.Area, 0, width*height/2)
oareas := make([]common.Area, 1, width*height/2)
oareas[0] = common.Area{
X1: 0, Z1: 0,
X2: int16(width) - 1, Z2: int16(height) - 1}
var err error
for _, yRange := range yRanges {
c1.Y = yRange[0]
c2.Y = yRange[1]
nareas = blw.renderer.UncoveredAreas(nareas, oareas)
if len(nareas) == 0 {
break
}
for _, area := range nareas {
c1.X = area.X1 + x
c1.Z = area.Z1 + z
c2.X = area.X2 + x
c2.Z = area.Z2 + z
query := common.Cuboid{P1: c1, P2: c2}
if err = blw.client.QueryCuboid(query, drawBlock); err != nil {
log.Printf("WARN: query failed: %s", err)
return
}
if err = blw.yOrder.Drain(blw.colors.NameIndex); err != nil {
log.Printf("WARN: rendering block failed: %s", err)
}
}
oareas, nareas = nareas, oareas[0:0]
}
image := blw.renderer.CreateShadedImage(
16, 16, (width-2)*16, (height-2)*16,
blw.colors.Colors, color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff})
path := filepath.Join(blw.baseDir, fmt.Sprintf("%d", i), fmt.Sprintf("%d.png", j))
log.Printf("Writing (%d, %d) (%d, %d)", i, j, x, z)
if err = common.SaveAsPNG(path, image); err != nil {
log.Fatalf("writing image failed: %s", err)
}
}
func (blw *baseLevelWorker) run(jobs chan blockPos, done *sync.WaitGroup) {
defer done.Done()
for job := range jobs {
blw.createTile(job.x-1, job.z-1, job.i, job.j)
}
}
func order(a, b int) (int, int) {
if a < b {
return a, b
}
return b, a
}
func main() { func main() {
var ( var (
port int port int
host string host string
xMin, zMin int xMin, zMin int
xMax, zMax int xMax, zMax int
colorsfile string colorsFile string
outDir string outDir string
numWorkers int numWorkers int
skipBaseLevel bool
) )
flag.IntVar(&port, "port", 6379, "port to of mtredisalize server") flag.IntVar(&port, "port", 6379, "port to of mtredisalize server")
@ -167,57 +29,22 @@ func main() {
flag.IntVar(&xMax, "xmax", 1920, "x max of the area to tile") flag.IntVar(&xMax, "xmax", 1920, "x max of the area to tile")
flag.IntVar(&zMin, "zmin", -1936, "z min of the area to tile") flag.IntVar(&zMin, "zmin", -1936, "z min of the area to tile")
flag.IntVar(&zMax, "zmax", 1920, "z max of the area to tile") flag.IntVar(&zMax, "zmax", 1920, "z max of the area to tile")
flag.StringVar(&colorsfile, "colors", "colors.txt", "definition of colors") flag.StringVar(&colorsFile, "colors", "colors.txt", "definition of colors")
flag.StringVar(&outDir, "output-dir", "map", "directory with the resulting image tree") flag.StringVar(&outDir, "output-dir", "map", "directory with the resulting image tree")
flag.StringVar(&outDir, "o", "map", "directory with the resulting image tree") flag.StringVar(&outDir, "o", "map", "directory with the resulting image tree")
flag.IntVar(&numWorkers, "worker", 1, "number of workers") flag.IntVar(&numWorkers, "worker", 1, "number of workers")
flag.IntVar(&numWorkers, "w", 1, "number of workers (shorthand)") flag.IntVar(&numWorkers, "w", 1, "number of workers (shorthand)")
flag.BoolVar(&skipBaseLevel, "skip-base-level", false, "Do not generate baselevel")
flag.BoolVar(&skipBaseLevel, "sb", false, "Do not generate baselevel (shorthand)")
flag.Parse() flag.Parse()
var err error var err error
var colors *common.Colors if !skipBaseLevel {
address := fmt.Sprintf("%s:%d", host, port)
if colors, err = common.ParseColors(colorsfile); err != nil { if err = createBaseLevel(
log.Fatalf("Cannot open color file: %s", err) address, xMin, zMin, xMax, zMax, colorsFile, outDir, numWorkers); err != nil {
} log.Fatalf("Creating base level failed: %s", err)
baseDir := filepath.Join(outDir, baseLevelDir)
if err = os.MkdirAll(baseDir, os.ModePerm); err != nil {
log.Fatalf("Cannot create base dir '%s': %s", baseDir, err)
}
jobs := make(chan blockPos)
var done sync.WaitGroup
address := fmt.Sprintf("%s:%d", host, port)
for i := 0; i < numWorkers; i++ {
var client *common.RedisClient
if client, err = common.NewRedisClient("tcp", address); err != nil {
log.Fatalf("Cannot connect to '%s': %s", address, err)
} }
done.Add(1)
blw := newBaseLevelWorker(client, colors, baseDir)
defer blw.close()
go blw.run(jobs, &done)
} }
zMin, zMax = order(zMin, zMax)
for x, i := int16(xMin), 0; x <= int16(xMax); x += 16 {
xDir := filepath.Join(baseDir, fmt.Sprintf("%d", i))
log.Printf("creating dir: %s", xDir)
if err = os.MkdirAll(xDir, os.ModePerm); err != nil {
log.Fatalf("Cannot create directory '%s': %s", xDir, err)
}
for z, j := int16(zMin), 0; z <= int16(zMax); z += 16 {
jobs <- blockPos{x: x, z: z, i: i, j: j}
j++
}
i++
}
close(jobs)
done.Wait()
} }