]> git.lizzy.rs Git - minetest.git/commitdiff
Optimize lighting calculation (#12797)
authorJude Melton-Houghton <jwmhjwmh@gmail.com>
Sun, 9 Oct 2022 14:50:26 +0000 (10:50 -0400)
committerGitHub <noreply@github.com>
Sun, 9 Oct 2022 14:50:26 +0000 (10:50 -0400)
18 files changed:
src/client/clientmap.cpp
src/client/content_cso.cpp
src/client/content_mapblock.cpp
src/client/mapblock_mesh.cpp
src/client/particles.cpp
src/map.cpp
src/mapblock.cpp
src/mapgen/mapgen.cpp
src/mapgen/mapgen_singlenode.cpp
src/mapnode.cpp
src/mapnode.h
src/nodedef.cpp
src/nodedef.h
src/script/lua_api/l_env.cpp
src/unittest/test_mapnode.cpp
src/unittest/test_voxelalgorithms.cpp
src/voxel.cpp
src/voxelalgorithms.cpp

index 23234c3651b05487dea6e7a5487fa9ae701ab1c4..b74499ac31915a92db564ebc18559185dafb4d41 100644 (file)
@@ -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;
                }
index f9641afbe9e9644a7133fe1629ffac72c9c65eaf..50ae4e41367da43c51a39014988d3a8050ed77f5 100644 (file)
@@ -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 @@ class SmokePuffCSO: public ClientSimpleObject
                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);
index 7fd5aefb1359248dac613335f47e239fad94fef8..a9abbceeb802613ece58cf068aa79484f83e3ec5 100644 (file)
@@ -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));
        }
index 5036f8bd68223a523406b7c8fd2d249508dc7862..519932cd44d259a043cce63a03f884ccde802142 100644 (file)
@@ -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);
index 99723d8d664a7ca41f7efce4547e07525d724422..b272976d5494377e8abb708f798b01446c83496a 100644 (file)
@@ -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);
 
index 5a303d9baad74b65bedfb3b102942c7dd03fa94f..d1a612c4cb19b7bf64de4461267b9fb3ffa32e43 100644 (file)
@@ -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<v3s16, MapBlock*> &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)
index 2bbc0ebbf9f76d9ab0750afb7d24f2caf5920a1b..bca0c9f2d56b90fd848ece1936acacac9541b09b 100644 (file)
@@ -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;
index 99db5042638905c6a5dd274676ed94b82201eaac..943ac4c4f3492af45cf3993b75c5e5878a4513f8 100644 (file)
@@ -450,7 +450,7 @@ void Mapgen::lightSpread(VoxelArea &a, std::queue<std::pair<v3s16, u8>> &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;
 
index 5382423fa1e7835444b086d331a00f0cd99fc7b1..3a41990358d27cc8a311f24e8206006c85e540c2 100644 (file)
@@ -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;
 }
 
 
index 1685dc11cfb9fa7a8266222ebb115967b4a0b663..ed5bcb87bd8b25bb3b8d1c8de6cd29feb1d737d9 100644 (file)
@@ -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
 {
index afd3a96be38c9da87eb5c3102534bb39ddacdb49..43ce7e621467abf301940341beb216cc66e05b9d 100644 (file)
@@ -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.
-        */
-       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
+        * \param f the ContentLightingFlags of this node.
         */
-       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);
        }
 
index 5707d31a0bcb17be5992e96ef644b3c5c886ac4d..e5f05680799326805a88cdd8b171c0053a5c3574 100644 (file)
@@ -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 << "\""<<std::endl;
 
@@ -1601,6 +1606,7 @@ void NodeDefManager::deSerialize(std::istream &is, u16 protocol_version)
                if (i >= 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);
 
index 8f0d0e9e8f865a66c88d959bed75ed654811624b..044fdd8b23a0aae201a761ae7b8b9620c08a100d 100644 (file)
@@ -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 @@ class NodeDefManager {
                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 @@ class NodeDefManager {
         * Even constant NodeDefManager instances can register listeners.
         */
        mutable std::vector<NodeResolver *> m_pending_resolve_callbacks;
+
+       /*!
+        * Fast cache of content lighting flags.
+        */
+       ContentLightingFlags m_content_lighting_flag_cache[CONTENT_MAX + 1L];
 };
 
 NodeDefManager *createNodeDefManager();
index 8f2dc0cb472d0b8275771d2054ebf8eb313f3d30..1956fb9480ed94d3c3281b896642becee7cd55f4 100644 (file)
@@ -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);
        }
index 365ee0c865e935fd61f4de757f069d5151f30de3..9a5c69bed7279925b82bf8411094b3399d4c4f36 100644 (file)
@@ -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);
index abe48893fb5c7db342fc476cc45af2cf3934c378..6514d3713d00f2b2681ec8b31ae0f72e71ca5b09 100644 (file)
@@ -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);
        }
 }
index 1f1d253731c558fdc8d8d586f3c4f7d12184756e..bb270f53b585cfd04375f834373cd108ecb70a5c 100644 (file)
@@ -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
index a119529163ea4bb24dc05ec20269ec078c8deba7..f95f65790ab69ba31f6f51413cb6e2868ea1a0c1 100644 (file)
@@ -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