mirror of
https://bitbucket.org/s_l_teichmann/mtsatellite
synced 2024-12-23 16:50:18 +01:00
Merged write-tiless-in-background back into default.
This commit is contained in:
commit
bc874e1c9a
@ -30,10 +30,29 @@ func createTiles(
|
|||||||
jobs chan blockPos,
|
jobs chan blockPos,
|
||||||
done *sync.WaitGroup) {
|
done *sync.WaitGroup) {
|
||||||
|
|
||||||
defer done.Done()
|
wFns := make(chan func() (bool, error))
|
||||||
defer btc.Close()
|
|
||||||
|
// Writing already rendered tiles to disk can be done in background.
|
||||||
|
go func() {
|
||||||
|
for wfn := range wFns {
|
||||||
|
if _, err := wfn(); err != nil {
|
||||||
|
log.Printf("WARN: writing file failed: %v.\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
close(wFns)
|
||||||
|
btc.Close()
|
||||||
|
done.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
for job := range jobs {
|
for job := range jobs {
|
||||||
btc.CreateTile(job.x-1, job.z-1, job.i, job.j)
|
if err := btc.RenderArea(job.x-1, job.z-1); err != nil {
|
||||||
|
log.Printf("WARN: rendering failed: %v.\n", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
wFns <- btc.WriteFunc(job.i, job.j, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +96,7 @@ func createBaseLevel(
|
|||||||
btc := common.NewBaseTileCreator(
|
btc := common.NewBaseTileCreator(
|
||||||
client, colors, bg,
|
client, colors, bg,
|
||||||
int16(yMin), int16(yMax),
|
int16(yMin), int16(yMax),
|
||||||
transparent, baseDir, nil)
|
transparent, baseDir)
|
||||||
go createTiles(btc, jobs, &done)
|
go createTiles(btc, jobs, &done)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,9 +213,9 @@ func (tu *tileUpdater) doUpdates() {
|
|||||||
btc := common.NewBaseTileCreator(
|
btc := common.NewBaseTileCreator(
|
||||||
client, tu.colors, tu.bg,
|
client, tu.colors, tu.bg,
|
||||||
tu.yMin, tu.yMax,
|
tu.yMin, tu.yMax,
|
||||||
tu.transparent, baseDir, bth.Update)
|
tu.transparent, baseDir)
|
||||||
done.Add(1)
|
done.Add(1)
|
||||||
go tu.updateBaseTiles(jobs, btc, &done)
|
go tu.updateBaseTiles(jobs, btc, &done, bth.Update)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range changes {
|
for i := range changes {
|
||||||
@ -338,19 +338,42 @@ func (tu *tileUpdater) updatePyramidTile(scratch, resized *image.RGBA, level int
|
|||||||
|
|
||||||
func (tu *tileUpdater) updateBaseTiles(
|
func (tu *tileUpdater) updateBaseTiles(
|
||||||
jobs chan *xzc,
|
jobs chan *xzc,
|
||||||
btc *common.BaseTileCreator, done *sync.WaitGroup) {
|
btc *common.BaseTileCreator,
|
||||||
|
done *sync.WaitGroup,
|
||||||
|
update common.BaseTileUpdateFunc) {
|
||||||
|
|
||||||
defer btc.Close()
|
type jobWriter struct {
|
||||||
defer done.Done()
|
job *xzc
|
||||||
for job := range jobs {
|
wFn func() (bool, error)
|
||||||
xz := job.dequantize()
|
}
|
||||||
//log.Printf("%d/%d %d/%d", x, z, job.X, job.Z)
|
|
||||||
updated, err := btc.CreateTile(xz.X-1, xz.Z-1, int(job.X), int(job.Z))
|
jWs := make(chan jobWriter)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for jw := range jWs {
|
||||||
|
updated, err := jw.wFn()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("WARN: create tile failed: %s\n", err)
|
log.Printf("WARN: writing tile failed: %v.\n", err)
|
||||||
}
|
}
|
||||||
if !updated {
|
if !updated {
|
||||||
job.canceled = true
|
jw.job.canceled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
close(jWs)
|
||||||
|
btc.Close()
|
||||||
|
done.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
for job := range jobs {
|
||||||
|
xz := job.dequantize()
|
||||||
|
if err := btc.RenderArea(xz.X-1, xz.Z-1); err != nil {
|
||||||
|
log.Printf("WARN: rendering tile failed: %v.\n", err)
|
||||||
|
job.canceled = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
jWs <- jobWriter{job, btc.WriteFunc(int(job.X), int(job.Z), update)}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,6 @@ type BaseTileCreator struct {
|
|||||||
yMin int16
|
yMin int16
|
||||||
yMax int16
|
yMax int16
|
||||||
baseDir string
|
baseDir string
|
||||||
update BaseTileUpdateFunc
|
|
||||||
emptyImage []byte
|
emptyImage []byte
|
||||||
bg color.RGBA
|
bg color.RGBA
|
||||||
}
|
}
|
||||||
@ -70,8 +69,8 @@ func NewBaseTileCreator(
|
|||||||
bg color.RGBA,
|
bg color.RGBA,
|
||||||
yMin, yMax int16,
|
yMin, yMax int16,
|
||||||
transparent bool,
|
transparent bool,
|
||||||
baseDir string,
|
baseDir string) *BaseTileCreator {
|
||||||
update BaseTileUpdateFunc) *BaseTileCreator {
|
|
||||||
renderer := NewRenderer(tileWidth, tileHeight, transparent)
|
renderer := NewRenderer(tileWidth, tileHeight, transparent)
|
||||||
yMin, yMax = Order16(yMin, yMax)
|
yMin, yMax = Order16(yMin, yMax)
|
||||||
btc := &BaseTileCreator{
|
btc := &BaseTileCreator{
|
||||||
@ -82,7 +81,7 @@ func NewBaseTileCreator(
|
|||||||
yMin: yMin,
|
yMin: yMin,
|
||||||
yMax: yMax,
|
yMax: yMax,
|
||||||
baseDir: baseDir,
|
baseDir: baseDir,
|
||||||
update: update}
|
}
|
||||||
btc.yOrder = NewYOrder(btc.renderBlock, yOrderCapacity)
|
btc.yOrder = NewYOrder(btc.renderBlock, yOrderCapacity)
|
||||||
return btc
|
return btc
|
||||||
}
|
}
|
||||||
@ -105,7 +104,7 @@ func (btc *BaseTileCreator) blockLoaded(block *Block) *Block {
|
|||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
||||||
func (btc *BaseTileCreator) CreateTile(x, z int16, i, j int) (bool, error) {
|
func (btc *BaseTileCreator) RenderArea(x, z int16) error {
|
||||||
btc.renderer.Reset()
|
btc.renderer.Reset()
|
||||||
btc.renderer.SetPos(x, z)
|
btc.renderer.SetPos(x, z)
|
||||||
btc.yOrder.Reset()
|
btc.yOrder.Reset()
|
||||||
@ -136,7 +135,7 @@ func (btc *BaseTileCreator) CreateTile(x, z int16, i, j int) (bool, error) {
|
|||||||
var count int
|
var count int
|
||||||
var err error
|
var err error
|
||||||
if count, err = btc.client.QueryCuboid(query, btc.blockLoaded); err != nil {
|
if count, err = btc.client.QueryCuboid(query, btc.blockLoaded); err != nil {
|
||||||
return false, err
|
return err
|
||||||
}
|
}
|
||||||
if err = btc.yOrder.Drain(); err != nil {
|
if err = btc.yOrder.Drain(); err != nil {
|
||||||
log.Printf("WARN: rendering block failed: %s\n", err)
|
log.Printf("WARN: rendering block failed: %s\n", err)
|
||||||
@ -155,38 +154,53 @@ func (btc *BaseTileCreator) CreateTile(x, z int16, i, j int) (bool, error) {
|
|||||||
}
|
}
|
||||||
areas, nareas = nareas, areas[:0]
|
areas, nareas = nareas, areas[:0]
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (btc *BaseTileCreator) blankImage() []byte {
|
||||||
|
// To avoid redundant encoding cache the resulting empty image.
|
||||||
|
if btc.emptyImage == nil {
|
||||||
|
m := BackgroundImage((tileWidth-2)*16, (tileHeight-2)*16, btc.bg)
|
||||||
|
btc.emptyImage = EncodeToMem(m)
|
||||||
|
}
|
||||||
|
return btc.emptyImage
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteFunc returns a function intended to be run in background so
|
||||||
|
// the creation of the next tile with this creator can be done
|
||||||
|
// concurrently.
|
||||||
|
func (btc *BaseTileCreator) WriteFunc(i, j int, update BaseTileUpdateFunc) func() (bool, error) {
|
||||||
|
|
||||||
path := filepath.Join(btc.baseDir, strconv.Itoa(i), strconv.Itoa(j)+".png")
|
path := filepath.Join(btc.baseDir, strconv.Itoa(i), strconv.Itoa(j)+".png")
|
||||||
|
|
||||||
// Empty images are likely to be produced during seeding.
|
// Empty images are likely to be produced during seeding.
|
||||||
if btc.update == nil && btc.renderer.IsEmpty() {
|
if update == nil && btc.renderer.IsEmpty() {
|
||||||
// To avoid redundant encoding cache the resulting empty image.
|
return func() (bool, error) {
|
||||||
if btc.emptyImage == nil {
|
|
||||||
var err error
|
|
||||||
m := BackgroundImage((tileWidth-2)*16, (tileHeight-2)*16, btc.bg)
|
|
||||||
if btc.emptyImage, err = EncodeToMem(m); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//log.Printf("Writing empty (%d, %d) to file %s\n", x, z, path)
|
//log.Printf("Writing empty (%d, %d) to file %s\n", x, z, path)
|
||||||
return true, ioutil.WriteFile(path, btc.emptyImage, 0666)
|
return true, ioutil.WriteFile(path, btc.blankImage(), 0666)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
image := btc.renderer.CreateShadedImage(
|
image := btc.renderer.CreateShadedImage(
|
||||||
16, 16, (tileWidth-2)*16, (tileHeight-2)*16,
|
16, 16, (tileWidth-2)*16, (tileHeight-2)*16,
|
||||||
btc.colors, btc.bg)
|
btc.colors, btc.bg)
|
||||||
|
|
||||||
if btc.update == nil {
|
x, z := btc.renderer.GetPos()
|
||||||
|
|
||||||
|
if update == nil {
|
||||||
|
return func() (bool, error) {
|
||||||
log.Printf("Writing (%d, %d) to file %s.\n", x, z, path)
|
log.Printf("Writing (%d, %d) to file %s.\n", x, z, path)
|
||||||
return true, SaveAsPNG(path, image)
|
return true, SaveAsPNG(path, image)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if btc.update(i, j, HashImage(image)) {
|
return func() (bool, error) {
|
||||||
|
if update(i, j, HashImage(image)) {
|
||||||
log.Printf("Writing (%d, %d) to file %s.\n", x, z, path)
|
log.Printf("Writing (%d, %d) to file %s.\n", x, z, path)
|
||||||
return true, SaveAsPNGAtomic(path, image)
|
return true, SaveAsPNGAtomic(path, image)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("(%d, %d) is unchanged.\n", x, z)
|
log.Printf("(%d, %d) is unchanged.\n", x, z)
|
||||||
|
|
||||||
return false, nil
|
return false, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
"image/draw"
|
||||||
"image/png"
|
"image/png"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
@ -44,13 +45,14 @@ func nextSuffix() string {
|
|||||||
return strconv.Itoa(int(1e9 + r%1e9))[1:]
|
return strconv.Itoa(int(1e9 + r%1e9))[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
func EncodeToMem(img image.Image) ([]byte, error) {
|
func EncodeToMem(img image.Image) []byte {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
enc := png.Encoder{CompressionLevel: png.BestCompression}
|
enc := png.Encoder{CompressionLevel: png.BestCompression}
|
||||||
if err := enc.Encode(&buf, img); err != nil {
|
if err := enc.Encode(&buf, img); err != nil {
|
||||||
return nil, err
|
// This really should not happen.
|
||||||
|
panic(err)
|
||||||
}
|
}
|
||||||
return buf.Bytes(), nil
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
func SaveAsPNG(path string, img image.Image) (err error) {
|
func SaveAsPNG(path string, img image.Image) (err error) {
|
||||||
@ -126,3 +128,9 @@ func HashImage(img *image.RGBA) []byte {
|
|||||||
|
|
||||||
return hash.Sum(nil)
|
return hash.Sum(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BackgroundImage(width, height int, bg color.RGBA) *image.RGBA {
|
||||||
|
m := image.NewRGBA(image.Rect(0, 0, width, height))
|
||||||
|
draw.Draw(m, m.Bounds(), &image.Uniform{bg}, image.ZP, draw.Src)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
@ -7,7 +7,6 @@ package common
|
|||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"image/draw"
|
|
||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -59,6 +58,10 @@ func (r *Renderer) SetPos(xOfs, zOfs int16) {
|
|||||||
r.zOfs = zOfs
|
r.zOfs = zOfs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Renderer) GetPos() (int16, int16) {
|
||||||
|
return r.xOfs, r.zOfs
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Renderer) initBuffers() {
|
func (r *Renderer) initBuffers() {
|
||||||
yb := r.yBuffer
|
yb := r.yBuffer
|
||||||
yb = yb[:len(yb)]
|
yb = yb[:len(yb)]
|
||||||
@ -269,12 +272,6 @@ func safeColor(x int32) uint8 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BackgroundImage(width, height int, bg color.RGBA) *image.RGBA {
|
|
||||||
m := image.NewRGBA(image.Rect(0, 0, width, height))
|
|
||||||
draw.Draw(m, m.Bounds(), &image.Uniform{bg}, image.ZP, draw.Src)
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *Renderer) CreateShadedImage(
|
func (r *Renderer) CreateShadedImage(
|
||||||
xOfs, zOfs, width, height int,
|
xOfs, zOfs, width, height int,
|
||||||
cols *Colors, background color.RGBA) *image.RGBA {
|
cols *Colors, background color.RGBA) *image.RGBA {
|
||||||
|
Loading…
Reference in New Issue
Block a user