mirror of
https://github.com/minetest/minetest.git
synced 2024-08-19 04:54:18 +02:00
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.
This commit is contained in:
parent
edd8c3c664
commit
83229921e5
@ -18,6 +18,7 @@ core.features = {
|
||||
pathfinder_works = true,
|
||||
object_step_has_moveresult = true,
|
||||
direct_velocity_on_players = true,
|
||||
use_texture_alpha_string_modes = true,
|
||||
}
|
||||
|
||||
function core.has_feature(arg)
|
||||
|
@ -4386,6 +4386,8 @@ Utilities
|
||||
object_step_has_moveresult = true,
|
||||
-- Whether get_velocity() and add_velocity() can be used on players (5.4.0)
|
||||
direct_velocity_on_players = true,
|
||||
-- nodedef's use_texture_alpha accepts new string modes (5.4.0)
|
||||
use_texture_alpha_string_modes = true,
|
||||
}
|
||||
|
||||
* `minetest.has_feature(arg)`: returns `boolean, missing_features`
|
||||
@ -7340,10 +7342,18 @@ Used by `minetest.register_node`.
|
||||
-- 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
|
||||
-- If this is set to false, the node will be rendered fully opaque
|
||||
-- regardless of any texture transparency.
|
||||
use_texture_alpha = ...,
|
||||
-- Specifies how the texture's alpha channel will be used for rendering.
|
||||
-- possible values:
|
||||
-- * "opaque": Node is rendered opaque regardless of alpha channel
|
||||
-- * "clip": A given pixel is either fully see-through or opaque
|
||||
-- depending on the alpha channel being below/above 50% in value
|
||||
-- * "blend": The alpha channel specifies how transparent a given pixel
|
||||
-- of the rendered node is
|
||||
-- The default is "opaque" for drawtypes normal, liquid and flowingliquid;
|
||||
-- "clip" otherwise.
|
||||
-- If set to a boolean value (deprecated): true either sets it to blend
|
||||
-- or clip, false sets it to clip or opaque mode depending on the drawtype.
|
||||
|
||||
palette = "palette.png",
|
||||
-- The node's `param2` is used to select a pixel from the image.
|
||||
|
110
src/nodedef.cpp
110
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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -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;
|
||||
|
||||
bool usealpha = getboolfield_default(L, index,
|
||||
"use_texture_alpha", false);
|
||||
if (usealpha)
|
||||
f.alpha = 0;
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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[];
|
||||
};
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user