summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDániel Juhász <juhdanad@gmail.com>2017-01-12 15:46:30 +0100
committerEkdohibs <nathanael.courant@laposte.net>2017-01-23 07:27:12 +0100
commitd04d8aba7029a2501854a2838fd282b81358a54e (patch)
treefd1a5515e17b2dd2da0a8ffe7f82f445e7fb48de
parent43822de5c6b35646feced5ac65331313f82f78ce (diff)
downloadminetest-d04d8aba7029a2501854a2838fd282b81358a54e.tar.gz
minetest-d04d8aba7029a2501854a2838fd282b81358a54e.tar.bz2
minetest-d04d8aba7029a2501854a2838fd282b81358a54e.zip
Add hardware node coloring. Includes:
- Increase ContentFeatures serialization version - Color property and palettes for nodes - paramtype2 = "color", "colored facedir" or "colored wallmounted"
-rw-r--r--client/shaders/nodes_shader/opengl_vertex.glsl43
-rw-r--r--client/shaders/water_surface_shader/opengl_vertex.glsl45
-rw-r--r--client/shaders/wielded_shader/opengl_vertex.glsl1
-rw-r--r--doc/lua_api.txt27
-rw-r--r--src/client/tile.cpp3
-rw-r--r--src/client/tile.h34
-rw-r--r--src/clientenvironment.cpp4
-rw-r--r--src/content_mapblock.cpp326
-rw-r--r--src/game.cpp30
-rw-r--r--src/mapblock_mesh.cpp263
-rw-r--r--src/mapblock_mesh.h57
-rw-r--r--src/mapnode.cpp20
-rw-r--r--src/mapnode.h12
-rw-r--r--src/mesh.cpp47
-rw-r--r--src/mesh.h14
-rw-r--r--src/minimap.cpp31
-rw-r--r--src/minimap.h4
-rw-r--r--src/network/networkprotocol.h5
-rw-r--r--src/nodedef.cpp513
-rw-r--r--src/nodedef.h108
-rw-r--r--src/particles.cpp65
-rw-r--r--src/particles.h19
-rw-r--r--src/script/common/c_content.cpp18
-rw-r--r--src/script/cpp_api/s_node.cpp3
-rw-r--r--src/shader.cpp2
-rw-r--r--src/wieldmesh.cpp62
-rw-r--r--src/wieldmesh.h5
27 files changed, 1207 insertions, 554 deletions
diff --git a/client/shaders/nodes_shader/opengl_vertex.glsl b/client/shaders/nodes_shader/opengl_vertex.glsl
index 44c48cc4c..3ac79c26d 100644
--- a/client/shaders/nodes_shader/opengl_vertex.glsl
+++ b/client/shaders/nodes_shader/opengl_vertex.glsl
@@ -1,7 +1,8 @@
uniform mat4 mWorldViewProj;
uniform mat4 mWorld;
-uniform float dayNightRatio;
+// Color of the light emitted by the sun.
+uniform vec3 dayLight;
uniform vec3 eyePosition;
uniform float animationTimer;
@@ -14,6 +15,8 @@ varying vec3 tsEyeVec;
varying vec3 tsLightVec;
varying float area_enable_parallax;
+// Color of the light emitted by the light sources.
+const vec3 artificialLight = vec3(1.04, 1.04, 1.04);
const float e = 2.718281828459;
const float BS = 10.0;
@@ -119,31 +122,23 @@ float disp_z;
v.z = dot(eyeVec, normal);
tsEyeVec = normalize (v);
+ // Calculate color.
+ // Red, green and blue components are pre-multiplied with
+ // the brightness, so now we have to multiply these
+ // colors with the color of the incoming light.
+ // The pre-baked colors are halved to prevent overflow.
vec4 color;
- float day = gl_Color.r;
- float night = gl_Color.g;
- float light_source = gl_Color.b;
-
- float rg = mix(night, day, dayNightRatio);
- rg += light_source * 2.5; // Make light sources brighter
- float b = rg;
-
- // Moonlight is blue
- b += (day - night) / 13.0;
- rg -= (day - night) / 23.0;
-
+ // The alpha gives the ratio of sunlight in the incoming light.
+ float nightRatio = 1 - gl_Color.a;
+ color.rgb = gl_Color.rgb * (gl_Color.a * dayLight.rgb +
+ nightRatio * artificialLight.rgb) * 2;
+ color.a = 1;
+
// Emphase blue a bit in darker places
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
- b += max(0.0, (1.0 - abs(b - 0.13) / 0.17) * 0.025);
-
- // Artificial light is yellow-ish
- // See C++ implementation in mapblock_mesh.cpp finalColorBlend()
- rg += max(0.0, (1.0 - abs(rg - 0.85) / 0.15) * 0.065);
-
- color.r = rg;
- color.g = rg;
- color.b = b;
-
- color.a = gl_Color.a;
+ float brightness = (color.r + color.g + color.b) / 3;
+ color.b += max(0.0, 0.021 - abs(0.2 * brightness - 0.021) +
+ 0.07 * brightness);
+
gl_FrontColor = gl_BackColor = clamp(color, 0.0, 1.0);
}
diff --git a/client/shaders/water_surface_shader/opengl_vertex.glsl b/client/shaders/water_surface_shader/opengl_vertex.glsl
index a930e7b8f..112db9bb5 100644
--- a/client/shaders/water_surface_shader/opengl_vertex.glsl
+++ b/client/shaders/water_surface_shader/opengl_vertex.glsl
@@ -1,7 +1,8 @@
uniform mat4 mWorldViewProj;
uniform mat4 mWorld;
-uniform float dayNightRatio;
+// Color of the light emitted by the sun.
+uniform vec3 dayLight;
uniform vec3 eyePosition;
uniform float animationTimer;
@@ -13,6 +14,8 @@ varying vec3 lightVec;
varying vec3 tsEyeVec;
varying vec3 tsLightVec;
+// Color of the light emitted by the light sources.
+const vec3 artificialLight = vec3(1.04, 1.04, 1.04);
const float e = 2.718281828459;
const float BS = 10.0;
@@ -112,31 +115,23 @@ void main(void)
eyeVec = (gl_ModelViewMatrix * gl_Vertex).xyz;
tsEyeVec = eyeVec * tbnMatrix;
+ // Calculate color.
+ // Red, green and blue components are pre-multiplied with
+ // the brightness, so now we have to multiply these
+ // colors with the color of the incoming light.
+ // The pre-baked colors are halved to prevent overflow.
vec4 color;
- float day = gl_Color.r;
- float night = gl_Color.g;
- float light_source = gl_Color.b;
-
- float rg = mix(night, day, dayNightRatio);
- rg += light_source * 2.5; // Make light sources brighter
- float b = rg;
-
- // Moonlight is blue
- b += (day - night) / 13.0;
- rg -= (day - night) / 23.0;
-
+ // The alpha gives the ratio of sunlight in the incoming light.
+ float nightRatio = 1 - gl_Color.a;
+ color.rgb = gl_Color.rgb * (gl_Color.a * dayLight.rgb +
+ nightRatio * artificialLight.rgb) * 2;
+ color.a = 1;
+
// Emphase blue a bit in darker places
// See C++ implementation in mapblock_mesh.cpp finalColorBlend()
- b += max(0.0, (1.0 - abs(b - 0.13)/0.17) * 0.025);
-
- // Artificial light is yellow-ish
- // See C++ implementation in mapblock_mesh.cpp finalColorBlend()
- rg += max(0.0, (1.0 - abs(rg - 0.85)/0.15) * 0.065);
-
- color.r = rg;
- color.g = rg;
- color.b = b;
-
- color.a = gl_Color.a;
- gl_FrontColor = gl_BackColor = clamp(color,0.0,1.0);
+ float brightness = (color.r + color.g + color.b) / 3;
+ color.b += max(0.0, 0.021 - abs(0.2 * brightness - 0.021) +
+ 0.07 * brightness);
+
+ gl_FrontColor = gl_BackColor = clamp(color, 0.0, 1.0);
}
diff --git a/client/shaders/wielded_shader/opengl_vertex.glsl b/client/shaders/wielded_shader/opengl_vertex.glsl
index 86c626896..9f05b833a 100644
--- a/client/shaders/wielded_shader/opengl_vertex.glsl
+++ b/client/shaders/wielded_shader/opengl_vertex.glsl
@@ -1,7 +1,6 @@
uniform mat4 mWorldViewProj;
uniform mat4 mWorld;
-uniform float dayNightRatio;
uniform vec3 eyePosition;
uniform float animationTimer;
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index e5a3362ee..2a0b72053 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -638,6 +638,19 @@ node definition:
bit 4 (0x10) - Makes the plant mesh 1.4x larger
bit 5 (0x20) - Moves each face randomly a small bit down (1/8 max)
bits 6-7 are reserved for future use.
+ paramtype2 == "color"
+ ^ `param2` tells which color is picked from the palette.
+ The palette should have 256 pixels.
+ paramtype2 == "colorfacedir"
+ ^ Same as `facedir`, but with colors.
+ The first three bits of `param2` tells which color
+ is picked from the palette.
+ The palette should have 8 pixels.
+ paramtype2 == "colorwallmounted"
+ ^ Same as `wallmounted`, but with colors.
+ The first five bits of `param2` tells which color
+ is picked from the palette.
+ The palette should have 32 pixels.
collision_box = {
type = "fixed",
fixed = {
@@ -3707,6 +3720,9 @@ Definition tables
when displacement mapping is used
Directions are from the point of view of the tile texture,
not the node it's on
+* `{name="image.png", color=ColorSpec}`
+ * the texture's color will be multiplied with this color.
+ * the tile's color overrides the owning node's color in all cases.
* deprecated, yet still supported field names:
* `image` (name)
@@ -3749,8 +3765,17 @@ Definition tables
special_tiles = {tile definition 1, Tile definition 2}, --[[
^ Special textures of node; used rarely (old field name: special_materials)
^ List can be shortened to needed length ]]
- alpha = 255,
+ color = ColorSpec, --[[
+ ^ The node's original color will be multiplied with this color.
+ ^ If the node has a palette, then this setting only has an effect
+ ^ in the inventory and on the wield item. ]]
use_texture_alpha = false, -- Use texture's alpha channel
+ palette = "palette.png", --[[
+ ^ The node's `param2` is used to select a pixel from the image
+ ^ (pixels are arranged from left to right and from top to bottom).
+ ^ The node's color will be multiplied with the selected pixel's
+ ^ color. Tiles can override this behavior.
+ ^ Only when `paramtype2` supports palettes. ]]
post_effect_color = "green#0F", -- If player is inside node, see "ColorSpec"
paramtype = "none", -- See "Nodes" --[[
^ paramtype = "light" allows light to propagate from or through the node with light value
diff --git a/src/client/tile.cpp b/src/client/tile.cpp
index 4d2166342..539c29445 100644
--- a/src/client/tile.cpp
+++ b/src/client/tile.cpp
@@ -378,9 +378,6 @@ public:
video::ITexture* generateTextureFromMesh(
const TextureFromMeshParams &params);
- // Generates an image from a full string like
- // "stone.png^mineral_coal.png^[crack:1:0".
- // Shall be called from the main thread.
video::IImage* generateImage(const std::string &name);
video::ITexture* getNormalTexture(const std::string &name);
diff --git a/src/client/tile.h b/src/client/tile.h
index 452804801..d04ab918a 100644
--- a/src/client/tile.h
+++ b/src/client/tile.h
@@ -108,6 +108,12 @@ public:
const std::string &name, u32 *id = NULL) = 0;
virtual IrrlichtDevice* getDevice()=0;
virtual bool isKnownSourceImage(const std::string &name)=0;
+ /*! Generates an image from a full string like
+ * "stone.png^mineral_coal.png^[crack:1:0".
+ * Shall be called from the main thread.
+ * The returned Image should be dropped.
+ */
+ virtual video::IImage* generateImage(const std::string &name)=0;
virtual video::ITexture* generateTextureFromMesh(
const TextureFromMeshParams &params)=0;
virtual video::ITexture* getNormalTexture(const std::string &name)=0;
@@ -192,7 +198,6 @@ struct TileSpec
texture(NULL),
normal_texture(NULL),
flags_texture(NULL),
- alpha(255),
material_type(TILE_MATERIAL_BASIC),
material_flags(
//0 // <- DEBUG, Use the one below
@@ -201,22 +206,30 @@ struct TileSpec
shader_id(0),
animation_frame_count(1),
animation_frame_length_ms(0),
- rotation(0)
+ rotation(0),
+ has_color(false),
+ color(),
+ emissive_light(0)
{
}
+ /*!
+ * Two tiles are equal if they can be appended to
+ * the same mesh buffer.
+ */
bool operator==(const TileSpec &other) const
{
return (
texture_id == other.texture_id &&
- /* texture == other.texture && */
- alpha == other.alpha &&
material_type == other.material_type &&
material_flags == other.material_flags &&
rotation == other.rotation
);
}
+ /*!
+ * Two tiles are not equal if they must be in different mesh buffers.
+ */
bool operator!=(const TileSpec &other) const
{
return !(*this == other);
@@ -233,7 +246,7 @@ struct TileSpec
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
break;
case TILE_MATERIAL_LIQUID_TRANSPARENT:
- material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
+ material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
break;
case TILE_MATERIAL_LIQUID_OPAQUE:
material.MaterialType = video::EMT_SOLID;
@@ -274,8 +287,6 @@ struct TileSpec
video::ITexture *normal_texture;
video::ITexture *flags_texture;
- // Vertex alpha (when MATERIAL_ALPHA_VERTEX is used)
- u8 alpha;
// Material parameters
u8 material_type;
u8 material_flags;
@@ -286,5 +297,14 @@ struct TileSpec
std::vector<FrameSpec> frames;
u8 rotation;
+ //! If true, the tile has its own color.
+ bool has_color;
+ /*!
+ * The color of the tile, or if the tile does not own
+ * a color then the color of the node owning this tile.
+ */
+ video::SColor color;
+ //! This much light does the tile emit.
+ u8 emissive_light;
};
#endif
diff --git a/src/clientenvironment.cpp b/src/clientenvironment.cpp
index b32a02f2d..77f53d214 100644
--- a/src/clientenvironment.cpp
+++ b/src/clientenvironment.cpp
@@ -334,9 +334,7 @@ void ClientEnvironment::step(float dtime)
node_at_lplayer = m_map->getNodeNoEx(p);
u16 light = getInteriorLight(node_at_lplayer, 0, m_client->ndef());
- u8 day = light & 0xff;
- u8 night = (light >> 8) & 0xff;
- finalColorBlend(lplayer->light_color, day, night, day_night_ratio);
+ final_color_blend(&lplayer->light_color, light, day_night_ratio);
}
/*
diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp
index a7134590b..742bfb1fd 100644
--- a/src/content_mapblock.cpp
+++ b/src/content_mapblock.cpp
@@ -32,28 +32,29 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// Create a cuboid.
-// collector - the MeshCollector for the resulting polygons
-// box - the position and size of the box
-// tiles - the tiles (materials) to use (for all 6 faces)
-// tilecount - number of entries in tiles, 1<=tilecount<=6
-// c - vertex colour - used for all
-// txc - texture coordinates - this is a list of texture coordinates
-// for the opposite corners of each face - therefore, there
-// should be (2+2)*6=24 values in the list. Alternatively, pass
-// NULL to use the entire texture for each face. The order of
-// the faces in the list is up-down-right-left-back-front
-// (compatible with ContentFeatures). If you specified 0,0,1,1
-// for each face, that would be the same as passing NULL.
+// collector - the MeshCollector for the resulting polygons
+// box - the position and size of the box
+// tiles - the tiles (materials) to use (for all 6 faces)
+// tilecount - number of entries in tiles, 1<=tilecount<=6
+// c - colors of the cuboid's six sides
+// txc - texture coordinates - this is a list of texture coordinates
+// for the opposite corners of each face - therefore, there
+// should be (2+2)*6=24 values in the list. Alternatively,
+// pass NULL to use the entire texture for each face. The
+// order of the faces in the list is up-down-right-left-back-
+// front (compatible with ContentFeatures). If you specified
+// 0,0,1,1 for each face, that would be the same as
+// passing NULL.
+// light source - if greater than zero, the box's faces will not be shaded
void makeCuboid(MeshCollector *collector, const aabb3f &box,
- TileSpec *tiles, int tilecount, video::SColor &c, const f32* txc)
+ TileSpec *tiles, int tilecount, const video::SColor *c,
+ const f32* txc, const u8 light_source)
{
assert(tilecount >= 1 && tilecount <= 6); // pre-condition
v3f min = box.MinEdge;
v3f max = box.MaxEdge;
-
-
if(txc == NULL) {
static const f32 txc_default[24] = {
0,0,1,1,
@@ -66,38 +67,53 @@ void makeCuboid(MeshCollector *collector, const aabb3f &box,
txc = txc_default;
}
+ video::SColor c1 = c[0];
+ video::SColor c2 = c[1];
+ video::SColor c3 = c[2];
+ video::SColor c4 = c[3];
+ video::SColor c5 = c[4];
+ video::SColor c6 = c[5];
+ if (!light_source) {
+ applyFacesShading(c1, v3f(0, 1, 0));
+ applyFacesShading(c2, v3f(0, -1, 0));
+ applyFacesShading(c3, v3f(1, 0, 0));
+ applyFacesShading(c4, v3f(-1, 0, 0));
+ applyFacesShading(c5, v3f(0, 0, 1));
+ applyFacesShading(c6, v3f(0, 0, -1));
+ }
+
video::S3DVertex vertices[24] =
{
// up
- video::S3DVertex(min.X,max.Y,max.Z, 0,1,0, c, txc[0],txc[1]),
- video::S3DVertex(max.X,max.Y,max.Z, 0,1,0, c, txc[2],txc[1]),
- video::S3DVertex(max.X,max.Y,min.Z, 0,1,0, c, txc[2],txc[3]),
- video::S3DVertex(min.X,max.Y,min.Z, 0,1,0, c, txc[0],txc[3]),
+ video::S3DVertex(min.X,max.Y,max.Z, 0,1,0, c1, txc[0],txc[1]),
+ video::S3DVertex(max.X,max.Y,max.Z, 0,1,0, c1, txc[2],txc[1]),
+ video::S3DVertex(max.X,max.Y,min.Z, 0,1,0, c1, txc[2],txc[3]),
+ video::S3DVertex(min.X,max.Y,min.Z, 0,1,0, c1, txc[0],txc[3]),
// down
- video::S3DVertex(min.X,min.Y,min.Z, 0,-1,0, c, txc[4],txc[5]),
- video::S3DVertex(max.X,min.Y,min.Z, 0,-1,0, c, txc[6],txc[5]),
- video::S3DVertex(max.X,min.Y,max.Z, 0,-1,0, c, txc[6],txc[7]),
- video::S3DVertex(min.X,min.Y,max.Z, 0,-1,0, c, txc[4],txc[7]),
+ video::S3DVertex(min.X,min.Y,min.Z, 0,-1,0, c2, txc[4],txc[5]),
+ video::S3DVertex(max.X,min.Y,min.Z, 0,-1,0, c2, txc[6],txc[5]),
+ video::S3DVertex(max.X,min.Y,max.Z, 0,-1,0, c2, txc[6],txc[7]),
+ video::S3DVertex(min.X,min.Y,max.Z, 0,-1,0, c2, txc[4],txc[7]),
// right
- video::S3DVertex(max.X,max.Y,min.Z, 1,0,0, c, txc[ 8],txc[9]),
- video::S3DVertex(max.X,max.Y,max.Z, 1,0,0, c, txc[10],txc[9]),
- video::S3DVertex(max.X,min.Y,max.Z, 1,0,0, c, txc[10],txc[11]),
- video::S3DVertex(max.X,min.Y,min.Z, 1,0,0, c, txc[ 8],txc[11]),
+ video::S3DVertex(max.X,max.Y,min.Z, 1,0,0, c3, txc[ 8],txc[9]),
+ video::S3DVertex(max.X,max.Y,max.Z, 1,0,0, c3, txc[10],txc[9]),
+ video::S3DVertex(max.X,min.Y,max.Z, 1,0,0, c3, txc[10],txc[11]),
+ video::S3DVertex(max.X,min.Y,min.Z, 1,0,0, c3, txc[ 8],txc[11]),
// left
- video::S3DVertex(min.X,max.Y,max.Z, -1,0,0, c, txc[12],txc[13]),
- video::S3DVertex(min.X,max.Y,min.Z, -1,0,0, c, txc[14],txc[13]),
- video::S3DVertex(min.X,min.Y,min.Z, -1,0,0, c, txc[14],txc[15]),
- video::S3DVertex(min.X,min.Y,max.Z, -1,0,0, c, txc[12],txc[15]),
+ video::S3DVertex(min.X,max.Y,max.Z, -1,0,0, c4, txc[12],txc[13]),
+ video::S3DVertex(min.X,max.Y,min.Z, -1,0,0, c4, txc[14],txc[13]),
+ video::S3DVertex(min.X,min.Y,min.Z, -1,0,0, c4, txc[14],txc[15]),
+ video::S3DVertex(min.X,min.Y,max.Z, -1,0,0, c4, txc[12],txc[15]),
// back
- video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c, txc[16],txc[17]),
- video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c, txc[18],txc[17]),
- video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c, txc[18],txc[19]),
- video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c, txc[16],txc[19]),
+ video::S3DVertex(max.X,max.Y,max.Z, 0,0,1, c5, txc[16],txc[17]),
+ video::S3DVertex(min.X,max.Y,max.Z, 0,0,1, c5, txc[18],txc[17]),
+ video::S3DVertex(min.X,min.Y,max.Z, 0,0,1, c5, txc[18],txc[19]),
+ video::S3DVertex(max.X,min.Y,max.Z, 0,0,1, c5, txc[16],txc[19]),
// front
- video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c, txc[20],txc[21]),
- video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c, txc[22],txc[21]),
- video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c, txc[22],txc[23]),
- video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c, txc[20],txc[23]),
+ video::S3DVertex(min.X,max.Y,min.Z, 0,0,-1, c6, txc[20],txc[21]),
+ video::S3DVertex(max.X,max.Y,min.Z, 0,0,-1, c6, txc[22],txc[21]),
+ video::S3DVertex(max.X,min.Y,min.Z, 0,0,-1, c6, txc[22],txc[23]),
+ video::S3DVertex(min.X,min.Y,min.Z, 0,0,-1, c6, txc[20],txc[23]),
};
for(int i = 0; i < 6; i++)
@@ -164,6 +180,31 @@ void makeCuboid(MeshCollector *collector, const aabb3f &box,
}
}
+// Create a cuboid.
+// collector - the MeshCollector for the resulting polygons
+// box - the position and size of the box
+// tiles - the tiles (materials) to use (for all 6 faces)
+// tilecount - number of entries in tiles, 1<=tilecount<=6
+// c - color of the cuboid
+// txc - texture coordinates - this is a list of texture coordinates
+// for the opposite corners of each face - therefore, there
+// should be (2+2)*6=24 values in the list. Alternatively,
+// pass NULL to use the entire texture for each face. The
+// order of the faces in the list is up-down-right-left-back-
+// front (compatible with ContentFeatures). If you specified
+// 0,0,1,1 for each face, that would be the same as
+// passing NULL.
+// light source - if greater than zero, the box's faces will not be shaded
+void makeCuboid(MeshCollector *collector, const aabb3f &box, TileSpec *tiles,
+ int tilecount, const video::SColor &c, const f32* txc,
+ const u8 light_source)
+{
+ video::SColor color[6];
+ for (u8 i = 0; i < 6; i++)
+ color[i] = c;
+ makeCuboid(collector, box, tiles, tilecount, color, txc, light_source);
+}
+
static inline void getNeighborConnectingFace(v3s16 p, INodeDefManager *nodedef,
MeshMakeData *data, MapNode n, int v, int *neighbors)
{
@@ -181,6 +222,18 @@ static inline int NeighborToIndex(const v3s16 &pos)
return 9 * pos.X + 3 * pos.Y + pos.Z + 13;
}
+/*!
+ * Returns the i-th special tile for a map node.
+ */
+static TileSpec getSpecialTile(const ContentFeatures &f,
+ const MapNode &n, u8 i)
+{
+ TileSpec copy = f.special_tiles[i];
+ if (!copy.has_color)
+ n.getColor(f, &copy.color);
+ return copy;
+}
+
/*
TODO: Fix alpha blending for special nodes
Currently only the last element rendered is blended correct
@@ -227,8 +280,13 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
/*
Add water sources to mesh if using new style
*/
- TileSpec tile_liquid = f.special_tiles[0];
+ TileSpec tile_liquid = getSpecialTile(f, n, 0);
TileSpec tile_liquid_bfculled = getNodeTile(n, p, v3s16(0,0,0), data);
+ u16 l = getInteriorLight(n, 0, nodedef);
+ video::SColor c1 = encode_light_and_color(l,
+ tile_liquid.color, f.light_source);
+ video::SColor c2 = encode_light_and_color(l,
+ tile_liquid_bfculled.color, f.light_source);
bool top_is_same_liquid = false;
MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
@@ -237,9 +295,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
if(ntop.getContent() == c_flowing || ntop.getContent() == c_source)
top_is_same_liquid = true;
- u16 l = getInteriorLight(n, 0, nodedef);
- video::SColor c = MapBlock_LightColor(f.alpha, l, f.light_source);
-
/*
Generate sides
*/
@@ -285,15 +340,18 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
// Use backface culled material if neighbor doesn't have a
// solidness of 0
const TileSpec *current_tile = &tile_liquid;
- if(n_feat.solidness != 0 || n_feat.visual_solidness != 0)
+ video::SColor *c = &c1;
+ if(n_feat.solidness != 0 || n_feat.visual_solidness != 0) {
current_tile = &tile_liquid_bfculled;
+ c = &c2;
+ }
video::S3DVertex vertices[4] =
{
- video::S3DVertex(-BS/2,0,BS/2,0,0,0, c, 0,1),
- video::S3DVertex(BS/2,0,BS/2,0,0,0, c, 1,1),
- video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
- video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),
+ video::S3DVertex(-BS/2,0,BS/2,0,0,0, *c, 0,1),
+ video::S3DVertex(BS/2,0,BS/2,0,0,0, *c, 1,1),
+ video::S3DVertex(BS/2,0,BS/2, 0,0,0, *c, 1,0),
+ video::S3DVertex(-BS/2,0,BS/2, 0,0,0, *c, 0,0),
};
/*
@@ -359,10 +417,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
video::S3DVertex vertices[4] =
{
- video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
- video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
- video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,0),
- video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,0),
+ video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c1, 0,1),
+ video::S3DVertex(BS/2,0,BS/2, 0,0,0, c1, 1,1),
+ video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c1, 1,0),
+ video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c1, 0,0),
};
v3f offset(p.X * BS, (p.Y + 0.5) * BS, p.Z * BS);
@@ -380,8 +438,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
/*
Add flowing liquid to mesh
*/
- TileSpec tile_liquid = f.special_tiles[0];
- TileSpec tile_liquid_bfculled = f.special_tiles[1];
+ TileSpec tile_liquid = getSpecialTile(f, n, 0);
+ TileSpec tile_liquid_bfculled = getSpecialTile(f, n, 1);
bool top_is_same_liquid = false;
MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(x,y+1,z));
@@ -404,7 +462,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
// Otherwise use the light of this node (the liquid)
else
l = getInteriorLight(n, 0, nodedef);
- video::SColor c = MapBlock_LightColor(f.alpha, l, f.light_source);
+ video::SColor c1 = encode_light_and_color(l,
+ tile_liquid.color, f.light_source);
+ video::SColor c2 = encode_light_and_color(l,
+ tile_liquid_bfculled.color, f.light_source);
u8 range = rangelim(nodedef->get(c_flowing).liquid_range, 1, 8);
@@ -552,7 +613,7 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
is liquid, don't draw side face
*/
if (top_is_same_liquid &&
- neighbor_data.flags & neighborflag_top_is_same_liquid)
+ (neighbor_data.flags & neighborflag_top_is_same_liquid))
continue;
content_t neighbor_content = neighbor_data.content;
@@ -574,15 +635,18 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
// Use backface culled material if neighbor doesn't have a
// solidness of 0
const TileSpec *current_tile = &tile_liquid;
- if(n_feat.solidness != 0 || n_feat.visual_solidness != 0)
+ video::SColor *c = &c1;
+ if(n_feat.solidness != 0 || n_feat.visual_solidness != 0) {
current_tile = &tile_liquid_bfculled;
+ c = &c2;
+ }
video::S3DVertex vertices[4] =
{
- video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
- video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
- video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,0),
- video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,0),
+ video::S3DVertex(-BS/2,0,BS/2, 0,0,0, *c, 0,1),
+ video::S3DVertex(BS/2,0,BS/2, 0,0,0, *c, 1,1),
+ video::S3DVertex(BS/2,0,BS/2, 0,0,0, *c, 1,0),
+ video::S3DVertex(-BS/2,0,BS/2, 0,0,0, *c, 0,0),
};
/*
@@ -656,10 +720,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
{
video::S3DVertex vertices[4] =
{
- video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c, 0,1),
- video::S3DVertex(BS/2,0,BS/2, 0,0,0, c, 1,1),
- video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c, 1,0),
- video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c, 0,0),
+ video::S3DVertex(-BS/2,0,BS/2, 0,0,0, c1, 0,1),
+ video::S3DVertex(BS/2,0,BS/2, 0,0,0, c1, 1,1),
+ video::S3DVertex(BS/2,0,-BS/2, 0,0,0, c1, 1,0),
+ video::S3DVertex(-BS/2,0,-BS/2, 0,0,0, c1, 0,0),
};
// To get backface culling right, the vertices need to go
@@ -720,8 +784,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
TileSpec tile = getNodeTile(n, p, v3s16(0,0,0), data);
u16 l = getInteriorLight(n, 1, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
-
+ video::SColor c = encode_light_and_color(l, tile.color,
+ f.light_source);
for(u32 j=0; j<6; j++)
{
// Check this neighbor
@@ -731,13 +795,17 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
// Don't make face if neighbor is of same type
if(n2.getContent() == n.getContent())
continue;
+ video::SColor c2=c;
+ if(!f.light_source)
+ applyFacesShading(c2, v3f(dir.X, dir.Y, dir.Z));
+
// The face at Z+
video::S3DVertex vertices[4] = {
- video::S3DVertex(-BS/2,-BS/2,BS/2, dir.X,dir.Y,dir.Z, c, 1,1),
- video::S3DVertex(BS/2,-BS/2,BS/2, dir.X,dir.Y,dir.Z, c, 0,1),
- video::S3DVertex(BS/2,BS/2,BS/2, dir.X,dir.Y,dir.Z, c, 0,0),
- video::S3DVertex(-BS/2,BS/2,BS/2, dir.X,dir.Y,dir.Z, c, 1,0),
+ video::S3DVertex(-BS/2,-BS/2,BS/2, dir.X,dir.Y,dir.Z, c2, 1,1),
+ video::S3DVertex(BS/2,-BS/2,BS/2, dir.X,dir.Y,dir.Z, c2, 0,1),
+ video::S3DVertex(BS/2,BS/2,BS/2, dir.X,dir.Y,dir.Z, c2, 0,0),
+ video::S3DVertex(-BS/2,BS/2,BS/2, dir.X,dir.Y,dir.Z, c2, 1,0),
};
// Rotations in the g_6dirs format
@@ -784,12 +852,20 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
v3s16( 0, 0,-1)
};
+ u16 l = getInteriorLight(n, 1, nodedef);
u8 i;
TileSpec tiles[6];
for (i = 0; i < 6; i++)
tiles[i] = getNodeTile(n, p, dirs[i], data);
+ video::SColor tile0color = encode_light_and_color(l,
+ tiles[0].color, f.light_source);
+ video::SColor tile0colors[6];
+ for (i = 0; i < 6; i++)
+ tile0colors[i] = tile0color;
+
TileSpec glass_tiles[6];
+ video::SColor glasscolor[6];
if (tiles[1].texture && tiles[2].texture && tiles[3].texture) {
glass_tiles[0] = tiles[2];
glass_tiles[1] = tiles[3];
@@ -801,14 +877,15 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
for (i = 0; i < 6; i++)
glass_tiles[i] = tiles[1];
}
+ for (i = 0; i < 6; i++)
+ glasscolor[i] = encode_light_and_color(l, glass_tiles[i].color,
+ f.light_source);
u8 param2 = n.getParam2();
bool H_merge = ! bool(param2 & 128);
bool V_merge = ! bool(param2 & 64);
param2 = param2 & 63;
- u16 l = getInteriorLight(n, 1, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
v3f pos = intToFloat(p, BS);
static const float a = BS / 2;
static const float g = a - 0.003;
@@ -947,7 +1024,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
1-tx2, 1-ty2, 1-tx1, 1-ty1,
tx1, 1-ty2, tx2, 1-ty1,
};
- makeCuboid(&collector, box, &tiles[0], 1, c, txc1);
+ makeCuboid(&collector, box, &tiles[0], 1, tile0colors,
+ txc1, f.light_source);
}
for(i = 0; i < 6; i++)
@@ -971,16 +1049,21 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
1-tx2, 1-ty2, 1-tx1, 1-ty1,
tx1, 1-ty2, tx2, 1-ty1,
};
- makeCuboid(&collector, box, &glass_tiles[i], 1, c, txc2);
+ makeCuboid(&collector, box, &glass_tiles[i], 1, glasscolor,
+ txc2, f.light_source);
}
if (param2 > 0 && f.special_tiles[0].texture) {
// Interior volume level is in range 0 .. 63,
// convert it to -0.5 .. 0.5
float vlev = (((float)param2 / 63.0 ) * 2.0 - 1.0);
+ TileSpec tile=getSpecialTile(f, n, 0);
+ video::SColor special_color = encode_light_and_color(l,
+ tile.color, f.light_source);
TileSpec interior_tiles[6];
for (i = 0; i < 6; i++)
- interior_tiles[i] = f.special_tiles[0];
+ interior_tiles[i] = tile;
+
float offset = 0.003;
box = aabb3f(visible_faces[3] ? -b : -a + offset,
visible_faces[1] ? -b : -a + offset,
@@ -1004,22 +1087,24 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
1-tx2, 1-ty2, 1-tx1, 1-ty1,
tx1, 1-ty2, tx2, 1-ty1,
};
- makeCuboid(&collector, box, interior_tiles, 6, c, txc3);
+ makeCuboid(&collector, box, interior_tiles, 6, special_color,
+ txc3, f.light_source);
}
break;}
case NDT_ALLFACES:
{
TileSpec tile_leaves = getNodeTile(n, p,
v3s16(0,0,0), data);
-
u16 l = getInteriorLight(n, 1, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
+ video::SColor c = encode_light_and_color(l,
+ tile_leaves.color, f.light_source);
v3f pos = intToFloat(p, BS);
aabb3f box(-BS/2,-BS/2,-BS/2,BS/2,BS/2,BS/2);
box.MinEdge += pos;
box.MaxEdge += pos;
- makeCuboid(&collector, box, &tile_leaves, 1, c, NULL);
+ makeCuboid(&collector, box, &tile_leaves, 1, c, NULL,
+ f.light_source);
break;}
case NDT_ALLFACES_OPTIONAL:
// This is always pre-converted to something else
@@ -1046,7 +1131,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
u16 l = getInteriorLight(n, 1, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
+ video::SColor c = encode_light_and_color(l, tile.color,
+ f.light_source);
float s = BS/2*f.visual_scale;
// Wall at X+ of node
@@ -1087,7 +1173,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
u16 l = getInteriorLight(n, 0, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
+ video::SColor c = encode_light_and_color(l, tile.color,
+ f.light_source);
float d = (float)BS/16;
float s = BS/2*f.visual_scale;
@@ -1132,7 +1219,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
u16 l = getInteriorLight(n, 1, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
+ video::SColor c = encode_light_and_color(l, tile.color,
+ f.light_source);
float s = BS / 2 * f.visual_scale;
// add sqrt(2) visual scale
@@ -1302,7 +1390,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
u16 l = getInteriorLight(n, 1, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
+ video::SColor c = encode_light_and_color(l, tile.color,
+ f.light_source);
float s = BS / 2 * f.visual_scale;
@@ -1437,7 +1526,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
tile_rot.rotation = 1;
u16 l = getInteriorLight(n, 1, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
+ video::SColor c = encode_light_and_color(l, tile.color,
+ f.light_source);
const f32 post_rad=(f32)BS/8;
const f32 bar_rad=(f32)BS/16;
@@ -1456,7 +1546,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
4/16.,0,8/16.,1,
8/16.,0,12/16.,1,
12/16.,0,16/16.,1};
- makeCuboid(&collector, post, &tile_rot, 1, c, postuv);
+ makeCuboid(&collector, post, &tile_rot, 1, c, postuv,
+ f.light_source);
// Now a section of fence, +X, if there's a post there
v3s16 p2 = p;
@@ -1477,11 +1568,11 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
0/16.,8/16.,16/16.,10/16.,
0/16.,14/16.,16/16.,16/16.};
makeCuboid(&collector, bar, &tile_nocrack, 1,
- c, xrailuv);
+ c, xrailuv, f.light_source);
bar.MinEdge.Y -= BS/2;
bar.MaxEdge.Y -= BS/2;
makeCuboid(&collector, bar, &tile_nocrack, 1,
- c, xrailuv);
+ c, xrailuv, f.light_source);
}
// Now a section of fence, +Z, if there's a post there
@@ -1503,11 +1594,11 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
6/16.,6/16.,8/16.,8/16.,
10/16.,10/16.,12/16.,12/16.};
makeCuboid(&collector, bar, &tile_nocrack, 1,
- c, zrailuv);
+ c, zrailuv, f.light_source);
bar.MinEdge.Y -= BS/2;
bar.MaxEdge.Y -= BS/2;
makeCuboid(&collector, bar, &tile_nocrack, 1,
- c, zrailuv);
+ c, zrailuv, f.light_source);
}
break;}
case NDT_RAILLIKE:
@@ -1616,7 +1707,8 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
u16 l = getInteriorLight(n, 0, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
+ video::SColor c = encode_light_and_color(l, tile.color,
+ f.light_source);
float d = (float)BS/64;
float s = BS/2;
@@ -1627,10 +1719,10 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
video::S3DVertex vertices[4] =
{
- video::S3DVertex(-s, -s+d,-s, 0,0,0, c,0,1),
- video::S3DVertex( s, -s+d,-s, 0,0,0, c,1,1),
- video::S3DVertex( s, g*s+d, s, 0,0,0, c,1,0),
- video::S3DVertex(-s, g*s+d, s, 0,0,0, c,0,0),
+ video::S3DVertex(-s, -s+d, -s, 0, 0, 0, c, 0, 1),
+ video::S3DVertex( s, -s+d, -s, 0, 0, 0, c, 1, 1),
+ video::S3DVertex( s, g*s+d, s, 0, 0, 0, c, 1, 0),
+ video::S3DVertex(-s, g*s+d, s, 0, 0, 0, c, 0, 0),
};
for(s32 i=0; i<4; i++)
@@ -1653,10 +1745,16 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
v3s16(0, 0, 1),
v3s16(0, 0, -1)
};
- TileSpec tiles[6];
u16 l = getInteriorLight(n, 1, nodedef);
- video::SColor c = MapBlock_LightColor(255, l, f.light_source);
+ TileSpec tiles[6];
+ video::SColor colors[6];
+ for(int j = 0; j < 6; j++) {
+ // Handles facedir rotation for textures
+ tiles[j] = getNodeTile(n, p, tile_dirs[j], data);
+ colors[j]= encode_light_and_color(l, tiles[j].color,
+ f.light_source);
+ }
v3f pos = intToFloat(p, BS);
@@ -1696,11 +1794,6 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
i = boxes.begin();
i != boxes.end(); ++i)
{
- for(int j = 0; j < 6; j++)
- {
- // Handles facedir rotation for textures
- tiles[j] = getNodeTile(n, p, tile_dirs[j], data);
- }
aabb3f box = *i;
box.MinEdge += pos;
box.MaxEdge += pos;
@@ -1747,18 +1840,19 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
// front
tx1, 1-ty2, tx2, 1-ty1,
};
- makeCuboid(&collector, box, tiles, 6, c, txc);
+ makeCuboid(&collector, box, tiles, 6, colors, txc, f.light_source);
}
break;}
case NDT_MESH:
{
v3f pos = intToFloat(p, BS);
- video::SColor c = MapBlock_LightColor(255, getInteriorLight(n, 1, nodedef), f.light_source);
-
+ u16 l = getInteriorLight(n, 1, nodedef);
u8 facedir = 0;
- if (f.param_type_2 == CPT2_FACEDIR) {
+ if (f.param_type_2 == CPT2_FACEDIR ||
+ f.param_type_2 == CPT2_COLORED_FACEDIR) {
facedir = n.getFaceDir(nodedef);
- } else if (f.param_type_2 == CPT2_WALLMOUNTED) {
+ } else if (f.param_type_2 == CPT2_WALLMOUNTED ||
+ f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
//convert wallmounted to 6dfacedir.
//when cache enabled, it is already converted
facedir = n.getWallMounted(nodedef);
@@ -1771,10 +1865,13 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
if (f.mesh_ptr[facedir]) {
// use cached meshes
for(u16 j = 0; j < f.mesh_ptr[0]->getMeshBufferCount(); j++) {
+ const TileSpec &tile = getNodeTileN(n, p, j, data);
scene::IMeshBuffer *buf = f.mesh_ptr[facedir]->getMeshBuffer(j);
- collector.append(getNodeTileN(n, p, j, data),
- (video::S3DVertex *)buf->getVertices(), buf->getVertexCount(),
- buf->getIndices(), buf->getIndexCount(), pos, c);
+ collector.append(tile, (video::S3DVertex *)
+ buf->getVertices(), buf->getVertexCount(),
+ buf->getIndices(), buf->getIndexCount(), pos,
+ encode_light_and_color(l, tile.color, f.light_source),
+ f.light_source);
}
} else if (f.mesh_ptr[0]) {
// no cache, clone and rotate mesh
@@ -1783,10 +1880,13 @@ void mapblock_mesh_generate_special(MeshMakeData *data,
recalculateBoundingBox(mesh);
meshmanip->recalculateNormals(mesh, true, false);
for(u16 j = 0; j < mesh->getMeshBufferCount(); j++) {
+ const TileSpec &tile = getNodeTileN(n, p, j, data);
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
- collector.append(getNodeTileN(n, p, j, data),
- (video::S3DVertex *)buf->getVertices(), buf->getVertexCount(),
- buf->getIndices(), buf->getIndexCount(), pos, c);
+ collector.append(tile, (video::S3DVertex *)
+ buf->getVertices(), buf->getVertexCount(),
+ buf->getIndices(), buf->getIndexCount(), pos,
+ encode_light_and_color(l, tile.color, f.light_source),
+ f.light_source);
}
mesh->drop();
}
diff --git a/src/game.cpp b/src/game.cpp
index 1070cb1b2..07d429c6b 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -642,7 +642,7 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
CachedPixelShaderSetting<float> m_fog_distance;
CachedVertexShaderSetting<float> m_animation_timer_vertex;
CachedPixelShaderSetting<float> m_animation_timer_pixel;
- CachedPixelShaderSetting<float> m_day_night_ratio;
+ CachedPixelShaderSetting<float, 3> m_day_light;
CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
CachedPixelShaderSetting<float, 3> m_minimap_yaw;
@@ -674,7 +674,7 @@ public:
m_fog_distance("fogDistance"),
m_animation_timer_vertex("animationTimer"),
m_animation_timer_pixel("animationTimer"),
- m_day_night_ratio("dayNightRatio"),
+ m_day_light("dayLight"),
m_eye_position_pixel("eyePosition"),
m_eye_position_vertex("eyePosition"),
m_minimap_yaw("yawVec"),
@@ -717,8 +717,14 @@ public:
m_fog_distance.set(&fog_distance, services);
- float daynight_ratio = (float)m_client->getEnv().getDayNightRatio() / 1000.f;
- m_day_night_ratio.set(&daynight_ratio, services);
+ u32 daynight_ratio = (float)m_client->getEnv().getDayNightRatio();
+ video::SColorf sunlight;
+ get_sunlight_color(&sunlight, daynight_ratio);
+ float dnc[3] = {
+ sunlight.r,
+ sunlight.g,
+ sunlight.b };
+ m_day_light.set(dnc, services);
u32 animation_timer = porting::getTimeMs() % 100000;
float animation_timer_f = (float)animation_timer / 100000.f;
@@ -840,7 +846,8 @@ bool nodePlacementPrediction(Client &client,
// Predict param2 for facedir and wallmounted nodes
u8 param2 = 0;
- if (nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED) {
+ if (nodedef->get(id).param_type_2 == CPT2_WALLMOUNTED ||
+ nodedef->get(id).param_type_2 == CPT2_COLORED_WALLMOUNTED) {
v3s16 dir = nodepos - neighbourpos;
if (abs(dir.Y) > MYMAX(abs(dir.X), abs(dir.Z))) {
@@ -852,7 +859,8 @@ bool nodePlacementPrediction(Client &client,
}
}
- if (nodedef->get(id).param_type_2 == CPT2_FACEDIR) {
+ if (nodedef->get(id).param_type_2 == CPT2_FACEDIR ||
+ nodedef->get(id).param_type_2 == CPT2_COLORED_FACEDIR) {
v3s16 dir = nodepos - floatToInt(client.getEnv().getLocalPlayer()->getPosition(), BS);
if (abs(dir.X) > abs(dir.Z)) {
@@ -3749,11 +3757,9 @@ PointedThing Game::updatePointedThing(
light_level = node_light;
}
- video::SColor c = MapBlock_LightColor(255, light_level, 0);
- u8 day = c.getRed();
- u8 night = c.getGreen();
u32 daynight_ratio = client->getEnv().getDayNightRatio();
- finalColorBlend(c, day, night, daynight_ratio);
+ video::SColor c;
+ final_color_blend(&c, light_level, daynight_ratio);
// Modify final color a bit with time
u32 timer = porting::getTimeMs() % 5000;
@@ -3964,7 +3970,7 @@ void Game::handleDigging(GameRunData *runData,
const ContentFeatures &features =
client->getNodeDefManager()->get(n);
client->getParticleManager()->addPunchingParticles(client, smgr,
- player, nodepos, features.tiles);
+ player, nodepos, n, features);
}
}
@@ -4011,7 +4017,7 @@ void Game::handleDigging(GameRunData *runData,
const ContentFeatures &features =
client->getNodeDefManager()->get(wasnode);
client->getParticleManager()->addDiggingParticles(client, smgr,
- player, nodepos, features.tiles);
+ player, nodepos, wasnode, features);
}
runData->dig_time = 0;
diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp
index 143adb410..dfd6f55a5 100644
--- a/src/mapblock_mesh.cpp
+++ b/src/mapblock_mesh.cpp
@@ -32,12 +32,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/directiontables.h"
#include <IMeshManipulator.h>
-static void applyFacesShading(video::SColor &color, const float factor)
-{
- color.setRed(core::clamp(core::round32(color.getRed() * factor), 0, 255));
- color.setGreen(core::clamp(core::round32(color.getGreen() * factor), 0, 255));
-}
-
/*
MeshMakeData
*/
@@ -321,19 +315,34 @@ u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
return getSmoothLightCombined(p, data);
}
-/*
- Converts from day + night color values (0..255)
- and a given daynight_ratio to the final SColor shown on screen.
-*/
-void finalColorBlend(video::SColor& result,
- u8 day, u8 night, u32 daynight_ratio)
+void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){
+ f32 rg = daynight_ratio / 1000.0f - 0.04f;
+ f32 b = (0.98f * daynight_ratio) / 1000.0f + 0.078f;
+ sunlight->r = rg;
+ sunlight->g = rg;
+ sunlight->b = b;
+}
+
+void final_color_blend(video::SColor *result,
+ u16 light, u32 daynight_ratio)
{
- s32 rg = (day * daynight_ratio + night * (1000-daynight_ratio)) / 1000;
- s32 b = rg;
+ video::SColorf dayLight;
+ get_sunlight_color(&dayLight, daynight_ratio);
+ final_color_blend(result,
+ encode_light_and_color(light, video::SColor(0xFFFFFFFF), 0), dayLight);
+}
- // Moonlight is blue
- b += (day - night) / 13;
- rg -= (day - night) / 23;
+void final_color_blend(video::SColor *result,
+ const video::SColor &data, const video::SColorf &dayLight)
+{
+ static const video::SColorf artificialColor(1.04f, 1.04f, 1.04f);
+
+ video::SColorf c(data);
+ f32 n = 1 - c.a;
+
+ f32 r = c.r * (c.a * dayLight.r + n * artificialColor.r) * 2.0f;
+ f32 g = c.g * (c.a * dayLight.g + n * artificialColor.g) * 2.0f;
+ f32 b = c.b * (c.a * dayLight.b + n * artificialColor.b) * 2.0f;
// Emphase blue a bit in darker places
// Each entry of this array represents a range of 8 blue levels
@@ -341,19 +350,13 @@ void finalColorBlend(video::SColor& result,
1, 4, 6, 6, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
- b += emphase_blue_when_dark[irr::core::clamp(b, 0, 255) / 8];
- b = irr::core::clamp(b, 0, 255);
- // Artificial light is yellow-ish
- static const u8 emphase_yellow_when_artificial[16] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 10, 15, 15, 15
- };
- rg += emphase_yellow_when_artificial[night/16];
- rg = irr::core::clamp(rg, 0, 255);
+ b += emphase_blue_when_dark[irr::core::clamp((s32) ((r + g + b) / 3 * 255),
+ 0, 255) / 8] / 255.0f;
- result.setRed(rg);
- result.setGreen(rg);
- result.setBlue(b);
+ result->setRed(core::clamp((s32) (r * 255.0f), 0, 255));
+ result->setGreen(core::clamp((s32) (g * 255.0f), 0, 255));
+ result->setBlue(core::clamp((s32) (b * 255.0f), 0, 255));
}
/*
@@ -430,7 +433,7 @@ struct FastFace
};
static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
- v3f p, v3s16 dir, v3f scale, u8 light_source, std::vector<FastFace> &dest)
+ v3f p, v3s16 dir, v3f scale, std::vector<FastFace> &dest)
{
// Position is at the center of the cube.
v3f pos = p * BS;
@@ -580,24 +583,25 @@ static void makeFastFace(TileSpec tile, u16 li0, u16 li1, u16 li2, u16 li3,
v3f normal(dir.X, dir.Y, dir.Z);
- u8 alpha = tile.alpha;
-
dest.push_back(FastFace());
FastFace& face = *dest.rbegin();
- face.vertices[0] = video::S3DVertex(vertex_pos[0], normal,
- MapBlock_LightColor(alpha, li0, light_source),
- core::vector2d<f32>(x0+w*abs_scale, y0+h));
- face.vertices[1] = video::S3DVertex(vertex_pos[1], normal,
- MapBlock_LightColor(alpha, li1, light_source),
- core::vector2d<f32>(x0, y0+h));
- face.vertices[2] = video::S3DVertex(vertex_pos[2], normal,
- MapBlock_LightColor(alpha, li2, light_source),
- core::vector2d<f32>(x0, y0));
- face.vertices[3] = video::S3DVertex(vertex_pos[3], normal,
- MapBlock_LightColor(alpha, li3, light_source),
- core::vector2d<f32>(x0+w*abs_scale, y0));
+ u16 li[4] = { li0, li1, li2, li3 };
+ v2f32 f[4] = {
+ core::vector2d<f32>(x0 + w * abs_scale, y0 + h),
+ core::vector2d<f32>(x0, y0 + h),
+ core::vector2d<f32>(x0, y0),
+ core::vector2d<f32>(x0 + w * abs_scale, y0) };
+
+ for (u8 i = 0; i < 4; i++) {
+ video::SColor c = encode_light_and_color(li[i], tile.color,
+ tile.emissive_light);
+ if (!tile.emissive_light)
+ applyFacesShading(c, normal);
+
+ face.vertices[i] = video::S3DVertex(vertex_pos[i], normal, c, f[i]);
+ }
face.tile = tile;
}
@@ -664,7 +668,10 @@ static u8 face_contents(content_t m1, content_t m2, bool *equivalent,
TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data)
{
INodeDefManager *ndef = data->m_client->ndef();
- TileSpec spec = ndef->get(mn).tiles[tileindex];
+ const ContentFeatures &f = ndef->get(mn);
+ TileSpec spec = f.tiles[tileindex];
+ if (!spec.has_color)
+ mn.getColor(f, &spec.color);
// Apply temporary crack
if (p == data->m_crack_pos_relative)
spec.material_flags |= MATERIAL_FLAG_CRACK;
@@ -747,8 +754,7 @@ static void getTileInfo(
v3s16 &p_corrected,
v3s16 &face_dir_corrected,
u16 *lights,
- TileSpec &tile,
- u8 &light_source
+ TileSpec &tile
)
{
VoxelManipulator &vmanip = data->m_vmanip;
@@ -763,7 +769,8 @@ static void getTileInfo(
return;
}
- const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(blockpos_nodes + p + face_dir);
+ const MapNode &n1 = vmanip.getNodeRefUnsafeCheckFlags(
+ blockpos_nodes + p + face_dir);
if (n1.getContent() == CONTENT_IGNORE) {
makes_face = false;
@@ -783,26 +790,25 @@ static void getTileInfo(
makes_face = true;
- if(mf == 1)
- {
- tile = getNodeTile(n0, p, face_dir, data);
+ MapNode n = n0;
+
+ if (mf == 1) {
p_corrected = p;
face_dir_corrected = face_dir;
- light_source = ndef->get(n0).light_source;
- }
- else
- {
- tile = getNodeTile(n1, p + face_dir, -face_dir, data);
+ } else {
+ n = n1;
p_corrected = p + face_dir;
face_dir_corrected = -face_dir;
- light_source = ndef->get(n1).light_source;
}
+ tile = getNodeTile(n, p_corrected, face_dir_corrected, data);
+ const ContentFeatures &f = ndef->get(n);
+ tile.emissive_light = f.light_source;
// eg. water and glass
- if(equivalent)
+ if (equivalent)
tile.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
- if(data->m_smooth_lighting == false)
+ if (data->m_smooth_lighting == false)
{
lights[0] = lights[1] = lights[2] = lights[3] =
getFaceLight(n0, n1, face_dir, ndef);
@@ -845,10 +851,9 @@ static void updateFastFaceRow(
v3s16 face_dir_corrected;
u16 lights[4] = {0,0,0,0};
TileSpec tile;
- u8 light_source = 0;
getTileInfo(data, p, face_dir,
makes_face, p_corrected, face_dir_corrected,
- lights, tile, light_source);
+ lights, tile);
for(u16 j=0; j<MAP_BLOCKSIZE; j++)
{
@@ -862,7 +867,6 @@ static void updateFastFaceRow(
v3s16 next_face_dir_corrected;
u16 next_lights[4] = {0,0,0,0};
TileSpec next_tile;
- u8 next_light_source = 0;
// If at last position, there is nothing to compare to and
// the face must be drawn anyway
@@ -873,7 +877,7 @@ static void updateFastFaceRow(
getTileInfo(data, p_next, face_dir,
next_makes_face, next_p_corrected,
next_face_dir_corrected, next_lights,
- next_tile, next_light_source);
+ next_tile);
if(next_makes_face == makes_face
&& next_p_corrected == p_corrected + translate_dir
@@ -884,9 +888,10 @@ static void updateFastFaceRow(
&& next_lights[3] == lights[3]
&& next_tile == tile
&& tile.rotation == 0
- && next_light_source == light_source
&& (tile.material_flags & MATERIAL_FLAG_TILEABLE_HORIZONTAL)
- && (tile.material_flags & MATERIAL_FLAG_TILEABLE_VERTICAL)) {
+ && (tile.material_flags & MATERIAL_FLAG_TILEABLE_VERTICAL)
+ && tile.color == next_tile.color
+ && tile.emissive_light == next_tile.emissive_light) {
next_is_different = false;
continuous_tiles_count++;
} else {
@@ -938,8 +943,7 @@ static void updateFastFaceRow(
}
makeFastFace(tile, lights[0], lights[1], lights[2], lights[3],
- sp, face_dir_corrected, scale, light_source,
- dest);
+ sp, face_dir_corrected, scale, dest);
g_profiler->avg("Meshgen: faces drawn by tiling", 0);
for(int i = 1; i < continuous_tiles_count; i++){
@@ -958,7 +962,6 @@ static void updateFastFaceRow(
lights[2] = next_lights[2];
lights[3] = next_lights[3];
tile = next_tile;
- light_source = next_light_source;
p = p_next;
}
}
@@ -1083,12 +1086,14 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
const u16 *indices_p = indices;
/*
- Revert triangles for nicer looking gradient if vertices
- 1 and 3 have same color or 0 and 2 have different color.
- getRed() is the day color.
+ Revert triangles for nicer looking gradient if the
+ brightness of vertices 1 and 3 differ less than
+ the brightness of vertices 0 and 2.
*/
- if(f.vertices[0].Color.getRed() != f.vertices[2].Color.getRed()
- || f.vertices[1].Color.getRed() == f.vertices[3].Color.getRed())
+ if (abs(f.vertices[0].Color.getAverage()
+ - f.vertices[2].Color.getAverage())
+ > abs(f.vertices[1].Color.getAverage()
+ - f.vertices[3].Color.getAverage()))
indices_p = indices_alternate;
collector.append(f.tile, f.vertices, 4, indices_p, 6);
@@ -1148,43 +1153,30 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
p.tile.texture = animation_frame.texture;
}
- u32 vertex_count = m_use_tangent_vertices ?
- p.tangent_vertices.size() : p.vertices.size();
- for (u32 j = 0; j < vertex_count; j++) {
- v3f *Normal;
- video::SColor *vc;
- if (m_use_tangent_vertices) {
- vc = &p.tangent_vertices[j].Color;
- Normal = &p.tangent_vertices[j].Normal;
- } else {
- vc = &p.vertices[j].Color;
- Normal = &p.vertices[j].Normal;
- }
- // Note applyFacesShading second parameter is precalculated sqrt
- // value for speed improvement
- // Skip it for lightsources and top faces.
- if (!vc->getBlue()) {
- if (Normal->Y < -0.5) {
- applyFacesShading(*vc, 0.447213);
- } else if (Normal->X > 0.5) {
- applyFacesShading(*vc, 0.670820);
- } else if (Normal->X < -0.5) {
- applyFacesShading(*vc, 0.670820);
- } else if (Normal->Z > 0.5) {
- applyFacesShading(*vc, 0.836660);
- } else if (Normal->Z < -0.5) {
- applyFacesShading(*vc, 0.836660);
- }
- }
- if (!m_enable_shaders) {
- // - Classic lighting (shaders handle this by themselves)
- // Set initial real color and store for later updates
- u8 day = vc->getRed();
- u8 night = vc->getGreen();
- finalColorBlend(*vc, day, night, 1000);
- if (day != night) {
- m_daynight_diffs[i][j] = std::make_pair(day, night);
+ if (!m_enable_shaders) {
+ // Extract colors for day-night animation
+ // Dummy sunlight to handle non-sunlit areas
+ video::SColorf sunlight;
+ get_sunlight_color(&sunlight, 0);
+ u32 vertex_count =
+ m_use_tangent_vertices ?
+ p.tangent_vertices.size() : p.vertices.size();
+ for (u32 j = 0; j < vertex_count; j++) {
+ video::SColor *vc;
+ if (m_use_tangent_vertices) {
+ vc = &p.tangent_vertices[j].Color;
+ } else {
+ vc = &p.vertices[j].Color;
}
+ video::SColor copy(*vc);
+ if (vc->getAlpha() == 0) // No sunlight - no need to animate
+ final_color_blend(vc, copy, sunlight); // Finalize color
+ else // Record color to animate
+ m_daynight_diffs[i][j] = copy;
+
+ // The sunlight ratio has been stored,
+ // delete alpha (for the final rendering).
+ vc->setAlpha(255);
}
}
@@ -1358,19 +1350,19 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, u32 daynight_rat
if (m_enable_vbo) {
m_mesh->setDirty();
}
- for(std::map<u32, std::map<u32, std::pair<u8, u8> > >::iterator
+ video::SColorf day_color;
+ get_sunlight_color(&day_color, daynight_ratio);
+ for(std::map<u32, std::map<u32, video::SColor > >::iterator
i = m_daynight_diffs.begin();
i != m_daynight_diffs.end(); ++i)
{
scene::IMeshBuffer *buf = m_mesh->getMeshBuffer(i->first);
video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
- for(std::map<u32, std::pair<u8, u8 > >::iterator
+ for(std::map<u32, video::SColor >::iterator
j = i->second.begin();
j != i->second.end(); ++j)
{
- u8 day = j->second.first;
- u8 night = j->second.second;
- finalColorBlend(vertices[j->first].Color, day, night, daynight_ratio);
+ final_color_blend(&(vertices[j->first].Color), j->second, day_color);
}
}
m_last_daynight_ratio = daynight_ratio;
@@ -1452,7 +1444,7 @@ void MeshCollector::append(const TileSpec &tile,
void MeshCollector::append(const TileSpec &tile,
const video::S3DVertex *vertices, u32 numVertices,
const u16 *indices, u32 numIndices,
- v3f pos, video::SColor c)
+ v3f pos, video::SColor c, u8 light_source)
{
if (numIndices > 65535) {
dstream<<"FIXME: MeshCollector::append() called with numIndices="<<numIndices<<" (limit 65535)"<<std::endl;
@@ -1478,10 +1470,15 @@ void MeshCollector::append(const TileSpec &tile,
p = &prebuffers[prebuffers.size() - 1];
}
+ video::SColor original_c = c;
u32 vertex_count;
if (m_use_tangent_vertices) {
vertex_count = p->tangent_vertices.size();
for (u32 i = 0; i < numVertices; i++) {
+ if (!light_source) {
+ c = original_c;
+ applyFacesShading(c, vertices[i].Normal);
+ }
video::S3DVertexTangents vert(vertices[i].Pos + pos,
vertices[i].Normal, c, vertices[i].TCoords);
p->tangent_vertices.push_back(vert);
@@ -1489,8 +1486,12 @@ void MeshCollector::append(const TileSpec &tile,
} else {
vertex_count = p->vertices.size();
for (u32 i = 0; i < numVertices; i++) {
- video::S3DVertex vert(vertices[i].Pos + pos,
- vertices[i].Normal, c, vertices[i].TCoords);
+ if (!light_source) {
+ c = original_c;
+ applyFacesShading(c, vertices[i].Normal);
+ }
+ video::S3DVertex vert(vertices[i].Pos + pos, vertices[i].Normal, c,
+ vertices[i].TCoords);
p->vertices.push_back(vert);
}
}
@@ -1500,3 +1501,33 @@ void MeshCollector::append(const TileSpec &tile,
p->indices.push_back(j);
}
}
+
+video::SColor encode_light_and_color(u16 light, const video::SColor &color,
+ u8 emissive_light)
+{
+ // Get components
+ f32 day = (light & 0xff) / 255.0f;
+ f32 night = (light >> 8) / 255.0f;
+ // Add emissive light
+ night += emissive_light * 0.01f;
+ if (night > 255)
+ night = 255;
+ // Since we don't know if the day light is sunlight or
+ // artificial light, assume it is artificial when the night
+ // light bank is also lit.
+ if (day < night)
+ day = 0;
+ else
+ day = day - night;
+ f32 sum = day + night;
+ // Ratio of sunlight:
+ float r;
+ if (sum > 0)
+ r = day / sum;
+ else
+ r = 0;
+ // Average light:
+ float b = (day + night) / 2;
+ return video::SColor(r * 255, b * color.getRed(), b * color.getGreen(),
+ b * color.getBlue());
+}
diff --git a/src/mapblock_mesh.h b/src/mapblock_mesh.h
index 5adb7df3f..916703f3e 100644
--- a/src/mapblock_mesh.h
+++ b/src/mapblock_mesh.h
@@ -156,8 +156,8 @@ private:
// Animation info: day/night transitions
// Last daynight_ratio value passed to animate()
u32 m_last_daynight_ratio;
- // For each meshbuffer, maps vertex indices to (day,night) pairs
- std::map<u32, std::map<u32, std::pair<u8, u8> > > m_daynight_diffs;
+ // For each meshbuffer, stores pre-baked colors of sunlit vertices
+ std::map<u32, std::map<u32, video::SColor > > m_daynight_diffs;
// Camera offset info -> do we have to translate the mesh?
v3s16 m_camera_offset;
@@ -192,28 +192,53 @@ struct MeshCollector
void append(const TileSpec &material,
const video::S3DVertex *vertices, u32 numVertices,
const u16 *indices, u32 numIndices,
- v3f pos, video::SColor c);
+ v3f pos, video::SColor c, u8 light_source);
};
-// This encodes
-// alpha in the A channel of the returned SColor
-// day light (0-255) in the R channel of the returned SColor
-// night light (0-255) in the G channel of the returned SColor
-// light source (0-255) in the B channel of the returned SColor
-inline video::SColor MapBlock_LightColor(u8 alpha, u16 light, u8 light_source=0)
-{
- return video::SColor(alpha, (light & 0xff), (light >> 8), light_source);
-}
+/*!
+ * Encodes light and color of a node.
+ * The result is not the final color, but a
+ * half-baked vertex color.
+ *
+ * \param light the first 8 bits are day light,
+ * the last 8 bits are night light
+ * \param color the node's color
+ * \param emissive_light amount of light the surface emits,
+ * from 0 to LIGHT_SUN.
+ */
+video::SColor encode_light_and_color(u16 light, const video::SColor &color,
+ u8 emissive_light);
// Compute light at node
u16 getInteriorLight(MapNode n, s32 increment, INodeDefManager *ndef);
u16 getFaceLight(MapNode n, MapNode n2, v3s16 face_dir, INodeDefManager *ndef);
u16 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data);
-// Converts from day + night color values (0..255)
-// and a given daynight_ratio to the final SColor shown on screen.
-void finalColorBlend(video::SColor& result,
- u8 day, u8 night, u32 daynight_ratio);
+/*!
+ * Returns the sunlight's color from the current
+ * day-night ratio.
+ */
+void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio);
+
+/*!
+ * Gives the final SColor shown on screen.
+ *
+ * \param result output color
+ * \param light first 8 bits are day light, second 8 bits are
+ * night light
+ */
+void final_color_blend(video::SColor *result,
+ u16 light, u32 daynight_ratio);
+
+/*!
+ * Gives the final SColor shown on screen.
+ *
+ * \param result output color
+ * \param data the half-baked vertex color
+ * \param dayLight color of the sunlight
+ */
+void final_color_blend(video::SColor *result,
+ const video::SColor &data, const video::SColorf &dayLight);
// Retrieves the TileSpec of a face of a node
// Adds MATERIAL_FLAG_CRACK if the node is cracked
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index f1a7f3e61..d835daba2 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -55,6 +55,15 @@ MapNode::MapNode(INodeDefManager *ndef, const std::string &name,
param2 = a_param2;
}
+void MapNode::getColor(const ContentFeatures &f, video::SColor *color) const
+{
+ if (f.palette) {
+ *color = (*f.palette)[param2];
+ return;
+ }
+ *color = f.color;
+}
+
void MapNode::setLight(enum LightBank bank, u8 a_light, const ContentFeatures &f)
{
// If node doesn't contain light data, ignore this
@@ -146,7 +155,8 @@ bool MapNode::getLightBanks(u8 &lightday, u8 &lightnight, INodeDefManager *nodem
u8 MapNode::getFaceDir(INodeDefManager *nodemgr) const
{
const ContentFeatures &f = nodemgr->get(*this);
- if(f.param_type_2 == CPT2_FACEDIR)
+ if (f.param_type_2 == CPT2_FACEDIR ||
+ f.param_type_2 == CPT2_COLORED_FACEDIR)
return (getParam2() & 0x1F) % 24;
return 0;
}
@@ -154,7 +164,8 @@ u8 MapNode::getFaceDir(INodeDefManager *nodemgr) const
u8 MapNode::getWallMounted(INodeDefManager *nodemgr) const
{
const ContentFeatures &f = nodemgr->get(*this);
- if(f.param_type_2 == CPT2_WALLMOUNTED)
+ if (f.param_type_2 == CPT2_WALLMOUNTED ||
+ f.param_type_2 == CPT2_COLORED_WALLMOUNTED)
return getParam2() & 0x07;
return 0;
}
@@ -176,7 +187,7 @@ void MapNode::rotateAlongYAxis(INodeDefManager *nodemgr, Rotation rot)
{
ContentParamType2 cpt2 = nodemgr->get(*this).param_type_2;
- if (cpt2 == CPT2_FACEDIR) {
+ if (cpt2 == CPT2_FACEDIR || cpt2 == CPT2_COLORED_FACEDIR) {
static const u8 rotate_facedir[24 * 4] = {
// Table value = rotated facedir
// Columns: 0, 90, 180, 270 degrees rotation around vertical axis
@@ -216,7 +227,8 @@ void MapNode::rotateAlongYAxis(INodeDefManager *nodemgr, Rotation rot)
u8 index = facedir * 4 + rot;
param2 &= ~31;
param2 |= rotate_facedir[index];
- } else if (cpt2 == CPT2_WALLMOUNTED) {
+ } else if (cpt2 == CPT2_WALLMOUNTED ||
+ cpt2 == CPT2_COLORED_WALLMOUNTED) {
u8 wmountface = (param2 & 7);
if (wmountface <= 1)
return;
diff --git a/src/mapnode.h b/src/mapnode.h
index ae0245cfe..9c56a7e17 100644
--- a/src/mapnode.h
+++ b/src/mapnode.h
@@ -20,9 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#ifndef MAPNODE_HEADER
#define MAPNODE_HEADER
-#include "irrlichttypes.h"
-#include "irr_v3d.h"
-#include "irr_aabb3d.h"
+#include "irrlichttypes_bloated.h"
#include "light.h"
#include <string>
#include <vector>
@@ -187,6 +185,14 @@ struct MapNode
param2 = p;
}
+ /*!
+ * Returns the color of the node.
+ *
+ * \param f content features of this node
+ * \param color output, contains the node's color.
+ */
+ void getColor(const ContentFeatures &f, video::SColor *color) const;
+
void setLight(enum LightBank bank, u8 a_light, const ContentFeatures &f);
void setLight(enum LightBank bank, u8 a_light, INodeDefManager *nodemgr);
diff --git a/src/mesh.cpp b/src/mesh.cpp
index 50465748c..84689b631 100644
--- a/src/mesh.cpp
+++ b/src/mesh.cpp
@@ -33,13 +33,25 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define MY_ETLM_READ_ONLY video::ETLM_READ_ONLY
#endif
-static void applyFacesShading(video::SColor& color, float factor)
+inline static void applyShadeFactor(video::SColor& color, float factor)
{
color.setRed(core::clamp(core::round32(color.getRed()*factor), 0, 255));
color.setGreen(core::clamp(core::round32(color.getGreen()*factor), 0, 255));
color.setBlue(core::clamp(core::round32(color.getBlue()*factor), 0, 255));
}
+void applyFacesShading(video::SColor &color, const v3f &normal)
+{
+ // Many special drawtypes have normals set to 0,0,0 and this
+ // must result in maximum brightness (no face shadng).
+ if (normal.Y < -0.5f)
+ applyShadeFactor (color, 0.447213f);
+ else if (normal.X > 0.5f || normal.X < -0.5f)
+ applyShadeFactor (color, 0.670820f);
+ else if (normal.Z > 0.5f || normal.Z < -0.5f)
+ applyShadeFactor (color, 0.836660f);
+}
+
scene::IAnimatedMesh* createCubeMesh(v3f scale)
{
video::SColor c(255,255,255,255);
@@ -172,29 +184,18 @@ void setMeshColor(scene::IMesh *mesh, const video::SColor &color)
}
}
-void shadeMeshFaces(scene::IMesh *mesh)
+void colorizeMeshBuffer(scene::IMeshBuffer *buf, const video::SColor *buffercolor)
{
- if (mesh == NULL)
- return;
-
- u32 mc = mesh->getMeshBufferCount();
- for (u32 j = 0; j < mc; j++) {
- scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
- const u32 stride = getVertexPitchFromType(buf->getVertexType());
- u32 vertex_count = buf->getVertexCount();
- u8 *vertices = (u8 *)buf->getVertices();
- for (u32 i = 0; i < vertex_count; i++) {
- video::S3DVertex *vertex = (video::S3DVertex *)(vertices + i * stride);
- video::SColor &vc = vertex->Color;
- // Many special drawtypes have normals set to 0,0,0 and this
- // must result in maximum brightness (no face shadng).
- if (vertex->Normal.Y < -0.5f)
- applyFacesShading (vc, 0.447213f);
- else if (vertex->Normal.X > 0.5f || vertex->Normal.X < -0.5f)
- applyFacesShading (vc, 0.670820f);
- else if (vertex->Normal.Z > 0.5f || vertex->Normal.Z < -0.5f)
- applyFacesShading (vc, 0.836660f);
- }
+ const u32 stride = getVertexPitchFromType(buf->getVertexType());
+ u32 vertex_count = buf->getVertexCount();
+ u8 *vertices = (u8 *) buf->getVertices();
+ for (u32 i = 0; i < vertex_count; i++) {
+ video::S3DVertex *vertex = (video::S3DVertex *) (vertices + i * stride);
+ video::SColor *vc = &(vertex->Color);
+ // Reset color
+ *vc = *buffercolor;
+ // Apply shading
+ applyFacesShading(*vc, vertex->Normal);
}
}
diff --git a/src/mesh.h b/src/mesh.h
index 10df97015..bcf0d771c 100644
--- a/src/mesh.h
+++ b/src/mesh.h
@@ -23,6 +23,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "irrlichttypes_extrabloated.h"
#include "nodedef.h"
+/*!
+ * Applies shading to a color based on the surface's
+ * normal vector.
+ */
+void applyFacesShading(video::SColor &color, const v3f &normal);
+
/*
Create a new cube mesh.
Vertices are at (+-scale.X/2, +-scale.Y/2, +-scale.Z/2).
@@ -48,11 +54,7 @@ void translateMesh(scene::IMesh *mesh, v3f vec);
*/
void setMeshColor(scene::IMesh *mesh, const video::SColor &color);
-/*
- Shade mesh faces according to their normals
-*/
-
-void shadeMeshFaces(scene::IMesh *mesh);
+void colorizeMeshBuffer(scene::IMeshBuffer *buf, const video::SColor *buffercolor);
/*
Set the color of all vertices in the mesh.
@@ -87,7 +89,7 @@ void rotateMeshYZby (scene::IMesh *mesh, f64 degrees);
scene::IMesh* cloneMesh(scene::IMesh *src_mesh);
/*
- Convert nodeboxes to mesh.
+ Convert nodeboxes to mesh. Each tile goes into a different buffer.
boxes - set of nodeboxes to be converted into cuboids
uv_coords[24] - table of texture uv coords for each cuboid face
expand - factor by which cuboids will be resized
diff --git a/src/minimap.cpp b/src/minimap.cpp
index f49adb517..a2e501751 100644
--- a/src/minimap.cpp
+++ b/src/minimap.cpp
@@ -144,7 +144,7 @@ MinimapPixel *MinimapUpdateThread::getMinimapPixel(v3s16 pos,
if (it != m_blocks_cache.end()) {
MinimapMapblock *mmblock = it->second;
MinimapPixel *pixel = &mmblock->data[relpos.Z * MAP_BLOCKSIZE + relpos.X];
- if (pixel->id != CONTENT_AIR) {
+ if (pixel->n.param0 != CONTENT_AIR) {
*pixel_height = height + pixel->height;
return pixel;
}
@@ -187,7 +187,7 @@ void MinimapUpdateThread::getMap(v3s16 pos, s16 size, s16 height, bool is_radar)
for (s16 x = 0; x < size; x++)
for (s16 z = 0; z < size; z++) {
- u16 id = CONTENT_AIR;
+ MapNode n(CONTENT_AIR);
MinimapPixel *mmpixel = &data->minimap_scan[x + z * size];
if (!is_radar) {
@@ -195,14 +195,14 @@ void MinimapUpdateThread::getMap(v3s16 pos, s16 size, s16 height, bool is_radar)
MinimapPixel *cached_pixel =
getMinimapPixel(v3s16(p.X + x, p.Y, p.Z + z), height, &pixel_height);
if (cached_pixel) {
- id = cached_pixel->id;
+ n = cached_pixel->n;
mmpixel->height = pixel_height;
}
} else {
mmpixel->air_count = getAirCount(v3s16(p.X + x, p.Y, p.Z + z), height);
}
- mmpixel->id = id;
+ mmpixel->n = n;
}
}
@@ -372,10 +372,21 @@ void Mapper::blitMinimapPixelsToImageSurface(
for (s16 z = 0; z < data->map_size; z++) {
MinimapPixel *mmpixel = &data->minimap_scan[x + z * data->map_size];
- video::SColor c = m_ndef->get(mmpixel->id).minimap_color;
- c.setAlpha(240);
-
- map_image->setPixel(x, data->map_size - z - 1, c);
+ const ContentFeatures &f = m_ndef->get(mmpixel->n);
+ const TileDef *tile = &f.tiledef[0];
+ // Color of the 0th tile (mostly this is the topmost)
+ video::SColor tilecolor;
+ if(tile->has_color)
+ tilecolor = tile->color;
+ else
+ mmpixel->n.getColor(f, &tilecolor);
+ tilecolor.setRed(tilecolor.getRed() * f.minimap_color.getRed() / 255);
+ tilecolor.setGreen(tilecolor.getGreen() * f.minimap_color.getGreen()
+ / 255);
+ tilecolor.setBlue(tilecolor.getBlue() * f.minimap_color.getBlue() / 255);
+ tilecolor.setAlpha(240);
+
+ map_image->setPixel(x, data->map_size - z - 1, tilecolor);
u32 h = mmpixel->height;
heightmap_image->setPixel(x,data->map_size - z - 1,
@@ -617,7 +628,7 @@ void MinimapMapblock::getMinimapNodes(VoxelManipulator *vmanip, v3s16 pos)
MapNode n = vmanip->getNodeNoEx(pos + p);
if (!surface_found && n.getContent() != CONTENT_AIR) {
mmpixel->height = y;
- mmpixel->id = n.getContent();
+ mmpixel->n = n;
surface_found = true;
} else if (n.getContent() == CONTENT_AIR) {
air_count++;
@@ -625,7 +636,7 @@ void MinimapMapblock::getMinimapNodes(VoxelManipulator *vmanip, v3s16 pos)
}
if (!surface_found)
- mmpixel->id = CONTENT_AIR;
+ mmpixel->n = MapNode(CONTENT_AIR);
mmpixel->air_count = air_count;
}
diff --git a/src/minimap.h b/src/minimap.h
index 743b2bff2..81ed0e49f 100644
--- a/src/minimap.h
+++ b/src/minimap.h
@@ -52,10 +52,10 @@ struct MinimapModeDef {
};
struct MinimapPixel {
- u16 id;
+ //! The topmost node that the minimap displays.
+ MapNode n;
u16 height;
u16 air_count;
- u16 light;
};
struct MinimapMapblock {
diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h
index 23c8a665b..a511d169b 100644
--- a/src/network/networkprotocol.h
+++ b/src/network/networkprotocol.h
@@ -143,9 +143,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
serialization of TileAnimation params changed
TAT_SHEET_2D
Removed client-sided chat perdiction
+ PROTOCOL VERSION 30:
+ New ContentFeatures serialization version
+ Add node and tile color and palette
*/
-#define LATEST_PROTOCOL_VERSION 29
+#define LATEST_PROTOCOL_VERSION 30
// Server's supported network protocol range
#define SERVER_PROTOCOL_VERSION_MIN 13
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index a4af26e87..98f795c7a 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -189,7 +189,9 @@ void NodeBox::deSerialize(std::istream &is)
void TileDef::serialize(std::ostream &os, u16 protocol_version) const
{
- if (protocol_version >= 29)
+ if (protocol_version >= 30)
+ writeU8(os, 4);
+ else if (protocol_version >= 29)
writeU8(os, 3);
else if (protocol_version >= 26)
writeU8(os, 2);
@@ -205,6 +207,14 @@ void TileDef::serialize(std::ostream &os, u16 protocol_version) const
writeU8(os, tileable_horizontal);
writeU8(os, tileable_vertical);
}
+ if (protocol_version >= 30) {
+ writeU8(os, has_color);
+ if (has_color) {
+ writeU8(os, color.getRed());
+ writeU8(os, color.getGreen());
+ writeU8(os, color.getBlue());
+ }
+ }
}
void TileDef::deSerialize(std::istream &is, const u8 contenfeatures_version, const NodeDrawType drawtype)
@@ -218,6 +228,14 @@ void TileDef::deSerialize(std::istream &is, const u8 contenfeatures_version, con
tileable_horizontal = readU8(is);
tileable_vertical = readU8(is);
}
+ if (version >= 4) {
+ has_color = readU8(is);
+ if (has_color) {
+ color.setRed(readU8(is));
+ color.setGreen(readU8(is));
+ color.setBlue(readU8(is));
+ }
+ }
if ((contenfeatures_version < 8) &&
((drawtype == NDT_MESH) ||
@@ -351,172 +369,222 @@ void ContentFeatures::reset()
connects_to.clear();
connects_to_ids.clear();
connect_sides = 0;
+ color = video::SColor(0xFFFFFFFF);
+ palette_name = "";
+ palette = NULL;
}
void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
{
- if(protocol_version < 24){
+ if (protocol_version < 30) {
serializeOld(os, protocol_version);
return;
}
- writeU8(os, protocol_version < 27 ? 7 : 8);
+ // version
+ writeU8(os, 9);
- os<<serializeString(name);
+ // general
+ os << serializeString(name);
writeU16(os, groups.size());
- for(ItemGroupList::const_iterator
- i = groups.begin(); i != groups.end(); ++i){
- os<<serializeString(i->first);
+ for (ItemGroupList::const_iterator i = groups.begin(); i != groups.end();
+ ++i) {
+ os << serializeString(i->first);
writeS16(os, i->second);
}
+ writeU8(os, param_type);
+ writeU8(os, param_type_2);
+
+ // visual
writeU8(os, drawtype);
+ os << serializeString(mesh);
writeF1000(os, visual_scale);
writeU8(os, 6);
- for(u32 i = 0; i < 6; i++)
+ for (u32 i = 0; i < 6; i++)
tiledef[i].serialize(os, protocol_version);
writeU8(os, CF_SPECIAL_COUNT);
- for(u32 i = 0; i < CF_SPECIAL_COUNT; i++){
+ for (u32 i = 0; i < CF_SPECIAL_COUNT; i++) {
tiledef_special[i].serialize(os, protocol_version);
}
writeU8(os, alpha);
+ writeU8(os, color.getRed());
+ writeU8(os, color.getGreen());
+ writeU8(os, color.getBlue());
+ os << serializeString(palette_name);
+ writeU8(os, waving);
+ writeU8(os, connect_sides);
+ writeU16(os, connects_to_ids.size());
+ for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
+ i != connects_to_ids.end(); ++i)
+ writeU16(os, *i);
writeU8(os, post_effect_color.getAlpha());
writeU8(os, post_effect_color.getRed());
writeU8(os, post_effect_color.getGreen());
writeU8(os, post_effect_color.getBlue());
- writeU8(os, param_type);
- if ((protocol_version < 28) && (param_type_2 == CPT2_MESHOPTIONS))
- writeU8(os, CPT2_NONE);
- else
- writeU8(os, param_type_2);
- writeU8(os, is_ground_content);
+ writeU8(os, leveled);
+
+ // lighting
writeU8(os, light_propagates);
writeU8(os, sunlight_propagates);
+ writeU8(os, light_source);
+
+ // map generation
+ writeU8(os, is_ground_content);
+
+ // interaction
writeU8(os, walkable);
writeU8(os, pointable);
writeU8(os, diggable);
writeU8(os, climbable);
writeU8(os, buildable_to);
- os<<serializeString(""); // legacy: used to be metadata_name
+ writeU8(os, rightclickable);
+ writeU32(os, damage_per_second);
+
+ // liquid
writeU8(os, liquid_type);
- os<<serializeString(liquid_alternative_flowing);
- os<<serializeString(liquid_alternative_source);
+ os << serializeString(liquid_alternative_flowing);
+ os << serializeString(liquid_alternative_source);
writeU8(os, liquid_viscosity);
writeU8(os, liquid_renewable);
- writeU8(os, light_source);
- writeU32(os, damage_per_second);
+ writeU8(os, liquid_range);
+ writeU8(os, drowning);
+ writeU8(os, floodable);
+
+ // node boxes
node_box.serialize(os, protocol_version);
selection_box.serialize(os, protocol_version);
- writeU8(os, legacy_facedir_simple);
- writeU8(os, legacy_wallmounted);
+ collision_box.serialize(os, protocol_version);
+
+ // sound
serializeSimpleSoundSpec(sound_footstep, os);
serializeSimpleSoundSpec(sound_dig, os);
serializeSimpleSoundSpec(sound_dug, os);
- writeU8(os, rightclickable);
- writeU8(os, drowning);
- writeU8(os, leveled);
- writeU8(os, liquid_range);
- writeU8(os, waving);
- // Stuff below should be moved to correct place in a version that otherwise changes
- // the protocol version
- os<<serializeString(mesh);
- collision_box.serialize(os, protocol_version);
- writeU8(os, floodable);
- writeU16(os, connects_to_ids.size());
- for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
- i != connects_to_ids.end(); ++i)
- writeU16(os, *i);
- writeU8(os, connect_sides);
+
+ // legacy
+ writeU8(os, legacy_facedir_simple);
+ writeU8(os, legacy_wallmounted);
+}
+
+void ContentFeatures::correctAlpha()
+{
+ if (alpha == 0 || alpha == 255)
+ return;
+
+ for (u32 i = 0; i < 6; i++) {
+ std::stringstream s;
+ s << tiledef[i].name << "^[noalpha^[opacity:" << ((int)alpha);
+ tiledef[i].name = s.str();
+ }
+
+ for (u32 i = 0; i < CF_SPECIAL_COUNT; i++) {
+ std::stringstream s;
+ s << tiledef_special[i].name << "^[noalpha^[opacity:" << ((int)alpha);
+ tiledef_special[i].name = s.str();
+ }
}
void ContentFeatures::deSerialize(std::istream &is)
{
+ // version detection
int version = readU8(is);
- if (version < 7) {
+ if (version < 9) {
deSerializeOld(is, version);
return;
- } else if (version > 8) {
+ } else if (version > 9) {
throw SerializationError("unsupported ContentFeatures version");
}
+ // general
name = deSerializeString(is);
groups.clear();
u32 groups_size = readU16(is);
- for(u32 i = 0; i < groups_size; i++){
+ for (u32 i = 0; i < groups_size; i++) {
std::string name = deSerializeString(is);
int value = readS16(is);
groups[name] = value;
}
- drawtype = (enum NodeDrawType)readU8(is);
+ param_type = (enum ContentParamType) readU8(is);
+ param_type_2 = (enum ContentParamType2) readU8(is);
+ // visual
+ drawtype = (enum NodeDrawType) readU8(is);
+ mesh = deSerializeString(is);
visual_scale = readF1000(is);
- if(readU8(is) != 6)
+ if (readU8(is) != 6)
throw SerializationError("unsupported tile count");
- for(u32 i = 0; i < 6; i++)
+ for (u32 i = 0; i < 6; i++)
tiledef[i].deSerialize(is, version, drawtype);
- if(readU8(is) != CF_SPECIAL_COUNT)
+ if (readU8(is) != CF_SPECIAL_COUNT)
throw SerializationError("unsupported CF_SPECIAL_COUNT");
- for(u32 i = 0; i < CF_SPECIAL_COUNT; i++)
+ for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
tiledef_special[i].deSerialize(is, version, drawtype);
alpha = readU8(is);
+ color.setRed(readU8(is));
+ color.setGreen(readU8(is));
+ color.setBlue(readU8(is));
+ palette_name = deSerializeString(is);
+ waving = readU8(is);
+ connect_sides = readU8(is);
+ u16 connects_to_size = readU16(is);
+ connects_to_ids.clear();
+ for (u16 i = 0; i < connects_to_size; i++)
+ connects_to_ids.insert(readU16(is));
post_effect_color.setAlpha(readU8(is));
post_effect_color.setRed(readU8(is));
post_effect_color.setGreen(readU8(is));
post_effect_color.setBlue(readU8(is));
- param_type = (enum ContentParamType)readU8(is);
- param_type_2 = (enum ContentParamType2)readU8(is);
- is_ground_content = readU8(is);
+ leveled = readU8(is);
+
+ // lighting-related
light_propagates = readU8(is);
sunlight_propagates = readU8(is);
+ light_source = readU8(is);
+ light_source = MYMIN(light_source, LIGHT_MAX);
+
+ // map generation
+ is_ground_content = readU8(is);
+
+ // interaction
walkable = readU8(is);
pointable = readU8(is);
diggable = readU8(is);
climbable = readU8(is);
buildable_to = readU8(is);
- deSerializeString(is); // legacy: used to be metadata_name
- liquid_type = (enum LiquidType)readU8(is);
+ rightclickable = readU8(is);
+ damage_per_second = readU32(is);
+
+ // liquid
+ liquid_type = (enum LiquidType) readU8(is);
liquid_alternative_flowing = deSerializeString(is);
liquid_alternative_source = deSerializeString(is);
liquid_viscosity = readU8(is);
liquid_renewable = readU8(is);
- light_source = readU8(is);
- light_source = MYMIN(light_source, LIGHT_MAX);
- damage_per_second = readU32(is);
+ liquid_range = readU8(is);
+ drowning = readU8(is);
+ floodable = readU8(is);
+
+ // node boxes
node_box.deSerialize(is);
selection_box.deSerialize(is);
- legacy_facedir_simple = readU8(is);
- legacy_wallmounted = readU8(is);
+ collision_box.deSerialize(is);
+
+ // sounds
deSerializeSimpleSoundSpec(sound_footstep, is);
deSerializeSimpleSoundSpec(sound_dig, is);
deSerializeSimpleSoundSpec(sound_dug, is);
- rightclickable = readU8(is);
- drowning = readU8(is);
- leveled = readU8(is);
- liquid_range = readU8(is);
- waving = readU8(is);
- // If you add anything here, insert it primarily inside the try-catch
- // block to not need to increase the version.
- try{
- // Stuff below should be moved to correct place in a version that
- // otherwise changes the protocol version
- mesh = deSerializeString(is);
- collision_box.deSerialize(is);
- floodable = readU8(is);
- u16 connects_to_size = readU16(is);
- connects_to_ids.clear();
- for (u16 i = 0; i < connects_to_size; i++)
- connects_to_ids.insert(readU16(is));
- connect_sides = readU8(is);
- }catch(SerializationError &e) {};
+
+ // read legacy properties
+ legacy_facedir_simple = readU8(is);
+ legacy_wallmounted = readU8(is);
}
#ifndef SERVER
void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
TileDef *tiledef, u32 shader_id, bool use_normal_texture,
- bool backface_culling, u8 alpha, u8 material_type)
+ bool backface_culling, u8 material_type)
{
tile->shader_id = shader_id;
tile->texture = tsrc->getTextureForMesh(tiledef->name, &tile->texture_id);
- tile->alpha = alpha;
tile->material_type = material_type;
// Normal texture and shader flags texture
@@ -536,6 +604,13 @@ void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile,
if (tiledef->tileable_vertical)
tile->material_flags |= MATERIAL_FLAG_TILEABLE_VERTICAL;
+ // Color
+ tile->has_color = tiledef->has_color;
+ if (tiledef->has_color)
+ tile->color = tiledef->color;
+ else
+ tile->color = color;
+
// Animation parameters
int frame_count = 1;
if (tile->material_flags & MATERIAL_FLAG_ANIMATION) {
@@ -681,6 +756,9 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
is_water_surface = true;
}
+ // Vertex alpha is no longer supported, correct if necessary.
+ correctAlpha();
+
u32 tile_shader[6];
for (u16 j = 0; j < 6; j++) {
tile_shader[j] = shdsrc->getShader("nodes_shader",
@@ -696,14 +774,14 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
for (u16 j = 0; j < 6; j++) {
fillTileAttribs(tsrc, &tiles[j], &tdef[j], tile_shader[j],
tsettings.use_normal_texture,
- tiledef[j].backface_culling, alpha, material_type);
+ tiledef[j].backface_culling, material_type);
}
// Special tiles (fill in f->special_tiles[])
for (u16 j = 0; j < CF_SPECIAL_COUNT; j++) {
fillTileAttribs(tsrc, &special_tiles[j], &tiledef_special[j],
tile_shader[j], tsettings.use_normal_texture,
- tiledef_special[j].backface_culling, alpha, material_type);
+ tiledef_special[j].backface_culling, material_type);
}
if ((drawtype == NDT_MESH) && (mesh != "")) {
@@ -731,15 +809,19 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
}
//Cache 6dfacedir and wallmounted rotated clones of meshes
- if (tsettings.enable_mesh_cache && mesh_ptr[0] && (param_type_2 == CPT2_FACEDIR)) {
+ if (tsettings.enable_mesh_cache && mesh_ptr[0] &&
+ (param_type_2 == CPT2_FACEDIR
+ || param_type_2 == CPT2_COLORED_FACEDIR)) {
for (u16 j = 1; j < 24; j++) {
mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
rotateMeshBy6dFacedir(mesh_ptr[j], j);
recalculateBoundingBox(mesh_ptr[j]);
meshmanip->recalculateNormals(mesh_ptr[j], true, false);
}
- } else if (tsettings.enable_mesh_cache && mesh_ptr[0] && (param_type_2 == CPT2_WALLMOUNTED)) {
- static const u8 wm_to_6d[6] = {20, 0, 16+1, 12+3, 8, 4+2};
+ } else if (tsettings.enable_mesh_cache && mesh_ptr[0]
+ && (param_type_2 == CPT2_WALLMOUNTED ||
+ param_type_2 == CPT2_COLORED_WALLMOUNTED)) {
+ static const u8 wm_to_6d[6] = { 20, 0, 16 + 1, 12 + 3, 8, 4 + 2 };
for (u16 j = 1; j < 6; j++) {
mesh_ptr[j] = cloneMesh(mesh_ptr[0]);
rotateMeshBy6dFacedir(mesh_ptr[j], wm_to_6d[j]);
@@ -775,6 +857,9 @@ public:
virtual void removeNode(const std::string &name);
virtual void updateAliases(IItemDefManager *idef);
virtual void applyTextureOverrides(const std::string &override_filepath);
+ //! Returns a palette or NULL if not found. Only on client.
+ std::vector<video::SColor> *getPalette(const ContentFeatures &f,
+ const IGameDef *gamedef);
virtual void updateTextures(IGameDef *gamedef,
void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress),
void *progress_cbk_args);
@@ -823,6 +908,9 @@ private:
// Next possibly free id
content_t m_next_id;
+ // Maps image file names to loaded palettes.
+ UNORDERED_MAP<std::string, std::vector<video::SColor> > m_palettes;
+
// NodeResolvers to callback once node registration has ended
std::vector<NodeResolver *> m_pending_resolve_callbacks;
@@ -1062,7 +1150,8 @@ void getNodeBoxUnion(const NodeBox &nodebox, const ContentFeatures &features,
if (nodebox.type == NODEBOX_LEVELED) {
half_processed.MaxEdge.Y = +BS / 2;
}
- if (features.param_type_2 == CPT2_FACEDIR) {
+ if (features.param_type_2 == CPT2_FACEDIR ||
+ features.param_type_2 == CPT2_COLORED_FACEDIR) {
// Get maximal coordinate
f32 coords[] = {
fabsf(half_processed.MinEdge.X),
@@ -1309,6 +1398,78 @@ void CNodeDefManager::applyTextureOverrides(const std::string &override_filepath
}
}
+std::vector<video::SColor> *CNodeDefManager::getPalette(
+ const ContentFeatures &f, const IGameDef *gamedef)
+{
+#ifndef SERVER
+ // This works because colors always use the most significant bits
+ // of param2. If you add a new colored type which uses param2
+ // in a more advanced way, you should change this code, too.
+ u32 palette_pixels = 0;
+ switch (f.param_type_2) {
+ case CPT2_COLOR:
+ palette_pixels = 256;
+ break;
+ case CPT2_COLORED_FACEDIR:
+ palette_pixels = 8;
+ break;
+ case CPT2_COLORED_WALLMOUNTED:
+ palette_pixels = 32;
+ break;
+ default:
+ return NULL;
+ }
+ // This many param2 values will have the same color
+ u32 step = 256 / palette_pixels;
+ const std::string &name = f.palette_name;
+ if (name == "")
+ return NULL;
+ Client *client = (Client *) gamedef;
+ ITextureSource *tsrc = client->tsrc();
+
+ UNORDERED_MAP<std::string, std::vector<video::SColor> >::iterator it =
+ m_palettes.find(name);
+ if (it == m_palettes.end()) {
+ // Create palette
+ if (!tsrc->isKnownSourceImage(name)) {
+ warningstream << "CNodeDefManager::getPalette(): palette \"" << name
+ << "\" could not be loaded." << std::endl;
+ return NULL;
+ }
+ video::IImage *img = tsrc->generateImage(name);
+ std::vector<video::SColor> new_palette;
+ u32 w = img->getDimension().Width;
+ u32 h = img->getDimension().Height;
+ // Real area of the image
+ u32 area = h * w;
+ if (area != palette_pixels)
+ warningstream << "CNodeDefManager::getPalette(): the "
+ << "specified palette image \"" << name << "\" does not "
+ << "contain exactly " << palette_pixels
+ << " pixels." << std::endl;
+ if (area > palette_pixels)
+ area = palette_pixels;
+ // For each pixel in the image
+ for (u32 i = 0; i < area; i++) {
+ video::SColor c = img->getPixel(i % w, i / w);
+ // Fill in palette with 'step' colors
+ for (u32 j = 0; j < step; j++)
+ new_palette.push_back(c);
+ }
+ img->drop();
+ // Fill in remaining elements
+ while (new_palette.size() < 256)
+ new_palette.push_back(video::SColor(0xFFFFFFFF));
+ m_palettes[name] = new_palette;
+ it = m_palettes.find(name);
+ }
+ if (it != m_palettes.end())
+ return &((*it).second);
+
+#endif
+ return NULL;
+}
+
void CNodeDefManager::updateTextures(IGameDef *gamedef,
void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
void *progress_callback_args)
@@ -1325,10 +1486,13 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef,
TextureSettings tsettings;
tsettings.readSettings();
+ m_palettes.clear();
u32 size = m_content_features.size();
for (u32 i = 0; i < size; i++) {
- m_content_features[i].updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
+ ContentFeatures *f = &(m_content_features[i]);
+ f->palette = getPalette(*f, gamedef);
+ f->updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
progress_callback(progress_callback_args, i, size);
}
#endif
@@ -1429,6 +1593,19 @@ IWritableNodeDefManager *createNodeDefManager()
//// Serialization of old ContentFeatures formats
void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
{
+ u8 compatible_param_type_2 = param_type_2;
+ if ((protocol_version < 28)
+ && (compatible_param_type_2 == CPT2_MESHOPTIONS))
+ compatible_param_type_2 = CPT2_NONE;
+ else if (protocol_version < 30) {
+ if (compatible_param_type_2 == CPT2_COLOR)
+ compatible_param_type_2 = CPT2_NONE;
+ else if (compatible_param_type_2 == CPT2_COLORED_FACEDIR)
+ compatible_param_type_2 = CPT2_FACEDIR;
+ else if (compatible_param_type_2 == CPT2_COLORED_WALLMOUNTED)
+ compatible_param_type_2 = CPT2_WALLMOUNTED;
+ }
+
if (protocol_version == 13)
{
writeU8(os, 5); // version
@@ -1454,7 +1631,7 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
writeU8(os, post_effect_color.getGreen());
writeU8(os, post_effect_color.getBlue());
writeU8(os, param_type);
- writeU8(os, param_type_2);
+ writeU8(os, compatible_param_type_2);
writeU8(os, is_ground_content);
writeU8(os, light_propagates);
writeU8(os, sunlight_propagates);
@@ -1483,9 +1660,9 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
os<<serializeString(name);
writeU16(os, groups.size());
for (ItemGroupList::const_iterator
- i = groups.begin(); i != groups.end(); ++i) {
- os<<serializeString(i->first);
- writeS16(os, i->second);
+ i = groups.begin(); i != groups.end(); ++i) {
+ os<<serializeString(i->first);
+ writeS16(os, i->second);
}
writeU8(os, drawtype);
writeF1000(os, visual_scale);
@@ -1502,7 +1679,7 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
writeU8(os, post_effect_color.getGreen());
writeU8(os, post_effect_color.getBlue());
writeU8(os, param_type);
- writeU8(os, param_type_2);
+ writeU8(os, compatible_param_type_2);
writeU8(os, is_ground_content);
writeU8(os, light_propagates);
writeU8(os, sunlight_propagates);
@@ -1530,6 +1707,68 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const
writeU8(os, drowning);
writeU8(os, leveled);
writeU8(os, liquid_range);
+ }
+ else if(protocol_version >= 24 && protocol_version < 30) {
+ writeU8(os, protocol_version < 27 ? 7 : 8);
+
+ os << serializeString(name);
+ writeU16(os, groups.size());
+ for (ItemGroupList::const_iterator i = groups.begin();
+ i != groups.end(); ++i) {
+ os << serializeString(i->first);
+ writeS16(os, i->second);
+ }
+ writeU8(os, drawtype);
+ writeF1000(os, visual_scale);
+ writeU8(os, 6);
+ for (u32 i = 0; i < 6; i++)
+ tiledef[i].serialize(os, protocol_version);
+ writeU8(os, CF_SPECIAL_COUNT);
+ for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
+ tiledef_special[i].serialize(os, protocol_version);
+ writeU8(os, alpha);
+ writeU8(os, post_effect_color.getAlpha());
+ writeU8(os, post_effect_color.getRed());
+ writeU8(os, post_effect_color.getGreen());
+ writeU8(os, post_effect_color.getBlue());
+ writeU8(os, param_type);
+ writeU8(os, compatible_param_type_2);
+ writeU8(os, is_ground_content);
+ writeU8(os, light_propagates);
+ writeU8(os, sunlight_propagates);
+ writeU8(os, walkable);
+ writeU8(os, pointable);
+ writeU8(os, diggable);
+ writeU8(os, climbable);
+ writeU8(os, buildable_to);
+ os << serializeString(""); // legacy: used to be metadata_name
+ writeU8(os, liquid_type);
+ os << serializeString(liquid_alternative_flowing);
+ os << serializeString(liquid_alternative_source);
+ writeU8(os, liquid_viscosity);
+ writeU8(os, liquid_renewable);
+ writeU8(os, light_source);
+ writeU32(os, damage_per_second);
+ node_box.serialize(os, protocol_version);
+ selection_box.serialize(os, protocol_version);
+ writeU8(os, legacy_facedir_simple);
+ writeU8(os, legacy_wallmounted);
+ serializeSimpleSoundSpec(sound_footstep, os);
+ serializeSimpleSoundSpec(sound_dig, os);
+ serializeSimpleSoundSpec(sound_dug, os);
+ writeU8(os, rightclickable);
+ writeU8(os, drowning);
+ writeU8(os, leveled);
+ writeU8(os, liquid_range);
+ writeU8(os, waving);
+ os << serializeString(mesh);
+ collision_box.serialize(os, protocol_version);
+ writeU8(os, floodable);
+ writeU16(os, connects_to_ids.size());
+ for (std::set<content_t>::const_iterator i = connects_to_ids.begin();
+ i != connects_to_ids.end(); ++i)
+ writeU16(os, *i);
+ writeU8(os, connect_sides);
} else
throw SerializationError("ContentFeatures::serialize(): "
"Unsupported version requested");
@@ -1642,7 +1881,73 @@ void ContentFeatures::deSerializeOld(std::istream &is, int version)
drowning = readU8(is);
leveled = readU8(is);
liquid_range = readU8(is);
- } else {
+ } else if (version == 7 || version == 8){
+ name = deSerializeString(is);
+ groups.clear();
+ u32 groups_size = readU16(is);
+ for (u32 i = 0; i < groups_size; i++) {
+ std::string name = deSerializeString(is);
+ int value = readS16(is);
+ groups[name] = value;
+ }
+ drawtype = (enum NodeDrawType) readU8(is);
+
+ visual_scale = readF1000(is);
+ if (readU8(is) != 6)
+ throw SerializationError("unsupported tile count");
+ for (u32 i = 0; i < 6; i++)
+ tiledef[i].deSerialize(is, version, drawtype);
+ if (readU8(is) != CF_SPECIAL_COUNT)
+ throw SerializationError("unsupported CF_SPECIAL_COUNT");
+ for (u32 i = 0; i < CF_SPECIAL_COUNT; i++)
+ tiledef_special[i].deSerialize(is, version, drawtype);
+ alpha = readU8(is);
+ post_effect_color.setAlpha(readU8(is));
+ post_effect_color.setRed(readU8(is));
+ post_effect_color.setGreen(readU8(is));
+ post_effect_color.setBlue(readU8(is));
+ param_type = (enum ContentParamType) readU8(is);
+ param_type_2 = (enum ContentParamType2) readU8(is);
+ is_ground_content = readU8(is);
+ light_propagates = readU8(is);
+ sunlight_propagates = readU8(is);
+ walkable = readU8(is);
+ pointable = readU8(is);
+ diggable = readU8(is);
+ climbable = readU8(is);
+ buildable_to = readU8(is);
+ deSerializeString(is); // legacy: used to be metadata_name
+ liquid_type = (enum LiquidType) readU8(is);
+ liquid_alternative_flowing = deSerializeString(is);
+ liquid_alternative_source = deSerializeString(is);
+ liquid_viscosity = readU8(is);
+ liquid_renewable = readU8(is);
+ light_source = readU8(is);
+ light_source = MYMIN(light_source, LIGHT_MAX);
+ damage_per_second = readU32(is);
+ node_box.deSerialize(is);
+ selection_box.deSerialize(is);
+ legacy_facedir_simple = readU8(is);
+ legacy_wallmounted = readU8(is);
+ deSerializeSimpleSoundSpec(sound_footstep, is);
+ deSerializeSimpleSoundSpec(sound_dig, is);
+ deSerializeSimpleSoundSpec(sound_dug, is);
+ rightclickable = readU8(is);
+ drowning = readU8(is);
+ leveled = readU8(is);
+ liquid_range = readU8(is);
+ waving = readU8(is);
+ try {
+ mesh = deSerializeString(is);
+ collision_box.deSerialize(is);
+ floodable = readU8(is);
+ u16 connects_to_size = readU16(is);
+ connects_to_ids.clear();
+ for (u16 i = 0; i < connects_to_size; i++)
+ connects_to_ids.insert(readU16(is));
+ connect_sides = readU8(is);
+ } catch (SerializationError &e) {};
+ }else{
throw SerializationError("unsupported ContentFeatures version");
}
}
@@ -1736,19 +2041,23 @@ bool CNodeDefManager::nodeboxConnects(MapNode from, MapNode to, u8 connect_face)
// does to node declare usable faces?
if (f2.connect_sides > 0) {
- if ((f2.param_type_2 == CPT2_FACEDIR) && (connect_face >= 4)) {
- static const u8 rot[33 * 4] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4 - back
- 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8 - right
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 16, 8, 4, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - front
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 32, 16, 8, 4 // 32 - left
- };
- return (f2.connect_sides & rot[(connect_face * 4) + to.param2]);
+ if ((f2.param_type_2 == CPT2_FACEDIR ||
+ f2.param_type_2 == CPT2_COLORED_FACEDIR)
+ && (connect_face >= 4)) {
+ static const u8 rot[33 * 4] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 4, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, // 4 - back
+ 8, 4, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, // 8 - right
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 8, 4, 32, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, // 16 - front
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 32, 16, 8, 4 // 32 - left
+ };
+ return (f2.connect_sides
+ & rot[(connect_face * 4) + (to.param2 & 0x1F)]);
}
return (f2.connect_sides & connect_face);
}
diff --git a/src/nodedef.h b/src/nodedef.h
index 183b95d87..6275b41ce 100644
--- a/src/nodedef.h
+++ b/src/nodedef.h
@@ -68,7 +68,13 @@ enum ContentParamType2
// 2D rotation for things like plants
CPT2_DEGROTATE,
// Mesh options for plants
- CPT2_MESHOPTIONS
+ CPT2_MESHOPTIONS,
+ // Index for palette
+ CPT2_COLOR,
+ // 3 bits of palette index, then facedir
+ CPT2_COLORED_FACEDIR,
+ // 5 bits of palette index, then wallmounted
+ CPT2_COLORED_WALLMOUNTED
};
enum LiquidType
@@ -170,6 +176,11 @@ struct TileDef
bool backface_culling; // Takes effect only in special cases
bool tileable_horizontal;
bool tileable_vertical;
+ //! If true, the tile has its own color.
+ bool has_color;
+ //! The color of the tile.
+ video::SColor color;
+
struct TileAnimationParams animation;
TileDef()
@@ -178,6 +189,8 @@ struct TileDef
backface_culling = true;
tileable_horizontal = true;
tileable_vertical = true;
+ has_color = false;
+ color = video::SColor(0xFFFFFFFF);
animation.type = TAT_NONE;
}
@@ -191,7 +204,7 @@ struct ContentFeatures
{
/*
Cached stuff
- */
+ */
#ifndef SERVER
// 0 1 2 3 4 5
// up down right left back front
@@ -211,12 +224,19 @@ struct ContentFeatures
/*
Actual data
- */
+ */
+
+ // --- GENERAL PROPERTIES ---
std::string name; // "" = undefined node
ItemGroupList groups; // Same as in itemdef
+ // Type of MapNode::param1
+ ContentParamType param_type;
+ // Type of MapNode::param2
+ ContentParamType2 param_type_2;
+
+ // --- VISUAL PROPERTIES ---
- // Visual definition
enum NodeDrawType drawtype;
std::string mesh;
#ifndef SERVER
@@ -226,19 +246,38 @@ struct ContentFeatures
float visual_scale; // Misc. scale parameter
TileDef tiledef[6];
TileDef tiledef_special[CF_SPECIAL_COUNT]; // eg. flowing liquid
+ // If 255, the node is opaque.
+ // Otherwise it uses texture alpha.
u8 alpha;
-
+ // The color of the node.
+ video::SColor color;
+ std::string palette_name;
+ std::vector<video::SColor> *palette;
+ // Used for waving leaves/plants
+ u8 waving;
+ // for NDT_CONNECTED pairing
+ u8 connect_sides;
+ std::vector<std::string> connects_to;
+ std::set<content_t> connects_to_ids;
// Post effect color, drawn when the camera is inside the node.
video::SColor post_effect_color;
+ // Flowing liquid or snow, value = default level
+ u8 leveled;
+
+ // --- LIGHTING-RELATED ---
- // Type of MapNode::param1
- ContentParamType param_type;
- // Type of MapNode::param2
- ContentParamType2 param_type_2;
- // True for all ground-like things like stone and mud, false for eg. trees
- bool is_ground_content;
bool light_propagates;
bool sunlight_propagates;
+ // Amount of light the node emits
+ u8 light_source;
+
+ // --- MAP GENERATION ---
+
+ // True for all ground-like things like stone and mud, false for eg. trees
+ bool is_ground_content;
+
+ // --- INTERACTION PROPERTIES ---
+
// This is used for collision detection.
// Also for general solidness queries.
bool walkable;
@@ -250,12 +289,12 @@ struct ContentFeatures
bool climbable;
// Player can build on these
bool buildable_to;
- // Liquids flow into and replace node
- bool floodable;
// Player cannot build to these (placement prediction disabled)
bool rightclickable;
- // Flowing liquid or snow, value = default level
- u8 leveled;
+ u32 damage_per_second;
+
+ // --- LIQUID PROPERTIES ---
+
// Whether the node is non-liquid, source liquid or flowing liquid
enum LiquidType liquid_type;
// If the content is liquid, this is the flowing version of the liquid.
@@ -271,29 +310,28 @@ struct ContentFeatures
// Number of flowing liquids surrounding source
u8 liquid_range;
u8 drowning;
- // Amount of light the node emits
- u8 light_source;
- u32 damage_per_second;
+ // Liquids flow into and replace node
+ bool floodable;
+
+ // --- NODEBOXES ---
+
NodeBox node_box;
NodeBox selection_box;
NodeBox collision_box;
- // Used for waving leaves/plants
- u8 waving;
- // Compatibility with old maps
- // Set to true if paramtype used to be 'facedir_simple'
- bool legacy_facedir_simple;
- // Set to true if wall_mounted used to be set to true
- bool legacy_wallmounted;
- // for NDT_CONNECTED pairing
- u8 connect_sides;
- // Sound properties
+ // --- SOUND PROPERTIES ---
+
SimpleSoundSpec sound_footstep;
SimpleSoundSpec sound_dig;
SimpleSoundSpec sound_dug;
- std::vector<std::string> connects_to;
- std::set<content_t> connects_to_ids;
+ // --- LEGACY ---
+
+ // Compatibility with old maps
+ // Set to true if paramtype used to be 'facedir_simple'
+ bool legacy_facedir_simple;
+ // Set to true if wall_mounted used to be set to true
+ bool legacy_wallmounted;
/*
Methods
@@ -306,6 +344,14 @@ struct ContentFeatures
void deSerialize(std::istream &is);
void serializeOld(std::ostream &os, u16 protocol_version) const;
void deSerializeOld(std::istream &is, int version);
+ /*!
+ * Since vertex alpha is no lnger supported, this method
+ * adds instructions to the texture names to blend alpha there.
+ *
+ * tiledef, tiledef_special and alpha must be initialized
+ * before calling this.
+ */
+ void correctAlpha();
/*
Some handy methods
@@ -321,7 +367,7 @@ struct ContentFeatures
#ifndef SERVER
void fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, TileDef *tiledef,
u32 shader_id, bool use_normal_texture, bool backface_culling,
- u8 alpha, u8 material_type);
+ u8 material_type);
void updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc,
scene::IMeshManipulator *meshmanip, Client *client, const TextureSettings &tsettings);
#endif
diff --git a/src/particles.cpp b/src/particles.cpp
index 5f17763e0..e1f292fb6 100644
--- a/src/particles.cpp
+++ b/src/particles.cpp
@@ -56,7 +56,8 @@ Particle::Particle(
v2f texpos,
v2f texsize,
const struct TileAnimationParams &anim,
- u8 glow
+ u8 glow,
+ video::SColor color
):
scene::ISceneNode(smgr->getRootSceneNode(), smgr)
{
@@ -77,6 +78,10 @@ Particle::Particle(
m_animation_frame = 0;
m_animation_time = 0.0;
+ // Color
+ m_base_color = color;
+ m_color = color;
+
// Particle related
m_pos = pos;
m_velocity = velocity;
@@ -183,12 +188,15 @@ void Particle::updateLight()
else
light = blend_light(m_env->getDayNightRatio(), LIGHT_SUN, 0);
- m_light = decode_light(light + m_glow);
+ u8 m_light = decode_light(light + m_glow);
+ m_color.set(255,
+ m_light * m_base_color.getRed() / 255,
+ m_light * m_base_color.getGreen() / 255,
+ m_light * m_base_color.getBlue() / 255);
}
void Particle::updateVertices()
{
- video::SColor c(255, m_light, m_light, m_light);
f32 tx0, tx1, ty0, ty1;
if (m_animation.type != TAT_NONE) {
@@ -210,14 +218,14 @@ void Particle::updateVertices()
ty1 = m_texpos.Y + m_texsize.Y;
}
- m_vertices[0] = video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0,
- c, tx0, ty1);
- m_vertices[1] = video::S3DVertex(m_size/2,-m_size/2,0, 0,0,0,
- c, tx1, ty1);
- m_vertices[2] = video::S3DVertex(m_size/2,m_size/2,0, 0,0,0,
- c, tx1, ty0);
- m_vertices[3] = video::S3DVertex(-m_size/2,m_size/2,0, 0,0,0,
- c, tx0, ty0);
+ m_vertices[0] = video::S3DVertex(-m_size / 2, -m_size / 2,
+ 0, 0, 0, 0, m_color, tx0, ty1);
+ m_vertices[1] = video::S3DVertex(m_size / 2, -m_size / 2,
+ 0, 0, 0, 0, m_color, tx1, ty1);
+ m_vertices[2] = video::S3DVertex(m_size / 2, m_size / 2,
+ 0, 0, 0, 0, m_color, tx1, ty0);
+ m_vertices[3] = video::S3DVertex(-m_size / 2, m_size / 2,
+ 0, 0, 0, 0, m_color, tx0, ty0);
v3s16 camera_offset = m_env->getCameraOffset();
for(u16 i=0; i<4; i++)
@@ -589,35 +597,39 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client,
}
}
-void ParticleManager::addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
- LocalPlayer *player, v3s16 pos, const TileSpec tiles[])
+void ParticleManager::addDiggingParticles(IGameDef* gamedef,
+ scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos,
+ const MapNode &n, const ContentFeatures &f)
{
for (u16 j = 0; j < 32; j++) // set the amount of particles here
{
- addNodeParticle(gamedef, smgr, player, pos, tiles);
+ addNodeParticle(gamedef, smgr, player, pos, n, f);
}
}
-void ParticleManager::addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
- LocalPlayer *player, v3s16 pos, const TileSpec tiles[])
+void ParticleManager::addPunchingParticles(IGameDef* gamedef,
+ scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos,
+ const MapNode &n, const ContentFeatures &f)
{
- addNodeParticle(gamedef, smgr, player, pos, tiles);
+ addNodeParticle(gamedef, smgr, player, pos, n, f);
}
-void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
- LocalPlayer *player, v3s16 pos, const TileSpec tiles[])
+void ParticleManager::addNodeParticle(IGameDef* gamedef,
+ scene::ISceneManager* smgr, LocalPlayer *player, v3s16 pos,
+ const MapNode &n, const ContentFeatures &f)
{
// Texture
u8 texid = myrand_range(0, 5);
+ const TileSpec &tile = f.tiles[texid];
video::ITexture *texture;
struct TileAnimationParams anim;
anim.type = TAT_NONE;
// Only use first frame of animated texture
- if (tiles[texid].material_flags & MATERIAL_FLAG_ANIMATION)
- texture = tiles[texid].frames[0].texture;
+ if (tile.material_flags & MATERIAL_FLAG_ANIMATION)
+ texture = tile.frames[0].texture;
else
- texture = tiles[texid].texture;
+ texture = tile.texture;
float size = rand() % 64 / 512.;
float visual_size = BS * size;
@@ -638,6 +650,12 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s
(f32) pos.Z + rand() %100 /200. - 0.25
);
+ video::SColor color;
+ if (tile.has_color)
+ color = tile.color;
+ else
+ n.getColor(f, &color);
+
Particle* toadd = new Particle(
gamedef,
smgr,
@@ -655,7 +673,8 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s
texpos,
texsize,
anim,
- 0);
+ 0,
+ color);
addParticle(toadd);
}
diff --git a/src/particles.h b/src/particles.h
index 5464e6672..3177f2cfd 100644
--- a/src/particles.h
+++ b/src/particles.h
@@ -32,6 +32,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
struct ClientEvent;
class ParticleManager;
class ClientEnvironment;
+class MapNode;
+class ContentFeatures;
class Particle : public scene::ISceneNode
{
@@ -53,7 +55,8 @@ class Particle : public scene::ISceneNode
v2f texpos,
v2f texsize,
const struct TileAnimationParams &anim,
- u8 glow
+ u8 glow,
+ video::SColor color = video::SColor(0xFFFFFFFF)
);
~Particle();
@@ -100,7 +103,10 @@ private:
v3f m_acceleration;
LocalPlayer *m_player;
float m_size;
- u8 m_light;
+ //! Color without lighting
+ video::SColor m_base_color;
+ //! Final rendered color
+ video::SColor m_color;
bool m_collisiondetection;
bool m_collision_removal;
bool m_vertical;
@@ -184,13 +190,16 @@ public:
scene::ISceneManager* smgr, LocalPlayer *player);
void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
- LocalPlayer *player, v3s16 pos, const TileSpec tiles[]);
+ LocalPlayer *player, v3s16 pos, const MapNode &n,
+ const ContentFeatures &f);
void addPunchingParticles(IGameDef* gamedef, scene::ISceneManager* smgr,
- LocalPlayer *player, v3s16 pos, const TileSpec tiles[]);
+ LocalPlayer *player, v3s16 pos, const MapNode &n,
+ const ContentFeatures &f);
void addNodeParticle(IGameDef* gamedef, scene::ISceneManager* smgr,
- LocalPlayer *player, v3s16 pos, const TileSpec tiles[]);
+ LocalPlayer *player, v3s16 pos, const MapNode &n,
+ const ContentFeatures &f);
protected:
void addParticle(Particle* toadd);
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index 84af4583b..ebc951295 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -332,6 +332,10 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype)
L, index, "tileable_horizontal", default_tiling);
tiledef.tileable_vertical = getboolfield_default(
L, index, "tileable_vertical", default_tiling);
+ // color = ...
+ lua_getfield(L, index, "color");
+ tiledef.has_color = read_color(L, -1, &tiledef.color);
+ lua_pop(L, 1);
// animation = {}
lua_getfield(L, index, "animation");
tiledef.animation = read_animation_definition(L, -1);
@@ -450,6 +454,13 @@ ContentFeatures read_content_features(lua_State *L, int index)
if (usealpha)
f.alpha = 0;
+ // Read node color.
+ lua_getfield(L, index, "color");
+ read_color(L, -1, &f.color);
+ lua_pop(L, 1);
+
+ getstringfield(L, index, "palette", f.palette_name);
+
/* Other stuff */
lua_getfield(L, index, "post_effect_color");
@@ -461,6 +472,13 @@ ContentFeatures read_content_features(lua_State *L, int index)
f.param_type_2 = (ContentParamType2)getenumfield(L, index, "paramtype2",
ScriptApiNode::es_ContentParamType2, CPT2_NONE);
+ if (f.palette_name != "" &&
+ !(f.param_type_2 == CPT2_COLOR ||
+ f.param_type_2 == CPT2_COLORED_FACEDIR ||
+ f.param_type_2 == CPT2_COLORED_WALLMOUNTED))
+ warningstream << "Node " << f.name.c_str()
+ << " has a palette, but not a suitable paramtype2." << std::endl;
+
// Warn about some deprecated fields
warn_if_field_exists(L, index, "wall_mounted",
"Deprecated; use paramtype2 = 'wallmounted'");
diff --git a/src/script/cpp_api/s_node.cpp b/src/script/cpp_api/s_node.cpp
index 379ed773f..23c8f43b9 100644
--- a/src/script/cpp_api/s_node.cpp
+++ b/src/script/cpp_api/s_node.cpp
@@ -59,6 +59,9 @@ struct EnumString ScriptApiNode::es_ContentParamType2[] =
{CPT2_LEVELED, "leveled"},
{CPT2_DEGROTATE, "degrotate"},
{CPT2_MESHOPTIONS, "meshoptions"},
+ {CPT2_COLOR, "color"},
+ {CPT2_COLORED_FACEDIR, "colorfacedir"},
+ {CPT2_COLORED_WALLMOUNTED, "colorwallmounted"},
{0, NULL},
};
diff --git a/src/shader.cpp b/src/shader.cpp
index c0ecf738d..79485025b 100644
--- a/src/shader.cpp
+++ b/src/shader.cpp
@@ -543,7 +543,7 @@ ShaderInfo generate_shader(std::string name, u8 material_type, u8 drawtype,
shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
break;
case TILE_MATERIAL_LIQUID_TRANSPARENT:
- shaderinfo.base_material = video::EMT_TRANSPARENT_VERTEX_ALPHA;
+ shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
break;
case TILE_MATERIAL_LIQUID_OPAQUE:
shaderinfo.base_material = video::EMT_SOLID;
diff --git a/src/wieldmesh.cpp b/src/wieldmesh.cpp
index c305238fe..089a67f33 100644
--- a/src/wieldmesh.cpp
+++ b/src/wieldmesh.cpp
@@ -318,6 +318,7 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client)
u32 shader_id = shdrsrc->getShader("wielded_shader", TILE_MATERIAL_BASIC, NDT_NORMAL);
m_material_type = shdrsrc->getShaderInfo(shader_id).material;
}
+ m_colors.clear();
// If wield_image is defined, it overrides everything else
if (def.wield_image != "") {
@@ -358,28 +359,30 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client)
material_count = 6;
}
for (u32 i = 0; i < material_count; ++i) {
+ const TileSpec *tile = &(f.tiles[i]);
video::SMaterial &material = m_meshnode->getMaterial(i);
material.setFlag(video::EMF_BACK_FACE_CULLING, true);
material.setFlag(video::EMF_BILINEAR_FILTER, m_bilinear_filter);
material.setFlag(video::EMF_TRILINEAR_FILTER, m_trilinear_filter);
- bool animated = (f.tiles[i].animation_frame_count > 1);
+ bool animated = (tile->animation_frame_count > 1);
if (animated) {
- FrameSpec animation_frame = f.tiles[i].frames[0];
+ FrameSpec animation_frame = tile->frames[0];
material.setTexture(0, animation_frame.texture);
} else {
- material.setTexture(0, f.tiles[i].texture);
+ material.setTexture(0, tile->texture);
}
+ m_colors.push_back(tile->color);
material.MaterialType = m_material_type;
if (m_enable_shaders) {
- if (f.tiles[i].normal_texture) {
+ if (tile->normal_texture) {
if (animated) {
- FrameSpec animation_frame = f.tiles[i].frames[0];
+ FrameSpec animation_frame = tile->frames[0];
material.setTexture(1, animation_frame.normal_texture);
} else {
- material.setTexture(1, f.tiles[i].normal_texture);
+ material.setTexture(1, tile->normal_texture);
}
}
- material.setTexture(2, f.tiles[i].flags_texture);
+ material.setTexture(2, tile->flags_texture);
}
}
return;
@@ -393,11 +396,28 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client)
changeToMesh(NULL);
}
-void WieldMeshSceneNode::setColor(video::SColor color)
+void WieldMeshSceneNode::setColor(video::SColor c)
{
assert(!m_lighting);
- setMeshColor(m_meshnode->getMesh(), color);
- shadeMeshFaces(m_meshnode->getMesh());
+ scene::IMesh *mesh=m_meshnode->getMesh();
+ if (mesh == NULL)
+ return;
+
+ u8 red = c.getRed();
+ u8 green = c.getGreen();
+ u8 blue = c.getBlue();
+ u32 mc = mesh->getMeshBufferCount();
+ for (u32 j = 0; j < mc; j++) {
+ video::SColor bc(0xFFFFFFFF);
+ if (m_colors.size() > j)
+ bc = m_colors[j];
+ video::SColor buffercolor(255,
+ bc.getRed() * red / 255,
+ bc.getGreen() * green / 255,
+ bc.getBlue() * blue / 255);
+ scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
+ colorizeMeshBuffer(buf, &buffercolor);
+ }
}
void WieldMeshSceneNode::render()
@@ -464,7 +484,6 @@ scene::IMesh *getItemMesh(Client *client, const ItemStack &item)
} else if (f.drawtype == NDT_PLANTLIKE) {
mesh = getExtrudedMesh(tsrc,
tsrc->getTextureName(f.tiles[0].texture_id));
- return mesh;
} else if (f.drawtype == NDT_NORMAL || f.drawtype == NDT_ALLFACES
|| f.drawtype == NDT_LIQUID || f.drawtype == NDT_FLOWINGLIQUID) {
mesh = cloneMesh(g_extrusion_mesh_cache->createCube());
@@ -477,8 +496,6 @@ scene::IMesh *getItemMesh(Client *client, const ItemStack &item)
mesh = cloneMesh(mapblock_mesh.getMesh());
translateMesh(mesh, v3f(-BS, -BS, -BS));
scaleMesh(mesh, v3f(0.12, 0.12, 0.12));
- rotateMeshXZby(mesh, -45);
- rotateMeshYZby(mesh, -30);
u32 mc = mesh->getMeshBufferCount();
for (u32 i = 0; i < mc; ++i) {
@@ -492,28 +509,29 @@ scene::IMesh *getItemMesh(Client *client, const ItemStack &item)
material1.setTexture(3, material2.getTexture(3));
material1.MaterialType = material2.MaterialType;
}
- return mesh;
}
- shadeMeshFaces(mesh);
- rotateMeshXZby(mesh, -45);
- rotateMeshYZby(mesh, -30);
-
u32 mc = mesh->getMeshBufferCount();
for (u32 i = 0; i < mc; ++i) {
- video::SMaterial &material = mesh->getMeshBuffer(i)->getMaterial();
+ const TileSpec *tile = &(f.tiles[i]);
+ scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
+ colorizeMeshBuffer(buf, &tile->color);
+ video::SMaterial &material = buf->getMaterial();
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
material.setFlag(video::EMF_BILINEAR_FILTER, false);
material.setFlag(video::EMF_TRILINEAR_FILTER, false);
material.setFlag(video::EMF_BACK_FACE_CULLING, true);
material.setFlag(video::EMF_LIGHTING, false);
- if (f.tiles[i].animation_frame_count > 1) {
- FrameSpec animation_frame = f.tiles[i].frames[0];
+ if (tile->animation_frame_count > 1) {
+ FrameSpec animation_frame = tile->frames[0];
material.setTexture(0, animation_frame.texture);
} else {
- material.setTexture(0, f.tiles[i].texture);
+ material.setTexture(0, tile->texture);
}
}
+
+ rotateMeshXZby(mesh, -45);
+ rotateMeshYZby(mesh, -30);
return mesh;
}
return NULL;
diff --git a/src/wieldmesh.h b/src/wieldmesh.h
index 0162c5e5a..2e78232ae 100644
--- a/src/wieldmesh.h
+++ b/src/wieldmesh.h
@@ -70,6 +70,11 @@ private:
bool m_anisotropic_filter;
bool m_bilinear_filter;
bool m_trilinear_filter;
+ /*!
+ * Stores the colors of the mesh's mesh buffers.
+ * This does not include lighting.
+ */
+ std::vector<video::SColor> m_colors;
// Bounding box culling is disabled for this type of scene node,
// so this variable is just required so we can implement