summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsfan5 <sfan5@live.de>2021-01-17 01:56:50 +0100
committersfan5 <sfan5@live.de>2021-01-29 17:34:41 +0100
commit83229921e5f378625d9ef63ede3dffbe778e1798 (patch)
tree8189436795cad017e2eb858b5d2cc23c16a55f46 /src
parentedd8c3c664ad005eb32e1968ce80091851ffb817 (diff)
downloadminetest-83229921e5f378625d9ef63ede3dffbe778e1798.tar.gz
minetest-83229921e5f378625d9ef63ede3dffbe778e1798.tar.bz2
minetest-83229921e5f378625d9ef63ede3dffbe778e1798.zip
Rework use_texture_alpha to provide three opaque/clip/blend modes
The change that turns nodeboxes and meshes opaque when possible is kept, as is the compatibility code that warns modders to adjust their nodedefs.
Diffstat (limited to 'src')
-rw-r--r--src/nodedef.cpp110
-rw-r--r--src/nodedef.h56
-rw-r--r--src/script/common/c_content.cpp32
-rw-r--r--src/script/cpp_api/s_node.cpp8
-rw-r--r--src/script/cpp_api/s_node.h1
-rw-r--r--src/unittest/test.cpp4
6 files changed, 149 insertions, 62 deletions
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index b2cfd1f87..57d4c008f 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -360,7 +360,7 @@ void ContentFeatures::reset()
i = TileDef();
for (auto &j : tiledef_special)
j = TileDef();
- alpha = 255;
+ alpha = ALPHAMODE_OPAQUE;
post_effect_color = video::SColor(0, 0, 0, 0);
param_type = CPT_NONE;
param_type_2 = CPT2_NONE;
@@ -405,6 +405,31 @@ void ContentFeatures::reset()
node_dig_prediction = "air";
}
+void ContentFeatures::setAlphaFromLegacy(u8 legacy_alpha)
+{
+ // No special handling for nodebox/mesh here as it doesn't make sense to
+ // throw warnings when the server is too old to support the "correct" way
+ switch (drawtype) {
+ case NDT_NORMAL:
+ alpha = legacy_alpha == 255 ? ALPHAMODE_OPAQUE : ALPHAMODE_CLIP;
+ break;
+ case NDT_LIQUID:
+ case NDT_FLOWINGLIQUID:
+ alpha = legacy_alpha == 255 ? ALPHAMODE_OPAQUE : ALPHAMODE_BLEND;
+ break;
+ default:
+ alpha = legacy_alpha == 255 ? ALPHAMODE_CLIP : ALPHAMODE_BLEND;
+ break;
+ }
+}
+
+u8 ContentFeatures::getAlphaForLegacy() const
+{
+ // This is so simple only because 255 and 0 mean wildly different things
+ // depending on drawtype...
+ return alpha == ALPHAMODE_OPAQUE ? 255 : 0;
+}
+
void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
{
const u8 version = CONTENTFEATURES_VERSION;
@@ -433,7 +458,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
for (const TileDef &td : tiledef_special) {
td.serialize(os, protocol_version);
}
- writeU8(os, alpha);
+ writeU8(os, getAlphaForLegacy());
writeU8(os, color.getRed());
writeU8(os, color.getGreen());
writeU8(os, color.getBlue());
@@ -489,6 +514,7 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
os << serializeString16(node_dig_prediction);
writeU8(os, leveled_max);
+ writeU8(os, alpha);
}
void ContentFeatures::deSerialize(std::istream &is)
@@ -524,7 +550,7 @@ void ContentFeatures::deSerialize(std::istream &is)
throw SerializationError("unsupported CF_SPECIAL_COUNT");
for (TileDef &td : tiledef_special)
td.deSerialize(is, version, drawtype);
- alpha = readU8(is);
+ setAlphaFromLegacy(readU8(is));
color.setRed(readU8(is));
color.setGreen(readU8(is));
color.setBlue(readU8(is));
@@ -582,10 +608,16 @@ void ContentFeatures::deSerialize(std::istream &is)
try {
node_dig_prediction = deSerializeString16(is);
- u8 tmp_leveled_max = readU8(is);
+
+ u8 tmp = readU8(is);
if (is.eof()) /* readU8 doesn't throw exceptions so we have to do this */
throw SerializationError("");
- leveled_max = tmp_leveled_max;
+ leveled_max = tmp;
+
+ tmp = readU8(is);
+ if (is.eof())
+ throw SerializationError("");
+ alpha = static_cast<enum AlphaMode>(tmp);
} catch(SerializationError &e) {};
}
@@ -677,6 +709,7 @@ bool ContentFeatures::textureAlphaCheck(ITextureSource *tsrc, const TileDef *til
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
static thread_local bool long_warning_printed = false;
std::set<std::string> seen;
+
for (int i = 0; i < length; i++) {
if (seen.find(tiles[i].name) != seen.end())
continue;
@@ -701,20 +734,21 @@ bool ContentFeatures::textureAlphaCheck(ITextureSource *tsrc, const TileDef *til
break_loop:
image->drop();
- if (!ok) {
- warningstream << "Texture \"" << tiles[i].name << "\" of "
- << name << " has transparent pixels, assuming "
- "use_texture_alpha = true." << std::endl;
- if (!long_warning_printed) {
- warningstream << " This warning can be a false-positive if "
- "unused pixels in the texture are transparent. However if "
- "it is meant to be transparent, you *MUST* update the "
- "nodedef and set use_texture_alpha = true! This compatibility "
- "code will be removed in a few releases." << std::endl;
- long_warning_printed = true;
- }
- return true;
+ if (ok)
+ continue;
+ warningstream << "Texture \"" << tiles[i].name << "\" of "
+ << name << " has transparency, assuming "
+ "use_texture_alpha = \"clip\"." << std::endl;
+ if (!long_warning_printed) {
+ warningstream << " This warning can be a false-positive if "
+ "unused pixels in the texture are transparent. However if "
+ "it is meant to be transparent, you *MUST* update the "
+ "nodedef and set use_texture_alpha = \"clip\"! This "
+ "compatibility code will be removed in a few releases."
+ << std::endl;
+ long_warning_printed = true;
}
+ return true;
}
return false;
}
@@ -759,14 +793,18 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
bool is_liquid = false;
- MaterialType material_type = (alpha == 255) ?
- TILE_MATERIAL_BASIC : TILE_MATERIAL_ALPHA;
+ if (alpha == ALPHAMODE_LEGACY_COMPAT) {
+ // Before working with the alpha mode, resolve any legacy kludges
+ alpha = textureAlphaCheck(tsrc, tdef, 6) ? ALPHAMODE_CLIP : ALPHAMODE_OPAQUE;
+ }
+
+ MaterialType material_type = alpha == ALPHAMODE_OPAQUE ?
+ TILE_MATERIAL_OPAQUE : (alpha == ALPHAMODE_CLIP ? TILE_MATERIAL_BASIC :
+ TILE_MATERIAL_ALPHA);
switch (drawtype) {
default:
case NDT_NORMAL:
- material_type = (alpha == 255) ?
- TILE_MATERIAL_OPAQUE : TILE_MATERIAL_ALPHA;
solidness = 2;
break;
case NDT_AIRLIKE:
@@ -774,14 +812,14 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
break;
case NDT_LIQUID:
if (tsettings.opaque_water)
- alpha = 255;
+ alpha = ALPHAMODE_OPAQUE;
solidness = 1;
is_liquid = true;
break;
case NDT_FLOWINGLIQUID:
solidness = 0;
if (tsettings.opaque_water)
- alpha = 255;
+ alpha = ALPHAMODE_OPAQUE;
is_liquid = true;
break;
case NDT_GLASSLIKE:
@@ -833,19 +871,16 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
break;
case NDT_MESH:
case NDT_NODEBOX:
- if (alpha == 255 && textureAlphaCheck(tsrc, tdef, 6))
- alpha = 0;
-
solidness = 0;
- if (waving == 1)
+ if (waving == 1) {
material_type = TILE_MATERIAL_WAVING_PLANTS;
- else if (waving == 2)
+ } else if (waving == 2) {
material_type = TILE_MATERIAL_WAVING_LEAVES;
- else if (waving == 3)
- material_type = (alpha == 255) ? TILE_MATERIAL_WAVING_LIQUID_OPAQUE :
- TILE_MATERIAL_WAVING_LIQUID_BASIC;
- else if (alpha == 255)
- material_type = TILE_MATERIAL_OPAQUE;
+ } else if (waving == 3) {
+ material_type = alpha == ALPHAMODE_OPAQUE ?
+ TILE_MATERIAL_WAVING_LIQUID_OPAQUE : (alpha == ALPHAMODE_CLIP ?
+ TILE_MATERIAL_WAVING_LIQUID_BASIC : TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT);
+ }
break;
case NDT_TORCHLIKE:
case NDT_SIGNLIKE:
@@ -860,10 +895,11 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
if (is_liquid) {
if (waving == 3) {
- material_type = (alpha == 255) ? TILE_MATERIAL_WAVING_LIQUID_OPAQUE :
- TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT;
+ material_type = alpha == ALPHAMODE_OPAQUE ?
+ TILE_MATERIAL_WAVING_LIQUID_OPAQUE : (alpha == ALPHAMODE_CLIP ?
+ TILE_MATERIAL_WAVING_LIQUID_BASIC : TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT);
} else {
- material_type = (alpha == 255) ? TILE_MATERIAL_LIQUID_OPAQUE :
+ material_type = alpha == ALPHAMODE_OPAQUE ? TILE_MATERIAL_LIQUID_OPAQUE :
TILE_MATERIAL_LIQUID_TRANSPARENT;
}
}
diff --git a/src/nodedef.h b/src/nodedef.h
index 63b9474b9..6fc20518d 100644
--- a/src/nodedef.h
+++ b/src/nodedef.h
@@ -231,6 +231,14 @@ enum AlignStyle : u8 {
ALIGN_STYLE_USER_DEFINED,
};
+enum AlphaMode : u8 {
+ ALPHAMODE_BLEND,
+ ALPHAMODE_CLIP,
+ ALPHAMODE_OPAQUE,
+ ALPHAMODE_LEGACY_COMPAT, /* means either opaque or clip */
+};
+
+
/*
Stand-alone definition of a TileSpec (basically a server-side TileSpec)
*/
@@ -315,9 +323,7 @@ struct ContentFeatures
// These will be drawn over the base tiles.
TileDef tiledef_overlay[6];
TileDef tiledef_special[CF_SPECIAL_COUNT]; // eg. flowing liquid
- // If 255, the node is opaque.
- // Otherwise it uses texture alpha.
- u8 alpha;
+ AlphaMode alpha;
// The color of the node.
video::SColor color;
std::string palette_name;
@@ -418,20 +424,27 @@ struct ContentFeatures
void serialize(std::ostream &os, u16 protocol_version) const;
void deSerialize(std::istream &is);
-#ifndef SERVER
- /*
- * Checks if any tile texture has any transparent pixels.
- * Prints a warning and returns true if that is the case, false otherwise.
- * This is supposed to be used for use_texture_alpha backwards compatibility.
- */
- bool textureAlphaCheck(ITextureSource *tsrc, const TileDef *tiles,
- int length);
-#endif
-
-
/*
Some handy methods
*/
+ void setDefaultAlphaMode()
+ {
+ switch (drawtype) {
+ case NDT_NORMAL:
+ case NDT_LIQUID:
+ case NDT_FLOWINGLIQUID:
+ alpha = ALPHAMODE_OPAQUE;
+ break;
+ case NDT_NODEBOX:
+ case NDT_MESH:
+ alpha = ALPHAMODE_LEGACY_COMPAT; // this should eventually be OPAQUE
+ break;
+ default:
+ alpha = ALPHAMODE_CLIP;
+ break;
+ }
+ }
+
bool needsBackfaceCulling() const
{
switch (drawtype) {
@@ -465,6 +478,21 @@ struct ContentFeatures
void updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc,
scene::IMeshManipulator *meshmanip, Client *client, const TextureSettings &tsettings);
#endif
+
+private:
+#ifndef SERVER
+ /*
+ * Checks if any tile texture has any transparent pixels.
+ * Prints a warning and returns true if that is the case, false otherwise.
+ * This is supposed to be used for use_texture_alpha backwards compatibility.
+ */
+ bool textureAlphaCheck(ITextureSource *tsrc, const TileDef *tiles,
+ int length);
+#endif
+
+ void setAlphaFromLegacy(u8 legacy_alpha);
+
+ u8 getAlphaForLegacy() const;
};
/*!
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index 5d29422af..ecab7baa1 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -618,25 +618,39 @@ void read_content_features(lua_State *L, ContentFeatures &f, int index)
}
lua_pop(L, 1);
+ /* alpha & use_texture_alpha */
+ // This is a bit complicated due to compatibility
+
+ f.setDefaultAlphaMode();
+
warn_if_field_exists(L, index, "alpha",
- "Obsolete, only limited compatibility provided");
+ "Obsolete, only limited compatibility provided; "
+ "replaced by \"use_texture_alpha\"");
if (getintfield_default(L, index, "alpha", 255) != 255)
- f.alpha = 0;
+ f.alpha = ALPHAMODE_BLEND;
+
+ lua_getfield(L, index, "use_texture_alpha");
+ if (lua_isboolean(L, -1)) {
+ warn_if_field_exists(L, index, "use_texture_alpha",
+ "Boolean values are deprecated; use the new choices");
+ if (lua_toboolean(L, -1))
+ f.alpha = (f.drawtype == NDT_NORMAL) ? ALPHAMODE_CLIP : ALPHAMODE_BLEND;
+ } else if (check_field_or_nil(L, -1, LUA_TSTRING, "use_texture_alpha")) {
+ int result = f.alpha;
+ string_to_enum(ScriptApiNode::es_TextureAlphaMode, result,
+ std::string(lua_tostring(L, -1)));
+ f.alpha = static_cast<enum AlphaMode>(result);
+ }
+ lua_pop(L, 1);
- bool usealpha = getboolfield_default(L, index,
- "use_texture_alpha", false);
- if (usealpha)
- f.alpha = 0;
+ /* Other stuff */
- // 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");
read_color(L, -1, &f.post_effect_color);
lua_pop(L, 1);
diff --git a/src/script/cpp_api/s_node.cpp b/src/script/cpp_api/s_node.cpp
index e0f9bcd78..269ebacb2 100644
--- a/src/script/cpp_api/s_node.cpp
+++ b/src/script/cpp_api/s_node.cpp
@@ -93,6 +93,14 @@ struct EnumString ScriptApiNode::es_NodeBoxType[] =
{0, NULL},
};
+struct EnumString ScriptApiNode::es_TextureAlphaMode[] =
+ {
+ {ALPHAMODE_OPAQUE, "opaque"},
+ {ALPHAMODE_CLIP, "clip"},
+ {ALPHAMODE_BLEND, "blend"},
+ {0, NULL},
+ };
+
bool ScriptApiNode::node_on_punch(v3s16 p, MapNode node,
ServerActiveObject *puncher, const PointedThing &pointed)
{
diff --git a/src/script/cpp_api/s_node.h b/src/script/cpp_api/s_node.h
index 81b44f0f0..3f771c838 100644
--- a/src/script/cpp_api/s_node.h
+++ b/src/script/cpp_api/s_node.h
@@ -54,4 +54,5 @@ public:
static struct EnumString es_ContentParamType2[];
static struct EnumString es_LiquidType[];
static struct EnumString es_NodeBoxType[];
+ static struct EnumString es_TextureAlphaMode[];
};
diff --git a/src/unittest/test.cpp b/src/unittest/test.cpp
index a783ccd32..af324e1b1 100644
--- a/src/unittest/test.cpp
+++ b/src/unittest/test.cpp
@@ -180,7 +180,7 @@ void TestGameDef::defineSomeNodes()
"{default_water.png";
f = ContentFeatures();
f.name = itemdef.name;
- f.alpha = 128;
+ f.alpha = ALPHAMODE_BLEND;
f.liquid_type = LIQUID_SOURCE;
f.liquid_viscosity = 4;
f.is_ground_content = true;
@@ -201,7 +201,7 @@ void TestGameDef::defineSomeNodes()
"{default_lava.png";
f = ContentFeatures();
f.name = itemdef.name;
- f.alpha = 128;
+ f.alpha = ALPHAMODE_OPAQUE;
f.liquid_type = LIQUID_SOURCE;
f.liquid_viscosity = 7;
f.light_source = LIGHT_MAX-1;