added correct chunk boundary lighting
This commit is contained in:
44
chunk.py
44
chunk.py
@@ -21,6 +21,7 @@ import hashlib
|
|||||||
|
|
||||||
import nbt
|
import nbt
|
||||||
import textures
|
import textures
|
||||||
|
import world
|
||||||
|
|
||||||
"""
|
"""
|
||||||
This module has routines related to rendering one particular chunk into an
|
This module has routines related to rendering one particular chunk into an
|
||||||
@@ -86,12 +87,12 @@ def get_blocklight_array(level):
|
|||||||
transparent_blocks = set([0, 6, 8, 9, 18, 20, 37, 38, 39, 40, 50, 51, 52, 53,
|
transparent_blocks = set([0, 6, 8, 9, 18, 20, 37, 38, 39, 40, 50, 51, 52, 53,
|
||||||
59, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 77, 79, 83, 85])
|
59, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 74, 75, 76, 77, 79, 83, 85])
|
||||||
|
|
||||||
def render_and_save(chunkfile, cachedir, cave=False):
|
def render_and_save(chunkfile, cachedir, worldobj, cave=False):
|
||||||
"""Used as the entry point for the multiprocessing workers (since processes
|
"""Used as the entry point for the multiprocessing workers (since processes
|
||||||
can't target bound methods) or to easily render and save one chunk
|
can't target bound methods) or to easily render and save one chunk
|
||||||
|
|
||||||
Returns the image file location"""
|
Returns the image file location"""
|
||||||
a = ChunkRenderer(chunkfile, cachedir)
|
a = ChunkRenderer(chunkfile, cachedir, worldobj)
|
||||||
try:
|
try:
|
||||||
return a.render_and_save(cave)
|
return a.render_and_save(cave)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
@@ -108,7 +109,7 @@ def render_and_save(chunkfile, cachedir, cave=False):
|
|||||||
raise Exception()
|
raise Exception()
|
||||||
|
|
||||||
class ChunkRenderer(object):
|
class ChunkRenderer(object):
|
||||||
def __init__(self, chunkfile, cachedir):
|
def __init__(self, chunkfile, cachedir, worldobj):
|
||||||
"""Make a new chunk renderer for the given chunkfile.
|
"""Make a new chunk renderer for the given chunkfile.
|
||||||
chunkfile should be a full path to the .dat file to process
|
chunkfile should be a full path to the .dat file to process
|
||||||
cachedir is a directory to save the resulting chunk images to
|
cachedir is a directory to save the resulting chunk images to
|
||||||
@@ -117,7 +118,11 @@ class ChunkRenderer(object):
|
|||||||
raise ValueError("Could not find chunkfile")
|
raise ValueError("Could not find chunkfile")
|
||||||
self.chunkfile = chunkfile
|
self.chunkfile = chunkfile
|
||||||
destdir, filename = os.path.split(self.chunkfile)
|
destdir, filename = os.path.split(self.chunkfile)
|
||||||
self.blockid = ".".join(filename.split(".")[1:3])
|
|
||||||
|
chunkcoords = filename.split(".")[1:3]
|
||||||
|
self.coords = map(world.base36decode, chunkcoords)
|
||||||
|
self.blockid = ".".join(chunkcoords)
|
||||||
|
self.world = worldobj
|
||||||
|
|
||||||
# Cachedir here is the base directory of the caches. We need to go 2
|
# Cachedir here is the base directory of the caches. We need to go 2
|
||||||
# levels deeper according to the chunk file. Get the last 2 components
|
# levels deeper according to the chunk file. Get the last 2 components
|
||||||
@@ -241,9 +246,36 @@ class ChunkRenderer(object):
|
|||||||
rendered, and blocks are drawn with a color tint depending on their
|
rendered, and blocks are drawn with a color tint depending on their
|
||||||
depth."""
|
depth."""
|
||||||
blocks = self.blocks
|
blocks = self.blocks
|
||||||
|
|
||||||
|
# light data for the current chunk
|
||||||
skylight = get_skylight_array(self.level)
|
skylight = get_skylight_array(self.level)
|
||||||
blocklight = get_blocklight_array(self.level)
|
blocklight = get_blocklight_array(self.level)
|
||||||
|
|
||||||
|
# light data for the chunk to the lower left
|
||||||
|
chunk_path = self.world.get_chunk_path(self.coords[0] - 1, self.coords[1])
|
||||||
|
try:
|
||||||
|
chunk_data = get_lvldata(chunk_path)
|
||||||
|
left_skylight = get_skylight_array(chunk_data)
|
||||||
|
left_blocklight = get_blocklight_array(chunk_data)
|
||||||
|
del chunk_data
|
||||||
|
except IOError:
|
||||||
|
left_skylight = None
|
||||||
|
left_blocklight = None
|
||||||
|
|
||||||
|
# light data for the chunk to the lower right
|
||||||
|
chunk_path = self.world.get_chunk_path(self.coords[0], self.coords[1] + 1)
|
||||||
|
try:
|
||||||
|
chunk_data = get_lvldata(chunk_path)
|
||||||
|
right_skylight = get_skylight_array(chunk_data)
|
||||||
|
right_blocklight = get_blocklight_array(chunk_data)
|
||||||
|
del chunk_data
|
||||||
|
except IOError:
|
||||||
|
right_skylight = None
|
||||||
|
right_blocklight = None
|
||||||
|
|
||||||
|
# clean up namespace a bit
|
||||||
|
del chunk_path
|
||||||
|
|
||||||
if cave:
|
if cave:
|
||||||
# Cave mode. Actually go through and 0 out all blocks that are not in a
|
# Cave mode. Actually go through and 0 out all blocks that are not in a
|
||||||
# cave, so that it only renders caves.
|
# cave, so that it only renders caves.
|
||||||
@@ -347,6 +379,8 @@ class ChunkRenderer(object):
|
|||||||
black_coeff = 0.0
|
black_coeff = 0.0
|
||||||
if x != 0:
|
if x != 0:
|
||||||
black_coeff = get_lighting_coefficient(skylight[x-1,y,z], blocklight[x-1,y,z])
|
black_coeff = get_lighting_coefficient(skylight[x-1,y,z], blocklight[x-1,y,z])
|
||||||
|
elif left_skylight != None and left_blocklight != None:
|
||||||
|
black_coeff = get_lighting_coefficient(left_skylight[15,y,z], left_blocklight[15,y,z])
|
||||||
if x == 0 or (blocks[x-1,y,z] in transparent_blocks):
|
if x == 0 or (blocks[x-1,y,z] in transparent_blocks):
|
||||||
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[1]).enhance(black_coeff))
|
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[1]).enhance(black_coeff))
|
||||||
|
|
||||||
@@ -354,6 +388,8 @@ class ChunkRenderer(object):
|
|||||||
black_coeff = 0.0
|
black_coeff = 0.0
|
||||||
if y != 15:
|
if y != 15:
|
||||||
black_coeff = get_lighting_coefficient(skylight[x,y+1,z], blocklight[x,y+1,z])
|
black_coeff = get_lighting_coefficient(skylight[x,y+1,z], blocklight[x,y+1,z])
|
||||||
|
elif right_skylight != None and right_blocklight != None:
|
||||||
|
black_coeff = get_lighting_coefficient(right_skylight[x,0,z], right_blocklight[x,0,z])
|
||||||
if y == 15 or (blocks[x,y+1,z] in transparent_blocks):
|
if y == 15 or (blocks[x,y+1,z] in transparent_blocks):
|
||||||
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[2]).enhance(black_coeff))
|
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[2]).enhance(black_coeff))
|
||||||
|
|
||||||
|
|||||||
29
world.py
29
world.py
@@ -130,7 +130,18 @@ class WorldRenderer(object):
|
|||||||
inclusion_set.add((col, row))
|
inclusion_set.add((col, row))
|
||||||
|
|
||||||
return inclusion_set
|
return inclusion_set
|
||||||
|
|
||||||
|
def get_chunk_path(self, chunkX, chunkY):
|
||||||
|
"""Returns the path to the chunk file at (chunkX, chunkY), if
|
||||||
|
it exists."""
|
||||||
|
|
||||||
|
chunkFile = "%s/%s/c.%s.%s.dat" % (base36encode(chunkX % 64),
|
||||||
|
base36encode(chunkY % 64),
|
||||||
|
base36encode(chunkX),
|
||||||
|
base36encode(chunkY))
|
||||||
|
|
||||||
|
return os.path.join(self.worlddir, chunkFile)
|
||||||
|
|
||||||
def findTrueSpawn(self):
|
def findTrueSpawn(self):
|
||||||
"""Adds the true spawn location to self.POI. The spawn Y coordinate
|
"""Adds the true spawn location to self.POI. The spawn Y coordinate
|
||||||
is almost always the default of 64. Find the first air block above
|
is almost always the default of 64. Find the first air block above
|
||||||
@@ -147,13 +158,9 @@ class WorldRenderer(object):
|
|||||||
chunkY = spawnZ/16
|
chunkY = spawnZ/16
|
||||||
|
|
||||||
## The filename of this chunk
|
## The filename of this chunk
|
||||||
chunkFile = "%s/%s/c.%s.%s.dat" % (base36encode(chunkX % 64),
|
chunkFile = self.get_chunk_path(chunkX, chunkY)
|
||||||
base36encode(chunkY % 64),
|
|
||||||
base36encode(chunkX),
|
|
||||||
base36encode(chunkY))
|
|
||||||
|
|
||||||
|
data=nbt.load(chunkFile)[1]
|
||||||
data=nbt.load(os.path.join(self.worlddir, chunkFile))[1]
|
|
||||||
level = data['Level']
|
level = data['Level']
|
||||||
blockArray = numpy.frombuffer(level['Blocks'], dtype=numpy.uint8).reshape((16,16,128))
|
blockArray = numpy.frombuffer(level['Blocks'], dtype=numpy.uint8).reshape((16,16,128))
|
||||||
|
|
||||||
@@ -234,12 +241,12 @@ class WorldRenderer(object):
|
|||||||
if inclusion_set and (col, row) not in inclusion_set:
|
if inclusion_set and (col, row) not in inclusion_set:
|
||||||
# Skip rendering, just find where the existing image is
|
# Skip rendering, just find where the existing image is
|
||||||
_, imgpath = chunk.ChunkRenderer(chunkfile,
|
_, imgpath = chunk.ChunkRenderer(chunkfile,
|
||||||
self.cachedir).find_oldimage(False)
|
self.cachedir, self).find_oldimage(False)
|
||||||
if imgpath:
|
if imgpath:
|
||||||
results[(col, row)] = imgpath
|
results[(col, row)] = imgpath
|
||||||
continue
|
continue
|
||||||
|
|
||||||
result = chunk.render_and_save(chunkfile, self.cachedir, cave=self.caves)
|
result = chunk.render_and_save(chunkfile, self.cachedir, self, cave=self.caves)
|
||||||
results[(col, row)] = result
|
results[(col, row)] = result
|
||||||
if i > 0:
|
if i > 0:
|
||||||
if 1000 % i == 0 or i % 1000 == 0:
|
if 1000 % i == 0 or i % 1000 == 0:
|
||||||
@@ -252,13 +259,13 @@ class WorldRenderer(object):
|
|||||||
if inclusion_set and (col, row) not in inclusion_set:
|
if inclusion_set and (col, row) not in inclusion_set:
|
||||||
# Skip rendering, just find where the existing image is
|
# Skip rendering, just find where the existing image is
|
||||||
_, imgpath = chunk.ChunkRenderer(chunkfile,
|
_, imgpath = chunk.ChunkRenderer(chunkfile,
|
||||||
self.cachedir).find_oldimage(False)
|
self.cachedir, self).find_oldimage(False)
|
||||||
if imgpath:
|
if imgpath:
|
||||||
results[(col, row)] = imgpath
|
results[(col, row)] = imgpath
|
||||||
continue
|
continue
|
||||||
|
|
||||||
result = pool.apply_async(chunk.render_and_save,
|
result = pool.apply_async(chunk.render_and_save,
|
||||||
args=(chunkfile,self.cachedir),
|
args=(chunkfile,self.cachedir,self),
|
||||||
kwds=dict(cave=self.caves))
|
kwds=dict(cave=self.caves))
|
||||||
asyncresults.append((col, row, result))
|
asyncresults.append((col, row, result))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user