1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-07-02 16:38:41 +00:00

Add node texture variants

This commit is contained in:
Jude Melton-Houghton 2022-11-03 21:18:49 -04:00 committed by SFENCE
parent 81d62d01d1
commit e638072e15
29 changed files with 984 additions and 208 deletions

View file

@ -316,12 +316,16 @@ ContentFeatures::ContentFeatures()
ContentFeatures::~ContentFeatures()
{
#if CHECK_CLIENT_BUILD()
for (u16 j = 0; j < 6; j++) {
delete tiles[j].layers[0].frames;
delete tiles[j].layers[1].frames;
for (auto &t : tiles) {
for (u16 j = 0; j < 6; j++) {
delete t[j].layers[0].frames;
delete t[j].layers[1].frames;
}
}
for (auto &t : special_tiles) {
for (u16 j = 0; j < CF_SPECIAL_COUNT; j++)
delete t[j].layers[0].frames;
}
for (u16 j = 0; j < CF_SPECIAL_COUNT; j++)
delete special_tiles[j].layers[0].frames;
#endif
}
@ -331,6 +335,8 @@ void ContentFeatures::reset()
Cached stuff
*/
#if CHECK_CLIENT_BUILD()
tiles = std::vector<std::array<TileSpec, 6> >(1);
special_tiles = std::vector<std::array<TileSpec, CF_SPECIAL_COUNT> >(1);
solidness = 2;
visual_solidness = 0;
backface_culling = true;
@ -355,17 +361,18 @@ void ContentFeatures::reset()
mesh.clear();
#if CHECK_CLIENT_BUILD()
mesh_ptr = nullptr;
minimap_color = video::SColor(0, 0, 0, 0);
minimap_color = std::vector<video::SColor>(1, video::SColor(0, 0, 0, 0));
#endif
visual_scale = 1.0;
for (auto &i : tiledef)
i = TileDef();
for (auto &j : tiledef_special)
j = TileDef();
tiledef = std::vector<std::array<TileDef, 6> >(1);
tiledef_overlay = std::vector<std::array<TileDef, 6> >(1);
tiledef_special = std::vector<std::array<TileDef, CF_SPECIAL_COUNT> >(1);
alpha = ALPHAMODE_OPAQUE;
post_effect_color = video::SColor(0, 0, 0, 0);
param_type = CPT_NONE;
param_type_2 = CPT2_NONE;
variant_count = 1;
param2_variant = BitField<u8>();
is_ground_content = false;
light_propagates = false;
sunlight_propagates = false;
@ -457,12 +464,12 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
os << serializeString16(mesh);
writeF32(os, visual_scale);
writeU8(os, 6);
for (const TileDef &td : tiledef)
for (const TileDef &td : tiledef[0])
td.serialize(os, protocol_version);
for (const TileDef &td : tiledef_overlay)
for (const TileDef &td : tiledef_overlay[0])
td.serialize(os, protocol_version);
writeU8(os, CF_SPECIAL_COUNT);
for (const TileDef &td : tiledef_special) {
for (const TileDef &td : tiledef_special[0]) {
td.serialize(os, protocol_version);
}
writeU8(os, getAlphaForLegacy());
@ -535,6 +542,21 @@ void ContentFeatures::serialize(std::ostream &os, u16 protocol_version) const
writeU8(os, move_resistance);
writeU8(os, liquid_move_physics);
writeU8(os, post_effect_color_shaded);
writeU16(os, variant_count);
writeU8(os, param2_variant.getWidth());
writeU8(os, param2_variant.getOffset());
for (u16 v = 1; v < variant_count; v++) {
for (const TileDef &td : tiledef[v])
td.serialize(os, protocol_version);
}
for (u16 v = 1; v < variant_count; v++) {
for (const TileDef &td : tiledef_overlay[v])
td.serialize(os, protocol_version);
}
for (u16 v = 1; v < variant_count; v++) {
for (const TileDef &td : tiledef_special[v])
td.serialize(os, protocol_version);
}
}
void ContentFeatures::deSerialize(std::istream &is, u16 protocol_version)
@ -568,13 +590,13 @@ void ContentFeatures::deSerialize(std::istream &is, u16 protocol_version)
visual_scale = readF32(is);
if (readU8(is) != 6)
throw SerializationError("unsupported tile count");
for (TileDef &td : tiledef)
for (TileDef &td : tiledef[0])
td.deSerialize(is, drawtype, protocol_version);
for (TileDef &td : tiledef_overlay)
for (TileDef &td : tiledef_overlay[0])
td.deSerialize(is, drawtype, protocol_version);
if (readU8(is) != CF_SPECIAL_COUNT)
throw SerializationError("unsupported CF_SPECIAL_COUNT");
for (TileDef &td : tiledef_special)
for (TileDef &td : tiledef_special[0])
td.deSerialize(is, drawtype, protocol_version);
setAlphaFromLegacy(readU8(is));
color.setRed(readU8(is));
@ -665,6 +687,43 @@ void ContentFeatures::deSerialize(std::istream &is, u16 protocol_version)
if (is.eof())
throw SerializationError("");
post_effect_color_shaded = tmp;
u16 tmp_variant_count = readU16(is);
if (is.eof())
throw SerializationError("");
// Reserve space first for memory safety.
tiledef.reserve(variant_count);
tiledef_overlay.reserve(variant_count);
tiledef_special.reserve(variant_count);
for (u16 v = 1; v < tmp_variant_count; v++) {
tiledef.emplace_back();
tiledef_overlay.emplace_back();
tiledef_special.emplace_back();
}
variant_count = tmp_variant_count;
tmp = readU8(is);
u8 tmp2 = readU8(is);
if (is.eof())
throw SerializationError("");
param2_variant = BitField<u8>(tmp, tmp2);
for (u16 v = 1; v < variant_count; v++) {
for (TileDef &td : tiledef[v])
td.deSerialize(is, drawtype, protocol_version);
}
for (u16 v = 1; v < variant_count; v++) {
for (TileDef &td : tiledef_overlay[v])
td.deSerialize(is, drawtype, protocol_version);
}
for (u16 v = 1; v < variant_count; v++) {
for (TileDef &td : tiledef_special[v])
td.deSerialize(is, drawtype, protocol_version);
}
} catch (SerializationError &e) {};
}
@ -763,22 +822,27 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
scene::IMeshManipulator *meshmanip, Client *client, const TextureSettings &tsettings)
{
// Figure out the actual tiles to use
TileDef tdef[6];
for (u32 j = 0; j < 6; j++) {
tdef[j] = tiledef[j];
if (tdef[j].name.empty()) {
tdef[j].name = "no_texture.png";
tdef[j].backface_culling = false;
std::vector<std::array<TileDef, 6> > tdef(variant_count);
for (u16 v = 0; v < variant_count; v++) {
for (u32 j = 0; j < 6; j++) {
tdef[v][j] = tiledef[v][j];
if (tdef[v][j].name.empty()) {
tdef[v][j].name = "no_texture.png";
tdef[v][j].backface_culling = false;
}
}
}
// also the overlay tiles
TileDef tdef_overlay[6];
for (u32 j = 0; j < 6; j++)
tdef_overlay[j] = tiledef_overlay[j];
std::vector<std::array<TileDef, 6> > tdef_overlay(variant_count);
for (u16 v = 0; v < variant_count; v++) {
for (u32 j = 0; j < 6; j++)
tdef_overlay[v][j] = tiledef_overlay[v][j];
}
// also the special tiles
TileDef tdef_spec[6];
for (u32 j = 0; j < CF_SPECIAL_COUNT; j++) {
tdef_spec[j] = tiledef_special[j];
std::vector<std::array<TileDef, CF_SPECIAL_COUNT> > tdef_spec(variant_count);
for (u16 v = 0; v < variant_count; v++) {
for (u32 j = 0; j < CF_SPECIAL_COUNT; j++)
tdef_spec[v][j] = tiledef_special[v][j];
}
bool is_liquid = false;
@ -830,9 +894,11 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
solidness = 0;
visual_solidness = 1;
} else if (tsettings.leaves_style == LEAVES_SIMPLE) {
for (u32 j = 0; j < 6; j++) {
if (!tdef_spec[j].name.empty())
tdef[j].name = tdef_spec[j].name;
for (u16 v = 0; v < variant_count; v++) {
for (u32 j = 0; j < 6; j++) {
if (!tdef_spec[v][j].name.empty())
tdef[v][j].name = tdef_spec[v][j].name;
}
}
drawtype = NDT_GLASSLIKE;
solidness = 0;
@ -847,8 +913,10 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
drawtype = NDT_NORMAL;
solidness = 2;
}
for (TileDef &td : tdef)
td.name += std::string("^[noalpha");
for (u16 v = 0; v < variant_count; v++) {
for (TileDef &td : tdef[v])
td.name += std::string("^[noalpha");
}
}
if (waving >= 1)
material_type = TILE_MATERIAL_WAVING_LEAVES;
@ -907,34 +975,42 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
u32 overlay_shader = shdsrc->getShader("nodes_shader", overlay_material, drawtype);
// minimap pixel color = average color of top tile
if (tsettings.enable_minimap && !tdef[0].name.empty() && drawtype != NDT_AIRLIKE)
minimap_color = tsrc->getTextureAverageColor(tdef[0].name);
if (tsettings.enable_minimap && !tdef[0][0].name.empty() && drawtype != NDT_AIRLIKE) {
minimap_color = std::vector<video::SColor>(variant_count);
for (u16 v = 0; v < variant_count; v++) {
if (!tdef[v][0].name.empty())
minimap_color[v] = tsrc->getTextureAverageColor(tdef[v][0].name);
}
}
// Tiles (fill in f->tiles[])
bool any_polygon_offset = false;
for (u16 j = 0; j < 6; j++) {
tiles[j].world_aligned = isWorldAligned(tdef[j].align_style,
tsettings.world_aligned_mode, drawtype);
fillTileAttribs(tsrc, &tiles[j].layers[0], tiles[j], tdef[j],
color, material_type, tile_shader,
tdef[j].backface_culling, tsettings);
if (!tdef_overlay[j].name.empty())
fillTileAttribs(tsrc, &tiles[j].layers[1], tiles[j], tdef_overlay[j],
color, overlay_material, overlay_shader,
tdef[j].backface_culling, tsettings);
tiles = std::vector<std::array<TileSpec, 6> >(variant_count);
for (u16 v = 0; v < variant_count; v++) {
for (u16 j = 0; j < 6; j++) {
tiles[v][j].world_aligned = isWorldAligned(tdef[v][j].align_style,
tsettings.world_aligned_mode, drawtype);
fillTileAttribs(tsrc, &tiles[v][j].layers[0], tiles[v][j], tdef[v][j],
color, material_type, tile_shader,
tdef[v][j].backface_culling, tsettings);
if (!tdef_overlay[v][j].name.empty())
fillTileAttribs(tsrc, &tiles[v][j].layers[1], tiles[v][j], tdef_overlay[v][j],
color, overlay_material, overlay_shader,
tdef[v][j].backface_culling, tsettings);
tiles[j].layers[0].need_polygon_offset = !tiles[j].layers[1].empty();
any_polygon_offset |= tiles[j].layers[0].need_polygon_offset;
}
tiles[v][j].layers[0].need_polygon_offset = !tiles[v][j].layers[1].empty();
any_polygon_offset |= tiles[v][j].layers[0].need_polygon_offset;
}
if (drawtype == NDT_MESH && any_polygon_offset) {
// Our per-tile polygon offset enablement workaround works fine for normal
// nodes and anything else, where we know that different tiles are different
// faces that couldn't possibly conflict with each other.
// We can't assume this for mesh nodes, so apply it to all tiles (= materials)
// then.
for (u16 j = 0; j < 6; j++)
tiles[j].layers[0].need_polygon_offset = true;
if (drawtype == NDT_MESH && any_polygon_offset) {
// Our per-tile polygon offset enablement workaround works fine for normal
// nodes and anything else, where we know that different tiles are different
// faces that couldn't possibly conflict with each other.
// We can't assume this for mesh nodes, so apply it to all tiles (= materials)
// then.
for (u16 j = 0; j < 6; j++)
tiles[v][j].layers[0].need_polygon_offset = true;
}
}
MaterialType special_material = material_type;
@ -947,10 +1023,14 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
u32 special_shader = shdsrc->getShader("nodes_shader", special_material, drawtype);
// Special tiles (fill in f->special_tiles[])
for (u16 j = 0; j < CF_SPECIAL_COUNT; j++)
fillTileAttribs(tsrc, &special_tiles[j].layers[0], special_tiles[j], tdef_spec[j],
color, special_material, special_shader,
tdef_spec[j].backface_culling, tsettings);
special_tiles = std::vector<std::array<TileSpec, CF_SPECIAL_COUNT> >(variant_count);
for (u16 v = 0; v < variant_count; v++) {
for (u16 j = 0; j < CF_SPECIAL_COUNT; j++)
fillTileAttribs(tsrc,
&special_tiles[v][j].layers[0], special_tiles[v][j], tdef_spec[v][j],
color, special_material, special_shader,
tdef_spec[v][j].backface_culling, tsettings);
}
if (param_type_2 == CPT2_COLOR ||
param_type_2 == CPT2_COLORED_FACEDIR ||
@ -1043,7 +1123,7 @@ void NodeDefManager::clear()
ContentFeatures f;
f.name = "unknown";
for (int t = 0; t < 6; t++)
f.tiledef[t].name = "unknown_node.png";
f.tiledef[0][t].name = "unknown_node.png";
// Insert directly into containers
content_t c = CONTENT_UNKNOWN;
m_content_features[c] = f;
@ -1409,52 +1489,55 @@ void NodeDefManager::applyTextureOverrides(const std::vector<TextureOverride> &o
ContentFeatures &nodedef = m_content_features[id];
auto apply = [&] (TileDef &tile) {
tile.name = texture_override.texture;
if (texture_override.world_scale > 0) {
tile.align_style = ALIGN_STYLE_WORLD;
tile.scale = texture_override.world_scale;
// For now this works with tiledef_special since CF_SPECIAL_COUNT == 6.
auto apply = [&] (std::vector<std::array<TileDef, 6> > &tiledef, u32 i) {
for (u16 v = 0; v < nodedef.variant_count; v++) {
tiledef[v][i].name = texture_override.texture;
if (texture_override.world_scale > 0) {
tiledef[v][i].align_style = ALIGN_STYLE_WORLD;
tiledef[v][i].scale = texture_override.world_scale;
}
}
};
// Override tiles
if (texture_override.hasTarget(OverrideTarget::TOP))
apply(nodedef.tiledef[0]);
apply(nodedef.tiledef, 0);
if (texture_override.hasTarget(OverrideTarget::BOTTOM))
apply(nodedef.tiledef[1]);
apply(nodedef.tiledef, 1);
if (texture_override.hasTarget(OverrideTarget::RIGHT))
apply(nodedef.tiledef[2]);
apply(nodedef.tiledef, 2);
if (texture_override.hasTarget(OverrideTarget::LEFT))
apply(nodedef.tiledef[3]);
apply(nodedef.tiledef, 3);
if (texture_override.hasTarget(OverrideTarget::BACK))
apply(nodedef.tiledef[4]);
apply(nodedef.tiledef, 4);
if (texture_override.hasTarget(OverrideTarget::FRONT))
apply(nodedef.tiledef[5]);
apply(nodedef.tiledef, 5);
// Override special tiles, if applicable
if (texture_override.hasTarget(OverrideTarget::SPECIAL_1))
apply(nodedef.tiledef_special[0]);
apply(nodedef.tiledef_special, 0);
if (texture_override.hasTarget(OverrideTarget::SPECIAL_2))
apply(nodedef.tiledef_special[1]);
apply(nodedef.tiledef_special, 1);
if (texture_override.hasTarget(OverrideTarget::SPECIAL_3))
apply(nodedef.tiledef_special[2]);
apply(nodedef.tiledef_special, 2);
if (texture_override.hasTarget(OverrideTarget::SPECIAL_4))
apply(nodedef.tiledef_special[3]);
apply(nodedef.tiledef_special, 3);
if (texture_override.hasTarget(OverrideTarget::SPECIAL_5))
apply(nodedef.tiledef_special[4]);
apply(nodedef.tiledef_special, 4);
if (texture_override.hasTarget(OverrideTarget::SPECIAL_6))
apply(nodedef.tiledef_special[5]);
apply(nodedef.tiledef_special, 5);
}
}