*/
MeshMakeData::MeshMakeData(Client *client, bool use_shaders):
+ m_mesh_grid(client->getMeshGrid()),
+ side_length(MAP_BLOCKSIZE * m_mesh_grid.cell_size),
m_client(client),
m_use_shaders(use_shaders)
{}
m_vmanip.clear();
VoxelArea voxel_area(blockpos_nodes - v3s16(1,1,1) * MAP_BLOCKSIZE,
- blockpos_nodes + v3s16(1,1,1) * MAP_BLOCKSIZE*2-v3s16(1,1,1));
+ blockpos_nodes + v3s16(1,1,1) * (side_length + MAP_BLOCKSIZE /* extra layer of blocks around the mesh */) - v3s16(1,1,1));
m_vmanip.addArea(voxel_area);
}
-void MeshMakeData::fillBlockData(const v3s16 &block_offset, MapNode *data)
+void MeshMakeData::fillBlockData(const v3s16 &bp, MapNode *data)
{
v3s16 data_size(MAP_BLOCKSIZE, MAP_BLOCKSIZE, MAP_BLOCKSIZE);
VoxelArea data_area(v3s16(0,0,0), data_size - v3s16(1,1,1));
- v3s16 bp = m_blockpos + block_offset;
v3s16 blockpos_nodes = bp * MAP_BLOCKSIZE;
m_vmanip.copyFrom(data, data_area, v3s16(0,0,0), blockpos_nodes, data_size);
}
-void MeshMakeData::fill(MapBlock *block)
-{
- fillBlockDataBegin(block->getPos());
-
- fillBlockData(v3s16(0,0,0), block->getData());
-
- // Get map for reading neighbor blocks
- Map *map = block->getParent();
-
- for (const v3s16 &dir : g_26dirs) {
- v3s16 bp = m_blockpos + dir;
- MapBlock *b = map->getBlockNoCreateNoEx(bp);
- if(b)
- fillBlockData(dir, b->getData());
- }
-}
-
void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
{
if (crack_level >= 0)
static u8 getInteriorLight(enum LightBank bank, MapNode n, s32 increment,
const NodeDefManager *ndef)
{
- u8 light = n.getLight(bank, ndef);
- if (light > 0)
- light = rangelim(light + increment, 0, LIGHT_SUN);
+ u8 light = n.getLight(bank, ndef->getLightingFlags(n));
+ light = rangelim(light + increment, 0, LIGHT_SUN);
return decode_light(light);
}
static u8 getFaceLight(enum LightBank bank, MapNode n, MapNode n2,
v3s16 face_dir, const NodeDefManager *ndef)
{
+ ContentLightingFlags f1 = ndef->getLightingFlags(n);
+ ContentLightingFlags f2 = ndef->getLightingFlags(n2);
+
u8 light;
- u8 l1 = n.getLight(bank, ndef);
- u8 l2 = n2.getLight(bank, ndef);
+ u8 l1 = n.getLight(bank, f1);
+ u8 l2 = n2.getLight(bank, f2);
if(l1 > l2)
light = l1;
else
light = l2;
// Boost light level for light sources
- u8 light_source = MYMAX(ndef->get(n).light_source,
- ndef->get(n2).light_source);
+ u8 light_source = MYMAX(f1.light_source, f2.light_source);
if(light_source > light)
light = light_source;
light_source_max = f.light_source;
// Check f.solidness because fast-style leaves look better this way
if (f.param_type == CPT_LIGHT && f.solidness != 2) {
- u8 light_level_day = n.getLightNoChecks(LIGHTBANK_DAY, &f);
- u8 light_level_night = n.getLightNoChecks(LIGHTBANK_NIGHT, &f);
+ u8 light_level_day = n.getLight(LIGHTBANK_DAY, f.getLightingFlags());
+ u8 light_level_night = n.getLight(LIGHTBANK_NIGHT, f.getLightingFlags());
if (light_level_day == LIGHT_SUN)
direct_sunlight = true;
light_day += decode_light(light_level_day);
const ContentFeatures &f2 = ndef->get(m2);
// Contents don't differ for different forms of same liquid
- if (f1.sameLiquid(f2))
+ if (f1.sameLiquidRender(f2))
return 0;
u8 c1 = f1.solidness;
if (c1 == c2) {
*equivalent = true;
// If same solidness, liquid takes precense
- if (f1.isLiquid())
+ if (f1.isLiquidRender())
return 1;
- if (f2.isLiquid())
+ if (f2.isLiquidRender())
return 2;
}
// Unroll this variable which has a significant build cost
TileSpec next_tile;
- for (u16 j = 0; j < MAP_BLOCKSIZE; j++) {
+ for (u16 j = 0; j < data->side_length; j++) {
// If tiling can be done, this is set to false in the next step
bool next_is_different = true;
// If at last position, there is nothing to compare to and
// the face must be drawn anyway
- if (j != MAP_BLOCKSIZE - 1) {
+ if (j != data->side_length - 1) {
p += translate_dir;
getTileInfo(data, p, face_dir,
/*
Go through every y,z and get top(y+) faces in rows of x+
*/
- for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
- for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
+ for (s16 y = 0; y < data->side_length; y++)
+ for (s16 z = 0; z < data->side_length; z++)
updateFastFaceRow(data,
v3s16(0, y, z),
v3s16(1, 0, 0), //dir
/*
Go through every x,y and get right(x+) faces in rows of z+
*/
- for (s16 x = 0; x < MAP_BLOCKSIZE; x++)
- for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
+ for (s16 x = 0; x < data->side_length; x++)
+ for (s16 y = 0; y < data->side_length; y++)
updateFastFaceRow(data,
v3s16(x, y, 0),
v3s16(0, 0, 1), //dir
/*
Go through every y,z and get back(z+) faces in rows of x+
*/
- for (s16 z = 0; z < MAP_BLOCKSIZE; z++)
- for (s16 y = 0; y < MAP_BLOCKSIZE; y++)
+ for (s16 z = 0; z < data->side_length; z++)
+ for (s16 y = 0; y < data->side_length; y++)
updateFastFaceRow(data,
v3s16(0, y, z),
v3s16(1, 0, 0), //dir
MapBlockBspTree
*/
-void MapBlockBspTree::buildTree(const std::vector<MeshTriangle> *triangles)
+void MapBlockBspTree::buildTree(const std::vector<MeshTriangle> *triangles, u16 side_length)
{
this->triangles = triangles;
for (u32 i = 0; i < triangles->size(); i++)
indexes.push_back(i);
- root = buildTree(v3f(1, 0, 0), v3f(85, 85, 85), 40, indexes, 0);
+ if (!indexes.empty()) {
+ // Start in the center of the block with increment of one quarter in each direction
+ root = buildTree(v3f(1, 0, 0), v3f((side_length + 1) * 0.5f * BS), side_length * 0.25f * BS, indexes, 0);
+ } else {
+ root = -1;
+ }
}
/**
* @brief Find a candidate plane to split a set of triangles in two
- *
+ *
* The candidate plane is represented by one of the triangles from the set.
- *
+ *
* @param list Vector of indexes of the triangles in the set
* @param triangles Vector of all triangles in the BSP tree
* @return Address of the triangle that represents the proposed split plane
v3f next_normal = candidate_normal;
v3f next_origin = origin + delta * normal;
float next_delta = candidate_delta;
- if (next_delta < 10) {
+ if (next_delta < 5) {
const MeshTriangle *candidate = findSplitCandidate(front_list, *triangles);
next_normal = candidate->getNormal();
next_origin = candidate->centroid;
v3f next_normal = candidate_normal;
v3f next_origin = origin - delta * normal;
float next_delta = candidate_delta;
- if (next_delta < 10) {
+ if (next_delta < 5) {
const MeshTriangle *candidate = findSplitCandidate(back_list, *triangles);
next_normal = candidate->getNormal();
next_origin = candidate->centroid;
void PartialMeshBuffer::afterDraw() const
{
// Take the data back
- m_vertex_indexes = std::move(m_buffer->Indices.steal());
+ m_vertex_indexes = m_buffer->Indices.steal();
}
/*
*/
MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
- m_minimap_mapblock(NULL),
m_tsrc(data->m_client->getTextureSource()),
m_shdrsrc(data->m_client->getShaderSource()),
m_animation_force_timer(0), // force initial animation
m_enable_shaders = data->m_use_shaders;
m_enable_vbo = g_settings->getBool("enable_vbo");
- if (data->m_client->getMinimap()) {
- m_minimap_mapblock = new MinimapMapblock;
- m_minimap_mapblock->getMinimapNodes(
- &data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
+ v3s16 bp = data->m_blockpos;
+ // Only generate minimap mapblocks at even coordinates.
+ if (data->m_mesh_grid.isMeshPos(bp) && data->m_client->getMinimap()) {
+ m_minimap_mapblocks.resize(data->m_mesh_grid.getCellVolume(), nullptr);
+ v3s16 ofs;
+
+ // See also client.cpp for the code that reads the array of minimap blocks.
+ for (ofs.Z = 0; ofs.Z < data->m_mesh_grid.cell_size; ofs.Z++)
+ for (ofs.Y = 0; ofs.Y < data->m_mesh_grid.cell_size; ofs.Y++)
+ for (ofs.X = 0; ofs.X < data->m_mesh_grid.cell_size; ofs.X++) {
+ v3s16 p = (bp + ofs) * MAP_BLOCKSIZE;
+ if (data->m_vmanip.getNodeNoEx(p).getContent() != CONTENT_IGNORE) {
+ MinimapMapblock *block = new MinimapMapblock;
+ m_minimap_mapblocks[data->m_mesh_grid.getOffsetIndex(ofs)] = block;
+ block->getMinimapNodes(&data->m_vmanip, p);
+ }
+ }
}
// 4-21ms for MAP_BLOCKSIZE=16 (NOTE: probably outdated)
Convert FastFaces to MeshCollector
*/
- MeshCollector collector;
+ v3f offset = intToFloat((data->m_blockpos - data->m_mesh_grid.getMeshPos(data->m_blockpos)) * MAP_BLOCKSIZE, BS);
+ MeshCollector collector(m_bounding_sphere_center, offset);
{
// avg 0ms (100ms spikes when loading textures the first time)
const bool desync_animations = g_settings->getBool(
"desynchronize_mapblock_texture_animation");
+ m_bounding_radius = std::sqrt(collector.m_bounding_radius_sq);
+
for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
for(u32 i = 0; i < collector.prebuffers[layer].size(); i++)
{
scene::SMeshBuffer *buf = new scene::SMeshBuffer();
buf->Material = material;
- switch (p.layer.material_type) {
- // list of transparent materials taken from tile.h
- case TILE_MATERIAL_ALPHA:
- case TILE_MATERIAL_LIQUID_TRANSPARENT:
- case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
- {
- buf->append(&p.vertices[0], p.vertices.size(),
- &p.indices[0], 0);
-
- MeshTriangle t;
- t.buffer = buf;
- for (u32 i = 0; i < p.indices.size(); i += 3) {
- t.p1 = p.indices[i];
- t.p2 = p.indices[i + 1];
- t.p3 = p.indices[i + 2];
- t.updateAttributes();
- m_transparent_triangles.push_back(t);
- }
+ if (p.layer.isTransparent()) {
+ buf->append(&p.vertices[0], p.vertices.size(), nullptr, 0);
+
+ MeshTriangle t;
+ t.buffer = buf;
+ m_transparent_triangles.reserve(p.indices.size() / 3);
+ for (u32 i = 0; i < p.indices.size(); i += 3) {
+ t.p1 = p.indices[i];
+ t.p2 = p.indices[i + 1];
+ t.p3 = p.indices[i + 2];
+ t.updateAttributes();
+ m_transparent_triangles.push_back(t);
}
- break;
- default:
+ } else {
buf->append(&p.vertices[0], p.vertices.size(),
&p.indices[0], p.indices.size());
- break;
}
mesh->addMeshBuffer(buf);
buf->drop();
}
//std::cout<<"added "<<fastfaces.getSize()<<" faces."<<std::endl;
- m_bsp_tree.buildTree(&m_transparent_triangles);
+ m_bsp_tree.buildTree(&m_transparent_triangles, data->side_length);
// Check if animation is required for this mesh
m_has_animation =
MapBlockMesh::~MapBlockMesh()
{
for (scene::IMesh *m : m_mesh) {
-#if IRRLICHT_VERSION_MT_REVISION < 5
- if (m_enable_vbo) {
- for (u32 i = 0; i < m->getMeshBufferCount(); i++) {
- scene::IMeshBuffer *buf = m->getMeshBuffer(i);
- RenderingEngine::get_video_driver()->removeHardwareBuffer(buf);
- }
- }
-#endif
m->drop();
}
- delete m_minimap_mapblock;
+ for (MinimapMapblock *block : m_minimap_mapblocks)
+ delete block;
}
bool MapBlockMesh::animate(bool faraway, float time, int crack,
float b = (day + night) / 2;
return video::SColor(r, b, b, b);
}
+
+std::unordered_map<v3s16, u8> get_solid_sides(MeshMakeData *data)
+{
+ std::unordered_map<v3s16, u8> results;
+ v3s16 ofs;
+ const u16 mesh_chunk = data->side_length / MAP_BLOCKSIZE;
+
+ for (ofs.X = 0; ofs.X < mesh_chunk; ofs.X++)
+ for (ofs.Y = 0; ofs.Y < mesh_chunk; ofs.Y++)
+ for (ofs.Z = 0; ofs.Z < mesh_chunk; ofs.Z++) {
+ v3s16 blockpos = data->m_blockpos + ofs;
+ v3s16 blockpos_nodes = blockpos * MAP_BLOCKSIZE;
+ const NodeDefManager *ndef = data->m_client->ndef();
+
+ u8 result = 0x3F; // all sides solid;
+
+ for (s16 i = 0; i < MAP_BLOCKSIZE && result != 0; i++)
+ for (s16 j = 0; j < MAP_BLOCKSIZE && result != 0; j++) {
+ v3s16 positions[6] = {
+ v3s16(0, i, j),
+ v3s16(MAP_BLOCKSIZE - 1, i, j),
+ v3s16(i, 0, j),
+ v3s16(i, MAP_BLOCKSIZE - 1, j),
+ v3s16(i, j, 0),
+ v3s16(i, j, MAP_BLOCKSIZE - 1)
+ };
+
+ for (u8 k = 0; k < 6; k++) {
+ const MapNode &top = data->m_vmanip.getNodeRefUnsafe(blockpos_nodes + positions[k]);
+ if (ndef->get(top).solidness != 2)
+ result &= ~(1 << k);
+ }
+ }
+
+ results[blockpos] = result;
+ }
+ return results;
+}