aboutsummaryrefslogtreecommitdiff
path: root/src/client/content_mapblock.cpp
diff options
context:
space:
mode:
authorVitaliy <numzer0@yandex.ru>2023-04-08 21:17:15 +0300
committerGitHub <noreply@github.com>2023-04-08 20:17:15 +0200
commit35929d27e3a93085c3a27180c1805711dcfe95d5 (patch)
tree5b7326c17d27103ae2876078b888df70eacc2283 /src/client/content_mapblock.cpp
parentc2a9ac24ac2e74b111b4bbdf42ee3a62514bc7a2 (diff)
downloadminetest-35929d27e3a93085c3a27180c1805711dcfe95d5.tar.xz
Remove fast faces (#13216)
Co-authored-by: Lars <larsh@apache.org>
Diffstat (limited to 'src/client/content_mapblock.cpp')
-rw-r--r--src/client/content_mapblock.cpp284
1 files changed, 199 insertions, 85 deletions
diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp
index 4db72c75f..0274c767b 100644
--- a/src/client/content_mapblock.cpp
+++ b/src/client/content_mapblock.cpp
@@ -44,6 +44,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// Corresponding offsets are listed in g_27dirs
#define FRAMED_NEIGHBOR_COUNT 18
+// Maps light index to corner direction
static const v3s16 light_dirs[8] = {
v3s16(-1, -1, -1),
v3s16(-1, -1, 1),
@@ -55,8 +56,20 @@ static const v3s16 light_dirs[8] = {
v3s16( 1, 1, 1),
};
+// Maps cuboid face and vertex indices to the corresponding light index
+static const u8 light_indices[6][4] = {
+ {3, 7, 6, 2},
+ {0, 4, 5, 1},
+ {6, 7, 5, 4},
+ {3, 2, 0, 1},
+ {7, 3, 1, 5},
+ {2, 6, 4, 0},
+};
+
// Standard index set to make a quad on 4 vertices
-static constexpr u16 quad_indices[] = {0, 1, 2, 2, 3, 0};
+static constexpr u16 quad_indices_02[] = {0, 1, 2, 2, 3, 0};
+static constexpr u16 quad_indices_13[] = {0, 1, 3, 3, 1, 2};
+static const auto &quad_indices = quad_indices_02;
const std::string MapblockMeshGenerator::raillike_groupname = "connect_to_raillike";
@@ -140,82 +153,42 @@ void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal,
collector->append(tile, vertices, 4, quad_indices, 6);
}
-// Create a cuboid.
-// tiles - the tiles (materials) to use (for all 6 faces)
-// tilecount - number of entries in tiles, 1<=tilecount<=6
-// lights - vertex light levels. The order is the same as in light_dirs.
-// NULL may be passed if smooth lighting is disabled.
-// txc - texture coordinates - this is a list of texture coordinates
-// for the opposite corners of each face - therefore, there
-// should be (2+2)*6=24 values in the list. The order of
-// the faces in the list is up-down-right-left-back-front
-// (compatible with ContentFeatures).
-// mask - a bit mask that suppresses drawing of tiles.
-// tile i will not be drawn if mask & (1 << i) is 1
-void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
- TileSpec *tiles, int tilecount, const LightInfo *lights, const f32 *txc, u8 mask)
-{
- assert(tilecount >= 1 && tilecount <= 6); // pre-condition
-
+static std::array<video::S3DVertex, 24> setupCuboidVertices(const aabb3f &box, const f32 *txc, TileSpec *tiles, int tilecount) {
v3f min = box.MinEdge;
v3f max = box.MaxEdge;
- video::SColor colors[6];
- if (!data->m_smooth_lighting) {
- for (int face = 0; face != 6; ++face) {
- colors[face] = encode_light(light, f->light_source);
- }
- if (!f->light_source) {
- applyFacesShading(colors[0], v3f(0, 1, 0));
- applyFacesShading(colors[1], v3f(0, -1, 0));
- applyFacesShading(colors[2], v3f(1, 0, 0));
- applyFacesShading(colors[3], v3f(-1, 0, 0));
- applyFacesShading(colors[4], v3f(0, 0, 1));
- applyFacesShading(colors[5], v3f(0, 0, -1));
- }
- }
-
- video::S3DVertex vertices[24] = {
+ std::array<video::S3DVertex, 24> vertices = {{
// top
- video::S3DVertex(min.X, max.Y, max.Z, 0, 1, 0, colors[0], txc[0], txc[1]),
- video::S3DVertex(max.X, max.Y, max.Z, 0, 1, 0, colors[0], txc[2], txc[1]),
- video::S3DVertex(max.X, max.Y, min.Z, 0, 1, 0, colors[0], txc[2], txc[3]),
- video::S3DVertex(min.X, max.Y, min.Z, 0, 1, 0, colors[0], txc[0], txc[3]),
+ video::S3DVertex(min.X, max.Y, max.Z, 0, 1, 0, {}, txc[0], txc[1]),
+ video::S3DVertex(max.X, max.Y, max.Z, 0, 1, 0, {}, txc[2], txc[1]),
+ video::S3DVertex(max.X, max.Y, min.Z, 0, 1, 0, {}, txc[2], txc[3]),
+ video::S3DVertex(min.X, max.Y, min.Z, 0, 1, 0, {}, txc[0], txc[3]),
// bottom
- video::S3DVertex(min.X, min.Y, min.Z, 0, -1, 0, colors[1], txc[4], txc[5]),
- video::S3DVertex(max.X, min.Y, min.Z, 0, -1, 0, colors[1], txc[6], txc[5]),
- video::S3DVertex(max.X, min.Y, max.Z, 0, -1, 0, colors[1], txc[6], txc[7]),
- video::S3DVertex(min.X, min.Y, max.Z, 0, -1, 0, colors[1], txc[4], txc[7]),
+ video::S3DVertex(min.X, min.Y, min.Z, 0, -1, 0, {}, txc[4], txc[5]),
+ video::S3DVertex(max.X, min.Y, min.Z, 0, -1, 0, {}, txc[6], txc[5]),
+ video::S3DVertex(max.X, min.Y, max.Z, 0, -1, 0, {}, txc[6], txc[7]),
+ video::S3DVertex(min.X, min.Y, max.Z, 0, -1, 0, {}, txc[4], txc[7]),
// right
- video::S3DVertex(max.X, max.Y, min.Z, 1, 0, 0, colors[2], txc[ 8], txc[9]),
- video::S3DVertex(max.X, max.Y, max.Z, 1, 0, 0, colors[2], txc[10], txc[9]),
- video::S3DVertex(max.X, min.Y, max.Z, 1, 0, 0, colors[2], txc[10], txc[11]),
- video::S3DVertex(max.X, min.Y, min.Z, 1, 0, 0, colors[2], txc[ 8], txc[11]),
+ video::S3DVertex(max.X, max.Y, min.Z, 1, 0, 0, {}, txc[ 8], txc[9]),
+ video::S3DVertex(max.X, max.Y, max.Z, 1, 0, 0, {}, txc[10], txc[9]),
+ video::S3DVertex(max.X, min.Y, max.Z, 1, 0, 0, {}, txc[10], txc[11]),
+ video::S3DVertex(max.X, min.Y, min.Z, 1, 0, 0, {}, txc[ 8], txc[11]),
// left
- video::S3DVertex(min.X, max.Y, max.Z, -1, 0, 0, colors[3], txc[12], txc[13]),
- video::S3DVertex(min.X, max.Y, min.Z, -1, 0, 0, colors[3], txc[14], txc[13]),
- video::S3DVertex(min.X, min.Y, min.Z, -1, 0, 0, colors[3], txc[14], txc[15]),
- video::S3DVertex(min.X, min.Y, max.Z, -1, 0, 0, colors[3], txc[12], txc[15]),
+ video::S3DVertex(min.X, max.Y, max.Z, -1, 0, 0, {}, txc[12], txc[13]),
+ video::S3DVertex(min.X, max.Y, min.Z, -1, 0, 0, {}, txc[14], txc[13]),
+ video::S3DVertex(min.X, min.Y, min.Z, -1, 0, 0, {}, txc[14], txc[15]),
+ video::S3DVertex(min.X, min.Y, max.Z, -1, 0, 0, {}, txc[12], txc[15]),
// back
- video::S3DVertex(max.X, max.Y, max.Z, 0, 0, 1, colors[4], txc[16], txc[17]),
- video::S3DVertex(min.X, max.Y, max.Z, 0, 0, 1, colors[4], txc[18], txc[17]),
- video::S3DVertex(min.X, min.Y, max.Z, 0, 0, 1, colors[4], txc[18], txc[19]),
- video::S3DVertex(max.X, min.Y, max.Z, 0, 0, 1, colors[4], txc[16], txc[19]),
+ video::S3DVertex(max.X, max.Y, max.Z, 0, 0, 1, {}, txc[16], txc[17]),
+ video::S3DVertex(min.X, max.Y, max.Z, 0, 0, 1, {}, txc[18], txc[17]),
+ video::S3DVertex(min.X, min.Y, max.Z, 0, 0, 1, {}, txc[18], txc[19]),
+ video::S3DVertex(max.X, min.Y, max.Z, 0, 0, 1, {}, txc[16], txc[19]),
// front
- video::S3DVertex(min.X, max.Y, min.Z, 0, 0, -1, colors[5], txc[20], txc[21]),
- video::S3DVertex(max.X, max.Y, min.Z, 0, 0, -1, colors[5], txc[22], txc[21]),
- video::S3DVertex(max.X, min.Y, min.Z, 0, 0, -1, colors[5], txc[22], txc[23]),
- video::S3DVertex(min.X, min.Y, min.Z, 0, 0, -1, colors[5], txc[20], txc[23]),
- };
-
- static const u8 light_indices[24] = {
- 3, 7, 6, 2,
- 0, 4, 5, 1,
- 6, 7, 5, 4,
- 3, 2, 0, 1,
- 7, 3, 1, 5,
- 2, 6, 4, 0
- };
+ video::S3DVertex(min.X, max.Y, min.Z, 0, 0, -1, {}, txc[20], txc[21]),
+ video::S3DVertex(max.X, max.Y, min.Z, 0, 0, -1, {}, txc[22], txc[21]),
+ video::S3DVertex(max.X, min.Y, min.Z, 0, 0, -1, {}, txc[22], txc[23]),
+ video::S3DVertex(min.X, min.Y, min.Z, 0, 0, -1, {}, txc[20], txc[23]),
+ }};
for (int face = 0; face < 6; face++) {
int tileindex = MYMIN(face, tilecount - 1);
@@ -263,23 +236,42 @@ void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
}
}
- if (data->m_smooth_lighting) {
- for (int j = 0; j < 24; ++j) {
- video::S3DVertex &vertex = vertices[j];
- vertex.Color = encode_light(
- lights[light_indices[j]].getPair(MYMAX(0.0f, vertex.Normal.Y)),
- f->light_source);
- if (!f->light_source)
- applyFacesShading(vertex.Color, vertex.Normal);
- }
- }
+ return vertices;
+}
+
+enum class QuadDiagonal {
+ Diag02,
+ Diag13,
+};
+
+// Create a cuboid with custom lighting.
+// tiles - the tiles (materials) to use (for all 6 faces)
+// tilecount - number of entries in tiles, 1<=tilecount<=6
+// txc - texture coordinates - this is a list of texture coordinates
+// for the opposite corners of each face - therefore, there
+// should be (2+2)*6=24 values in the list. The order of
+// the faces in the list is up-down-right-left-back-front
+// (compatible with ContentFeatures).
+// mask - a bit mask that suppresses drawing of tiles.
+// tile i will not be drawn if mask & (1 << i) is 1
+// face_lighter(int face, video::S3DVertex vertices[4]) -> QuadDiagonal -
+// a callback that will be called for each face drawn to setup vertex colors,
+// and to choose diagonal to split the quad at.
+template <typename Fn>
+void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
+ TileSpec *tiles, int tilecount, const f32 *txc, u8 mask, Fn &&face_lighter)
+{
+ assert(tilecount >= 1 && tilecount <= 6); // pre-condition
+
+ auto vertices = setupCuboidVertices(box, txc, tiles, tilecount);
- // Add to mesh collector
for (int k = 0; k < 6; ++k) {
if (mask & (1 << k))
continue;
+ QuadDiagonal diagonal = face_lighter(k, &vertices[4 * k]);
+ const u16 *indices = diagonal == QuadDiagonal::Diag13 ? quad_indices_13 : quad_indices_02;
int tileindex = MYMIN(k, tilecount - 1);
- collector->append(tiles[tileindex], vertices + 4 * k, 4, quad_indices, 6);
+ collector->append(tiles[tileindex], &vertices[4 * k], 4, indices, 6);
}
}
@@ -366,6 +358,11 @@ void MapblockMeshGenerator::generateCuboidTextureCoords(const aabb3f &box, f32 *
coords[i] = txc[i];
}
+static inline int lightDiff(LightPair a, LightPair b)
+{
+ return abs(a.lightDay - b.lightDay) + abs(a.lightNight - b.lightNight);
+}
+
void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
TileSpec *tiles, int tile_count, u8 mask)
{
@@ -404,9 +401,124 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
d.Z = (j & 1) ? dz2 : dz1;
lights[j] = blendLight(d);
}
- drawCuboid(box, tiles, tile_count, lights, txc, mask);
+
+ drawCuboid(box, tiles, tile_count, txc, mask, [&] (int face, video::S3DVertex vertices[4]) {
+ LightPair final_lights[4];
+ for (int j = 0; j < 4; j++) {
+ video::S3DVertex &vertex = vertices[j];
+ final_lights[j] = lights[light_indices[face][j]].getPair(MYMAX(0.0f, vertex.Normal.Y));
+ vertex.Color = encode_light(final_lights[j], f->light_source);
+ if (!f->light_source)
+ applyFacesShading(vertex.Color, vertex.Normal);
+ }
+ if (lightDiff(final_lights[1], final_lights[3]) < lightDiff(final_lights[0], final_lights[2]))
+ return QuadDiagonal::Diag13;
+ return QuadDiagonal::Diag02;
+ });
} else {
- drawCuboid(box, tiles, tile_count, nullptr, txc, mask);
+ drawCuboid(box, tiles, tile_count, txc, mask, [&] (int face, video::S3DVertex vertices[4]) {
+ video::SColor color = encode_light(light, f->light_source);
+ if (!f->light_source)
+ applyFacesShading(color, vertices[0].Normal);
+ for (int j = 0; j < 4; j++) {
+ video::S3DVertex &vertex = vertices[j];
+ vertex.Color = color;
+ }
+ return QuadDiagonal::Diag02;
+ });
+ }
+}
+
+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 = n.getContent();
+ for (int face = 0; face < 6; face++) {
+ v3s16 p2 = blockpos_nodes + p + tile_dirs[face];
+ MapNode neighbor = data->m_vmanip.getNodeNoEx(p2);
+ content_t n2 = neighbor.getContent();
+ bool backface_culling = f->drawtype == NDT_NORMAL;
+ if (n2 == n1)
+ continue;
+ if (n2 == CONTENT_IGNORE)
+ continue;
+ if (n2 != CONTENT_AIR) {
+ const ContentFeatures &f2 = nodedef->get(n2);
+ if (f2.solidness == 2)
+ continue;
+ if (f->drawtype == NDT_LIQUID) {
+ if (n2 == nodedef->getId(f->liquid_alternative_flowing))
+ continue;
+ if (n2 == nodedef->getId(f->liquid_alternative_source))
+ continue;
+ backface_culling = f2.solidness >= 1;
+ }
+ }
+ faces |= 1 << face;
+ getTile(tile_dirs[face], &tiles[face]);
+ for (auto &layer : tiles[face].layers) {
+ if (backface_culling)
+ layer.material_flags |= MATERIAL_FLAG_BACKFACE_CULLING;
+ else
+ layer.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
+ layer.material_flags |= MATERIAL_FLAG_TILEABLE_HORIZONTAL;
+ layer.material_flags |= MATERIAL_FLAG_TILEABLE_VERTICAL;
+ }
+ if (!data->m_smooth_lighting) {
+ lights[face] = getFaceLight(n, neighbor, nodedef);
+ }
+ }
+ if (!faces)
+ return;
+ u8 mask = faces ^ 0b0011'1111; // k-th bit is set if k-th face is to be *omitted*, as expected by cuboid drawing functions.
+ origin = intToFloat(p, BS);
+ auto box = aabb3f(v3f(-0.5 * BS), v3f(0.5 * BS));
+ f32 texture_coord_buf[24];
+ box.MinEdge += origin;
+ box.MaxEdge += origin;
+ generateCuboidTextureCoords(box, texture_coord_buf);
+ if (data->m_smooth_lighting) {
+ LightPair lights[6][4];
+ for (int face = 0; face < 6; ++face) {
+ for (int k = 0; k < 4; k++) {
+ v3s16 corner = light_dirs[light_indices[face][k]];
+ lights[face][k] = LightPair(getSmoothLightSolid(blockpos_nodes + p, tile_dirs[face], corner, data));
+ }
+ }
+
+ drawCuboid(box, tiles, 6, texture_coord_buf, mask, [&] (int face, video::S3DVertex vertices[4]) {
+ auto final_lights = lights[face];
+ for (int j = 0; j < 4; j++) {
+ video::S3DVertex &vertex = vertices[j];
+ vertex.Color = encode_light(final_lights[j], f->light_source);
+ if (!f->light_source)
+ applyFacesShading(vertex.Color, vertex.Normal);
+ }
+ if (lightDiff(final_lights[1], final_lights[3]) < lightDiff(final_lights[0], final_lights[2]))
+ return QuadDiagonal::Diag13;
+ return QuadDiagonal::Diag02;
+ });
+ } else {
+ drawCuboid(box, tiles, 6, texture_coord_buf, mask, [&] (int face, video::S3DVertex vertices[4]) {
+ video::SColor color = encode_light(lights[face], f->light_source);
+ if (!f->light_source)
+ applyFacesShading(color, vertices[0].Normal);
+ for (int j = 0; j < 4; j++) {
+ video::S3DVertex &vertex = vertices[j];
+ vertex.Color = color;
+ }
+ return QuadDiagonal::Diag02;
+ });
}
}
@@ -1124,6 +1236,7 @@ void MapblockMeshGenerator::drawPlantlikeNode()
void MapblockMeshGenerator::drawPlantlikeRootedNode()
{
+ drawSolidNode();
useTile(0, MATERIAL_FLAG_CRACK_OVERLAY, 0, true);
origin += v3f(0.0, BS, 0.0);
p.Y++;
@@ -1581,11 +1694,12 @@ void MapblockMeshGenerator::errorUnknownDrawtype()
void MapblockMeshGenerator::drawNode()
{
- // skip some drawtypes early
switch (f->drawtype) {
- case NDT_NORMAL: // Drawn by MapBlockMesh
case NDT_AIRLIKE: // Not drawn at all
- case NDT_LIQUID: // Drawn by MapBlockMesh
+ return;
+ case NDT_LIQUID:
+ case NDT_NORMAL: // solid nodes don’t need the usual setup
+ drawSolidNode();
return;
default:
break;