mirror of
https://github.com/luanti-org/luanti.git
synced 2026-10-12 02:18:30 +00:00
Move solid light functions to content_mapblock.cpp and refactor them
This commit is contained in:
+187
-39
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user