preliminary chunk-scan algorithm activated.
forcerender and stochastic are currently broken.
This commit is contained in:
@@ -218,7 +218,11 @@ class QuadtreeGen(object):
|
|||||||
|
|
||||||
def get_chunks_in_range(self, colstart, colend, rowstart, rowend):
|
def get_chunks_in_range(self, colstart, colend, rowstart, rowend):
|
||||||
"""Get chunks that are relevant to the tile rendering function that's
|
"""Get chunks that are relevant to the tile rendering function that's
|
||||||
rendering that range"""
|
rendering that range
|
||||||
|
|
||||||
|
Returns a list of chunks where each item is
|
||||||
|
(col, row, chunkx, chunky, regionfilename)
|
||||||
|
"""
|
||||||
chunklist = []
|
chunklist = []
|
||||||
unconvert_coords = self.world.unconvert_coords
|
unconvert_coords = self.world.unconvert_coords
|
||||||
#get_region_path = self.world.get_region_path
|
#get_region_path = self.world.get_region_path
|
||||||
@@ -250,17 +254,14 @@ class QuadtreeGen(object):
|
|||||||
return chunklist
|
return chunklist
|
||||||
|
|
||||||
def get_worldtiles(self):
|
def get_worldtiles(self):
|
||||||
"""Returns an iterator over the tiles of the most detailed layer
|
"""Returns an iterator over the tiles of the most detailed layer that
|
||||||
|
need to be rendered
|
||||||
|
|
||||||
"""
|
"""
|
||||||
for path in iterate_base4(self.p):
|
# This quadtree object gets replaced by the caller in rendernode.py,
|
||||||
# Get the range for this tile
|
# but we still have to let them know which quadtree this tile belongs
|
||||||
tile = Tile.from_path(path)
|
# to. Hence returning both self and the tile.
|
||||||
|
return ((self, tile) for tile in self.scan_chunks())
|
||||||
# Put this in the batch to be submited to the pool.
|
|
||||||
# The quadtree object gets replaced by the caller in rendernode.py,
|
|
||||||
# but we still have to let them know which quadtree this tile
|
|
||||||
# belongs to.
|
|
||||||
yield [self, tile]
|
|
||||||
|
|
||||||
def get_innertiles(self,zoom):
|
def get_innertiles(self,zoom):
|
||||||
"""Same as get_worldtiles but for the inntertile routine.
|
"""Same as get_worldtiles but for the inntertile routine.
|
||||||
@@ -340,15 +341,21 @@ class QuadtreeGen(object):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def render_worldtile(self, tile):
|
def render_worldtile(self, tile, check_tile=False):
|
||||||
"""Renders the given tile. All the other relevant information is
|
"""Renders the given tile. All the other relevant information is
|
||||||
already stored in this quadtree object or in self.world.
|
already stored in this quadtree object or in self.world.
|
||||||
|
|
||||||
|
This function is typically called in the child process. The tile is
|
||||||
|
assumed to need rendering unless the check_tile flag is given.
|
||||||
|
|
||||||
|
If check_tile is true, the mtimes of the chunk are compared with the
|
||||||
|
mtime of this tile and the tile is conditionally rendered.
|
||||||
|
|
||||||
The image is rendered and saved to disk in the place this quadtree is
|
The image is rendered and saved to disk in the place this quadtree is
|
||||||
configured to store images.
|
configured to store images.
|
||||||
|
|
||||||
If there are no chunks, this tile is not saved (if it already exists, it is
|
If there are no chunks, this tile is not saved. If this is the case but
|
||||||
deleted)
|
the tile exists, it is deleted
|
||||||
|
|
||||||
There is no return value
|
There is no return value
|
||||||
"""
|
"""
|
||||||
@@ -371,19 +378,26 @@ class QuadtreeGen(object):
|
|||||||
chunks = self.get_chunks_in_range(colstart, colend, rowstart, rowend)
|
chunks = self.get_chunks_in_range(colstart, colend, rowstart, rowend)
|
||||||
|
|
||||||
world = self.world
|
world = self.world
|
||||||
#stat the file, we need to know if it exists or it's mtime
|
|
||||||
try:
|
tile_mtime = None
|
||||||
tile_mtime = os.stat(imgpath)[stat.ST_MTIME]
|
if check_tile:
|
||||||
except OSError, e:
|
#stat the file, we need to know if it exists or it's mtime
|
||||||
if e.errno != errno.ENOENT:
|
try:
|
||||||
raise
|
tile_mtime = os.stat(imgpath)[stat.ST_MTIME]
|
||||||
tile_mtime = None
|
except OSError, e:
|
||||||
|
# ignore only if the error was "file not found"
|
||||||
|
if e.errno != errno.ENOENT:
|
||||||
|
raise
|
||||||
|
|
||||||
if not chunks:
|
if not chunks:
|
||||||
# No chunks were found in this tile
|
# No chunks were found in this tile
|
||||||
if tile_mtime is not None:
|
try:
|
||||||
os.unlink(imgpath)
|
os.unlink(imgpath)
|
||||||
return None
|
except OSError, e:
|
||||||
|
# ignore only if the error was "file not found"
|
||||||
|
if e.errno != errno.ENOENT:
|
||||||
|
raise
|
||||||
|
return
|
||||||
|
|
||||||
# Create the directory if not exists
|
# Create the directory if not exists
|
||||||
dirdest = os.path.dirname(imgpath)
|
dirdest = os.path.dirname(imgpath)
|
||||||
@@ -391,58 +405,55 @@ class QuadtreeGen(object):
|
|||||||
try:
|
try:
|
||||||
os.makedirs(dirdest)
|
os.makedirs(dirdest)
|
||||||
except OSError, e:
|
except OSError, e:
|
||||||
# Ignore errno EEXIST: file exists. Since this is multithreaded,
|
# Ignore errno EEXIST: file exists. Due to a race condition,
|
||||||
# two processes could conceivably try and create the same directory
|
# two processes could conceivably try and create the same
|
||||||
# at the same time.
|
# directory at the same time
|
||||||
if e.errno != errno.EEXIST:
|
if e.errno != errno.EEXIST:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# check chunk mtimes to see if they are newer
|
if check_tile:
|
||||||
try:
|
# Look at all the chunks that touch this tile and their mtimes to
|
||||||
needs_rerender = False
|
# determine if this tile actually needs rendering
|
||||||
get_region_mtime = world.get_region_mtime
|
try:
|
||||||
|
needs_rerender = False
|
||||||
for col, row, chunkx, chunky, regionfile in chunks:
|
get_region_mtime = world.get_region_mtime
|
||||||
region, regionMtime = get_region_mtime(regionfile)
|
|
||||||
|
|
||||||
# don't even check if it's not in the regionlist
|
|
||||||
if self.world.regionlist and os.path.abspath(region._filename) not in self.world.regionlist:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# bail early if forcerender is set
|
|
||||||
if self.forcerender:
|
|
||||||
needs_rerender = True
|
|
||||||
break
|
|
||||||
|
|
||||||
# check region file mtime first.
|
for col, row, chunkx, chunky, regionfile in chunks:
|
||||||
# on windows (and possibly elsewhere) minecraft won't update
|
region, regionMtime = get_region_mtime(regionfile)
|
||||||
# the region file mtime until after shutdown.
|
|
||||||
# for servers this is unacceptable, so skip this check.
|
# don't even check if it's not in the regionlist
|
||||||
#if regionMtime <= tile_mtime:
|
if self.world.regionlist and os.path.abspath(region._filename) not in self.world.regionlist:
|
||||||
# continue
|
continue
|
||||||
|
|
||||||
# checking chunk mtime
|
# bail early if forcerender is set
|
||||||
if region.get_chunk_timestamp(chunkx, chunky) > tile_mtime:
|
if self.forcerender:
|
||||||
|
needs_rerender = True
|
||||||
|
break
|
||||||
|
|
||||||
|
# checking chunk mtime
|
||||||
|
if region.get_chunk_timestamp(chunkx, chunky) > tile_mtime:
|
||||||
|
needs_rerender = True
|
||||||
|
break
|
||||||
|
|
||||||
|
# stochastic render check
|
||||||
|
if not needs_rerender and self.rerender_probability > 0.0 and random.uniform(0, 1) < self.rerender_probability:
|
||||||
needs_rerender = True
|
needs_rerender = True
|
||||||
break
|
|
||||||
|
# if after all that, we don't need a rerender, return
|
||||||
# stochastic render check
|
if not needs_rerender:
|
||||||
if not needs_rerender and self.rerender_probability > 0.0 and random.uniform(0, 1) < self.rerender_probability:
|
return
|
||||||
needs_rerender = True
|
except OSError:
|
||||||
|
# couldn't get tile mtime, skip check and assume it does
|
||||||
# if after all that, we don't need a rerender, return
|
pass
|
||||||
if not needs_rerender:
|
|
||||||
return None
|
|
||||||
except OSError:
|
|
||||||
# couldn't get tile mtime, skip check
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
# We have all the necessary info and this tile has passed the checks
|
||||||
|
# and should be rendered. So do it!
|
||||||
|
|
||||||
#logging.debug("writing out worldtile {0}".format(imgpath))
|
#logging.debug("writing out worldtile {0}".format(imgpath))
|
||||||
|
|
||||||
# Compile this image
|
# Compile this image
|
||||||
tileimg = Image.new("RGBA", (width, height), self.bgcolor)
|
tileimg = Image.new("RGBA", (width, height), self.bgcolor)
|
||||||
|
|
||||||
world = self.world
|
|
||||||
rendermode = self.rendermode
|
rendermode = self.rendermode
|
||||||
# col colstart will get drawn on the image starting at x coordinates -(384/2)
|
# col colstart will get drawn on the image starting at x coordinates -(384/2)
|
||||||
# row rowstart will get drawn on the image starting at y coordinates -(192/2)
|
# row rowstart will get drawn on the image starting at y coordinates -(192/2)
|
||||||
|
|||||||
Reference in New Issue
Block a user