diff options
| author | Vitaliy <numzer0@yandex.ru> | 2023-04-08 21:17:15 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-04-08 20:17:15 +0200 |
| commit | 35929d27e3a93085c3a27180c1805711dcfe95d5 (patch) | |
| tree | 5b7326c17d27103ae2876078b888df70eacc2283 /src/client/content_mapblock.cpp | |
| parent | c2a9ac24ac2e74b111b4bbdf42ee3a62514bc7a2 (diff) | |
| download | minetest-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.cpp | 284 |
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; |
