void MapblockMeshGenerator::useTile(int index, bool disable_backface_culling)
{
- tile = getNodeTileN(n, p, index, data);
+ getNodeTileN(n, p, index, data, tile);
if (!data->m_smooth_lighting)
- color = encode_light_and_color(light, tile.color, f->light_source);
- if (disable_backface_culling)
- tile.material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
- tile.material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
+ color = encode_light(light, f->light_source);
+ for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
+ tile.layers[layer].material_flags |= MATERIAL_FLAG_CRACK_OVERLAY;
+ if (disable_backface_culling)
+ tile.layers[layer].material_flags &= ~MATERIAL_FLAG_BACKFACE_CULLING;
+ }
}
void MapblockMeshGenerator::useDefaultTile(bool set_color)
{
- tile = getNodeTile(n, p, v3s16(0, 0, 0), data);
+ getNodeTile(n, p, v3s16(0, 0, 0), data, tile);
if (set_color && !data->m_smooth_lighting)
- color = encode_light_and_color(light, tile.color, f->light_source);
+ color = encode_light(light, f->light_source);
}
-TileSpec MapblockMeshGenerator::getTile(const v3s16& direction)
+void MapblockMeshGenerator::getTile(const v3s16& direction, TileSpec &tile)
{
- return getNodeTile(n, p, direction, data);
+ getNodeTile(n, p, direction, data, tile);
}
void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal)
{
- static const v2f tcoords[4] = {v2f(0, 1), v2f(1, 1), v2f(1, 0), v2f(0, 0)};
+ static const v2f tcoords[4] = {v2f(0, 0), v2f(1, 0), v2f(1, 1), v2f(0, 1)};
video::S3DVertex vertices[4];
bool shade_face = !f->light_source && (normal != v3s16(0, 0, 0));
v3f normal2(normal.X, normal.Y, normal.Z);
vertices[j].Pos = coords[j] + origin;
vertices[j].Normal = normal2;
if (data->m_smooth_lighting)
- vertices[j].Color = blendLight(coords[j], tile.color);
+ vertices[j].Color = blendLightColor(coords[j]);
else
vertices[j].Color = color;
if (shade_face)
video::SColor colors[6];
if (!data->m_smooth_lighting) {
for (int face = 0; face != 6; ++face) {
- int tileindex = MYMIN(face, tilecount - 1);
- colors[face] = encode_light_and_color(light, tiles[tileindex].color, f->light_source);
+ colors[face] = encode_light(light, f->light_source);
}
if (!f->light_source) {
applyFacesShading(colors[0], v3f(0, 1, 0));
if (data->m_smooth_lighting) {
for (int j = 0; j < 24; ++j) {
- int tileindex = MYMIN(j / 4, tilecount - 1);
- vertices[j].Color = encode_light_and_color(lights[light_indices[j]],
- tiles[tileindex].color, f->light_source);
+ vertices[j].Color = encode_light(lights[light_indices[j]],
+ f->light_source);
if (!f->light_source)
applyFacesShading(vertices[j].Color, vertices[j].Normal);
}
// Calculates vertex color to be used in mapblock mesh
// vertex_pos - vertex position in the node (coordinates are clamped to [0.0, 1.0] or so)
// tile_color - node's tile color
-video::SColor MapblockMeshGenerator::blendLight(const v3f &vertex_pos,
- video::SColor tile_color)
+video::SColor MapblockMeshGenerator::blendLightColor(const v3f &vertex_pos)
{
u16 light = blendLight(vertex_pos);
- return encode_light_and_color(light, tile_color, f->light_source);
+ return encode_light(light, f->light_source);
}
-video::SColor MapblockMeshGenerator::blendLight(const v3f &vertex_pos,
- const v3f &vertex_normal, video::SColor tile_color)
+video::SColor MapblockMeshGenerator::blendLightColor(const v3f &vertex_pos,
+ const v3f &vertex_normal)
{
- video::SColor color = blendLight(vertex_pos, tile_color);
+ video::SColor color = blendLightColor(vertex_pos);
if (!f->light_source)
applyFacesShading(color, vertex_normal);
return color;
const MapNode &n, u8 i)
{
TileSpec copy = f.special_tiles[i];
- if (!copy.has_color)
- n.getColor(f, ©.color);
+ for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
+ TileLayer *layer = ©.layers[layernum];
+ if (layer->texture_id == 0)
+ continue;
+ if (!layer->has_color)
+ n.getColor(f, &(layer->color));
+ }
return copy;
}
-void MapblockMeshGenerator::prepareLiquidNodeDrawing(bool flowing)
+void MapblockMeshGenerator::prepareLiquidNodeDrawing()
{
tile_liquid_top = getSpecialTile(*f, n, 0);
- tile_liquid = getSpecialTile(*f, n, flowing ? 1 : 0);
+ tile_liquid = getSpecialTile(*f, n, 1);
MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(p.X, p.Y + 1, p.Z));
c_flowing = nodedef->getId(f->liquid_alternative_flowing);
light = getInteriorLight(ntop, 0, nodedef);
}
- color_liquid_top = encode_light_and_color(light, tile_liquid_top.color, f->light_source);
- color = encode_light_and_color(light, tile_liquid.color, f->light_source);
+ color_liquid_top = encode_light(light, f->light_source);
+ color = encode_light(light, f->light_source);
}
-void MapblockMeshGenerator::getLiquidNeighborhood(bool flowing)
+void MapblockMeshGenerator::getLiquidNeighborhood()
{
u8 range = rangelim(nodedef->get(c_flowing).liquid_range, 1, 8);
for (int w = -1; w <= 1; w++)
for (int u = -1; u <= 1; u++) {
- // Skip getting unneeded data
- if (!flowing && u && w)
- continue;
-
NeighborData &neighbor = liquid_neighbors[w + 1][u + 1];
v3s16 p2 = p + v3s16(u, 0, w);
MapNode n2 = data->m_vmanip.getNodeNoEx(blockpos_nodes + p2);
}
}
-void MapblockMeshGenerator::resetCornerLevels()
-{
- for (int k = 0; k < 2; k++)
- for (int i = 0; i < 2; i++)
- corner_levels[k][i] = 0.5 * BS;
-}
-
void MapblockMeshGenerator::calculateCornerLevels()
{
for (int k = 0; k < 2; k++)
return 0;
}
-void MapblockMeshGenerator::drawLiquidSides(bool flowing)
+void MapblockMeshGenerator::drawLiquidSides()
{
struct LiquidFaceDesc {
v3s16 dir; // XZ
// at the top to which it should be connected. Again, unless the face
// there would be inside the liquid
if (neighbor.is_same_liquid) {
- if (!flowing)
- continue;
if (!top_is_same_liquid)
continue;
if (neighbor.top_is_same_liquid)
continue;
}
- if (!flowing && (neighbor.content == CONTENT_IGNORE))
- continue;
-
const ContentFeatures &neighbor_features = nodedef->get(neighbor.content);
// Don't draw face if neighbor is blocking the view
if (neighbor_features.solidness == 2)
else
pos.Y = !top_is_same_liquid ? corner_levels[base.Z][base.X] : 0.5 * BS;
if (data->m_smooth_lighting)
- color = blendLight(pos, tile_liquid.color);
+ color = blendLightColor(pos);
pos += origin;
vertices[j] = video::S3DVertex(pos.X, pos.Y, pos.Z, 0, 0, 0, color, vertex.u, vertex.v);
};
}
}
-void MapblockMeshGenerator::drawLiquidTop(bool flowing)
+void MapblockMeshGenerator::drawLiquidTop()
{
// To get backface culling right, the vertices need to go
// clockwise around the front of the face. And we happened to
int w = corner_resolve[i][1];
vertices[i].Pos.Y += corner_levels[w][u];
if (data->m_smooth_lighting)
- vertices[i].Color = blendLight(vertices[i].Pos, tile_liquid_top.color);
+ vertices[i].Color = blendLightColor(vertices[i].Pos);
vertices[i].Pos += origin;
}
- if (flowing) {
- // Default downwards-flowing texture animation goes from
- // -Z towards +Z, thus the direction is +Z.
- // Rotate texture to make animation go in flow direction
- // Positive if liquid moves towards +Z
- f32 dz = (corner_levels[0][0] + corner_levels[0][1]) -
- (corner_levels[1][0] + corner_levels[1][1]);
- // Positive if liquid moves towards +X
- f32 dx = (corner_levels[0][0] + corner_levels[1][0]) -
- (corner_levels[0][1] + corner_levels[1][1]);
- f32 tcoord_angle = atan2(dz, dx) * core::RADTODEG;
- v2f tcoord_center(0.5, 0.5);
- v2f tcoord_translate(blockpos_nodes.Z + p.Z, blockpos_nodes.X + p.X);
- tcoord_translate.rotateBy(tcoord_angle);
- tcoord_translate.X -= floor(tcoord_translate.X);
- tcoord_translate.Y -= floor(tcoord_translate.Y);
-
- for (int i = 0; i < 4; i++) {
- vertices[i].TCoords.rotateBy(tcoord_angle, tcoord_center);
- vertices[i].TCoords += tcoord_translate;
- }
+ // Default downwards-flowing texture animation goes from
+ // -Z towards +Z, thus the direction is +Z.
+ // Rotate texture to make animation go in flow direction
+ // Positive if liquid moves towards +Z
+ f32 dz = (corner_levels[0][0] + corner_levels[0][1]) -
+ (corner_levels[1][0] + corner_levels[1][1]);
+ // Positive if liquid moves towards +X
+ f32 dx = (corner_levels[0][0] + corner_levels[1][0]) -
+ (corner_levels[0][1] + corner_levels[1][1]);
+ f32 tcoord_angle = atan2(dz, dx) * core::RADTODEG;
+ v2f tcoord_center(0.5, 0.5);
+ v2f tcoord_translate(blockpos_nodes.Z + p.Z, blockpos_nodes.X + p.X);
+ tcoord_translate.rotateBy(tcoord_angle);
+ tcoord_translate.X -= floor(tcoord_translate.X);
+ tcoord_translate.Y -= floor(tcoord_translate.Y);
- std::swap(vertices[0].TCoords, vertices[2].TCoords);
+ for (int i = 0; i < 4; i++) {
+ vertices[i].TCoords.rotateBy(tcoord_angle, tcoord_center);
+ vertices[i].TCoords += tcoord_translate;
}
+ std::swap(vertices[0].TCoords, vertices[2].TCoords);
+
collector->append(tile_liquid_top, vertices, 4, quad_indices, 6);
}
-void MapblockMeshGenerator::drawLiquidNode(bool flowing)
+void MapblockMeshGenerator::drawLiquidNode()
{
- prepareLiquidNodeDrawing(flowing);
- getLiquidNeighborhood(flowing);
- if (flowing)
- calculateCornerLevels();
- else
- resetCornerLevels();
- drawLiquidSides(flowing);
+ prepareLiquidNodeDrawing();
+ getLiquidNeighborhood();
+ calculateCornerLevels();
+ drawLiquidSides();
if (!top_is_same_liquid)
- drawLiquidTop(flowing);
+ drawLiquidTop();
}
void MapblockMeshGenerator::drawGlasslikeNode()
// Don't make face if neighbor is of same type
if (neighbor.getContent() == n.getContent())
continue;
+ // Face at Z-
v3f vertices[4] = {
- v3f(-BS / 2, -BS / 2, BS / 2),
- v3f( BS / 2, -BS / 2, BS / 2),
- v3f( BS / 2, BS / 2, BS / 2),
- v3f(-BS / 2, BS / 2, BS / 2),
+ v3f(-BS / 2, BS / 2, -BS / 2),
+ v3f( BS / 2, BS / 2, -BS / 2),
+ v3f( BS / 2, -BS / 2, -BS / 2),
+ v3f(-BS / 2, -BS / 2, -BS / 2),
};
for (int i = 0; i < 4; i++) {
- // Rotations in the g_6dirs format
switch (face) {
- case 0: vertices[i].rotateXZBy( 0); break; // Z+
- case 1: vertices[i].rotateYZBy(-90); break; // Y+
- case 2: vertices[i].rotateXZBy(-90); break; // X+
- case 3: vertices[i].rotateXZBy(180); break; // Z-
- case 4: vertices[i].rotateYZBy( 90); break; // Y-
- case 5: vertices[i].rotateXZBy( 90); break; // X-
- };
+ case D6D_ZP: vertices[i].rotateXZBy(180); break;
+ case D6D_YP: vertices[i].rotateYZBy( 90); break;
+ case D6D_XP: vertices[i].rotateXZBy( 90); break;
+ case D6D_ZN: vertices[i].rotateXZBy( 0); break;
+ case D6D_YN: vertices[i].rotateYZBy(-90); break;
+ case D6D_XN: vertices[i].rotateXZBy(-90); break;
+ }
}
drawQuad(vertices, dir);
}
{
TileSpec tiles[6];
for (int face = 0; face < 6; face++)
- tiles[face] = getTile(g_6dirs[face]);
+ getTile(g_6dirs[face], tiles[face]);
TileSpec glass_tiles[6];
- if (tiles[0].texture && tiles[3].texture && tiles[4].texture) {
+ if (tiles[1].layers[0].texture &&
+ tiles[2].layers[0].texture &&
+ tiles[3].layers[0].texture) {
glass_tiles[0] = tiles[4];
glass_tiles[1] = tiles[0];
glass_tiles[2] = tiles[4];
drawAutoLightedCuboid(glass_faces[face]);
}
- if (param2 > 0 && f->special_tiles[0].texture) {
- // Interior volume level is in range 0 .. 63,
+ // Optionally render internal liquid level defined by param2
+ // Liquid is textured with 1 tile defined in nodedef 'special_tiles'
+ if (param2 > 0 && f->param_type_2 == CPT2_GLASSLIKE_LIQUID_LEVEL &&
+ f->special_tiles[0].layers[0].texture) {
+ // Internal liquid level has param2 range 0 .. 63,
// convert it to -0.5 .. 0.5
float vlev = (param2 / 63.0) * 2.0 - 1.0;
tile = getSpecialTile(*f, n, 0);
float size = BS / 2 * f->visual_scale;
v3f vertices[4] = {
- v3f(-size, -size, 0),
- v3f( size, -size, 0),
- v3f( size, size, 0),
v3f(-size, size, 0),
+ v3f( size, size, 0),
+ v3f( size, -size, 0),
+ v3f(-size, -size, 0),
};
for (int i = 0; i < 4; i++) {
switch (wall) {
bool offset_top_only)
{
v3f vertices[4] = {
- v3f(-scale, -BS / 2, 0),
- v3f( scale, -BS / 2, 0),
- v3f( scale, -BS / 2 + scale * 2, 0),
v3f(-scale, -BS / 2 + scale * 2, 0),
+ v3f( scale, -BS / 2 + scale * 2, 0),
+ v3f( scale, -BS / 2, 0),
+ v3f(-scale, -BS / 2, 0),
};
if (random_offset_Y) {
PseudoRandom yrng(face_num++ | p.X << 16 | p.Z << 8 | p.Y << 24);
offset.Y = BS * ((yrng.next() % 16 / 16.0) * 0.125);
}
- int offset_first_index = offset_top_only ? 2 : 0;
+ int offset_count = offset_top_only ? 2 : 4;
+ for (int i = 0; i < offset_count; i++)
+ vertices[i].Z += quad_offset;
for (int i = 0; i < 4; i++) {
- if (i >= offset_first_index)
- vertices[i].Z += quad_offset;
vertices[i].rotateXZBy(rotation + rotate_degree);
vertices[i] += offset;
}
float offset_h, float offset_v)
{
v3f vertices[4] = {
- v3f(-scale, -BS / 2, 0),
- v3f( scale, -BS / 2, 0),
- v3f( scale, -BS / 2 + scale * 2, 0),
v3f(-scale, -BS / 2 + scale * 2, 0),
+ v3f( scale, -BS / 2 + scale * 2, 0),
+ v3f( scale, -BS / 2, 0),
+ v3f(-scale, -BS / 2, 0),
};
for (int i = 0; i < 4; i++) {
vertices[i].rotateYZBy(opening_angle);
{
useDefaultTile(false);
TileSpec tile_nocrack = tile;
- tile_nocrack.material_flags &= ~MATERIAL_FLAG_CRACK;
+ for (int layer = 0; layer < MAX_TILE_LAYERS; layer++)
+ tile_nocrack.layers[layer].material_flags &= ~MATERIAL_FLAG_CRACK;
// Put wood the right way around in the posts
TileSpec tile_rot = tile;
static const float size = BS / 2;
float y2 = sloped ? size : -size;
v3f vertices[4] = {
- v3f(-size, -size + offset, -size),
- v3f( size, -size + offset, -size),
- v3f( size, y2 + offset, size),
v3f(-size, y2 + offset, size),
+ v3f( size, y2 + offset, size),
+ v3f( size, -size + offset, -size),
+ v3f(-size, -size + offset, -size),
};
if (angle)
for (int i = 0; i < 4; i++)
TileSpec tiles[6];
for (int face = 0; face < 6; face++) {
// Handles facedir rotation for textures
- tiles[face] = getTile(tile_dirs[face]);
+ getTile(tile_dirs[face], tiles[face]);
}
// locate possible neighboring nodes to connect to
// vertex right here.
for (int k = 0; k < vertex_count; k++) {
video::S3DVertex &vertex = vertices[k];
- vertex.Color = blendLight(vertex.Pos, vertex.Normal, tile.color);
+ vertex.Color = blendLightColor(vertex.Pos, vertex.Normal);
vertex.Pos += origin;
}
collector->append(tile, vertices, vertex_count,
else
light = getInteriorLight(n, 1, nodedef);
switch (f->drawtype) {
- case NDT_LIQUID: drawLiquidNode(false); break;
- case NDT_FLOWINGLIQUID: drawLiquidNode(true); break;
+ case NDT_FLOWINGLIQUID: drawLiquidNode(); break;
case NDT_GLASSLIKE: drawGlasslikeNode(); break;
case NDT_GLASSLIKE_FRAMED: drawGlasslikeFramedNode(); break;
case NDT_ALLFACES: drawAllfacesNode(); break;