From 8d145f2b58c2842eaf8aa22c124b73fb59c3b5f9 Mon Sep 17 00:00:00 2001 From: Aaron Griffith Date: Mon, 27 Sep 2010 19:59:41 -0400 Subject: [PATCH] added correct chunk boundary lighting --- chunk.py | 44 ++++++++++++++++++++++++++++++++++++++++---- world.py | 29 ++++++++++++++++++----------- 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/chunk.py b/chunk.py index 03469af..a2e314f 100644 --- a/chunk.py +++ b/chunk.py @@ -21,6 +21,7 @@ import hashlib import nbt import textures +import world """ 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, 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 can't target bound methods) or to easily render and save one chunk Returns the image file location""" - a = ChunkRenderer(chunkfile, cachedir) + a = ChunkRenderer(chunkfile, cachedir, worldobj) try: return a.render_and_save(cave) except Exception, e: @@ -108,7 +109,7 @@ def render_and_save(chunkfile, cachedir, cave=False): raise Exception() class ChunkRenderer(object): - def __init__(self, chunkfile, cachedir): + def __init__(self, chunkfile, cachedir, worldobj): """Make a new chunk renderer for the given chunkfile. chunkfile should be a full path to the .dat file to process cachedir is a directory to save the resulting chunk images to @@ -117,7 +118,11 @@ class ChunkRenderer(object): raise ValueError("Could not find chunkfile") self.chunkfile = 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 # 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 depth.""" blocks = self.blocks + + # light data for the current chunk skylight = get_skylight_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: # Cave mode. Actually go through and 0 out all blocks that are not in a # cave, so that it only renders caves. @@ -347,6 +379,8 @@ class ChunkRenderer(object): black_coeff = 0.0 if x != 0: 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): 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 if y != 15: 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): img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[2]).enhance(black_coeff)) diff --git a/world.py b/world.py index 99728c1..a03a00a 100644 --- a/world.py +++ b/world.py @@ -130,7 +130,18 @@ class WorldRenderer(object): inclusion_set.add((col, row)) 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): """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 @@ -147,13 +158,9 @@ class WorldRenderer(object): chunkY = spawnZ/16 ## The filename of this chunk - chunkFile = "%s/%s/c.%s.%s.dat" % (base36encode(chunkX % 64), - base36encode(chunkY % 64), - base36encode(chunkX), - base36encode(chunkY)) + chunkFile = self.get_chunk_path(chunkX, chunkY) - - data=nbt.load(os.path.join(self.worlddir, chunkFile))[1] + data=nbt.load(chunkFile)[1] level = data['Level'] 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: # Skip rendering, just find where the existing image is _, imgpath = chunk.ChunkRenderer(chunkfile, - self.cachedir).find_oldimage(False) + self.cachedir, self).find_oldimage(False) if imgpath: results[(col, row)] = imgpath 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 if i > 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: # Skip rendering, just find where the existing image is _, imgpath = chunk.ChunkRenderer(chunkfile, - self.cachedir).find_oldimage(False) + self.cachedir, self).find_oldimage(False) if imgpath: results[(col, row)] = imgpath continue result = pool.apply_async(chunk.render_and_save, - args=(chunkfile,self.cachedir), + args=(chunkfile,self.cachedir,self), kwds=dict(cave=self.caves)) asyncresults.append((col, row, result))