Skip to content

Commit

Permalink
Add 'plantlike_rooted' drawtype
Browse files Browse the repository at this point in the history
Useful for underwater plants.
Node consists of a base cube plus a plantlike extension that can pass through
liquid nodes above without creating air bubbles or interfering with liquid flow.
Uses paramtype2 'leveled', param2 defines height of plantlike extension.
  • Loading branch information
numberZero authored and paramat committed Jul 11, 2017
1 parent f871852 commit ef285b2
Show file tree
Hide file tree
Showing 9 changed files with 193 additions and 121 deletions.
1 change: 1 addition & 0 deletions doc/lua_api.txt
Expand Up @@ -860,6 +860,7 @@ Look for examples in `games/minimal` or `games/minetest_game`.
* `raillike`
* `nodebox` -- See below. (**Experimental!**)
* `mesh` -- use models for nodes
* `plantlike_rooted`

`*_optional` drawtypes need less rendering time if deactivated (always client side).

Expand Down
129 changes: 76 additions & 53 deletions src/content_mapblock.cpp
Expand Up @@ -73,33 +73,49 @@ MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector
blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
}

void MapblockMeshGenerator::useTile(int index, bool disable_backface_culling)
void MapblockMeshGenerator::useTile(int index, u8 set_flags, u8 reset_flags, bool special)
{
getNodeTileN(n, p, index, data, tile);
if (special)
getSpecialTile(index, &tile, p == data->m_crack_pos_relative);
else
getNodeTileN(n, p, index, data, tile);
if (!data->m_smooth_lighting)
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;
tile.layers[layer].material_flags |= set_flags;
tile.layers[layer].material_flags &= ~reset_flags;
}
}

void MapblockMeshGenerator::useDefaultTile(bool set_color)
void MapblockMeshGenerator::getTile(v3s16 direction, TileSpec *tile)
{
getNodeTile(n, p, v3s16(0, 0, 0), data, tile);
if (set_color && !data->m_smooth_lighting)
color = encode_light(light, f->light_source);
getNodeTile(n, p, direction, data, *tile);
}

void MapblockMeshGenerator::getTile(const v3s16& direction, TileSpec &tile)
/*!
* Returns the i-th special tile for a map node.
*/
void MapblockMeshGenerator::getSpecialTile(int index, TileSpec *tile, bool apply_crack)
{
getNodeTile(n, p, direction, data, tile);
*tile = f->special_tiles[index];
TileLayer *top_layer = NULL;
for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
TileLayer *layer = &tile->layers[layernum];
if (layer->texture_id == 0)
continue;
top_layer = layer;
if (!layer->has_color)
n.getColor(*f, &layer->color);
}
if (apply_crack)
top_layer->material_flags |= MATERIAL_FLAG_CRACK;
}

void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal)
void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal,
float vertical_tiling)
{
static const v2f tcoords[4] = {v2f(0, 0), v2f(1, 0), v2f(1, 1), v2f(0, 1)};
const v2f tcoords[4] = {v2f(0.0, 0.0), v2f(1.0, 0.0),
v2f(1.0, vertical_tiling), v2f(0.0, vertical_tiling)};
video::S3DVertex vertices[4];
bool shade_face = !f->light_source && (normal != v3s16(0, 0, 0));
v3f normal2(normal.X, normal.Y, normal.Z);
Expand Down Expand Up @@ -358,27 +374,10 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
}
}

/*!
* Returns the i-th special tile for a map node.
*/
static TileSpec getSpecialTile(const ContentFeatures &f,
const MapNode &n, u8 i)
{
TileSpec copy = f.special_tiles[i];
for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
TileLayer *layer = &copy.layers[layernum];
if (layer->texture_id == 0)
continue;
if (!layer->has_color)
n.getColor(f, &(layer->color));
}
return copy;
}

void MapblockMeshGenerator::prepareLiquidNodeDrawing()
{
tile_liquid_top = getSpecialTile(*f, n, 0);
tile_liquid = getSpecialTile(*f, n, 1);
getSpecialTile(0, &tile_liquid_top);
getSpecialTile(1, &tile_liquid);

MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + v3s16(p.X, p.Y + 1, p.Z));
c_flowing = nodedef->getId(f->liquid_alternative_flowing);
Expand Down Expand Up @@ -603,7 +602,7 @@ void MapblockMeshGenerator::drawLiquidNode()

void MapblockMeshGenerator::drawGlasslikeNode()
{
useDefaultTile();
useTile(0, 0, 0);

for (int face = 0; face < 6; face++) {
// Check this neighbor
Expand Down Expand Up @@ -638,7 +637,7 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
{
TileSpec tiles[6];
for (int face = 0; face < 6; face++)
getTile(g_6dirs[face], tiles[face]);
getTile(g_6dirs[face], &tiles[face]);

TileSpec glass_tiles[6];
if (tiles[1].layers[0].texture &&
Expand Down Expand Up @@ -751,7 +750,7 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
// 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);
getSpecialTile(0, &tile);
drawAutoLightedCuboid(aabb3f(-(nb[5] ? g : b),
-(nb[4] ? g : b),
-(nb[3] ? g : b),
Expand All @@ -764,7 +763,7 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
void MapblockMeshGenerator::drawAllfacesNode()
{
static const aabb3f box(-BS / 2, -BS / 2, -BS / 2, BS / 2, BS / 2, BS / 2);
useDefaultTile(false);
useTile(0, 0, 0);
drawAutoLightedCuboid(box);
}

Expand All @@ -777,7 +776,7 @@ void MapblockMeshGenerator::drawTorchlikeNode()
case DWM_YN: tileindex = 0; break; // floor
default: tileindex = 2; // side (or invalid—should we care?)
}
useTile(tileindex, true);
useTile(tileindex, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);

float size = BS / 2 * f->visual_scale;
v3f vertices[4] = {
Expand All @@ -802,7 +801,7 @@ void MapblockMeshGenerator::drawTorchlikeNode()
void MapblockMeshGenerator::drawSignlikeNode()
{
u8 wall = n.getWallMounted(nodedef);
useTile(0, true);
useTile(0, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
static const float offset = BS / 16;
float size = BS / 2 * f->visual_scale;
// Wall at X+ of node
Expand All @@ -829,8 +828,8 @@ void MapblockMeshGenerator::drawPlantlikeQuad(float rotation, float quad_offset,
bool offset_top_only)
{
v3f vertices[4] = {
v3f(-scale, -BS / 2 + scale * 2, 0),
v3f( scale, -BS / 2 + scale * 2, 0),
v3f(-scale, -BS / 2 + 2.0 * scale * plant_height, 0),
v3f( scale, -BS / 2 + 2.0 * scale * plant_height, 0),
v3f( scale, -BS / 2, 0),
v3f(-scale, -BS / 2, 0),
};
Expand All @@ -845,18 +844,18 @@ void MapblockMeshGenerator::drawPlantlikeQuad(float rotation, float quad_offset,
vertices[i].rotateXZBy(rotation + rotate_degree);
vertices[i] += offset;
}
drawQuad(vertices);
drawQuad(vertices, v3s16(0, 0, 0), plant_height);
}

void MapblockMeshGenerator::drawPlantlikeNode()
void MapblockMeshGenerator::drawPlantlike()
{
useTile(0, false);
draw_style = PLANT_STYLE_CROSS;
scale = BS / 2 * f->visual_scale;
offset = v3f(0, 0, 0);
rotate_degree = 0;
random_offset_Y = false;
face_num = 0;
plant_height = 1.0;

switch (f->param_type_2) {
case CPT2_MESHOPTIONS:
Expand All @@ -876,6 +875,10 @@ void MapblockMeshGenerator::drawPlantlikeNode()
rotate_degree = n.param2 * 2;
break;

case CPT2_LEVELED:
plant_height = n.param2 / 16.0;
break;

default:
break;
}
Expand Down Expand Up @@ -913,6 +916,27 @@ void MapblockMeshGenerator::drawPlantlikeNode()
}
}

void MapblockMeshGenerator::drawPlantlikeNode()
{
useTile();
drawPlantlike();
}

void MapblockMeshGenerator::drawPlantlikeRootedNode()
{
useTile(0, MATERIAL_FLAG_CRACK_OVERLAY, 0, true);
origin += v3f(0.0, BS, 0.0);
p.Y++;
if (data->m_smooth_lighting) {
getSmoothLightFrame();
} else {
MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + p);
light = getInteriorLight(ntop, 1, nodedef);
}
drawPlantlike();
p.Y--;
}

void MapblockMeshGenerator::drawFirelikeQuad(float rotation, float opening_angle,
float offset_h, float offset_v)
{
Expand All @@ -933,7 +957,7 @@ void MapblockMeshGenerator::drawFirelikeQuad(float rotation, float opening_angle

void MapblockMeshGenerator::drawFirelikeNode()
{
useTile(0, false);
useTile();
scale = BS / 2 * f->visual_scale;

// Check for adjacent nodes
Expand Down Expand Up @@ -980,7 +1004,7 @@ void MapblockMeshGenerator::drawFirelikeNode()

void MapblockMeshGenerator::drawFencelikeNode()
{
useDefaultTile(false);
useTile(0, 0, 0);
TileSpec tile_nocrack = tile;
for (int layer = 0; layer < MAX_TILE_LAYERS; layer++)
tile_nocrack.layers[layer].material_flags &= ~MATERIAL_FLAG_CRACK;
Expand Down Expand Up @@ -1130,7 +1154,7 @@ void MapblockMeshGenerator::drawRaillikeNode()
angle = rail_kinds[code].angle;
}

useTile(tile_index, true);
useTile(tile_index, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);

static const float offset = BS / 64;
static const float size = BS / 2;
Expand Down Expand Up @@ -1171,7 +1195,7 @@ void MapblockMeshGenerator::drawNodeboxNode()
TileSpec tiles[6];
for (int face = 0; face < 6; face++) {
// Handles facedir rotation for textures
getTile(tile_dirs[face], tiles[face]);
getTile(tile_dirs[face], &tiles[face]);
}

// locate possible neighboring nodes to connect to
Expand Down Expand Up @@ -1228,7 +1252,7 @@ void MapblockMeshGenerator::drawMeshNode()

int mesh_buffer_count = mesh->getMeshBufferCount();
for (int j = 0; j < mesh_buffer_count; j++) {
useTile(j, false);
useTile(j);
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
int vertex_count = buf->getVertexCount();
Expand Down Expand Up @@ -1269,13 +1293,17 @@ void MapblockMeshGenerator::drawNode()
else
light = getInteriorLight(n, 1, nodedef);
switch (f->drawtype) {
case NDT_NORMAL: break; // Drawn by MapBlockMesh
case NDT_AIRLIKE: break; // Not drawn at all
case NDT_LIQUID: break; // Drawn by MapBlockMesh
case NDT_FLOWINGLIQUID: drawLiquidNode(); break;
case NDT_GLASSLIKE: drawGlasslikeNode(); break;
case NDT_GLASSLIKE_FRAMED: drawGlasslikeFramedNode(); break;
case NDT_ALLFACES: drawAllfacesNode(); break;
case NDT_TORCHLIKE: drawTorchlikeNode(); break;
case NDT_SIGNLIKE: drawSignlikeNode(); break;
case NDT_PLANTLIKE: drawPlantlikeNode(); break;
case NDT_PLANTLIKE_ROOTED: drawPlantlikeRootedNode(); break;
case NDT_FIRELIKE: drawFirelikeNode(); break;
case NDT_FENCELIKE: drawFencelikeNode(); break;
case NDT_RAILLIKE: drawRaillikeNode(); break;
Expand All @@ -1296,11 +1324,6 @@ void MapblockMeshGenerator::generate()
for (p.X = 0; p.X < MAP_BLOCKSIZE; p.X++) {
n = data->m_vmanip.getNodeNoEx(blockpos_nodes + p);
f = &nodedef->get(n);
// Solid nodes are drawn by MapBlockMesh
if (f->solidness != 0)
continue;
if (f->drawtype == NDT_AIRLIKE)
continue;
origin = intToFloat(p, BS);
drawNode();
}
Expand Down
13 changes: 9 additions & 4 deletions src/content_mapblock.h
Expand Up @@ -62,12 +62,14 @@ class MapblockMeshGenerator
video::SColor blendLightColor(const v3f &vertex_pos);
video::SColor blendLightColor(const v3f &vertex_pos, const v3f &vertex_normal);

void useTile(int index, bool disable_backface_culling);
void useDefaultTile(bool set_color = true);
void getTile(const v3s16 &direction, TileSpec &tile);
void useTile(int index = 0, u8 set_flags = MATERIAL_FLAG_CRACK_OVERLAY,
u8 reset_flags = 0, bool special = false);
void getTile(v3s16 direction, TileSpec *tile);
void getSpecialTile(int index, TileSpec *tile, bool apply_crack = false);

// face drawing
void drawQuad(v3f *vertices, const v3s16 &normal = v3s16(0, 0, 0));
void drawQuad(v3f *vertices, const v3s16 &normal = v3s16(0, 0, 0),
float vertical_tiling = 1.0);

// cuboid drawing!
void drawCuboid(const aabb3f &box, TileSpec *tiles, int tilecount,
Expand Down Expand Up @@ -111,9 +113,11 @@ class MapblockMeshGenerator
int rotate_degree;
bool random_offset_Y;
int face_num;
float plant_height;

void drawPlantlikeQuad(float rotation, float quad_offset = 0,
bool offset_top_only = false);
void drawPlantlike();

// firelike-specific
void drawFirelikeQuad(float rotation, float opening_angle,
Expand All @@ -127,6 +131,7 @@ class MapblockMeshGenerator
void drawTorchlikeNode();
void drawSignlikeNode();
void drawPlantlikeNode();
void drawPlantlikeRootedNode();
void drawFirelikeNode();
void drawFencelikeNode();
void drawRaillikeNode();
Expand Down

0 comments on commit ef285b2

Please sign in to comment.