added run-time flags to enable lighting or nighttime rendering
This commit is contained in:
109
chunk.py
109
chunk.py
@@ -38,15 +38,17 @@ image
|
|||||||
# use that as the mask. Then take the image and use im.convert("RGB") to strip
|
# 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()
|
# 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
|
"""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
|
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
|
an alpha value for a blend with a black source image. It mimics
|
||||||
Minecraft lighting calculations."""
|
Minecraft lighting calculations."""
|
||||||
# Daytime
|
if not night:
|
||||||
return 1.0 - pow(0.8, 15 - max(blocklight, skylight))
|
# Daytime
|
||||||
# Nighttime
|
return 1.0 - pow(0.8, 15 - max(blocklight, skylight))
|
||||||
#return 1.0 - pow(0.8, 15 - max(blocklight, skylight - 11))
|
else:
|
||||||
|
# Nighttime
|
||||||
|
return 1.0 - pow(0.8, 15 - max(blocklight, skylight - 11))
|
||||||
|
|
||||||
def get_lvldata(filename):
|
def get_lvldata(filename):
|
||||||
"""Takes a filename and returns the Level struct, which contains all the
|
"""Takes a filename and returns the Level struct, which contains all the
|
||||||
@@ -250,40 +252,52 @@ class ChunkRenderer(object):
|
|||||||
depth."""
|
depth."""
|
||||||
blocks = self.blocks
|
blocks = self.blocks
|
||||||
|
|
||||||
# light data for the current chunk
|
# dummy variables that may be filled in later based on render options
|
||||||
skylight = get_skylight_array(self.level)
|
skylight = None
|
||||||
blocklight = get_blocklight_array(self.level)
|
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
|
if self.world.lighting or cave:
|
||||||
chunk_path = self.world.get_chunk_path(self.coords[0] - 1, self.coords[1])
|
# light data for the current chunk
|
||||||
try:
|
skylight = get_skylight_array(self.level)
|
||||||
chunk_data = get_lvldata(chunk_path)
|
blocklight = get_blocklight_array(self.level)
|
||||||
# we only need +X-most side
|
|
||||||
left_skylight = get_skylight_array(chunk_data)[15,:,:]
|
if self.world.lighting:
|
||||||
left_blocklight = get_blocklight_array(chunk_data)[15,:,:]
|
# light data for the chunk to the lower left
|
||||||
left_blocks = get_blockarray(chunk_data)[15,:,:]
|
chunk_path = self.world.get_chunk_path(self.coords[0] - 1, self.coords[1])
|
||||||
del chunk_data
|
try:
|
||||||
except IOError:
|
chunk_data = get_lvldata(chunk_path)
|
||||||
left_skylight = None
|
# we only need +X-most side
|
||||||
left_blocklight = None
|
left_skylight = get_skylight_array(chunk_data)[15,:,:]
|
||||||
left_blocks = None
|
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
|
||||||
|
|
||||||
# light data for the chunk to the lower right
|
# light data for the chunk to the lower right
|
||||||
chunk_path = self.world.get_chunk_path(self.coords[0], self.coords[1] + 1)
|
chunk_path = self.world.get_chunk_path(self.coords[0], self.coords[1] + 1)
|
||||||
try:
|
try:
|
||||||
chunk_data = get_lvldata(chunk_path)
|
chunk_data = get_lvldata(chunk_path)
|
||||||
# we only need -Y-most side
|
# we only need -Y-most side
|
||||||
right_skylight = get_skylight_array(chunk_data)[:,0,:]
|
right_skylight = get_skylight_array(chunk_data)[:,0,:]
|
||||||
right_blocklight = get_blocklight_array(chunk_data)[:,0,:]
|
right_blocklight = get_blocklight_array(chunk_data)[:,0,:]
|
||||||
right_blocks = get_blockarray(chunk_data)[:,0,:]
|
right_blocks = get_blockarray(chunk_data)[:,0,:]
|
||||||
del chunk_data
|
del chunk_data
|
||||||
except IOError:
|
except IOError:
|
||||||
right_skylight = None
|
right_skylight = None
|
||||||
right_blocklight = None
|
right_blocklight = None
|
||||||
right_blocks = None
|
right_blocks = None
|
||||||
|
|
||||||
# clean up namespace a bit
|
# clean up namespace a bit
|
||||||
del chunk_path
|
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
|
||||||
@@ -368,11 +382,14 @@ class ChunkRenderer(object):
|
|||||||
# no lighting for cave -- depth is probably more useful
|
# no lighting for cave -- depth is probably more useful
|
||||||
img.paste(Image.blend(t[0],depth_colors[z],0.3), (imgx, imgy), t[1])
|
img.paste(Image.blend(t[0],depth_colors[z],0.3), (imgx, imgy), t[1])
|
||||||
else:
|
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
|
# transparent means draw the whole
|
||||||
# block shaded with the current
|
# block shaded with the current
|
||||||
# block's light
|
# 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])
|
img.paste(Image.blend(t[0], black_color, black_coeff), (imgx, imgy), t[1])
|
||||||
else:
|
else:
|
||||||
# draw each face lit appropriately,
|
# draw each face lit appropriately,
|
||||||
@@ -381,24 +398,24 @@ class ChunkRenderer(object):
|
|||||||
|
|
||||||
# top face
|
# top face
|
||||||
if z != 127 and (blocks[x,y,z+1] in transparent_blocks):
|
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))
|
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[0]).enhance(black_coeff))
|
||||||
|
|
||||||
# left face
|
# left face
|
||||||
black_coeff = get_lighting_coefficient(15, 0)
|
black_coeff = get_lighting_coefficient(15, 0, self.world.night)
|
||||||
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], self.world.night)
|
||||||
elif left_skylight != None and left_blocklight != None:
|
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):
|
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))
|
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[1]).enhance(black_coeff))
|
||||||
|
|
||||||
# right face
|
# right face
|
||||||
black_coeff = get_lighting_coefficient(15, 0)
|
black_coeff = get_lighting_coefficient(15, 0, self.world.night)
|
||||||
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], self.world.night)
|
||||||
elif right_skylight != None and right_blocklight != None:
|
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):
|
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))
|
img.paste((0,0,0), (imgx, imgy), ImageEnhance.Brightness(facemasks[2]).enhance(black_coeff))
|
||||||
|
|
||||||
|
|||||||
4
gmap.py
4
gmap.py
@@ -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("-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("--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("--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()
|
options, args = parser.parse_args()
|
||||||
|
|
||||||
@@ -86,7 +88,7 @@ def main():
|
|||||||
chunklist = None
|
chunklist = None
|
||||||
|
|
||||||
# First generate the world's chunk images
|
# 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)
|
w.go(options.procs)
|
||||||
|
|
||||||
# Now generate the tiles
|
# Now generate the tiles
|
||||||
|
|||||||
4
world.py
4
world.py
@@ -92,9 +92,11 @@ class WorldRenderer(object):
|
|||||||
files to update. If it includes a trailing newline, it is stripped, so you
|
files to update. If it includes a trailing newline, it is stripped, so you
|
||||||
can pass in file handles just fine.
|
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.worlddir = worlddir
|
||||||
self.caves = False
|
self.caves = False
|
||||||
|
self.lighting = lighting or night
|
||||||
|
self.night = night
|
||||||
self.cachedir = cachedir
|
self.cachedir = cachedir
|
||||||
|
|
||||||
self.chunklist = chunklist
|
self.chunklist = chunklist
|
||||||
|
|||||||
Reference in New Issue
Block a user