0
This repository has been archived on 2025-04-25. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Minecraft-Overviewer/overviewer_core/rendermodes.py
Franz Dietrich 086820ac72 Adding StructureOverlay an overlay to color the map according to structures.
A usecase to demonstrate a possible application of the extended functionality:

**"Rails Overlay that draws only the rails that are on Cobblestone for a subway map."**

With this patch it is very easy to achive that:

```python
MineralOverlay(minerals=[(((0, 0, 0, 66), (0, -1, 0, 4)), (255, 0, 0, 255)),
                         (((0, 0, 0, 27), (0, -1, 0, 4)), (0, 255, 0, 255))])
```

In this case the overlay will be red for rails on cobblestone and green for powerrails on cobblestone.
The syntax is `(<tuple of conditions>, <target color>)`
 * where `<target color>` is a 4 tuple with a `(r, g, b, a)` color
 * and `<tuple of conditions>` is a tuple with an arbitrary number of conditions with the following syntax:
`((relx, rely, relz, blkid), ...)` where the `rel<>` parameters specify the relative coordinates to the block that is checked if it matches bklid.

In the example the fist tuple `(0,0,0,66)` checks if at the current position is a
rail while `(0,-1,0,4)` checks if at one below the current position is a cobblestone.
If both are true then the color `(255, 0, 0, 255)` is used.

A Sample Config file exploiting the capabilities:

``` python
worlds['My World'] = "~/.minecraft/saves/test/"
outputdir = "/tmp/test_render"
rendermode = "lighting"

renders["render1"] = {
    'world': 'My World',
    'title': 'A regular render',
}
renders["render_overlay_dafault_rails"] = {
    'world': 'My World',
    'title': 'Default Rails',
    'rendermode': [ClearBase(), StructureOverlay()],
    'overlay': ['render1'],
}
renders["render_overlay_cust_rails"] = {
    'world': 'My World',
    'title': 'Custom Rails',
    #relative coordinates [[(relx, rely, relz, mineral)], (red, green, blue, alpha)]
    'rendermode': [ClearBase(), StructureOverlay(structures=[(((0, 0, 0, 66), (0, -1, 0, 4)), (255, 0, 0, 255)),
                                                            (((0, 0, 0, 27), (0, -1, 0, 4)), (0, 255, 0, 255))])],
    'overlay': ['render1'],
}
```

The "Default Rails" overlay uses default coloring of the structures overlay. "Custom Rails" uses some custom coloring.

fixes overviewer/Minecraft-Overviewer#556 and fixes overviewer/Minecraft-Overviewer#787
2014-09-03 12:05:11 +02:00

253 lines
8.0 KiB
Python

# This file is part of the Minecraft Overviewer.
#
# Minecraft Overviewer is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# Minecraft Overviewer is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with the Overviewer. If not, see <http://www.gnu.org/licenses/>.
from PIL import Image
import textures
"""The contents of this file are imported into the namespace of config files.
It also defines the render primitive objects, which are used by the C code.
Each render primitive has a corresponding section of C code, so both places
must be changed simultaneously if you want to make any changes.
"""
class RenderPrimitive(object):
options = {}
name = None
def __init__(self, **kwargs):
if self.name is None:
raise RuntimeError("RenderPrimitive cannot be used directly")
self.option_values = {}
for key, val in kwargs.iteritems():
if not key in self.options:
raise ValueError("primitive `{0}' has no option `{1}'".format(self.name, key))
self.option_values[key] = val
# set up defaults
for name, (description, default) in self.options.iteritems():
if not name in self.option_values:
self.option_values[name] = default
class Base(RenderPrimitive):
name = "base"
options = {
"biomes": ("whether or not to use biomes", True),
}
class NetherOld(RenderPrimitive):
name = "netherold"
class Nether(RenderPrimitive):
name = "nether"
class HeightFading(RenderPrimitive):
name = "height-fading"
options = {
# 128 is *WRONG*, it should be 64. but we're grandfathered in for now
"sealevel": ("target sea level", 128),
}
black_color = Image.new("RGB", (24,24), (0,0,0))
white_color = Image.new("RGB", (24,24), (255,255,255))
class Depth(RenderPrimitive):
name = "depth"
options = {
"min": ("lowest level of blocks to render", 0),
"max": ("highest level of blocks to render", 255),
}
class Exposed(RenderPrimitive):
name = "exposed"
options = {
"mode": ("0 = exposed blocks only, 1 = unexposed blocks only", 0),
}
class NoFluids(RenderPrimitive):
name = "no-fluids"
class EdgeLines(RenderPrimitive):
name = "edge-lines"
options = {
"opacity": ("darkness of the edge lines, from 0.0 to 1.0", 0.15),
}
class Cave(RenderPrimitive):
name = "cave"
options = {
"only_lit": ("only render lit caves", False),
}
class DepthTinting(RenderPrimitive):
name = "depth-tinting"
@property
def depth_colors(self):
depth_colors = getattr(self, "_depth_colors", [])
if depth_colors:
return depth_colors
r = 255
g = 0
b = 0
for z in range(128):
depth_colors.append(r)
depth_colors.append(g)
depth_colors.append(b)
if z < 32:
g += 7
elif z < 64:
r -= 7
elif z < 96:
b += 7
else:
g -= 7
self._depth_colors = depth_colors
return depth_colors
class Lighting(RenderPrimitive):
name = "lighting"
options = {
"strength": ("how dark to make the shadows, from 0.0 to 1.0", 1.0),
"night": ("whether to use nighttime skylight settings", False),
"color": ("whether to use colored light", False),
}
@property
def facemasks(self):
facemasks = getattr(self, "_facemasks", None)
if facemasks:
return facemasks
white = Image.new("L", (24,24), 255)
top = Image.new("L", (24,24), 0)
left = Image.new("L", (24,24), 0)
whole = Image.new("L", (24,24), 0)
toppart = textures.Textures.transform_image_top(white)
leftpart = textures.Textures.transform_image_side(white)
# using the real PIL paste here (not alpha_over) because there is
# no alpha channel (and it's mode "L")
top.paste(toppart, (0,0))
left.paste(leftpart, (0,6))
right = left.transpose(Image.FLIP_LEFT_RIGHT)
# Manually touch up 6 pixels that leave a gap, like in
# textures._build_block()
for x,y in [(13,23), (17,21), (21,19)]:
right.putpixel((x,y), 255)
for x,y in [(3,4), (7,2), (11,0)]:
top.putpixel((x,y), 255)
# special fix for chunk boundary stipple
for x,y in [(13,11), (17,9), (21,7)]:
right.putpixel((x,y), 0)
self._facemasks = (top, left, right)
return self._facemasks
class SmoothLighting(Lighting):
name = "smooth-lighting"
class ClearBase(RenderPrimitive):
name = "clear-base"
class Overlay(RenderPrimitive):
name = "overlay"
options = {
'overlay_color' : ('a tuple of (r, g, b, a) for coloring the overlay', None),
}
@property
def whitecolor(self):
whitecolor = getattr(self, "_whitecolor", None)
if whitecolor:
return whitecolor
white = Image.new("RGBA", (24,24), (255, 255, 255, 255))
self._whitecolor = white
return white
@property
def facemask_top(self):
facemask_top = getattr(self, "_facemask_top", None)
if facemask_top:
return facemask_top
white = Image.new("L", (24,24), 255)
top = Image.new("L", (24,24), 0)
toppart = textures.Textures.transform_image_top(white)
top.paste(toppart, (0,0))
for x,y in [(3,4), (7,2), (11,0)]:
top.putpixel((x,y), 255)
self._facemask_top = top
return top
class SpawnOverlay(Overlay):
name = "overlay-spawn"
class SlimeOverlay(Overlay):
name = "overlay-slime"
class StructureOverlay(Overlay):
name = "overlay-structure"
options = {
'structures': ('a list of ((((relx, rely, relz), blockid), ...), (r, g, b, a)) tuples for coloring minerals',
[(((0, 0, 0, 66), (0, -1, 0, 4)), (255, 0, 0, 255)),
(((0, 0, 0, 27), (0, -1, 0, 4)), (0, 255, 0, 255)),
(((0, 0, 0, 28), (0, -1, 0, 4)), (255, 255, 0, 255)),
(((0, 0, 0, 157), (0, -1, 0, 4)), (255, 100, 0, 255)),
]),
}
class MineralOverlay(Overlay):
name = "overlay-mineral"
options = {
'minerals' : ('a list of (blockid, (r, g, b)) tuples for coloring minerals', None),
}
class BiomeOverlay(Overlay):
name = "overlay-biomes"
options = {
'biomes' : ('a list of (biome, (r, g, b)) tuples for coloring biomes', None),
'alpha' : ('an integer value between 0 (transparent) and 255 (opaque)', None),
}
class Hide(RenderPrimitive):
name = "hide"
options = {
'blocks' : ('a list of blockids or (blockid, data) tuples of blocks to hide', []),
}
# Built-in rendermodes for your convenience!
normal = [Base(), EdgeLines()]
lighting = [Base(), EdgeLines(), Lighting()]
smooth_lighting = [Base(), EdgeLines(), SmoothLighting()]
night = [Base(), EdgeLines(), Lighting(night=True)]
smooth_night = [Base(), EdgeLines(), SmoothLighting(night=True)]
netherold = [Base(), EdgeLines(), NetherOld()]
netherold_lighting = [Base(), EdgeLines(), NetherOld(), Lighting()]
netherold_smooth_lighting = [Base(), EdgeLines(), NetherOld(), SmoothLighting()]
nether = [Base(), EdgeLines(), Nether()]
nether_lighting = [Base(), EdgeLines(), Nether(), Lighting()]
nether_smooth_lighting = [Base(), EdgeLines(), Nether(), SmoothLighting()]
cave = [Base(), EdgeLines(), Cave(), DepthTinting()]