From 9676364c1fe5fe5eae69c55e7d7a45392decfb2d Mon Sep 17 00:00:00 2001 From: Jude Melton-Houghton Date: Sun, 9 Oct 2022 10:50:26 -0400 Subject: [PATCH] Optimize lighting calculation (#12797) --- src/client/clientmap.cpp | 21 +++--- src/client/content_cso.cpp | 3 +- src/client/content_mapblock.cpp | 2 +- src/client/mapblock_mesh.cpp | 16 +++-- src/client/particles.cpp | 3 +- src/map.cpp | 21 +++--- src/mapblock.cpp | 2 +- src/mapgen/mapgen.cpp | 6 +- src/mapgen/mapgen_singlenode.cpp | 2 +- src/mapnode.cpp | 89 ------------------------ src/mapnode.h | 84 ++++++++++++++--------- src/nodedef.cpp | 6 ++ src/nodedef.h | 25 +++++-- src/script/lua_api/l_env.cpp | 2 +- src/unittest/test_mapnode.cpp | 5 +- src/unittest/test_voxelalgorithms.cpp | 20 +++--- src/voxel.cpp | 2 +- src/voxelalgorithms.cpp | 99 ++++++++++++++------------- 18 files changed, 188 insertions(+), 220 deletions(-) diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index 23234c365..b74499ac3 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -527,8 +527,8 @@ static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step, { v3s16 p = floatToInt(p0 /*+ dir * 3*BS*/, BS); MapNode n = map->getNode(p); - if(ndef->get(n).param_type == CPT_LIGHT && - !ndef->get(n).sunlight_propagates) + if(ndef->getLightingFlags(n).has_light && + !ndef->getLightingFlags(n).sunlight_propagates) allow_allowing_non_sunlight_propagates = true; } // If would start at CONTENT_IGNORE, start closer @@ -549,15 +549,13 @@ static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step, v3s16 p = floatToInt(pf, BS); MapNode n = map->getNode(p); + ContentLightingFlags f = ndef->getLightingFlags(n); if (allow_allowing_non_sunlight_propagates && i == 0 && - ndef->get(n).param_type == CPT_LIGHT && - !ndef->get(n).sunlight_propagates) { + f.has_light && !f.sunlight_propagates) { allow_non_sunlight_propagates = true; } - if (ndef->get(n).param_type != CPT_LIGHT || - (!ndef->get(n).sunlight_propagates && - !allow_non_sunlight_propagates)){ + if (!f.has_light || (!f.sunlight_propagates && !allow_non_sunlight_propagates)){ nonlight_seen = true; noncount++; if(noncount >= 4) @@ -566,10 +564,10 @@ static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step, } if (distance >= sunlight_min_d && !*sunlight_seen && !nonlight_seen) - if (n.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN) + if (n.getLight(LIGHTBANK_DAY, f) == LIGHT_SUN) *sunlight_seen = true; noncount = 0; - brightness_sum += decode_light(n.getLightBlend(daylight_factor, ndef)); + brightness_sum += decode_light(n.getLightBlend(daylight_factor, f)); brightness_count++; } *result = 0; @@ -653,8 +651,9 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor, int ret = 0; if(brightness_count == 0){ MapNode n = getNode(floatToInt(m_camera_position, BS)); - if(m_nodedef->get(n).param_type == CPT_LIGHT){ - ret = decode_light(n.getLightBlend(daylight_factor, m_nodedef)); + ContentLightingFlags f = m_nodedef->getLightingFlags(n); + if(f.has_light){ + ret = decode_light(n.getLightBlend(daylight_factor, f)); } else { ret = oldvalue; } diff --git a/src/client/content_cso.cpp b/src/client/content_cso.cpp index f9641afbe..50ae4e413 100644 --- a/src/client/content_cso.cpp +++ b/src/client/content_cso.cpp @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "clientenvironment.h" #include "client.h" #include "map.h" +#include "nodedef.h" class SmokePuffCSO: public ClientSimpleObject { @@ -50,7 +51,7 @@ public: bool pos_ok; MapNode n = env->getMap().getNode(floatToInt(pos, BS), &pos_ok); light = pos_ok ? decode_light(n.getLightBlend(env->getDayNightRatio(), - env->getGameDef()->ndef())) + env->getGameDef()->ndef()->getLightingFlags(n))) : 64; video::SColor color(255,light,light,light); m_spritenode->setColor(color); diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index 7fd5aefb1..a9abbceeb 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -472,7 +472,7 @@ void MapblockMeshGenerator::prepareLiquidNodeDrawing() // it at what it emits, for an increased effect u8 e = decode_light(f->light_source); light = LightPair(std::max(e, light.lightDay), std::max(e, light.lightNight)); - } else if (nodedef->get(ntop).param_type == CPT_LIGHT) { + } else if (nodedef->getLightingFlags(ntop).has_light) { // Otherwise, use the light of the node on top if possible light = LightPair(getInteriorLight(ntop, 0, nodedef)); } diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index 5036f8bd6..519932cd4 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -102,7 +102,7 @@ void MeshMakeData::setSmoothLighting(bool smooth_lighting) static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment, const NodeDefManager *ndef) { - u8 light = n.getLight(bank, ndef); + u8 light = n.getLight(bank, ndef->getLightingFlags(n)); if (light > 0) light = rangelim(light + increment, 0, LIGHT_SUN); return decode_light(light); @@ -126,17 +126,19 @@ u16 getInteriorLight(MapNode n, s32 increment, const NodeDefManager *ndef) static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2, v3s16 face_dir, const NodeDefManager *ndef) { + ContentLightingFlags f1 = ndef->getLightingFlags(n); + ContentLightingFlags f2 = ndef->getLightingFlags(n2); + u8 light; - u8 l1 = n.getLight(bank, ndef); - u8 l2 = n2.getLight(bank, ndef); + u8 l1 = n.getLight(bank, f1); + u8 l2 = n2.getLight(bank, f2); if(l1 > l2) light = l1; else light = l2; // Boost light level for light sources - u8 light_source = MYMAX(ndef->get(n).light_source, - ndef->get(n2).light_source); + u8 light_source = MYMAX(f1.light_source, f2.light_source); if(light_source > light) light = light_source; @@ -184,8 +186,8 @@ static u16 getSmoothLightCombined(const v3s16 &p, light_source_max = f.light_source; // Check f.solidness because fast-style leaves look better this way if (f.param_type == CPT_LIGHT && f.solidness != 2) { - u8 light_level_day = n.getLightNoChecks(LIGHTBANK_DAY, &f); - u8 light_level_night = n.getLightNoChecks(LIGHTBANK_NIGHT, &f); + u8 light_level_day = n.getLight(LIGHTBANK_DAY, f.getLightingFlags()); + u8 light_level_night = n.getLight(LIGHTBANK_NIGHT, f.getLightingFlags()); if (light_level_day == LIGHT_SUN) direct_sunlight = true; light_day += decode_light(light_level_day); diff --git a/src/client/particles.cpp b/src/client/particles.cpp index 99723d8d6..b272976d5 100644 --- a/src/client/particles.cpp +++ b/src/client/particles.cpp @@ -265,7 +265,8 @@ void Particle::updateLight() ); MapNode n = m_env->getClientMap().getNode(p, &pos_ok); if (pos_ok) - light = n.getLightBlend(m_env->getDayNightRatio(), m_gamedef->ndef()); + light = n.getLightBlend(m_env->getDayNightRatio(), + m_gamedef->ndef()->getLightingFlags(n)); else light = blend_light(m_env->getDayNightRatio(), LIGHT_SUN, 0); diff --git a/src/map.cpp b/src/map.cpp index 5a303d9ba..d1a612c4c 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -213,19 +213,19 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n, } // Set the node on the map - const ContentFeatures &cf = m_nodedef->get(n); - const ContentFeatures &oldcf = m_nodedef->get(oldnode); - if (cf.lightingEquivalent(oldcf)) { + ContentLightingFlags f = m_nodedef->getLightingFlags(n); + ContentLightingFlags oldf = m_nodedef->getLightingFlags(oldnode); + if (f == oldf) { // No light update needed, just copy over the old light. - n.setLight(LIGHTBANK_DAY, oldnode.getLightRaw(LIGHTBANK_DAY, oldcf), cf); - n.setLight(LIGHTBANK_NIGHT, oldnode.getLightRaw(LIGHTBANK_NIGHT, oldcf), cf); + n.setLight(LIGHTBANK_DAY, oldnode.getLightRaw(LIGHTBANK_DAY, oldf), f); + n.setLight(LIGHTBANK_NIGHT, oldnode.getLightRaw(LIGHTBANK_NIGHT, oldf), f); set_node_in_block(block, relpos, n); modified_blocks[blockpos] = block; } else { // Ignore light (because calling voxalgo::update_lighting_nodes) - n.setLight(LIGHTBANK_DAY, 0, cf); - n.setLight(LIGHTBANK_NIGHT, 0, cf); + n.setLight(LIGHTBANK_DAY, 0, f); + n.setLight(LIGHTBANK_NIGHT, 0, f); set_node_in_block(block, relpos, n); // Update lighting @@ -780,8 +780,9 @@ void ServerMap::transformLiquids(std::map &modified_blocks, } // Ignore light (because calling voxalgo::update_lighting_nodes) - n0.setLight(LIGHTBANK_DAY, 0, m_nodedef); - n0.setLight(LIGHTBANK_NIGHT, 0, m_nodedef); + ContentLightingFlags f0 = m_nodedef->getLightingFlags(n0); + n0.setLight(LIGHTBANK_DAY, 0, f0); + n0.setLight(LIGHTBANK_NIGHT, 0, f0); // Find out whether there is a suspect for this action std::string suspect; @@ -1122,7 +1123,7 @@ bool Map::isOccluded(const v3s16 &pos_camera, const v3s16 &pos_target, MapNode node = getNode(pos_node, &is_valid_position); if (is_valid_position && - !m_nodedef->get(node).light_propagates) { + !m_nodedef->getLightingFlags(node).light_propagates) { // Cannot see through light-blocking nodes --> occluded count++; if (count >= needed_count) diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 2bbc0ebbf..bca0c9f2d 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -180,7 +180,7 @@ void MapBlock::actuallyUpdateDayNightDiff() if (n == previous_n) continue; - differs = !n.isLightDayNightEq(nodemgr); + differs = !n.isLightDayNightEq(nodemgr->getLightingFlags(n)); if (differs) break; previous_n = n; diff --git a/src/mapgen/mapgen.cpp b/src/mapgen/mapgen.cpp index 99db50426..943ac4c4f 100644 --- a/src/mapgen/mapgen.cpp +++ b/src/mapgen/mapgen.cpp @@ -450,7 +450,7 @@ void Mapgen::lightSpread(VoxelArea &a, std::queue> &queue, // we hit a solid block that light cannot pass through. if ((light_day <= (n.param1 & 0x0F) && light_night <= (n.param1 & 0xF0)) || - !ndef->get(n).light_propagates) + !ndef->getLightingFlags(n).light_propagates) return; // MYMAX still needed here because we only exit early if both banks have @@ -500,7 +500,7 @@ void Mapgen::propagateSunlight(v3s16 nmin, v3s16 nmax, bool propagate_shadow) for (int y = a.MaxEdge.Y; y >= a.MinEdge.Y; y--) { MapNode &n = vm->m_data[i]; - if (!ndef->get(n).sunlight_propagates) + if (!ndef->getLightingFlags(n).sunlight_propagates) break; n.param1 = LIGHT_SUN; VoxelArea::add_y(em, i, -1); @@ -525,7 +525,7 @@ void Mapgen::spreadLight(const v3s16 &nmin, const v3s16 &nmax) if (n.getContent() == CONTENT_IGNORE) continue; - const ContentFeatures &cf = ndef->get(n); + ContentLightingFlags cf = ndef->getLightingFlags(n); if (!cf.light_propagates) continue; diff --git a/src/mapgen/mapgen_singlenode.cpp b/src/mapgen/mapgen_singlenode.cpp index 5382423fa..3a4199035 100644 --- a/src/mapgen/mapgen_singlenode.cpp +++ b/src/mapgen/mapgen_singlenode.cpp @@ -39,7 +39,7 @@ MapgenSinglenode::MapgenSinglenode(MapgenParams *params, EmergeParams *emerge) c_node = CONTENT_AIR; MapNode n_node(c_node); - set_light = (ndef->get(n_node).sunlight_propagates) ? LIGHT_SUN : 0x00; + set_light = (ndef->getLightingFlags(n_node).sunlight_propagates) ? LIGHT_SUN : 0x00; } diff --git a/src/mapnode.cpp b/src/mapnode.cpp index 1685dc11c..ed5bcb87b 100644 --- a/src/mapnode.cpp +++ b/src/mapnode.cpp @@ -53,95 +53,6 @@ void MapNode::getColor(const ContentFeatures &f, video::SColor *color) const *color = f.color; } -void MapNode::setLight(LightBank bank, u8 a_light, const ContentFeatures &f) noexcept -{ - // If node doesn't contain light data, ignore this - if(f.param_type != CPT_LIGHT) - return; - if(bank == LIGHTBANK_DAY) - { - param1 &= 0xf0; - param1 |= a_light & 0x0f; - } - else if(bank == LIGHTBANK_NIGHT) - { - param1 &= 0x0f; - param1 |= (a_light & 0x0f)<<4; - } - else - assert("Invalid light bank" == NULL); -} - -void MapNode::setLight(LightBank bank, u8 a_light, const NodeDefManager *nodemgr) -{ - setLight(bank, a_light, nodemgr->get(*this)); -} - -bool MapNode::isLightDayNightEq(const NodeDefManager *nodemgr) const -{ - const ContentFeatures &f = nodemgr->get(*this); - bool isEqual; - - if (f.param_type == CPT_LIGHT) { - u8 day = MYMAX(f.light_source, param1 & 0x0f); - u8 night = MYMAX(f.light_source, (param1 >> 4) & 0x0f); - isEqual = day == night; - } else { - isEqual = true; - } - - return isEqual; -} - -u8 MapNode::getLight(LightBank bank, const NodeDefManager *nodemgr) const -{ - // Select the brightest of [light source, propagated light] - const ContentFeatures &f = nodemgr->get(*this); - - u8 light; - if(f.param_type == CPT_LIGHT) - light = bank == LIGHTBANK_DAY ? param1 & 0x0f : (param1 >> 4) & 0x0f; - else - light = 0; - - return MYMAX(f.light_source, light); -} - -u8 MapNode::getLightRaw(LightBank bank, const ContentFeatures &f) const noexcept -{ - if(f.param_type == CPT_LIGHT) - return bank == LIGHTBANK_DAY ? param1 & 0x0f : (param1 >> 4) & 0x0f; - return 0; -} - -u8 MapNode::getLightNoChecks(LightBank bank, const ContentFeatures *f) const noexcept -{ - return MYMAX(f->light_source, - bank == LIGHTBANK_DAY ? param1 & 0x0f : (param1 >> 4) & 0x0f); -} - -bool MapNode::getLightBanks(u8 &lightday, u8 &lightnight, - const NodeDefManager *nodemgr) const -{ - // Select the brightest of [light source, propagated light] - const ContentFeatures &f = nodemgr->get(*this); - if(f.param_type == CPT_LIGHT) - { - lightday = param1 & 0x0f; - lightnight = (param1>>4)&0x0f; - } - else - { - lightday = 0; - lightnight = 0; - } - if(f.light_source > lightday) - lightday = f.light_source; - if(f.light_source > lightnight) - lightnight = f.light_source; - return f.param_type == CPT_LIGHT || f.light_source != 0; -} - u8 MapNode::getFaceDir(const NodeDefManager *nodemgr, bool allow_wallmounted) const { diff --git a/src/mapnode.h b/src/mapnode.h index afd3a96be..43ce7e621 100644 --- a/src/mapnode.h +++ b/src/mapnode.h @@ -35,6 +35,7 @@ class Map; - Tile = TileSpec at some side of a node of some content type */ typedef u16 content_t; +#define CONTENT_MAX UINT16_MAX /* The maximum node ID that can be registered by mods. This must @@ -71,6 +72,25 @@ typedef u16 content_t; */ #define CONTENT_IGNORE 127 +/* + Content lighting information that fits into a single byte. +*/ +struct ContentLightingFlags { + u8 light_source : 4; + bool has_light : 1; + bool light_propagates : 1; + bool sunlight_propagates : 1; + + bool operator==(const ContentLightingFlags &other) const + { + return has_light == other.has_light && light_propagates == other.light_propagates && + sunlight_propagates == other.sunlight_propagates && + light_source == other.light_source; + } + bool operator!=(const ContentLightingFlags &other) const { return !(*this == other); } +}; +static_assert(sizeof(ContentLightingFlags) == 1, "Unexpected ContentLightingFlags size"); + enum LightBank { LIGHTBANK_DAY, @@ -187,53 +207,55 @@ struct MapNode */ void getColor(const ContentFeatures &f, video::SColor *color) const; - void setLight(LightBank bank, u8 a_light, const ContentFeatures &f) noexcept; - - void setLight(LightBank bank, u8 a_light, const NodeDefManager *nodemgr); + inline void setLight(LightBank bank, u8 a_light, ContentLightingFlags f) noexcept + { + // If node doesn't contain light data, ignore this + if (!f.has_light) + return; + if (bank == LIGHTBANK_DAY) { + param1 &= 0xf0; + param1 |= a_light & 0x0f; + } else { + assert(bank == LIGHTBANK_NIGHT); + param1 &= 0x0f; + param1 |= (a_light & 0x0f)<<4; + } + } /** * Check if the light value for night differs from the light value for day. * * @return If the light values are equal, returns true; otherwise false */ - bool isLightDayNightEq(const NodeDefManager *nodemgr) const; + inline bool isLightDayNightEq(ContentLightingFlags f) const noexcept + { + return !f.has_light || getLight(LIGHTBANK_DAY, f) == getLight(LIGHTBANK_NIGHT, f); + } - u8 getLight(LightBank bank, const NodeDefManager *nodemgr) const; + inline u8 getLight(LightBank bank, ContentLightingFlags f) const noexcept + { + u8 raw_light = getLightRaw(bank, f); + return MYMAX(f.light_source, raw_light); + } /*! * Returns the node's light level from param1. * If the node emits light, it is ignored. - * \param f the ContentFeatures of this node. + * \param f the ContentLightingFlags of this node. */ - u8 getLightRaw(LightBank bank, const ContentFeatures &f) const noexcept; - - /** - * This function differs from getLight(LightBank bank, NodeDefManager *nodemgr) - * in that the ContentFeatures of the node in question are not retrieved by - * the function itself. Thus, if you have already called nodemgr->get() to - * get the ContentFeatures you pass it to this function instead of the - * function getting ContentFeatures itself. Since NodeDefManager::get() - * is relatively expensive this can lead to significant performance - * improvements in some situations. Call this function if (and only if) - * you have already retrieved the ContentFeatures by calling - * NodeDefManager::get() for the node you're working with and the - * pre-conditions listed are true. - * - * @pre f != NULL - * @pre f->param_type == CPT_LIGHT - */ - u8 getLightNoChecks(LightBank bank, const ContentFeatures *f) const noexcept; - - bool getLightBanks(u8 &lightday, u8 &lightnight, - const NodeDefManager *nodemgr) const; + inline u8 getLightRaw(LightBank bank, ContentLightingFlags f) const noexcept + { + if(f.has_light) + return bank == LIGHTBANK_DAY ? param1 & 0x0f : (param1 >> 4) & 0x0f; + return 0; + } // 0 <= daylight_factor <= 1000 // 0 <= return value <= LIGHT_SUN - u8 getLightBlend(u32 daylight_factor, const NodeDefManager *nodemgr) const + u8 getLightBlend(u32 daylight_factor, ContentLightingFlags f) const { - u8 lightday = 0; - u8 lightnight = 0; - getLightBanks(lightday, lightnight, nodemgr); + u8 lightday = getLight(LIGHTBANK_DAY, f); + u8 lightnight = getLight(LIGHTBANK_NIGHT, f); return blend_light(daylight_factor, lightday, lightnight); } diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 5707d31a0..e5f056807 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -1098,6 +1098,8 @@ void NodeDefManager::clear() // Insert directly into containers content_t c = CONTENT_UNKNOWN; m_content_features[c] = f; + for (u32 ci = 0; ci <= CONTENT_MAX; ci++) + m_content_lighting_flag_cache[ci] = f.getLightingFlags(); addNameIdMapping(c, f.name); } @@ -1118,6 +1120,7 @@ void NodeDefManager::clear() // Insert directly into containers content_t c = CONTENT_AIR; m_content_features[c] = f; + m_content_lighting_flag_cache[c] = f.getLightingFlags(); addNameIdMapping(c, f.name); } @@ -1137,6 +1140,7 @@ void NodeDefManager::clear() // Insert directly into containers content_t c = CONTENT_IGNORE; m_content_features[c] = f; + m_content_lighting_flag_cache[c] = f.getLightingFlags(); addNameIdMapping(c, f.name); } } @@ -1389,6 +1393,7 @@ content_t NodeDefManager::set(const std::string &name, const ContentFeatures &de eraseIdFromGroups(id); m_content_features[id] = def; + m_content_lighting_flag_cache[id] = def.getLightingFlags(); verbosestream << "NodeDefManager: registering content id \"" << id << "\": name=\"" << def.name << "\""<= m_content_features.size()) m_content_features.resize((u32)(i) + 1); m_content_features[i] = f; + m_content_lighting_flag_cache[i] = f.getLightingFlags(); addNameIdMapping(i, f.name); TRACESTREAM(<< "NodeDef: deserialized " << f.name << std::endl); diff --git a/src/nodedef.h b/src/nodedef.h index 8f0d0e9e8..044fdd8b2 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -505,10 +505,13 @@ struct ContentFeatures liquid_alternative_source_id == f.liquid_alternative_source_id; } - bool lightingEquivalent(const ContentFeatures &other) const { - return light_propagates == other.light_propagates - && sunlight_propagates == other.sunlight_propagates - && light_source == other.light_source; + ContentLightingFlags getLightingFlags() const { + ContentLightingFlags flags; + flags.has_light = param_type == CPT_LIGHT; + flags.light_propagates = light_propagates; + flags.sunlight_propagates = sunlight_propagates; + flags.light_source = light_source; + return flags; } int getGroup(const std::string &group) const @@ -580,6 +583,15 @@ public: return get(n.getContent()); } + inline ContentLightingFlags getLightingFlags(content_t c) const { + // No bound check is necessary, since the array's length is CONTENT_MAX + 1. + return m_content_lighting_flag_cache[c]; + } + + inline ContentLightingFlags getLightingFlags(const MapNode &n) const { + return getLightingFlags(n.getContent()); + } + /*! * Returns the node properties for a node name. * @param name name of a node @@ -826,6 +838,11 @@ private: * Even constant NodeDefManager instances can register listeners. */ mutable std::vector m_pending_resolve_callbacks; + + /*! + * Fast cache of content lighting flags. + */ + ContentLightingFlags m_content_lighting_flag_cache[CONTENT_MAX + 1L]; }; NodeDefManager *createNodeDefManager(); diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 8f2dc0cb4..1956fb948 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -379,7 +379,7 @@ int ModApiEnvMod::l_get_node_light(lua_State *L) MapNode n = env->getMap().getNode(pos, &is_position_ok); if (is_position_ok) { const NodeDefManager *ndef = env->getGameDef()->ndef(); - lua_pushinteger(L, n.getLightBlend(dnr, ndef)); + lua_pushinteger(L, n.getLightBlend(dnr, ndef->getLightingFlags(n))); } else { lua_pushnil(L); } diff --git a/src/unittest/test_mapnode.cpp b/src/unittest/test_mapnode.cpp index 365ee0c86..9a5c69bed 100644 --- a/src/unittest/test_mapnode.cpp +++ b/src/unittest/test_mapnode.cpp @@ -47,9 +47,10 @@ void TestMapNode::testNodeProperties(const NodeDefManager *nodedef) { MapNode n(CONTENT_AIR); + ContentLightingFlags f = nodedef->getLightingFlags(n); UASSERT(n.getContent() == CONTENT_AIR); - UASSERT(n.getLight(LIGHTBANK_DAY, nodedef) == 0); - UASSERT(n.getLight(LIGHTBANK_NIGHT, nodedef) == 0); + UASSERT(n.getLight(LIGHTBANK_DAY, f) == 0); + UASSERT(n.getLight(LIGHTBANK_NIGHT, f) == 0); // Transparency n.setContent(CONTENT_AIR); diff --git a/src/unittest/test_voxelalgorithms.cpp b/src/unittest/test_voxelalgorithms.cpp index abe48893f..6514d3713 100644 --- a/src/unittest/test_voxelalgorithms.cpp +++ b/src/unittest/test_voxelalgorithms.cpp @@ -138,27 +138,27 @@ void TestVoxelAlgorithms::testLighting(IGameDef *gamedef) const NodeDefManager *ndef = gamedef->ndef(); { MapNode n = map.getNode(v3s16(9, 9, -9)); - UASSERTEQ(int, n.getLight(LIGHTBANK_NIGHT, ndef), 0); - UASSERTEQ(int, n.getLight(LIGHTBANK_DAY, ndef), 13); + UASSERTEQ(int, n.getLight(LIGHTBANK_NIGHT, ndef->getLightingFlags(n)), 0); + UASSERTEQ(int, n.getLight(LIGHTBANK_DAY, ndef->getLightingFlags(n)), 13); } { MapNode n = map.getNode(v3s16(0, 1, 0)); - UASSERTEQ(int, n.getLight(LIGHTBANK_NIGHT, ndef), 12); - UASSERTEQ(int, n.getLight(LIGHTBANK_DAY, ndef), 12); + UASSERTEQ(int, n.getLight(LIGHTBANK_NIGHT, ndef->getLightingFlags(n)), 12); + UASSERTEQ(int, n.getLight(LIGHTBANK_DAY, ndef->getLightingFlags(n)), 12); } { MapNode n = map.getNode(v3s16(-9, -1, 0)); - UASSERTEQ(int, n.getLight(LIGHTBANK_NIGHT, ndef), 3); - UASSERTEQ(int, n.getLight(LIGHTBANK_DAY, ndef), 12); + UASSERTEQ(int, n.getLight(LIGHTBANK_NIGHT, ndef->getLightingFlags(n)), 3); + UASSERTEQ(int, n.getLight(LIGHTBANK_DAY, ndef->getLightingFlags(n)), 12); } { MapNode n = map.getNode(v3s16(-10, 0, 0)); - UASSERTEQ(int, n.getLight(LIGHTBANK_NIGHT, ndef), 3); - UASSERTEQ(int, n.getLight(LIGHTBANK_DAY, ndef), 14); + UASSERTEQ(int, n.getLight(LIGHTBANK_NIGHT, ndef->getLightingFlags(n)), 3); + UASSERTEQ(int, n.getLight(LIGHTBANK_DAY, ndef->getLightingFlags(n)), 14); } { MapNode n = map.getNode(v3s16(-11, 0, 0)); - UASSERTEQ(int, n.getLight(LIGHTBANK_NIGHT, ndef), 2); - UASSERTEQ(int, n.getLight(LIGHTBANK_DAY, ndef), 15); + UASSERTEQ(int, n.getLight(LIGHTBANK_NIGHT, ndef->getLightingFlags(n)), 2); + UASSERTEQ(int, n.getLight(LIGHTBANK_DAY, ndef->getLightingFlags(n)), 15); } } diff --git a/src/voxel.cpp b/src/voxel.cpp index 1f1d25373..bb270f53b 100644 --- a/src/voxel.cpp +++ b/src/voxel.cpp @@ -110,7 +110,7 @@ void VoxelManipulator::print(std::ostream &o, const NodeDefManager *ndef, c = 'X'; else { - u8 light = n.getLight(LIGHTBANK_DAY, ndef); + u8 light = n.getLight(LIGHTBANK_DAY, ndef->getLightingFlags(n)); if(light < 10) c = '0' + light; else diff --git a/src/voxelalgorithms.cpp b/src/voxelalgorithms.cpp index a11952916..f95f65790 100644 --- a/src/voxelalgorithms.cpp +++ b/src/voxelalgorithms.cpp @@ -268,7 +268,7 @@ void unspread_light(Map *map, const NodeDefManager *nodemgr, LightBank bank, // The current node const MapNode &node = current.block->getNodeNoCheck( current.rel_position, &is_valid_position); - const ContentFeatures &f = nodemgr->get(node); + ContentLightingFlags f = nodemgr->getLightingFlags(node); // If the node emits light, it behaves like it had a // brighter neighbor. u8 brightest_neighbor_light = f.light_source + 1; @@ -296,7 +296,7 @@ void unspread_light(Map *map, const NodeDefManager *nodemgr, LightBank bank, // Get the neighbor itself MapNode neighbor = neighbor_block->getNodeNoCheck(neighbor_rel_pos, &is_valid_position); - const ContentFeatures &neighbor_f = nodemgr->get( + ContentLightingFlags neighbor_f = nodemgr->getLightingFlags( neighbor.getContent()); u8 neighbor_light = neighbor.getLightRaw(bank, neighbor_f); // If the neighbor has at least as much light as this node, then @@ -386,7 +386,7 @@ void spread_light(Map *map, const NodeDefManager *nodemgr, LightBank bank, // Get the neighbor itself MapNode neighbor = neighbor_block->getNodeNoCheck(neighbor_rel_pos, &is_valid_position); - const ContentFeatures &f = nodemgr->get(neighbor.getContent()); + ContentLightingFlags f = nodemgr->getLightingFlags(neighbor); if (f.light_propagates) { // Light up the neighbor, if it has less light than it should. u8 neighbor_light = neighbor.getLightRaw(bank, f); @@ -454,10 +454,13 @@ bool is_sunlight_above(Map *map, v3s16 pos, const NodeDefManager *ndef) if (source_block->getIsUnderground()) { sunlight = false; } - } else if (above.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN) { - // If the node above doesn't have sunlight, this - // node is in shadow. - sunlight = false; + } else { + ContentLightingFlags above_f = ndef->getLightingFlags(above); + if (above.getLight(LIGHTBANK_DAY, above_f) != LIGHT_SUN) { + // If the node above doesn't have sunlight, this + // node is in shadow. + sunlight = false; + } } } } @@ -483,7 +486,7 @@ void update_lighting_nodes(Map *map, // modified node. u8 min_safe_light = 0; for (auto it = oldnodes.cbegin(); it < oldnodes.cend(); ++it) { - u8 old_light = it->second.getLight(bank, ndef); + u8 old_light = it->second.getLight(bank, ndef->getLightingFlags(it->second)); if (old_light > min_safe_light) { min_safe_light = old_light; } @@ -511,25 +514,26 @@ void update_lighting_nodes(Map *map, } // Light of the old node - u8 old_light = it->second.getLight(bank, ndef); + u8 old_light = it->second.getLight(bank, ndef->getLightingFlags(it->second)); // Add the block of the added node to modified_blocks modified_blocks[block_pos] = block; // Get new light level of the node u8 new_light = 0; - if (ndef->get(n).light_propagates) { - if (bank == LIGHTBANK_DAY && ndef->get(n).sunlight_propagates + ContentLightingFlags f = ndef->getLightingFlags(n); + if (f.light_propagates) { + if (bank == LIGHTBANK_DAY && f.sunlight_propagates && is_sunlight_above(map, p, ndef)) { new_light = LIGHT_SUN; } else { - new_light = ndef->get(n).light_source; + new_light = f.light_source; for (const v3s16 &neighbor_dir : neighbor_dirs) { v3s16 p2 = p + neighbor_dir; bool is_valid; MapNode n2 = map->getNode(p2, &is_valid); if (is_valid) { - u8 spread = n2.getLight(bank, ndef); + u8 spread = n2.getLight(bank, ndef->getLightingFlags(n2)); // If it is sure that the neighbor won't be // unlighted, its light can spread to this node. if (spread > new_light && spread >= min_safe_light) { @@ -540,7 +544,7 @@ void update_lighting_nodes(Map *map, } } else { // If this is an opaque node, it still can emit light. - new_light = ndef->get(n).light_source; + new_light = f.light_source; } if (new_light > 0) { @@ -552,7 +556,7 @@ void update_lighting_nodes(Map *map, // light as the previous one, so it must be unlighted. // Add to unlight queue - n.setLight(bank, 0, ndef); + n.setLight(bank, 0, f); block->setNodeNoCheck(rel_pos, n); disappearing_lights.push(old_light, rel_pos, block_pos, block, 6); @@ -570,11 +574,12 @@ void update_lighting_nodes(Map *map, // If this node doesn't have sunlight, the nodes below // it don't have too. - if (n2.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN) { + ContentLightingFlags f2 = ndef->getLightingFlags(n2); + if (n2.getLight(LIGHTBANK_DAY, f2) != LIGHT_SUN) { break; } // Remove sunlight and add to unlight queue. - n2.setLight(LIGHTBANK_DAY, 0, ndef); + n2.setLight(LIGHTBANK_DAY, 0, f2); map->setNode(n2pos, n2); relative_v3 rel_pos2; mapblock_v3 block_pos2; @@ -602,11 +607,12 @@ void update_lighting_nodes(Map *map, // This should not happen, but if the node has sunlight // then the iteration should stop. - if (n2.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN) { + ContentLightingFlags f2 = ndef->getLightingFlags(n2); + if (n2.getLight(LIGHTBANK_DAY, f2) == LIGHT_SUN) { break; } // If the node terminates sunlight, stop. - if (!ndef->get(n2).sunlight_propagates) { + if (!f2.sunlight_propagates) { break; } relative_v3 rel_pos2; @@ -632,7 +638,7 @@ void update_lighting_nodes(Map *map, it < lights.end(); ++it) { MapNode n = it->block->getNodeNoCheck(it->rel_position, &is_valid_position); - n.setLight(bank, i, ndef); + n.setLight(bank, i, ndef->getLightingFlags(n)); it->block->setNodeNoCheck(it->rel_position, n); } } @@ -667,17 +673,17 @@ bool is_light_locally_correct(Map *map, const NodeDefManager *ndef, { bool is_valid_position; MapNode n = map->getNode(pos, &is_valid_position); - const ContentFeatures &f = ndef->get(n); - if (f.param_type != CPT_LIGHT) { + ContentLightingFlags f = ndef->getLightingFlags(n); + if (!f.has_light) { return true; } - u8 light = n.getLightNoChecks(bank, &f); + u8 light = n.getLight(bank, f); assert(f.light_source <= LIGHT_MAX); u8 brightest_neighbor = f.light_source + 1; for (const v3s16 &neighbor_dir : neighbor_dirs) { MapNode n2 = map->getNode(pos + neighbor_dir, &is_valid_position); - u8 light2 = n2.getLight(bank, ndef); + u8 light2 = n2.getLight(bank, ndef->getLightingFlags(n2)); if (brightest_neighbor < light2) { brightest_neighbor = light2; } @@ -725,14 +731,15 @@ void update_block_border_lighting(Map *map, MapBlock *block, for (s32 y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) { MapNode n = b->getNodeNoCheck(x, y, z, &is_valid_position); - u8 light = n.getLight(bank, ndef); + ContentLightingFlags f = ndef->getLightingFlags(n); + u8 light = n.getLight(bank, f); // Sunlight is fixed if (light < LIGHT_SUN) { // Unlight if not correct if (!is_light_locally_correct(map, ndef, bank, v3s16(x, y, z) + b->getPosRelative())) { // Initialize for unlighting - n.setLight(bank, 0, ndef); + n.setLight(bank, 0, ndef->getLightingFlags(n)); b->setNodeNoCheck(x, y, z, n); modified_blocks[b->getPos()]=b; disappearing_lights.push(light, @@ -753,7 +760,7 @@ void update_block_border_lighting(Map *map, MapBlock *block, it < lights.end(); ++it) { MapNode n = it->block->getNodeNoCheck(it->rel_position, &is_valid_position); - n.setLight(bank, i, ndef); + n.setLight(bank, i, ndef->getLightingFlags(n)); it->block->setNodeNoCheck(it->rel_position, n); } } @@ -804,7 +811,7 @@ void fill_with_sunlight(MMVManip *vm, const NodeDefManager *ndef, v2s16 offset, // Ignore IGNORE nodes, these are not generated yet. if(n->getContent() == CONTENT_IGNORE) continue; - const ContentFeatures &f = ndef->get(n->getContent()); + ContentLightingFlags f = ndef->getLightingFlags(*n); if (lig && !f.sunlight_propagates) // Sunlight is stopped. lig = false; @@ -857,7 +864,8 @@ void is_sunlight_above_block(Map *map, mapblock_v3 pos, // Get the bottom block. MapNode above = source_block->getNodeNoCheck(x, 0, z, &is_valid_position); - light[z][x] = above.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN; + ContentLightingFlags above_f = ndef->getLightingFlags(above); + light[z][x] = above.getLight(LIGHTBANK_DAY, above_f) == LIGHT_SUN; } } } @@ -897,7 +905,7 @@ bool propagate_block_sunlight(Map *map, const NodeDefManager *ndef, // For each node downwards: for (; current_pos.Y >= 0; current_pos.Y--) { MapNode n = block->getNodeNoCheck(current_pos, &is_valid); - const ContentFeatures &f = ndef->get(n); + ContentLightingFlags f = ndef->getLightingFlags(n); if (n.getLightRaw(LIGHTBANK_DAY, f) < LIGHT_SUN && f.sunlight_propagates) { // This node gets sunlight. @@ -916,7 +924,7 @@ bool propagate_block_sunlight(Map *map, const NodeDefManager *ndef, // For each node downwards: for (; current_pos.Y >= 0; current_pos.Y--) { MapNode n = block->getNodeNoCheck(current_pos, &is_valid); - const ContentFeatures &f = ndef->get(n); + ContentLightingFlags f = ndef->getLightingFlags(n); if (n.getLightRaw(LIGHTBANK_DAY, f) == LIGHT_SUN) { // The sunlight is no longer valid. n.setLight(LIGHTBANK_DAY, 0, f); @@ -1007,13 +1015,13 @@ void finish_bulk_light_update(Map *map, mapblock_v3 minblock, for (relpos.Z = 0; relpos.Z < MAP_BLOCKSIZE; relpos.Z++) for (relpos.Y = 0; relpos.Y < MAP_BLOCKSIZE; relpos.Y++) { MapNode node = block->getNodeNoCheck(relpos.X, relpos.Y, relpos.Z, &is_valid); - const ContentFeatures &f = ndef->get(node); + ContentLightingFlags f = ndef->getLightingFlags(node); // For each light bank for (size_t b = 0; b < 2; b++) { LightBank bank = banks[b]; - u8 light = f.param_type == CPT_LIGHT ? - node.getLightNoChecks(bank, &f): + u8 light = f.has_light ? + node.getLight(bank, f): f.light_source; if (light > 1) relight[b].push(light, relpos, blockpos, block, 6); @@ -1035,7 +1043,7 @@ void finish_bulk_light_update(Map *map, mapblock_v3 minblock, it < lights.end(); ++it) { MapNode n = it->block->getNodeNoCheck(it->rel_position, &is_valid); - n.setLight(bank, i, ndef); + n.setLight(bank, i, ndef->getLightingFlags(n)); it->block->setNodeNoCheck(it->rel_position, n); } } @@ -1110,19 +1118,18 @@ void blit_back_with_light(Map *map, MMVManip *vm, // Get old and new node MapNode oldnode = block->getNodeNoCheck(relpos, &is_valid); - const ContentFeatures &oldf = ndef->get(oldnode); + ContentLightingFlags oldf = ndef->getLightingFlags(oldnode); MapNode newnode = vm->getNodeNoExNoEmerge(relpos + offset); - const ContentFeatures &newf = oldnode == newnode ? oldf : - ndef->get(newnode); + ContentLightingFlags newf = ndef->getLightingFlags(newnode); // For each light bank for (size_t b = 0; b < 2; b++) { LightBank bank = banks[b]; - u8 oldlight = oldf.param_type == CPT_LIGHT ? - oldnode.getLightNoChecks(bank, &oldf): + u8 oldlight = oldf.has_light ? + oldnode.getLight(bank, oldf): LIGHT_SUN; // no light information, force unlighting - u8 newlight = newf.param_type == CPT_LIGHT ? - newnode.getLightNoChecks(bank, &newf): + u8 newlight = newf.has_light ? + newnode.getLight(bank, newf): newf.light_source; // If the new node is dimmer, unlight. if (oldlight > newlight) { @@ -1172,7 +1179,7 @@ void fill_with_sunlight(MapBlock *block, const NodeDefManager *ndef, // Ignore IGNORE nodes, these are not generated yet. if (n.getContent() == CONTENT_IGNORE) continue; - const ContentFeatures &f = ndef->get(n.getContent()); + ContentLightingFlags f = ndef->getLightingFlags(n); if (lig && !f.sunlight_propagates) { // Sunlight is stopped. lig = false; @@ -1239,12 +1246,12 @@ void repair_block_light(Map *map, MapBlock *block, // Get node MapNode node = block->getNodeNoCheck(relpos, &is_valid); - const ContentFeatures &f = ndef->get(node); + ContentLightingFlags f = ndef->getLightingFlags(node); // For each light bank for (size_t b = 0; b < 2; b++) { LightBank bank = banks[b]; - u8 light = f.param_type == CPT_LIGHT ? - node.getLightNoChecks(bank, &f): + u8 light = f.has_light ? + node.getLight(bank, f): f.light_source; // If the new node is dimmer than sunlight, unlight. // (if it has maximal light, it is pointless to remove