mirror of
https://github.com/luanti-org/luanti.git
synced 2025-08-06 17:41:04 +00:00
parent
c2a9ac24ac
commit
35929d27e3
5 changed files with 208 additions and 695 deletions
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue