diff options
author | sfan5 <sfan5@live.de> | 2021-01-17 01:56:50 +0100 |
---|---|---|
committer | sfan5 <sfan5@live.de> | 2021-01-29 17:34:41 +0100 |
commit | 83229921e5f378625d9ef63ede3dffbe778e1798 (patch) | |
tree | 8189436795cad017e2eb858b5d2cc23c16a55f46 /src | |
parent | edd8c3c664ad005eb32e1968ce80091851ffb817 (diff) | |
download | minetest-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.cpp | 110 | ||||
-rw-r--r-- | src/nodedef.h | 56 | ||||
-rw-r--r-- | src/script/common/c_content.cpp | 32 | ||||
-rw-r--r-- | src/script/cpp_api/s_node.cpp | 8 | ||||
-rw-r--r-- | src/script/cpp_api/s_node.h | 1 | ||||
-rw-r--r-- | src/unittest/test.cpp | 4 |
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; |