added a tree class to keep track of dirty tiles
This commit is contained in:
@@ -379,7 +379,7 @@ dir but you forgot to put quotes around the directory, since it contains spaces.
|
|||||||
# Create the quadtrees. There is one quadtree per rendermode requested, and
|
# Create the quadtrees. There is one quadtree per rendermode requested, and
|
||||||
# therefore, per output directory hierarchy of tiles. Each quadtree
|
# therefore, per output directory hierarchy of tiles. Each quadtree
|
||||||
# individually computes its depth and size. The constructor computes the
|
# individually computes its depth and size. The constructor computes the
|
||||||
# depth of the tree, while the go() method re-arranges tiles if teh current
|
# depth of the tree, while the go() method re-arranges tiles if the current
|
||||||
# depth differs from the computed depth.
|
# depth differs from the computed depth.
|
||||||
q = []
|
q = []
|
||||||
qtree_args = {'depth' : options.zoom,
|
qtree_args = {'depth' : options.zoom,
|
||||||
|
|||||||
@@ -500,3 +500,121 @@ class QuadtreeGen(object):
|
|||||||
|
|
||||||
if self.optimizeimg:
|
if self.optimizeimg:
|
||||||
optimize_image(imgpath, self.imgformat, self.optimizeimg)
|
optimize_image(imgpath, self.imgformat, self.optimizeimg)
|
||||||
|
|
||||||
|
|
||||||
|
class DirtyTiles(object):
|
||||||
|
"""This tree holds which tiles need rendering.
|
||||||
|
Each instance is a node, and the root of a subtree.
|
||||||
|
|
||||||
|
Each node knows its "level", which corresponds to the zoom level where 0 is
|
||||||
|
the inner-most (most zoomed in) tiles.
|
||||||
|
|
||||||
|
Instances hold the clean/dirty state of their children. Leaf nodes are
|
||||||
|
images and do not physically exist in the tree, level 1 nodes keep track of
|
||||||
|
leaf image state. Level 2 nodes keep track of level 1 state, and so fourth.
|
||||||
|
|
||||||
|
In attempt to keep things memory efficient, subtrees that are completely
|
||||||
|
dirty are collapsed
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, level):
|
||||||
|
"""Initialize a new node of the tree at the specified level
|
||||||
|
|
||||||
|
"""
|
||||||
|
self.level = level
|
||||||
|
|
||||||
|
# the self.children array holds the 4 children of this node. This
|
||||||
|
# follows the same quadtree convention as elsewhere: children 0, 1, 2,
|
||||||
|
# 3 are the upper-left, upper-right, lower-left, and lower-right
|
||||||
|
# respectively
|
||||||
|
# Values are:
|
||||||
|
# False
|
||||||
|
# All children down this subtree are clean
|
||||||
|
# True
|
||||||
|
# All children down this subtree are dirty
|
||||||
|
# A DirtyTileTree instance
|
||||||
|
# the instance defines which children down that subtree are
|
||||||
|
# clean/dirty.
|
||||||
|
# A node with level=1 cannot have a DirtyTileTree instance in its
|
||||||
|
# children since its leaves are images, not more tree
|
||||||
|
self.children = [False] * 4
|
||||||
|
|
||||||
|
def set_dirty(self, path):
|
||||||
|
"""Marks the requested leaf node as "dirty".
|
||||||
|
|
||||||
|
Path is a list of integers representing the path to the leaf node
|
||||||
|
that is requested to be marked as dirty. Path must be presented in
|
||||||
|
reverse order (leaf node at index 0, root node at index -1)
|
||||||
|
|
||||||
|
If *all* the nodes below this one are dirty, this function returns
|
||||||
|
true. Otherwise, returns None.
|
||||||
|
|
||||||
|
"""
|
||||||
|
assert len(path) == self.level
|
||||||
|
|
||||||
|
if self.level == 1:
|
||||||
|
# Base case
|
||||||
|
self.children[path[0]] = True
|
||||||
|
|
||||||
|
# Check to see if all children are dirty
|
||||||
|
if all(self.children):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
# Recursive case
|
||||||
|
if not isinstance(path,list):
|
||||||
|
path = list(path)
|
||||||
|
|
||||||
|
childnum = path.pop()
|
||||||
|
child = self.children[childnum]
|
||||||
|
|
||||||
|
if child == False:
|
||||||
|
# Create a new node
|
||||||
|
child = self.__class__(self.level-1)
|
||||||
|
child.set_dirty(path)
|
||||||
|
self.children[childnum] = child
|
||||||
|
elif child == True:
|
||||||
|
# Every child is already dirty. Nothing to do.
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
# subtree is mixed clean/dirty. Recurse
|
||||||
|
ret = child.set_dirty(path)
|
||||||
|
if ret:
|
||||||
|
# Child says it's completely dirty, so we can purge the
|
||||||
|
# subtree and mark it as dirty. The subtree will be garbage
|
||||||
|
# collected when this method exits.
|
||||||
|
self.children[childnum] = True
|
||||||
|
|
||||||
|
# Since we've marked an entire sub-tree as dirty, we may be
|
||||||
|
# able to signal to our parent
|
||||||
|
if all(x is True for x in self.children):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def iterate_dirty(self):
|
||||||
|
"""Returns an iterator over every dirty tile in this subtree. Each item
|
||||||
|
yielded is a sequence of integers representing the quadtree path to the
|
||||||
|
dirty tile. Yielded sequences are of length self.level.
|
||||||
|
|
||||||
|
Remember yielded paths are in reverse order. Leaf nodes at index 0!
|
||||||
|
|
||||||
|
"""
|
||||||
|
if self.level == 1:
|
||||||
|
# Base case
|
||||||
|
if self.children[0]: yield [0]
|
||||||
|
if self.children[1]: yield [1]
|
||||||
|
if self.children[2]: yield [2]
|
||||||
|
if self.children[3]: yield [3]
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Higher levels:
|
||||||
|
for c, child in enumerate(self.children):
|
||||||
|
if child == True:
|
||||||
|
# All dirty down this subtree, iterate over every leaf
|
||||||
|
for x in quadtree.iterate_base4(self.level-1):
|
||||||
|
x = list(x)
|
||||||
|
x.append(c)
|
||||||
|
yield x
|
||||||
|
elif child != False:
|
||||||
|
# Mixed dirty/clean down this subtree, recurse
|
||||||
|
for path in child.iterate_dirty():
|
||||||
|
path.append(c)
|
||||||
|
yield path
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ import logging
|
|||||||
import cPickle
|
import cPickle
|
||||||
import collections
|
import collections
|
||||||
import itertools
|
import itertools
|
||||||
|
import time
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
|
|
||||||
from chunk import ChunkCorrupt
|
import chunk
|
||||||
import nbt
|
import nbt
|
||||||
import textures
|
import textures
|
||||||
import time
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This module has routines for extracting information about available worlds
|
This module has routines for extracting information about available worlds
|
||||||
@@ -291,7 +291,7 @@ class World(object):
|
|||||||
spawnY += 1
|
spawnY += 1
|
||||||
if spawnY == 128:
|
if spawnY == 128:
|
||||||
break
|
break
|
||||||
except ChunkCorrupt:
|
except chunk.ChunkCorrupt:
|
||||||
#ignore corrupt spawn, and continue
|
#ignore corrupt spawn, and continue
|
||||||
pass
|
pass
|
||||||
self.POI.append( dict(x=disp_spawnX, y=spawnY, z=disp_spawnZ,
|
self.POI.append( dict(x=disp_spawnX, y=spawnY, z=disp_spawnZ,
|
||||||
@@ -447,3 +447,4 @@ def get_worlds():
|
|||||||
ret[info['Data']['LevelName']] = info['Data']
|
ret[info['Data']['LevelName']] = info['Data']
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user