mirror of
https://github.com/minetest/minetest.git
synced 2024-08-18 20:44:16 +02:00
Add hardware node coloring. Includes:
- Increase ContentFeatures serialization version - Color property and palettes for nodes - paramtype2 = "color", "colored facedir" or "colored wallmounted"
This commit is contained in:
parent
43822de5c6
commit
d04d8aba70
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
uniform mat4 mWorldViewProj;
|
||||
uniform mat4 mWorld;
|
||||
|
||||
uniform float dayNightRatio;
|
||||
uniform vec3 eyePosition;
|
||||
uniform float animationTimer;
|
||||
|
||||
|
@ -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
|
||||
|
@ -378,9 +378,6 @@ public:
|
||||
video::ITexture* generateTextureFromMesh(
|
||||
const TextureFromMeshParams ¶ms);
|
||||
|
||||
// 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);
|
||||
|
@ -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 ¶ms)=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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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, ©.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();
|
||||
}
|
||||
|
30
src/game.cpp
30
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;
|
||||
|
@ -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)
|
||||
{
|
||||
s32 rg = (day * daynight_ratio + night * (1000-daynight_ratio)) / 1000;
|
||||
s32 b = rg;
|
||||
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;
|
||||
}
|
||||
|
||||
// Moonlight is blue
|
||||
b += (day - night) / 13;
|
||||
rg -= (day - night) / 23;
|
||||
void final_color_blend(video::SColor *result,
|
||||
u16 light, u32 daynight_ratio)
|
||||
{
|
||||
video::SColorf dayLight;
|
||||
get_sunlight_color(&dayLight, daynight_ratio);
|
||||
final_color_blend(result,
|
||||
encode_light_and_color(light, video::SColor(0xFFFFFFFF), 0), dayLight);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
47
src/mesh.cpp
47
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
14
src/mesh.h
14
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
|
||||
|
@ -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);
|
||||
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, c);
|
||||
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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
513
src/nodedef.cpp
513
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);
|
||||
}
|
||||
|
108
src/nodedef.h
108
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;
|
||||
|
||||
// --- SOUND PROPERTIES ---
|
||||
|
||||
SimpleSoundSpec sound_footstep;
|
||||
SimpleSoundSpec sound_dig;
|
||||
SimpleSoundSpec sound_dug;
|
||||
|
||||
// --- 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;
|
||||
// for NDT_CONNECTED pairing
|
||||
u8 connect_sides;
|
||||
|
||||
// Sound properties
|
||||
SimpleSoundSpec sound_footstep;
|
||||
SimpleSoundSpec sound_dig;
|
||||
SimpleSoundSpec sound_dug;
|
||||
|
||||
std::vector<std::string> connects_to;
|
||||
std::set<content_t> connects_to_ids;
|
||||
|
||||
/*
|
||||
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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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'");
|
||||
|
@ -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},
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user