0

preliminary chunk-scan algorithm activated.

forcerender and stochastic are currently broken.
This commit is contained in:
Andrew Brown
2011-11-07 22:18:51 -05:00
parent 636913af57
commit 13f3ba90ab

View File

@@ -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):
# Get the range for this tile
tile = Tile.from_path(path)
# Put this in the batch to be submited to the pool. """
# The quadtree object gets replaced by the caller in rendernode.py, # This quadtree object gets replaced by the caller in rendernode.py,
# but we still have to let them know which quadtree this tile # but we still have to let them know which quadtree this tile belongs
# belongs to. # to. Hence returning both self and the tile.
yield [self, tile] return ((self, tile) for tile in self.scan_chunks())
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
get_region_mtime = world.get_region_mtime
for col, row, chunkx, chunky, regionfile in chunks: for col, row, chunkx, chunky, regionfile in chunks:
region, regionMtime = get_region_mtime(regionfile) region, regionMtime = get_region_mtime(regionfile)
# don't even check if it's not in the regionlist # 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: if self.world.regionlist and os.path.abspath(region._filename) not in self.world.regionlist:
continue continue
# bail early if forcerender is set # bail early if forcerender is set
if self.forcerender: 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
# check region file mtime first. # if after all that, we don't need a rerender, return
# on windows (and possibly elsewhere) minecraft won't update if not needs_rerender:
# the region file mtime until after shutdown. return
# for servers this is unacceptable, so skip this check. except OSError:
#if regionMtime <= tile_mtime: # couldn't get tile mtime, skip check and assume it does
# continue pass
# checking chunk mtime # We have all the necessary info and this tile has passed the checks
if region.get_chunk_timestamp(chunkx, chunky) > tile_mtime: # and should be rendered. So do it!
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
# if after all that, we don't need a rerender, return
if not needs_rerender:
return None
except OSError:
# couldn't get tile mtime, skip check
pass
#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)