0

added run-time flags to enable lighting or nighttime rendering

This commit is contained in:
Aaron Griffith
2010-09-28 16:57:23 -04:00
parent d6fc49e1d9
commit 8dccf4162c
3 changed files with 69 additions and 48 deletions

107
chunk.py
View File

@@ -38,15 +38,17 @@ image
# use that as the mask. Then take the image and use im.convert("RGB") to strip
# the image from its alpha channel, and use that as the source to paste()
def get_lighting_coefficient(skylight, blocklight):
def get_lighting_coefficient(skylight, blocklight, night):
"""Takes a raw blocklight and skylight, and returns a value
between 0.0 (fully lit) and 1.0 (fully black) that can be used as
an alpha value for a blend with a black source image. It mimics
Minecraft lighting calculations."""
# Daytime
return 1.0 - pow(0.8, 15 - max(blocklight, skylight))
# Nighttime
#return 1.0 - pow(0.8, 15 - max(blocklight, skylight - 11))
if not night:
# Daytime
return 1.0 - pow(0.8, 15 - max(blocklight, skylight))
else:
# Nighttime
return 1.0 - pow(0.8, 15 - max(blocklight, skylight - 11))
def get_lvldata(filename):
"""Takes a filename and returns the Level struct, which contains all the
@@ -250,40 +252,52 @@ class ChunkRenderer(object):
depth."""
blocks = self.blocks
# light data for the current chunk
skylight = get_skylight_array(self.level)
blocklight = get_blocklight_array(self.level)
# dummy variables that may be filled in later based on render options
skylight = None
blocklight = None
left_skylight = None
left_blocklight = None
left_blocks = None
right_skylight = None
right_blocklight = None
right_blocks = None
# 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)
# we only need +X-most side
left_skylight = get_skylight_array(chunk_data)[15,:,:]
left_blocklight = get_blocklight_array(chunk_data)[15,:,:]
left_blocks = get_blockarray(chunk_data)[15,:,:]
del chunk_data
except IOError:
left_skylight = None
left_blocklight = None
left_blocks = None
if self.world.lighting or cave:
# 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 right
chunk_path = self.world.get_chunk_path(self.coords[0], self.coords[1] + 1)
try:
chunk_data = get_lvldata(chunk_path)
# we only need -Y-most side
right_skylight = get_skylight_array(chunk_data)[:,0,:]
right_blocklight = get_blocklight_array(chunk_data)[:,0,:]
right_blocks = get_blockarray(chunk_data)[:,0,:]
del chunk_data
except IOError:
right_skylight = None
right_blocklight = None
right_blocks = None
if self.world.lighting:
# 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)
# we only need +X-most side
left_skylight = get_skylight_array(chunk_data)[15,:,:]
left_blocklight = get_blocklight_array(chunk_data)[15,:,:]
left_blocks = get_blockarray(chunk_data)[15,:,:]
del chunk_data
except IOError:
left_skylight = None
left_blocklight = None
left_blocks = None
# clean up namespace a bit
del chunk_path
# 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)
# we only need -Y-most side
right_skylight = get_skylight_array(chunk_data)[:,0,:]
right_blocklight = get_blocklight_array(chunk_data)[:,0,:]
right_blocks = get_blockarray(chunk_data)[:,0,:]
del chunk_data
except IOError:
right_skylight = None
right_blocklight = None
right_blocks = 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
@@ -368,11 +382,14 @@ class ChunkRenderer(object):
# no lighting for cave -- depth is probably more useful
img.paste(Image.blend(t[0],depth_colors[z],0.3), (imgx, imgy), t[1])
else:
if blockid in transparent_blocks:
if not (blocklight != None and skylight != None):
# no lighting at all
img.paste(t[0], (imgx, imgy), t[1])
elif blockid in transparent_blocks:
# transparent means draw the whole
# block shaded with the current
# block's light
black_coeff = get_lighting_coefficient(skylight[x,y,z], blocklight[x,y,z])
black_coeff = get_lighting_coefficient(skylight[x,y,z], blocklight[x,y,z], self.world.night)
img.paste(Image.blend(t[0], black_color, black_coeff), (imgx, imgy), t[1])
else:
# draw each face lit appropriately,
@@ -381,24 +398,24 @@ class ChunkRenderer(object):
# top face
if z != 127 and (blocks[x,y,z+1] in transparent_blocks):
black_coeff = get_lighting_coefficient(skylight[x,y,z+1], blocklight[x,y,z+1])
black_coeff = get_lighting_coefficient(skylight[x,y,z+1], blocklight[x,y,z+1], self.world.night)
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff))
# left face
black_coeff = get_lighting_coefficient(15, 0)
black_coeff = get_lighting_coefficient(15, 0, self.world.night)
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], self.world.night)
elif left_skylight != None and left_blocklight != None:
black_coeff = get_lighting_coefficient(left_skylight[y,z], left_blocklight[y,z])
black_coeff = get_lighting_coefficient(left_skylight[y,z], left_blocklight[y,z], self.world.night)
if (x == 0 and (left_blocks == None or left_blocks[y,z] in transparent_blocks)) or (x != 0 and blocks[x-1,y,z] in transparent_blocks):
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[1]).enhance(black_coeff))
# right face
black_coeff = get_lighting_coefficient(15, 0)
black_coeff = get_lighting_coefficient(15, 0, self.world.night)
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], self.world.night)
elif right_skylight != None and right_blocklight != None:
black_coeff = get_lighting_coefficient(right_skylight[x,z], right_blocklight[x,z])
black_coeff = get_lighting_coefficient(right_skylight[x,z], right_blocklight[x,z], self.world.night)
if (y == 15 and (right_blocks == None or right_blocks[x,z] in transparent_blocks)) or (y != 15 and blocks[x,y+1,z] in transparent_blocks):
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[2]).enhance(black_coeff))

View File

@@ -46,6 +46,8 @@ def main():
parser.add_option("-d", "--delete", dest="delete", help="Clear all caches. Next time you render your world, it will have to start completely over again. This is probably not a good idea for large worlds. Use this if you change texture packs and want to re-render everything.", action="store_true")
parser.add_option("--cachedir", dest="cachedir", help="Sets the directory where the Overviewer will save chunk images, which is an intermediate step before the tiles are generated. You must use the same directory each time to gain any benefit from the cache. If not set, this defaults to your world directory.")
parser.add_option("--chunklist", dest="chunklist", help="A file containing, on each line, a path to a chunkfile to update. Instead of scanning the world directory for chunks, it will just use this list. Normal caching rules still apply.")
parser.add_option("--lighting", dest="lighting", help="Renders shadows using light data from each chunk.", action="store_true")
parser.add_option("--night", dest="night", help="Renders shadows using light data from each chunk, as if it were night. Implies --lighting.", action="store_true")
options, args = parser.parse_args()
@@ -86,7 +88,7 @@ def main():
chunklist = None
# First generate the world's chunk images
w = world.WorldRenderer(worlddir, cachedir, chunklist=chunklist)
w = world.WorldRenderer(worlddir, cachedir, chunklist=chunklist, lighting=options.lighting, night=options.night)
w.go(options.procs)
# Now generate the tiles

View File

@@ -92,9 +92,11 @@ class WorldRenderer(object):
files to update. If it includes a trailing newline, it is stripped, so you
can pass in file handles just fine.
"""
def __init__(self, worlddir, cachedir, chunklist=None):
def __init__(self, worlddir, cachedir, chunklist=None, lighting=False, night=False):
self.worlddir = worlddir
self.caves = False
self.lighting = lighting or night
self.night = night
self.cachedir = cachedir
self.chunklist = chunklist