Move solid light functions to content_mapblock.cpp and refactor them

This commit is contained in:
cx384
2026-09-26 14:00:54 +02:00
committed by sfan5
parent 52e25d50f9
commit 3d36a7b878
3 changed files with 187 additions and 219 deletions
+187 -39
View File
@@ -33,7 +33,7 @@
#define FRAMED_NEIGHBOR_COUNT 18
// Maps light index to corner direction
static const v3s16 light_dirs[8] = {
static constexpr v3s16 light_dirs[8] = {
v3s16(-1, -1, -1),
v3s16(-1, -1, 1),
v3s16(-1, 1, -1),
@@ -44,8 +44,28 @@ static const v3s16 light_dirs[8] = {
v3s16( 1, 1, 1),
};
// Direction of solid node tiles
static constexpr v3s16 tile_dirs[6] = {
v3s16( 0, 1, 0),
v3s16( 0, -1, 0),
v3s16( 1, 0, 0),
v3s16(-1, 0, 0),
v3s16( 0, 0, 1),
v3s16( 0, 0, -1)
};
// we have this order for some reason...
static constexpr v3s16 nodebox_connection_dirs[6] = {
v3s16( 0, 1, 0), // top
v3s16( 0, -1, 0), // bottom
v3s16( 0, 0, -1), // front
v3s16(-1, 0, 0), // left
v3s16( 0, 0, 1), // back
v3s16( 1, 0, 0), // right
};
// Maps cuboid face and vertex indices to the corresponding light index
static const u8 light_indices[6][4] = {
static constexpr u8 light_indices[6][4] = {
{3, 7, 6, 2},
{0, 4, 5, 1},
{6, 7, 5, 4},
@@ -279,13 +299,167 @@ void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
}
}
/*
Calculate non-smooth lighting at face of node.
Single light bank.
*/
static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2, const NodeDefManager *ndef)
{
ContentLightingFlags f1 = ndef->getLightingFlags(n);
ContentLightingFlags f2 = ndef->getLightingFlags(n2);
u8 light;
u8 l1 = n.getLight(bank, f1);
u8 l2 = n2.getLight(bank, f2);
light = std::max(l1, l2);
// Boost light level for light sources
u8 light_source = std::max(f1.light_source, f2.light_source);
light = std::max(light, light_source);
return decode_light(light);
}
/*
Calculate non-smooth lighting at face of node.
Both light banks.
*/
static LightPair getFaceLight(MapNode n, MapNode n2, const NodeDefManager *ndef)
{
u8 day = getFaceLight(LIGHTBANK_DAY, n, n2, ndef);
u8 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, ndef);
return LightPair(day, night);
}
/*
Calculate smooth lighting at the XYZ- corner of p.
Both light banks
*/
static LightPair getSmoothLightCorner(const v3s16 &p,
const v3s16 &corner, MeshMakeData *data)
{
const NodeDefManager *ndef = data->m_nodedef;
const std::array<v3s16,8> dirs {
// Always shine light
v3s16(0,0,0),
v3s16(corner.X,0,0),
v3s16(0,corner.Y,0),
v3s16(0,0,corner.Z),
// Can be obstructed
v3s16(corner.X,corner.Y,0),
v3s16(corner.X,0,corner.Z),
v3s16(0,corner.Y,corner.Z),
v3s16(corner.X,corner.Y,corner.Z)
};
u16 ambient_occlusion = 0;
u16 light_count = 0;
u8 light_source_max = 0;
u16 light_day = 0;
u16 light_night = 0;
bool direct_sunlight = false;
auto add_node = [&] (u8 i, bool obstructed = false) -> bool {
if (obstructed) {
ambient_occlusion++;
return false;
}
MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p + dirs[i]);
if (n.getContent() == CONTENT_IGNORE)
return true;
const ContentFeatures &f = ndef->get(n);
if (f.light_source > light_source_max)
light_source_max = f.light_source;
// Check f.solidness because fast-style leaves look better this way
if (f.param_type == CPT_LIGHT && NDT_solidness[f.drawtype] != 2) {
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);
light_night += decode_light(light_level_night);
light_count++;
} else {
ambient_occlusion++;
}
return f.light_propagates;
};
bool obstructed[4] = { true, true, true, true };
add_node(0);
bool opaque1 = !add_node(1);
bool opaque2 = !add_node(2);
bool opaque3 = !add_node(3);
obstructed[0] = opaque1 && opaque2;
obstructed[1] = opaque1 && opaque3;
obstructed[2] = opaque2 && opaque3;
for (u8 k = 0; k < 3; ++k)
if (add_node(k + 4, obstructed[k]))
obstructed[3] = false;
if (add_node(7, obstructed[3])) { // wrap light around nodes
ambient_occlusion -= 3;
for (u8 k = 0; k < 3; ++k)
add_node(k + 4, !obstructed[k]);
}
if (light_count == 0) {
light_day = light_night = 0;
} else {
light_day /= light_count;
light_night /= light_count;
}
// boost direct sunlight, if any
if (direct_sunlight)
light_day = 0xFF;
// Boost brightness around light sources
bool skip_ambient_occlusion_day = false;
if (decode_light(light_source_max) >= light_day) {
light_day = decode_light(light_source_max);
skip_ambient_occlusion_day = true;
}
bool skip_ambient_occlusion_night = false;
if(decode_light(light_source_max) >= light_night) {
light_night = decode_light(light_source_max);
skip_ambient_occlusion_night = true;
}
if (ambient_occlusion > 4) {
static thread_local const float ao_gamma = rangelim(
g_settings->getFloat("ambient_occlusion_gamma"), 0.25, 4.0);
// Table of gamma space multiply factors.
static thread_local const float light_amount[3] = {
powf(0.75, 1.0 / ao_gamma),
powf(0.5, 1.0 / ao_gamma),
powf(0.25, 1.0 / ao_gamma)
};
//calculate table index for gamma space multiplier
ambient_occlusion -= 5;
if (!skip_ambient_occlusion_day)
light_day = rangelim(core::round32(
light_day * light_amount[ambient_occlusion]), 0, 255);
if (!skip_ambient_occlusion_night)
light_night = rangelim(core::round32(
light_night * light_amount[ambient_occlusion]), 0, 255);
}
return LightPair((u8)light_day, (u8)light_night);
}
// Gets the base lighting values for a node
void MapblockMeshGenerator::getSmoothLightFrame()
{
for (int k = 0; k < 8; ++k)
cur_node.lframe.sunlight[k] = false;
for (int k = 0; k < 8; ++k) {
LightPair light(getSmoothLightTransparent(blockpos_nodes + cur_node.p, light_dirs[k], data));
LightPair light = getSmoothLightCorner(blockpos_nodes + cur_node.p, light_dirs[k], data);
cur_node.lframe.lightsDay[k] = light.lightDay;
cur_node.lframe.lightsNight[k] = light.lightNight;
// If there is direct sunlight and no ambient occlusion at some corner,
@@ -434,19 +608,12 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box,
void MapblockMeshGenerator::drawSolidNode()
{
u8 faces = 0; // k-th bit will be set if k-th face is to be drawn.
static const v3s16 tile_dirs[6] = {
v3s16(0, 1, 0),
v3s16(0, -1, 0),
v3s16(1, 0, 0),
v3s16(-1, 0, 0),
v3s16(0, 0, 1),
v3s16(0, 0, -1)
};
TileSpec tiles[6];
u16 lights[6];
content_t n1 = cur_node.n.getContent();
v3s16 p1 = blockpos_nodes + cur_node.p;
for (int face = 0; face < 6; face++) {
v3s16 p2 = blockpos_nodes + cur_node.p + tile_dirs[face];
v3s16 p2 = p1 + tile_dirs[face];
MapNode neighbor = data->m_vmanip.getNodeRefUnsafeCheckFlags(p2);
content_t n2 = neighbor.getContent();
bool backface_culling = cur_node.f->drawtype == NDT_NORMAL;
@@ -517,10 +684,12 @@ void MapblockMeshGenerator::drawSolidNode()
for (int face = 0; face < 6; ++face) {
if (mask & (1 << face))
continue;
const v3s16 &face_dir = tile_dirs[face];
v3s16 p2 = p1 + face_dir;
for (int k = 0; k < 4; k++) {
v3s16 corner = light_dirs[light_indices[face][k]];
lights[face][k] = LightPair(getSmoothLightSolid(
blockpos_nodes + cur_node.p, tile_dirs[face], corner, data));
// Solid nodes obstruct light, so take the light from the (non-solid) neighbor node.
const v3s16 corner = light_dirs[light_indices[face][k]] - 2 * face_dir;
lights[face][k] = getSmoothLightCorner(p2, corner, data);
}
}
@@ -1583,33 +1752,12 @@ void MapblockMeshGenerator::drawRaillikeNode()
drawQuad(tile, vertices);
}
namespace {
static const v3s16 nodebox_tile_dirs[6] = {
v3s16(0, 1, 0),
v3s16(0, -1, 0),
v3s16(1, 0, 0),
v3s16(-1, 0, 0),
v3s16(0, 0, 1),
v3s16(0, 0, -1)
};
// we have this order for some reason...
static const v3s16 nodebox_connection_dirs[6] = {
v3s16( 0, 1, 0), // top
v3s16( 0, -1, 0), // bottom
v3s16( 0, 0, -1), // front
v3s16(-1, 0, 0), // left
v3s16( 0, 0, 1), // back
v3s16( 1, 0, 0), // right
};
}
void MapblockMeshGenerator::drawAllfacesNode()
{
static const aabb3f box(-BS / 2, -BS / 2, -BS / 2, BS / 2, BS / 2, BS / 2);
TileSpec tiles[6];
for (int face = 0; face < 6; face++)
getTile(nodebox_tile_dirs[face], &tiles[face]);
getTile(tile_dirs[face], &tiles[face]);
drawAutoLightedCuboid(box, tiles, 6);
}
@@ -1618,7 +1766,7 @@ void MapblockMeshGenerator::drawNodeboxNode()
TileSpec tiles[6];
for (int face = 0; face < 6; face++) {
// Handles facedir rotation for textures
getTile(nodebox_tile_dirs[face], &tiles[face]);
getTile(tile_dirs[face], &tiles[face]);
}
bool param2_is_rotation =
@@ -1638,7 +1786,7 @@ void MapblockMeshGenerator::drawNodeboxNode()
u8 sametype_neighbors = 0;
for (int dir = 0; dir != 6; dir++) {
u8 flag = 1 << dir;
v3s16 p2 = blockpos_nodes + cur_node.p + nodebox_tile_dirs[dir];
v3s16 p2 = blockpos_nodes + cur_node.p + tile_dirs[dir];
MapNode n2 = data->m_vmanip.getNodeRefUnsafeCheckFlags(p2);
// mark neighbors that are the same node type
-177
View File
@@ -101,183 +101,6 @@ u16 getInteriorLight(MapNode n, s32 increment, const NodeDefManager *ndef)
return day | (night << 8);
}
/*
Calculate non-smooth lighting at face of node.
Single light bank.
*/
static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2, const NodeDefManager *ndef)
{
ContentLightingFlags f1 = ndef->getLightingFlags(n);
ContentLightingFlags f2 = ndef->getLightingFlags(n2);
u8 light;
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(f1.light_source, f2.light_source);
if(light_source > light)
light = light_source;
return decode_light(light);
}
/*
Calculate non-smooth lighting at face of node.
Both light banks.
*/
u16 getFaceLight(MapNode n, MapNode n2, const NodeDefManager *ndef)
{
u16 day = getFaceLight(LIGHTBANK_DAY, n, n2, ndef);
u16 night = getFaceLight(LIGHTBANK_NIGHT, n, n2, ndef);
return day | (night << 8);
}
/*
Calculate smooth lighting at the XYZ- corner of p.
Both light banks
*/
static u16 getSmoothLightCombined(const v3s16 &p,
const std::array<v3s16,8> &dirs, MeshMakeData *data)
{
const NodeDefManager *ndef = data->m_nodedef;
u16 ambient_occlusion = 0;
u16 light_count = 0;
u8 light_source_max = 0;
u16 light_day = 0;
u16 light_night = 0;
bool direct_sunlight = false;
auto add_node = [&] (u8 i, bool obstructed = false) -> bool {
if (obstructed) {
ambient_occlusion++;
return false;
}
MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p + dirs[i]);
if (n.getContent() == CONTENT_IGNORE)
return true;
const ContentFeatures &f = ndef->get(n);
if (f.light_source > light_source_max)
light_source_max = f.light_source;
// Check solidness because fast-style leaves look better this way
if (f.param_type == CPT_LIGHT && NDT_solidness[f.drawtype] != 2) {
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);
light_night += decode_light(light_level_night);
light_count++;
} else {
ambient_occlusion++;
}
return f.light_propagates;
};
bool obstructed[4] = { true, true, true, true };
add_node(0);
bool opaque1 = !add_node(1);
bool opaque2 = !add_node(2);
bool opaque3 = !add_node(3);
obstructed[0] = opaque1 && opaque2;
obstructed[1] = opaque1 && opaque3;
obstructed[2] = opaque2 && opaque3;
for (u8 k = 0; k < 3; ++k)
if (add_node(k + 4, obstructed[k]))
obstructed[3] = false;
if (add_node(7, obstructed[3])) { // wrap light around nodes
ambient_occlusion -= 3;
for (u8 k = 0; k < 3; ++k)
add_node(k + 4, !obstructed[k]);
}
if (light_count == 0) {
light_day = light_night = 0;
} else {
light_day /= light_count;
light_night /= light_count;
}
// boost direct sunlight, if any
if (direct_sunlight)
light_day = 0xFF;
// Boost brightness around light sources
bool skip_ambient_occlusion_day = false;
if (decode_light(light_source_max) >= light_day) {
light_day = decode_light(light_source_max);
skip_ambient_occlusion_day = true;
}
bool skip_ambient_occlusion_night = false;
if(decode_light(light_source_max) >= light_night) {
light_night = decode_light(light_source_max);
skip_ambient_occlusion_night = true;
}
if (ambient_occlusion > 4) {
static thread_local const float ao_gamma = rangelim(
g_settings->getFloat("ambient_occlusion_gamma"), 0.25, 4.0);
// Table of gamma space multiply factors.
static thread_local const float light_amount[3] = {
powf(0.75, 1.0 / ao_gamma),
powf(0.5, 1.0 / ao_gamma),
powf(0.25, 1.0 / ao_gamma)
};
//calculate table index for gamma space multiplier
ambient_occlusion -= 5;
if (!skip_ambient_occlusion_day)
light_day = rangelim(core::round32(
light_day * light_amount[ambient_occlusion]), 0, 255);
if (!skip_ambient_occlusion_night)
light_night = rangelim(core::round32(
light_night * light_amount[ambient_occlusion]), 0, 255);
}
return light_day | (light_night << 8);
}
/*
Calculate smooth lighting at the given corner of p.
Both light banks.
Node at p is solid, and thus the lighting is face-dependent.
*/
u16 getSmoothLightSolid(const v3s16 &p, const v3s16 &face_dir, const v3s16 &corner, MeshMakeData *data)
{
return getSmoothLightTransparent(p + face_dir, corner - 2 * face_dir, data);
}
/*
Calculate smooth lighting at the given corner of p.
Both light banks.
Node at p is not solid, and the lighting is not face-dependent.
*/
u16 getSmoothLightTransparent(const v3s16 &p, const v3s16 &corner, MeshMakeData *data)
{
const std::array<v3s16,8> dirs = {{
// Always shine light
v3s16(0,0,0),
v3s16(corner.X,0,0),
v3s16(0,corner.Y,0),
v3s16(0,0,corner.Z),
// Can be obstructed
v3s16(corner.X,corner.Y,0),
v3s16(corner.X,0,corner.Z),
v3s16(0,corner.Y,corner.Z),
v3s16(corner.X,corner.Y,corner.Z)
}};
return getSmoothLightCombined(p, dirs, data);
}
void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio)
{
f32 rg = daynight_ratio / 1000.0f - 0.04f;
-3
View File
@@ -328,9 +328,6 @@ video::SColor encode_light(LightPair light, u8 emissive_light);
// Compute light at node
u16 getInteriorLight(MapNode n, s32 increment, const NodeDefManager *ndef);
u16 getFaceLight(MapNode n, MapNode n2, const NodeDefManager *ndef);
u16 getSmoothLightSolid(const v3s16 &p, const v3s16 &face_dir, const v3s16 &corner, MeshMakeData *data);
u16 getSmoothLightTransparent(const v3s16 &p, const v3s16 &corner, MeshMakeData *data);
/*!
* Returns the sunlight's color from the current