#include "content_mapblock.h"
#include "util/directiontables.h"
#include "client/renderingengine.h"
+#include <array>
/*
MeshMakeData
fillBlockData(v3s16(0,0,0), block->getData());
- // Get map for reading neigbhor blocks
+ // Get map for reading neighbor blocks
Map *map = block->getParent();
for (const v3s16 &dir : g_26dirs) {
Calculate smooth lighting at the XYZ- corner of p.
Both light banks
*/
-static u16 getSmoothLightCombined(const v3s16 &p, MeshMakeData *data)
+static u16 getSmoothLightCombined(const v3s16 &p,
+ const std::array<v3s16,8> &dirs, MeshMakeData *data, bool node_solid)
{
- static const v3s16 dirs8[8] = {
- v3s16(0,0,0),
- v3s16(0,0,1),
- v3s16(0,1,0),
- v3s16(0,1,1),
- v3s16(1,0,0),
- v3s16(1,1,0),
- v3s16(1,0,1),
- v3s16(1,1,1),
- };
-
INodeDefManager *ndef = data->m_client->ndef();
u16 ambient_occlusion = 0;
u16 light_day = 0;
u16 light_night = 0;
- for (const v3s16 &dir : dirs8) {
- MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p - dir);
-
- // if it's CONTENT_IGNORE we can't do any light calculations
- if (n.getContent() == CONTENT_IGNORE)
- continue;
-
+ auto add_node = [&] (int i) -> const ContentFeatures& {
+ MapNode n = data->m_vmanip.getNodeNoExNoEmerge(p + dirs[i]);
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 && f.solidness != 2) {
light_day += decode_light(n.getLightNoChecks(LIGHTBANK_DAY, &f));
- light_night += decode_light(
- n.getLightNoChecks(LIGHTBANK_NIGHT, &f));
+ light_night += decode_light(n.getLightNoChecks(LIGHTBANK_NIGHT, &f));
light_count++;
} else {
ambient_occlusion++;
}
- }
+ return f;
+ };
- if(light_count == 0)
- return 0xffff;
+ if (node_solid) {
+ ambient_occlusion = 3;
+ bool corner_obstructed = true;
+ for (int i = 0; i < 2; ++i) {
+ if (add_node(i).light_propagates)
+ corner_obstructed = false;
+ }
+ add_node(2);
+ add_node(3);
+ if (corner_obstructed)
+ ambient_occlusion++;
+ else
+ add_node(4);
+ } else {
+ std::array<bool, 4> obstructed = {{ 1, 1, 1, 1 }};
+ add_node(0);
+ bool opaque1 = !add_node(1).light_propagates;
+ bool opaque2 = !add_node(2).light_propagates;
+ bool opaque3 = !add_node(3).light_propagates;
+ obstructed[0] = opaque1 && opaque2;
+ obstructed[1] = opaque1 && opaque3;
+ obstructed[2] = opaque2 && opaque3;
+ for (int k = 0; k < 4; ++k) {
+ if (obstructed[k])
+ ambient_occlusion++;
+ else if (add_node(k + 4).light_propagates)
+ obstructed[3] = false;
+ }
+ }
- light_day /= light_count;
- light_night /= light_count;
+ if (light_count == 0) {
+ light_day = light_night = 0;
+ } else {
+ light_day /= light_count;
+ light_night /= light_count;
+ }
// Boost brightness around light sources
bool skip_ambient_occlusion_day = false;
/*
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 getSmoothLight(v3s16 p, v3s16 corner, MeshMakeData *data)
+u16 getSmoothLightSolid(const v3s16 &p, const v3s16 &face_dir, const v3s16 &corner, MeshMakeData *data)
{
- if (corner.X == 1)
- ++p.X;
- // else corner.X == -1
- if (corner.Y == 1)
- ++p.Y;
- // else corner.Y == -1
- if (corner.Z == 1)
- ++p.Z;
- // else corner.Z == -1
-
- return getSmoothLightCombined(p, data);
+ v3s16 neighbor_offset1, neighbor_offset2;
+
+ /*
+ * face_dir, neighbor_offset1 and neighbor_offset2 define an
+ * orthonormal basis which is used to define the offsets of the 8
+ * surrounding nodes and to differentiate the "distance" (by going only
+ * along directly neighboring nodes) relative to the node at p.
+ * Apart from the node at p, only the 4 nodes which contain face_dir
+ * can contribute light.
+ */
+ if (face_dir.X != 0) {
+ neighbor_offset1 = v3s16(0, corner.Y, 0);
+ neighbor_offset2 = v3s16(0, 0, corner.Z);
+ } else if (face_dir.Y != 0) {
+ neighbor_offset1 = v3s16(0, 0, corner.Z);
+ neighbor_offset2 = v3s16(corner.X, 0, 0);
+ } else if (face_dir.Z != 0) {
+ neighbor_offset1 = v3s16(corner.X,0,0);
+ neighbor_offset2 = v3s16(0,corner.Y,0);
+ }
+
+ const std::array<v3s16,8> dirs = {{
+ // Always shine light
+ neighbor_offset1 + face_dir,
+ neighbor_offset2 + face_dir,
+ v3s16(0,0,0),
+ face_dir,
+
+ // Can be obstructed
+ neighbor_offset1 + neighbor_offset2 + face_dir,
+
+ // Do not shine light, only for ambient occlusion
+ neighbor_offset1,
+ neighbor_offset2,
+ neighbor_offset1 + neighbor_offset2
+ }};
+ return getSmoothLightCombined(p, dirs, data, true);
+}
+
+/*
+ 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, false);
}
void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){
v3s16 light_p = blockpos_nodes + p_corrected;
for (u16 i = 0; i < 4; i++)
- lights[i] = getSmoothLight(light_p, vertex_dirs[i], data);
+ lights[i] = getSmoothLightSolid(light_p, face_dir_corrected, vertex_dirs[i], data);
}
}