mirror of
https://github.com/luanti-org/luanti.git
synced 2025-08-01 17:38:41 +00:00
Merge remote-tracking branch 'upstream/master' into Visuals-Vol-2
This commit is contained in:
commit
6b1785eb2c
128 changed files with 1273 additions and 1076 deletions
|
@ -417,7 +417,6 @@ set(independent_SRCS
|
|||
hud.cpp
|
||||
inventory.cpp
|
||||
itemstackmetadata.cpp
|
||||
lighting.cpp
|
||||
log.cpp
|
||||
metadata.cpp
|
||||
modchannels.cpp
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include "debug.h"
|
||||
#include "util/container.h"
|
||||
#include "irrlichttypes.h"
|
||||
#include "util/basic_macros.h"
|
||||
|
|
|
@ -112,7 +112,8 @@ public:
|
|||
|
||||
void resize(u32 scrollback);
|
||||
|
||||
protected:
|
||||
// Get the current scroll position
|
||||
s32 getScrollPosition() const { return m_scroll; }
|
||||
s32 getTopScrollPos() const;
|
||||
s32 getBottomScrollPos() const;
|
||||
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "util/container.h"
|
||||
#include <string>
|
||||
#include <queue>
|
||||
#include "irrlichttypes.h"
|
||||
#include "util/container.h" // MutexedQueue
|
||||
#include <string>
|
||||
|
||||
enum ChatEventType {
|
||||
CET_CHAT,
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "profiler.h"
|
||||
#include "shader.h"
|
||||
#include "gettext.h"
|
||||
#include "gettime.h"
|
||||
#include "clientdynamicinfo.h"
|
||||
#include "clientmap.h"
|
||||
#include "clientmedia.h"
|
||||
|
|
|
@ -91,8 +91,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
|
|||
init_args(start_data, cmd_args);
|
||||
|
||||
#if USE_SOUND
|
||||
if (g_settings->getBool("enable_sound"))
|
||||
g_sound_manager_singleton = createSoundManagerSingleton();
|
||||
g_sound_manager_singleton = createSoundManagerSingleton();
|
||||
#endif
|
||||
|
||||
if (!init_engine())
|
||||
|
|
|
@ -445,8 +445,8 @@ void Clouds::readSettings()
|
|||
// chosen to avoid exactly that.
|
||||
// refer to vertex_count in updateMesh()
|
||||
m_enable_3d = g_settings->getBool("enable_3d_clouds");
|
||||
const u16 maximum = m_enable_3d ? 62 : 25;
|
||||
m_cloud_radius_i = rangelim(g_settings->getU16("cloud_radius"), 1, maximum);
|
||||
const u16 maximum = !m_enable_3d ? 62 : 25;
|
||||
m_cloud_radius_i = rangelim(g_settings->getU16("cloud_radius"), 8, maximum);
|
||||
|
||||
invalidateMesh();
|
||||
}
|
||||
|
|
|
@ -656,25 +656,33 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
|
|||
}
|
||||
} else if (m_prop.visual == "upright_sprite") {
|
||||
grabMatrixNode();
|
||||
scene::SMesh *mesh = new scene::SMesh();
|
||||
double dx = BS * m_prop.visual_size.X / 2;
|
||||
double dy = BS * m_prop.visual_size.Y / 2;
|
||||
auto mesh = make_irr<scene::SMesh>();
|
||||
f32 dx = BS * m_prop.visual_size.X / 2;
|
||||
f32 dy = BS * m_prop.visual_size.Y / 2;
|
||||
video::SColor c(0xFFFFFFFF);
|
||||
|
||||
{ // Front
|
||||
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
|
||||
video::S3DVertex vertices[4] = {
|
||||
video::S3DVertex(-dx, -dy, 0, 0,0,1, c, 1,1),
|
||||
video::S3DVertex( dx, -dy, 0, 0,0,1, c, 0,1),
|
||||
video::S3DVertex( dx, dy, 0, 0,0,1, c, 0,0),
|
||||
video::S3DVertex(-dx, dy, 0, 0,0,1, c, 1,0),
|
||||
};
|
||||
if (m_is_player) {
|
||||
// Move minimal Y position to 0 (feet position)
|
||||
for (video::S3DVertex &vertex : vertices)
|
||||
vertex.Pos.Y += dy;
|
||||
video::S3DVertex vertices[4] = {
|
||||
video::S3DVertex(-dx, -dy, 0, 0,0,1, c, 1,1),
|
||||
video::S3DVertex( dx, -dy, 0, 0,0,1, c, 0,1),
|
||||
video::S3DVertex( dx, dy, 0, 0,0,1, c, 0,0),
|
||||
video::S3DVertex(-dx, dy, 0, 0,0,1, c, 1,0),
|
||||
};
|
||||
if (m_is_player) {
|
||||
// Move minimal Y position to 0 (feet position)
|
||||
for (auto &vertex : vertices)
|
||||
vertex.Pos.Y += dy;
|
||||
}
|
||||
const u16 indices[] = {0,1,2,2,3,0};
|
||||
|
||||
for (int face : {0, 1}) {
|
||||
auto buf = make_irr<scene::SMeshBuffer>();
|
||||
// Front (0) or Back (1)
|
||||
if (face == 1) {
|
||||
for (auto &v : vertices)
|
||||
v.Normal *= -1;
|
||||
for (int i : {0, 2})
|
||||
std::swap(vertices[i].Pos, vertices[i+1].Pos);
|
||||
}
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
buf->append(vertices, 4, indices, 6);
|
||||
|
||||
// Set material
|
||||
|
@ -682,36 +690,12 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
|
|||
buf->getMaterial().ColorParam = c;
|
||||
|
||||
// Add to mesh
|
||||
mesh->addMeshBuffer(buf);
|
||||
buf->drop();
|
||||
mesh->addMeshBuffer(buf.get());
|
||||
}
|
||||
{ // Back
|
||||
scene::IMeshBuffer *buf = new scene::SMeshBuffer();
|
||||
video::S3DVertex vertices[4] = {
|
||||
video::S3DVertex( dx,-dy, 0, 0,0,-1, c, 1,1),
|
||||
video::S3DVertex(-dx,-dy, 0, 0,0,-1, c, 0,1),
|
||||
video::S3DVertex(-dx, dy, 0, 0,0,-1, c, 0,0),
|
||||
video::S3DVertex( dx, dy, 0, 0,0,-1, c, 1,0),
|
||||
};
|
||||
if (m_is_player) {
|
||||
// Move minimal Y position to 0 (feet position)
|
||||
for (video::S3DVertex &vertex : vertices)
|
||||
vertex.Pos.Y += dy;
|
||||
}
|
||||
u16 indices[] = {0,1,2,2,3,0};
|
||||
buf->append(vertices, 4, indices, 6);
|
||||
|
||||
// Set material
|
||||
setMaterial(buf->getMaterial());
|
||||
buf->getMaterial().ColorParam = c;
|
||||
|
||||
// Add to mesh
|
||||
mesh->addMeshBuffer(buf);
|
||||
buf->drop();
|
||||
}
|
||||
m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode);
|
||||
mesh->recalculateBoundingBox();
|
||||
m_meshnode = m_smgr->addMeshSceneNode(mesh.get(), m_matrixnode);
|
||||
m_meshnode->grab();
|
||||
mesh->drop();
|
||||
} else if (m_prop.visual == "cube") {
|
||||
grabMatrixNode();
|
||||
scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));
|
||||
|
|
|
@ -4,15 +4,23 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "clientobject.h"
|
||||
#include "EMaterialTypes.h"
|
||||
#include "IDummyTransformationSceneNode.h"
|
||||
#include "irrlichttypes.h"
|
||||
|
||||
#include "object_properties.h"
|
||||
#include "itemgroup.h"
|
||||
#include "clientobject.h"
|
||||
#include "constants.h"
|
||||
#include "itemgroup.h"
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace irr::scene {
|
||||
class IMeshSceneNode;
|
||||
class IBillboardSceneNode;
|
||||
}
|
||||
|
||||
class Camera;
|
||||
class Client;
|
||||
struct Nametag;
|
||||
|
|
|
@ -62,46 +62,44 @@ const std::string MapblockMeshGenerator::raillike_groupname = "connect_to_railli
|
|||
MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output):
|
||||
data(input),
|
||||
collector(output),
|
||||
nodedef(data->nodedef),
|
||||
blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE),
|
||||
smooth_liquids(g_settings->getBool("enable_water_reflections"))
|
||||
nodedef(data->m_nodedef),
|
||||
blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE)
|
||||
{
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::useTile(int index, u8 set_flags, u8 reset_flags, bool special)
|
||||
void MapblockMeshGenerator::useTile(TileSpec *tile_ret, int index, u8 set_flags,
|
||||
u8 reset_flags, bool special)
|
||||
{
|
||||
if (special)
|
||||
getSpecialTile(index, &cur_node.tile, cur_node.p == data->m_crack_pos_relative);
|
||||
getSpecialTile(index, tile_ret, cur_node.p == data->m_crack_pos_relative);
|
||||
else
|
||||
getTile(index, &cur_node.tile);
|
||||
if (!data->m_smooth_lighting)
|
||||
cur_node.color = encode_light(cur_node.light, cur_node.f->light_source);
|
||||
getTile(index, tile_ret);
|
||||
|
||||
for (auto &layer : cur_node.tile.layers) {
|
||||
for (auto &layer : tile_ret->layers) {
|
||||
layer.material_flags |= set_flags;
|
||||
layer.material_flags &= ~reset_flags;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a tile, ready for use, non-rotated.
|
||||
void MapblockMeshGenerator::getTile(int index, TileSpec *tile)
|
||||
void MapblockMeshGenerator::getTile(int index, TileSpec *tile_ret)
|
||||
{
|
||||
getNodeTileN(cur_node.n, cur_node.p, index, data, *tile);
|
||||
getNodeTileN(cur_node.n, cur_node.p, index, data, *tile_ret);
|
||||
}
|
||||
|
||||
// Returns a tile, ready for use, rotated according to the node facedir.
|
||||
void MapblockMeshGenerator::getTile(v3s16 direction, TileSpec *tile)
|
||||
void MapblockMeshGenerator::getTile(v3s16 direction, TileSpec *tile_ret)
|
||||
{
|
||||
getNodeTile(cur_node.n, cur_node.p, direction, data, *tile);
|
||||
getNodeTile(cur_node.n, cur_node.p, direction, data, *tile_ret);
|
||||
}
|
||||
|
||||
// Returns a special tile, ready for use, non-rotated.
|
||||
void MapblockMeshGenerator::getSpecialTile(int index, TileSpec *tile, bool apply_crack)
|
||||
void MapblockMeshGenerator::getSpecialTile(int index, TileSpec *tile_ret, bool apply_crack)
|
||||
{
|
||||
*tile = cur_node.f->special_tiles[index];
|
||||
*tile_ret = cur_node.f->special_tiles[index];
|
||||
TileLayer *top_layer = nullptr;
|
||||
|
||||
for (auto &layernum : tile->layers) {
|
||||
for (auto &layernum : tile_ret->layers) {
|
||||
TileLayer *layer = &layernum;
|
||||
if (layer->texture_id == 0)
|
||||
continue;
|
||||
|
@ -114,7 +112,7 @@ void MapblockMeshGenerator::getSpecialTile(int index, TileSpec *tile, bool apply
|
|||
top_layer->material_flags |= MATERIAL_FLAG_CRACK;
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal,
|
||||
void MapblockMeshGenerator::drawQuad(const TileSpec &tile, v3f *coords, const v3s16 &normal,
|
||||
float vertical_tiling)
|
||||
{
|
||||
const v2f tcoords[4] = {v2f(0.0, 0.0), v2f(1.0, 0.0),
|
||||
|
@ -128,15 +126,17 @@ void MapblockMeshGenerator::drawQuad(v3f *coords, const v3s16 &normal,
|
|||
if (data->m_smooth_lighting)
|
||||
vertices[j].Color = blendLightColor(coords[j]);
|
||||
else
|
||||
vertices[j].Color = cur_node.color;
|
||||
vertices[j].Color = cur_node.lcolor;
|
||||
if (shade_face)
|
||||
applyFacesShading(vertices[j].Color, normal2);
|
||||
vertices[j].TCoords = tcoords[j];
|
||||
}
|
||||
collector->append(cur_node.tile, vertices, 4, quad_indices, 6);
|
||||
collector->append(tile, vertices, 4, quad_indices, 6);
|
||||
}
|
||||
|
||||
static std::array<video::S3DVertex, 24> setupCuboidVertices(const aabb3f &box, const f32 *txc, TileSpec *tiles, int tilecount) {
|
||||
static std::array<video::S3DVertex, 24> setupCuboidVertices(const aabb3f &box,
|
||||
const f32 *txc, const TileSpec *tiles, int tilecount)
|
||||
{
|
||||
v3f min = box.MinEdge;
|
||||
v3f max = box.MaxEdge;
|
||||
|
||||
|
@ -218,7 +218,7 @@ enum class QuadDiagonal {
|
|||
// 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)
|
||||
const TileSpec *tiles, int tilecount, const f32 *txc, u8 mask, Fn &&face_lighter)
|
||||
{
|
||||
assert(tilecount >= 1 && tilecount <= 6); // pre-condition
|
||||
|
||||
|
@ -238,16 +238,16 @@ void MapblockMeshGenerator::drawCuboid(const aabb3f &box,
|
|||
void MapblockMeshGenerator::getSmoothLightFrame()
|
||||
{
|
||||
for (int k = 0; k < 8; ++k)
|
||||
cur_node.frame.sunlight[k] = false;
|
||||
cur_node.lframe.sunlight[k] = false;
|
||||
for (int k = 0; k < 8; ++k) {
|
||||
LightPair light(getSmoothLightTransparent(blockpos_nodes + cur_node.p, light_dirs[k], data));
|
||||
cur_node.frame.lightsDay[k] = light.lightDay;
|
||||
cur_node.frame.lightsNight[k] = light.lightNight;
|
||||
cur_node.lframe.lightsDay[k] = light.lightDay;
|
||||
cur_node.lframe.lightsNight[k] = light.lightNight;
|
||||
// If there is direct sunlight and no ambient occlusion at some corner,
|
||||
// mark the vertical edge (top and bottom corners) containing it.
|
||||
if (light.lightDay == 255) {
|
||||
cur_node.frame.sunlight[k] = true;
|
||||
cur_node.frame.sunlight[k ^ 2] = true;
|
||||
cur_node.lframe.sunlight[k] = true;
|
||||
cur_node.lframe.sunlight[k ^ 2] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -270,9 +270,9 @@ LightInfo MapblockMeshGenerator::blendLight(const v3f &vertex_pos)
|
|||
f32 dy = (k & 2) ? y : 1 - y;
|
||||
f32 dz = (k & 1) ? z : 1 - z;
|
||||
// Use direct sunlight (255), if any; use daylight otherwise.
|
||||
f32 light_boosted = cur_node.frame.sunlight[k] ? 255 : cur_node.frame.lightsDay[k];
|
||||
lightDay += dx * dy * dz * cur_node.frame.lightsDay[k];
|
||||
lightNight += dx * dy * dz * cur_node.frame.lightsNight[k];
|
||||
f32 light_boosted = cur_node.lframe.sunlight[k] ? 255 : cur_node.lframe.lightsDay[k];
|
||||
lightDay += dx * dy * dz * cur_node.lframe.lightsDay[k];
|
||||
lightNight += dx * dy * dz * cur_node.lframe.lightsNight[k];
|
||||
lightBoosted += dx * dy * dz * light_boosted;
|
||||
}
|
||||
return LightInfo{lightDay, lightNight, lightBoosted};
|
||||
|
@ -280,7 +280,6 @@ LightInfo MapblockMeshGenerator::blendLight(const v3f &vertex_pos)
|
|||
|
||||
// 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::blendLightColor(const v3f &vertex_pos)
|
||||
{
|
||||
LightInfo light = blendLight(vertex_pos);
|
||||
|
@ -323,8 +322,14 @@ 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)
|
||||
void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const TileSpec &tile,
|
||||
const f32 *txc, u8 mask)
|
||||
{
|
||||
drawAutoLightedCuboid(box, &tile, 1, txc, mask);
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box,
|
||||
const TileSpec *tiles, int tile_count, const f32 *txc, u8 mask)
|
||||
{
|
||||
bool scale = std::fabs(cur_node.f->visual_scale - 1.0f) > 1e-3f;
|
||||
f32 texture_coord_buf[24];
|
||||
|
@ -348,10 +353,6 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
|
|||
generateCuboidTextureCoords(box, texture_coord_buf);
|
||||
txc = texture_coord_buf;
|
||||
}
|
||||
if (!tiles) {
|
||||
tiles = &cur_node.tile;
|
||||
tile_count = 1;
|
||||
}
|
||||
if (data->m_smooth_lighting) {
|
||||
LightInfo lights[8];
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
|
@ -377,7 +378,7 @@ void MapblockMeshGenerator::drawAutoLightedCuboid(aabb3f box, const f32 *txc,
|
|||
});
|
||||
} else {
|
||||
drawCuboid(box, tiles, tile_count, txc, mask, [&] (int face, video::S3DVertex vertices[4]) {
|
||||
video::SColor color = encode_light(cur_node.light, cur_node.f->light_source);
|
||||
video::SColor color = cur_node.lcolor;
|
||||
if (!cur_node.f->light_source)
|
||||
applyFacesShading(color, vertices[0].Normal);
|
||||
for (int j = 0; j < 4; j++) {
|
||||
|
@ -540,19 +541,20 @@ void MapblockMeshGenerator::prepareLiquidNodeDrawing()
|
|||
if (data->m_smooth_lighting)
|
||||
return; // don't need to pre-compute anything in this case
|
||||
|
||||
auto light = LightPair(getInteriorLight(cur_node.n, 0, nodedef));
|
||||
if (cur_node.f->light_source != 0) {
|
||||
// If this liquid emits light and doesn't contain light, draw
|
||||
// it at what it emits, for an increased effect
|
||||
u8 e = decode_light(cur_node.f->light_source);
|
||||
cur_node.light = LightPair(std::max(e, cur_node.light.lightDay),
|
||||
std::max(e, cur_node.light.lightNight));
|
||||
light = LightPair(std::max(e, light.lightDay),
|
||||
std::max(e, light.lightNight));
|
||||
} else if (nodedef->getLightingFlags(ntop).has_light) {
|
||||
// Otherwise, use the light of the node on top if possible
|
||||
cur_node.light = LightPair(getInteriorLight(ntop, 0, nodedef));
|
||||
light = LightPair(getInteriorLight(ntop, 0, nodedef));
|
||||
}
|
||||
|
||||
cur_liquid.color_top = encode_light(cur_node.light, cur_node.f->light_source);
|
||||
cur_node.color = encode_light(cur_node.light, cur_node.f->light_source);
|
||||
cur_liquid.color_top = encode_light(light, cur_node.f->light_source);
|
||||
cur_node.lcolor = encode_light(light, cur_node.f->light_source);
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::getLiquidNeighborhood()
|
||||
|
@ -695,10 +697,18 @@ void MapblockMeshGenerator::drawLiquidSides()
|
|||
v += 0.5f - cur_liquid.corner_levels[base.Z][base.X];
|
||||
}
|
||||
|
||||
video::SColor color;
|
||||
if (data->m_smooth_lighting)
|
||||
cur_node.color = blendLightColor(pos);
|
||||
color = blendLightColor(pos);
|
||||
else
|
||||
color = cur_node.lcolor;
|
||||
|
||||
pos += cur_node.origin;
|
||||
vertices[j] = video::S3DVertex(pos.X, pos.Y, pos.Z, face.dir.X, face.dir.Y, face.dir.Z, cur_node.color, vertex.u, v);
|
||||
|
||||
vertices[j] = video::S3DVertex(pos.X, pos.Y, pos.Z,
|
||||
face.dir.X, face.dir.Y, face.dir.Z,
|
||||
color,
|
||||
vertex.u, v);
|
||||
};
|
||||
collector->append(cur_liquid.tile, vertices, 4, quad_indices, 6);
|
||||
}
|
||||
|
@ -722,7 +732,7 @@ void MapblockMeshGenerator::drawLiquidTop()
|
|||
int u = corner_resolve[i][0];
|
||||
int w = corner_resolve[i][1];
|
||||
|
||||
if (smooth_liquids) {
|
||||
if (data->m_enable_water_reflections) {
|
||||
int x = vertices[i].Pos.X > 0;
|
||||
int z = vertices[i].Pos.Z > 0;
|
||||
|
||||
|
@ -774,7 +784,7 @@ void MapblockMeshGenerator::drawLiquidTop()
|
|||
|
||||
vertex.TCoords += tcoord_translate;
|
||||
|
||||
if (!smooth_liquids) {
|
||||
if (!data->m_enable_water_reflections) {
|
||||
vertex.Normal = v3f(dx, 1., dz).normalize();
|
||||
}
|
||||
}
|
||||
|
@ -816,7 +826,8 @@ void MapblockMeshGenerator::drawLiquidNode()
|
|||
|
||||
void MapblockMeshGenerator::drawGlasslikeNode()
|
||||
{
|
||||
useTile(0, 0, 0);
|
||||
TileSpec tile;
|
||||
useTile(&tile, 0, 0, 0);
|
||||
|
||||
for (int face = 0; face < 6; face++) {
|
||||
// Check this neighbor
|
||||
|
@ -850,7 +861,7 @@ void MapblockMeshGenerator::drawGlasslikeNode()
|
|||
vertex.rotateXZBy(-90); break;
|
||||
}
|
||||
}
|
||||
drawQuad(vertices, dir);
|
||||
drawQuad(tile, vertices, dir);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -860,9 +871,6 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
|
|||
for (int face = 0; face < 6; face++)
|
||||
getTile(g_6dirs[face], &tiles[face]);
|
||||
|
||||
if (!data->m_smooth_lighting)
|
||||
cur_node.color = encode_light(cur_node.light, cur_node.f->light_source);
|
||||
|
||||
TileSpec glass_tiles[6];
|
||||
for (auto &glass_tile : glass_tiles)
|
||||
glass_tile = tiles[4];
|
||||
|
@ -934,7 +942,6 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
|
|||
{0, 1, 8}, {0, 4, 16}, {3, 4, 17}, {3, 1, 9},
|
||||
};
|
||||
|
||||
cur_node.tile = tiles[1];
|
||||
for (int edge = 0; edge < FRAMED_EDGE_COUNT; edge++) {
|
||||
bool edge_invisible;
|
||||
if (nb[nb_triplet[edge][2]])
|
||||
|
@ -943,14 +950,13 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
|
|||
edge_invisible = nb[nb_triplet[edge][0]] ^ nb[nb_triplet[edge][1]];
|
||||
if (edge_invisible)
|
||||
continue;
|
||||
drawAutoLightedCuboid(frame_edges[edge]);
|
||||
drawAutoLightedCuboid(frame_edges[edge], tiles[1]);
|
||||
}
|
||||
|
||||
for (int face = 0; face < 6; face++) {
|
||||
if (nb[face])
|
||||
continue;
|
||||
|
||||
cur_node.tile = glass_tiles[face];
|
||||
// Face at Z-
|
||||
v3f vertices[4] = {
|
||||
v3f(-a, a, -g),
|
||||
|
@ -976,7 +982,7 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
|
|||
}
|
||||
}
|
||||
v3s16 dir = g_6dirs[face];
|
||||
drawQuad(vertices, dir);
|
||||
drawQuad(glass_tiles[face], vertices, dir);
|
||||
}
|
||||
|
||||
// Optionally render internal liquid level defined by param2
|
||||
|
@ -986,13 +992,18 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
|
|||
// Internal liquid level has param2 range 0 .. 63,
|
||||
// convert it to -0.5 .. 0.5
|
||||
float vlev = (param2 / 63.0f) * 2.0f - 1.0f;
|
||||
getSpecialTile(0, &cur_node.tile);
|
||||
drawAutoLightedCuboid(aabb3f(-(nb[5] ? g : b),
|
||||
-(nb[4] ? g : b),
|
||||
-(nb[3] ? g : b),
|
||||
(nb[2] ? g : b),
|
||||
(nb[1] ? g : b) * vlev,
|
||||
(nb[0] ? g : b)));
|
||||
TileSpec tile;
|
||||
getSpecialTile(0, &tile);
|
||||
drawAutoLightedCuboid(
|
||||
aabb3f(
|
||||
-(nb[5] ? g : b),
|
||||
-(nb[4] ? g : b),
|
||||
-(nb[3] ? g : b),
|
||||
(nb[2] ? g : b),
|
||||
(nb[1] ? g : b) * vlev,
|
||||
(nb[0] ? g : b)
|
||||
),
|
||||
tile);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1007,7 +1018,8 @@ void MapblockMeshGenerator::drawTorchlikeNode()
|
|||
case DWM_S2: tileindex = 0; break; // floor, but rotated
|
||||
default: tileindex = 2; // side (or invalid, shouldn't happen)
|
||||
}
|
||||
useTile(tileindex, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
|
||||
TileSpec tile;
|
||||
useTile(&tile, tileindex, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
|
||||
|
||||
float size = BS / 2 * cur_node.f->visual_scale;
|
||||
v3f vertices[4] = {
|
||||
|
@ -1054,13 +1066,14 @@ void MapblockMeshGenerator::drawTorchlikeNode()
|
|||
break;
|
||||
}
|
||||
}
|
||||
drawQuad(vertices);
|
||||
drawQuad(tile, vertices);
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawSignlikeNode()
|
||||
{
|
||||
u8 wall = cur_node.n.getWallMounted(nodedef);
|
||||
useTile(0, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
|
||||
TileSpec tile;
|
||||
useTile(&tile, 0, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
|
||||
static const float offset = BS / 16;
|
||||
float size = BS / 2 * cur_node.f->visual_scale;
|
||||
// Wall at X+ of node
|
||||
|
@ -1091,13 +1104,13 @@ void MapblockMeshGenerator::drawSignlikeNode()
|
|||
vertex.rotateXYBy(-90); vertex.rotateXZBy(-90); break;
|
||||
}
|
||||
}
|
||||
drawQuad(vertices);
|
||||
drawQuad(tile, vertices);
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawPlantlikeQuad(float rotation, float quad_offset,
|
||||
bool offset_top_only)
|
||||
void MapblockMeshGenerator::drawPlantlikeQuad(const TileSpec &tile,
|
||||
float rotation, float quad_offset, bool offset_top_only)
|
||||
{
|
||||
const f32 scale = cur_node.scale;
|
||||
const f32 scale = cur_plant.scale;
|
||||
v3f vertices[4] = {
|
||||
v3f(-scale, -BS / 2 + 2.0 * scale * cur_plant.plant_height, 0),
|
||||
v3f( scale, -BS / 2 + 2.0 * scale * cur_plant.plant_height, 0),
|
||||
|
@ -1147,14 +1160,14 @@ void MapblockMeshGenerator::drawPlantlikeQuad(float rotation, float quad_offset,
|
|||
}
|
||||
}
|
||||
|
||||
drawQuad(vertices, v3s16(0, 0, 0), cur_plant.plant_height);
|
||||
drawQuad(tile, vertices, v3s16(0, 0, 0), cur_plant.plant_height);
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawPlantlike(bool is_rooted)
|
||||
void MapblockMeshGenerator::drawPlantlike(const TileSpec &tile, bool is_rooted)
|
||||
{
|
||||
cur_plant.draw_style = PLANT_STYLE_CROSS;
|
||||
cur_node.scale = BS / 2 * cur_node.f->visual_scale;
|
||||
cur_plant.offset = v3f(0, 0, 0);
|
||||
cur_plant.scale = BS / 2 * cur_node.f->visual_scale;
|
||||
cur_plant.rotate_degree = 0.0f;
|
||||
cur_plant.random_offset_Y = false;
|
||||
cur_plant.face_num = 0;
|
||||
|
@ -1164,7 +1177,7 @@ void MapblockMeshGenerator::drawPlantlike(bool is_rooted)
|
|||
case CPT2_MESHOPTIONS:
|
||||
cur_plant.draw_style = PlantlikeStyle(cur_node.n.param2 & MO_MASK_STYLE);
|
||||
if (cur_node.n.param2 & MO_BIT_SCALE_SQRT2)
|
||||
cur_node.scale *= 1.41421;
|
||||
cur_plant.scale *= 1.41421;
|
||||
if (cur_node.n.param2 & MO_BIT_RANDOM_OFFSET) {
|
||||
PseudoRandom rng(cur_node.p.X << 8 | cur_node.p.Z | cur_node.p.Y << 16);
|
||||
cur_plant.offset.X = BS * ((rng.next() % 16 / 16.0) * 0.29 - 0.145);
|
||||
|
@ -1205,63 +1218,66 @@ void MapblockMeshGenerator::drawPlantlike(bool is_rooted)
|
|||
|
||||
switch (cur_plant.draw_style) {
|
||||
case PLANT_STYLE_CROSS:
|
||||
drawPlantlikeQuad(46);
|
||||
drawPlantlikeQuad(-44);
|
||||
drawPlantlikeQuad(tile, 46);
|
||||
drawPlantlikeQuad(tile, -44);
|
||||
break;
|
||||
|
||||
case PLANT_STYLE_CROSS2:
|
||||
drawPlantlikeQuad(91);
|
||||
drawPlantlikeQuad(1);
|
||||
drawPlantlikeQuad(tile, 91);
|
||||
drawPlantlikeQuad(tile, 1);
|
||||
break;
|
||||
|
||||
case PLANT_STYLE_STAR:
|
||||
drawPlantlikeQuad(121);
|
||||
drawPlantlikeQuad(241);
|
||||
drawPlantlikeQuad(1);
|
||||
drawPlantlikeQuad(tile, 121);
|
||||
drawPlantlikeQuad(tile, 241);
|
||||
drawPlantlikeQuad(tile, 1);
|
||||
break;
|
||||
|
||||
case PLANT_STYLE_HASH:
|
||||
drawPlantlikeQuad( 1, BS / 4);
|
||||
drawPlantlikeQuad( 91, BS / 4);
|
||||
drawPlantlikeQuad(181, BS / 4);
|
||||
drawPlantlikeQuad(271, BS / 4);
|
||||
drawPlantlikeQuad(tile, 1, BS / 4);
|
||||
drawPlantlikeQuad(tile, 91, BS / 4);
|
||||
drawPlantlikeQuad(tile, 181, BS / 4);
|
||||
drawPlantlikeQuad(tile, 271, BS / 4);
|
||||
break;
|
||||
|
||||
case PLANT_STYLE_HASH2:
|
||||
drawPlantlikeQuad( 1, -BS / 2, true);
|
||||
drawPlantlikeQuad( 91, -BS / 2, true);
|
||||
drawPlantlikeQuad(181, -BS / 2, true);
|
||||
drawPlantlikeQuad(271, -BS / 2, true);
|
||||
drawPlantlikeQuad(tile, 1, -BS / 2, true);
|
||||
drawPlantlikeQuad(tile, 91, -BS / 2, true);
|
||||
drawPlantlikeQuad(tile, 181, -BS / 2, true);
|
||||
drawPlantlikeQuad(tile, 271, -BS / 2, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawPlantlikeNode()
|
||||
{
|
||||
useTile();
|
||||
drawPlantlike();
|
||||
TileSpec tile;
|
||||
useTile(&tile);
|
||||
drawPlantlike(tile);
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawPlantlikeRootedNode()
|
||||
{
|
||||
drawSolidNode();
|
||||
useTile(0, MATERIAL_FLAG_CRACK_OVERLAY, 0, true);
|
||||
TileSpec tile;
|
||||
useTile(&tile, 0, MATERIAL_FLAG_CRACK_OVERLAY, 0, true);
|
||||
cur_node.origin += v3f(0.0, BS, 0.0);
|
||||
cur_node.p.Y++;
|
||||
if (data->m_smooth_lighting) {
|
||||
getSmoothLightFrame();
|
||||
} else {
|
||||
MapNode ntop = data->m_vmanip.getNodeNoEx(blockpos_nodes + cur_node.p);
|
||||
cur_node.light = LightPair(getInteriorLight(ntop, 0, nodedef));
|
||||
auto light = LightPair(getInteriorLight(ntop, 0, nodedef));
|
||||
cur_node.lcolor = encode_light(light, cur_node.f->light_source);
|
||||
}
|
||||
drawPlantlike(true);
|
||||
drawPlantlike(tile, true);
|
||||
cur_node.p.Y--;
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawFirelikeQuad(float rotation, float opening_angle,
|
||||
float offset_h, float offset_v)
|
||||
void MapblockMeshGenerator::drawFirelikeQuad(const TileSpec &tile, float rotation,
|
||||
float opening_angle, float offset_h, float offset_v)
|
||||
{
|
||||
const f32 scale = cur_node.scale;
|
||||
const f32 scale = BS / 2 * cur_node.f->visual_scale;
|
||||
v3f vertices[4] = {
|
||||
v3f(-scale, -BS / 2 + scale * 2, 0),
|
||||
v3f( scale, -BS / 2 + scale * 2, 0),
|
||||
|
@ -1275,13 +1291,13 @@ void MapblockMeshGenerator::drawFirelikeQuad(float rotation, float opening_angle
|
|||
vertex.rotateXZBy(rotation);
|
||||
vertex.Y += offset_v;
|
||||
}
|
||||
drawQuad(vertices);
|
||||
drawQuad(tile, vertices);
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawFirelikeNode()
|
||||
{
|
||||
useTile();
|
||||
cur_node.scale = BS / 2 * cur_node.f->visual_scale;
|
||||
TileSpec tile;
|
||||
useTile(&tile);
|
||||
|
||||
// Check for adjacent nodes
|
||||
bool neighbors = false;
|
||||
|
@ -1300,41 +1316,41 @@ void MapblockMeshGenerator::drawFirelikeNode()
|
|||
bool drawBottomFire = neighbor[D6D_YP];
|
||||
|
||||
if (drawBasicFire || neighbor[D6D_ZP])
|
||||
drawFirelikeQuad(0, -10, 0.4 * BS);
|
||||
drawFirelikeQuad(tile, 0, -10, 0.4 * BS);
|
||||
else if (drawBottomFire)
|
||||
drawFirelikeQuad(0, 70, 0.47 * BS, 0.484 * BS);
|
||||
drawFirelikeQuad(tile, 0, 70, 0.47 * BS, 0.484 * BS);
|
||||
|
||||
if (drawBasicFire || neighbor[D6D_XN])
|
||||
drawFirelikeQuad(90, -10, 0.4 * BS);
|
||||
drawFirelikeQuad(tile, 90, -10, 0.4 * BS);
|
||||
else if (drawBottomFire)
|
||||
drawFirelikeQuad(90, 70, 0.47 * BS, 0.484 * BS);
|
||||
drawFirelikeQuad(tile, 90, 70, 0.47 * BS, 0.484 * BS);
|
||||
|
||||
if (drawBasicFire || neighbor[D6D_ZN])
|
||||
drawFirelikeQuad(180, -10, 0.4 * BS);
|
||||
drawFirelikeQuad(tile, 180, -10, 0.4 * BS);
|
||||
else if (drawBottomFire)
|
||||
drawFirelikeQuad(180, 70, 0.47 * BS, 0.484 * BS);
|
||||
drawFirelikeQuad(tile, 180, 70, 0.47 * BS, 0.484 * BS);
|
||||
|
||||
if (drawBasicFire || neighbor[D6D_XP])
|
||||
drawFirelikeQuad(270, -10, 0.4 * BS);
|
||||
drawFirelikeQuad(tile, 270, -10, 0.4 * BS);
|
||||
else if (drawBottomFire)
|
||||
drawFirelikeQuad(270, 70, 0.47 * BS, 0.484 * BS);
|
||||
drawFirelikeQuad(tile, 270, 70, 0.47 * BS, 0.484 * BS);
|
||||
|
||||
if (drawBasicFire) {
|
||||
drawFirelikeQuad(45, 0, 0.0);
|
||||
drawFirelikeQuad(-45, 0, 0.0);
|
||||
drawFirelikeQuad(tile, 45, 0, 0.0);
|
||||
drawFirelikeQuad(tile, -45, 0, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawFencelikeNode()
|
||||
{
|
||||
useTile(0, 0, 0);
|
||||
TileSpec tile_nocrack = cur_node.tile;
|
||||
TileSpec tile_nocrack;
|
||||
useTile(&tile_nocrack, 0, 0, 0);
|
||||
|
||||
for (auto &layer : tile_nocrack.layers)
|
||||
layer.material_flags &= ~MATERIAL_FLAG_CRACK;
|
||||
|
||||
// Put wood the right way around in the posts
|
||||
TileSpec tile_rot = cur_node.tile;
|
||||
TileSpec tile_rot = tile_nocrack;
|
||||
tile_rot.rotation = TileRotation::R90;
|
||||
|
||||
static const f32 post_rad = BS / 8;
|
||||
|
@ -1352,10 +1368,7 @@ void MapblockMeshGenerator::drawFencelikeNode()
|
|||
0.500, 0.000, 0.750, 1.000,
|
||||
0.750, 0.000, 1.000, 1.000,
|
||||
};
|
||||
cur_node.tile = tile_rot;
|
||||
drawAutoLightedCuboid(post, postuv);
|
||||
|
||||
cur_node.tile = tile_nocrack;
|
||||
drawAutoLightedCuboid(post, tile_rot, postuv);
|
||||
|
||||
// Now a section of fence, +X, if there's a post there
|
||||
v3s16 p2 = cur_node.p;
|
||||
|
@ -1375,8 +1388,8 @@ void MapblockMeshGenerator::drawFencelikeNode()
|
|||
0.000, 0.500, 1.000, 0.625,
|
||||
0.000, 0.875, 1.000, 1.000,
|
||||
};
|
||||
drawAutoLightedCuboid(bar_x1, xrailuv);
|
||||
drawAutoLightedCuboid(bar_x2, xrailuv);
|
||||
drawAutoLightedCuboid(bar_x1, tile_nocrack, xrailuv);
|
||||
drawAutoLightedCuboid(bar_x2, tile_nocrack, xrailuv);
|
||||
}
|
||||
|
||||
// Now a section of fence, +Z, if there's a post there
|
||||
|
@ -1397,8 +1410,8 @@ void MapblockMeshGenerator::drawFencelikeNode()
|
|||
0.3750, 0.3750, 0.5000, 0.5000,
|
||||
0.6250, 0.6250, 0.7500, 0.7500,
|
||||
};
|
||||
drawAutoLightedCuboid(bar_z1, zrailuv);
|
||||
drawAutoLightedCuboid(bar_z2, zrailuv);
|
||||
drawAutoLightedCuboid(bar_z1, tile_nocrack, zrailuv);
|
||||
drawAutoLightedCuboid(bar_z2, tile_nocrack, zrailuv);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1480,7 +1493,8 @@ void MapblockMeshGenerator::drawRaillikeNode()
|
|||
angle = rail_kinds[code].angle;
|
||||
}
|
||||
|
||||
useTile(tile_index, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
|
||||
TileSpec tile;
|
||||
useTile(&tile, tile_index, MATERIAL_FLAG_CRACK_OVERLAY, MATERIAL_FLAG_BACKFACE_CULLING);
|
||||
|
||||
static const float offset = BS / 64;
|
||||
static const float size = BS / 2;
|
||||
|
@ -1494,7 +1508,7 @@ void MapblockMeshGenerator::drawRaillikeNode()
|
|||
if (angle)
|
||||
for (v3f &vertex : vertices)
|
||||
vertex.rotateXZBy(angle);
|
||||
drawQuad(vertices);
|
||||
drawQuad(tile, vertices);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -1526,7 +1540,7 @@ void MapblockMeshGenerator::drawAllfacesNode()
|
|||
getTile(nodebox_tile_dirs[face], &tiles[face]);
|
||||
if (data->m_smooth_lighting)
|
||||
getSmoothLightFrame();
|
||||
drawAutoLightedCuboid(box, nullptr, tiles, 6);
|
||||
drawAutoLightedCuboid(box, tiles, 6);
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::drawNodeboxNode()
|
||||
|
@ -1633,7 +1647,7 @@ void MapblockMeshGenerator::drawNodeboxNode()
|
|||
|
||||
for (auto &box : boxes) {
|
||||
u8 mask = getNodeBoxMask(box, solid_neighbors, sametype_neighbors);
|
||||
drawAutoLightedCuboid(box, nullptr, tiles, 6, mask);
|
||||
drawAutoLightedCuboid(box, tiles, 6, nullptr, mask);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1678,29 +1692,35 @@ void MapblockMeshGenerator::drawMeshNode()
|
|||
|
||||
for (u32 j = 0; j < mesh->getMeshBufferCount(); j++) {
|
||||
// Only up to 6 tiles are supported
|
||||
const u32 tile = mesh->getTextureSlot(j);
|
||||
useTile(MYMIN(tile, 5));
|
||||
const u32 tile_idx = mesh->getTextureSlot(j);
|
||||
TileSpec tile;
|
||||
useTile(&tile, MYMIN(tile_idx, 5));
|
||||
|
||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(j);
|
||||
video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices();
|
||||
u32 vertex_count = buf->getVertexCount();
|
||||
|
||||
// Mesh is always private here. So the lighting is applied to each
|
||||
// vertex right here.
|
||||
if (data->m_smooth_lighting) {
|
||||
// Mesh is always private here. So the lighting is applied to each
|
||||
// vertex right here.
|
||||
for (u32 k = 0; k < vertex_count; k++) {
|
||||
video::S3DVertex &vertex = vertices[k];
|
||||
vertex.Color = blendLightColor(vertex.Pos, vertex.Normal);
|
||||
vertex.Pos += cur_node.origin;
|
||||
}
|
||||
collector->append(cur_node.tile, vertices, vertex_count,
|
||||
buf->getIndices(), buf->getIndexCount());
|
||||
} else {
|
||||
// Let the collector process colors, etc.
|
||||
collector->append(cur_node.tile, vertices, vertex_count,
|
||||
buf->getIndices(), buf->getIndexCount(), cur_node.origin,
|
||||
cur_node.color, cur_node.f->light_source);
|
||||
bool is_light_source = cur_node.f->light_source != 0;
|
||||
for (u32 k = 0; k < vertex_count; k++) {
|
||||
video::S3DVertex &vertex = vertices[k];
|
||||
video::SColor color = cur_node.lcolor;
|
||||
if (!is_light_source)
|
||||
applyFacesShading(color, vertex.Normal);
|
||||
vertex.Color = color;
|
||||
vertex.Pos += cur_node.origin;
|
||||
}
|
||||
}
|
||||
collector->append(tile, vertices, vertex_count,
|
||||
buf->getIndices(), buf->getIndexCount());
|
||||
}
|
||||
mesh->drop();
|
||||
}
|
||||
|
@ -1725,10 +1745,12 @@ void MapblockMeshGenerator::drawNode()
|
|||
break;
|
||||
}
|
||||
cur_node.origin = intToFloat(cur_node.p, BS);
|
||||
if (data->m_smooth_lighting)
|
||||
if (data->m_smooth_lighting) {
|
||||
getSmoothLightFrame();
|
||||
else
|
||||
cur_node.light = LightPair(getInteriorLight(cur_node.n, 0, nodedef));
|
||||
} else {
|
||||
auto light = LightPair(getInteriorLight(cur_node.n, 0, nodedef));
|
||||
cur_node.lcolor = encode_light(light, cur_node.f->light_source);
|
||||
}
|
||||
switch (cur_node.f->drawtype) {
|
||||
case NDT_FLOWINGLIQUID: drawLiquidNode(); break;
|
||||
case NDT_GLASSLIKE: drawGlasslikeNode(); break;
|
||||
|
@ -1751,19 +1773,11 @@ void MapblockMeshGenerator::generate()
|
|||
{
|
||||
ZoneScoped;
|
||||
|
||||
for (cur_node.p.Z = 0; cur_node.p.Z < data->side_length; cur_node.p.Z++)
|
||||
for (cur_node.p.Y = 0; cur_node.p.Y < data->side_length; cur_node.p.Y++)
|
||||
for (cur_node.p.X = 0; cur_node.p.X < data->side_length; cur_node.p.X++) {
|
||||
for (cur_node.p.Z = 0; cur_node.p.Z < data->m_side_length; cur_node.p.Z++)
|
||||
for (cur_node.p.Y = 0; cur_node.p.Y < data->m_side_length; cur_node.p.Y++)
|
||||
for (cur_node.p.X = 0; cur_node.p.X < data->m_side_length; cur_node.p.X++) {
|
||||
cur_node.n = data->m_vmanip.getNodeNoEx(blockpos_nodes + cur_node.p);
|
||||
cur_node.f = &nodedef->get(cur_node.n);
|
||||
drawNode();
|
||||
}
|
||||
}
|
||||
|
||||
void MapblockMeshGenerator::renderSingle(content_t node, u8 param2)
|
||||
{
|
||||
cur_node.p = {0, 0, 0};
|
||||
cur_node.n = MapNode(node, 0xff, param2);
|
||||
cur_node.f = &nodedef->get(cur_node.n);
|
||||
drawNode();
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@ class MapblockMeshGenerator
|
|||
public:
|
||||
MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output);
|
||||
void generate();
|
||||
void renderSingle(content_t node, u8 param2 = 0x00);
|
||||
|
||||
private:
|
||||
MeshMakeData *const data;
|
||||
|
@ -59,15 +58,12 @@ private:
|
|||
|
||||
// current node
|
||||
struct {
|
||||
v3s16 p;
|
||||
v3f origin;
|
||||
v3s16 p; // relative to blockpos_nodes
|
||||
v3f origin; // p in BS space
|
||||
MapNode n;
|
||||
const ContentFeatures *f;
|
||||
LightPair light;
|
||||
LightFrame frame;
|
||||
video::SColor color;
|
||||
TileSpec tile;
|
||||
f32 scale;
|
||||
LightFrame lframe; // smooth lighting
|
||||
video::SColor lcolor; // unsmooth lighting
|
||||
} cur_node;
|
||||
|
||||
// lighting
|
||||
|
@ -76,21 +72,23 @@ private:
|
|||
video::SColor blendLightColor(const v3f &vertex_pos);
|
||||
video::SColor blendLightColor(const v3f &vertex_pos, const v3f &vertex_normal);
|
||||
|
||||
void useTile(int index = 0, u8 set_flags = MATERIAL_FLAG_CRACK_OVERLAY,
|
||||
void useTile(TileSpec *tile_ret, int index = 0, u8 set_flags = MATERIAL_FLAG_CRACK_OVERLAY,
|
||||
u8 reset_flags = 0, bool special = false);
|
||||
void getTile(int index, TileSpec *tile);
|
||||
void getTile(v3s16 direction, TileSpec *tile);
|
||||
void getSpecialTile(int index, TileSpec *tile, bool apply_crack = false);
|
||||
void getTile(int index, TileSpec *tile_ret);
|
||||
void getTile(v3s16 direction, TileSpec *tile_ret);
|
||||
void getSpecialTile(int index, TileSpec *tile_ret, bool apply_crack = false);
|
||||
|
||||
// face drawing
|
||||
void drawQuad(v3f *vertices, const v3s16 &normal = v3s16(0, 0, 0),
|
||||
void drawQuad(const TileSpec &tile, v3f *vertices, const v3s16 &normal = v3s16(0, 0, 0),
|
||||
float vertical_tiling = 1.0);
|
||||
|
||||
// cuboid drawing!
|
||||
template <typename Fn>
|
||||
void drawCuboid(const aabb3f &box, TileSpec *tiles, int tilecount, const f32 *txc, u8 mask, Fn &&face_lighter);
|
||||
void drawCuboid(const aabb3f &box, const TileSpec *tiles, int tilecount,
|
||||
const f32 *txc, u8 mask, Fn &&face_lighter);
|
||||
void generateCuboidTextureCoords(aabb3f const &box, f32 *coords);
|
||||
void drawAutoLightedCuboid(aabb3f box, f32 const *txc = nullptr, TileSpec *tiles = nullptr, int tile_count = 0, u8 mask = 0);
|
||||
void drawAutoLightedCuboid(aabb3f box, const TileSpec &tile, f32 const *txc = nullptr, u8 mask = 0);
|
||||
void drawAutoLightedCuboid(aabb3f box, const TileSpec *tiles, int tile_count, f32 const *txc = nullptr, u8 mask = 0);
|
||||
u8 getNodeBoxMask(aabb3f box, u8 solid_neighbors, u8 sametype_neighbors) const;
|
||||
|
||||
// liquid-specific
|
||||
|
@ -113,7 +111,6 @@ private:
|
|||
f32 corner_levels[2][2];
|
||||
};
|
||||
LiquidData cur_liquid;
|
||||
bool smooth_liquids = false;
|
||||
|
||||
void prepareLiquidNodeDrawing();
|
||||
void getLiquidNeighborhood();
|
||||
|
@ -136,6 +133,7 @@ private:
|
|||
struct PlantlikeData {
|
||||
PlantlikeStyle draw_style;
|
||||
v3f offset;
|
||||
float scale;
|
||||
float rotate_degree;
|
||||
bool random_offset_Y;
|
||||
int face_num;
|
||||
|
@ -143,12 +141,12 @@ private:
|
|||
};
|
||||
PlantlikeData cur_plant;
|
||||
|
||||
void drawPlantlikeQuad(float rotation, float quad_offset = 0,
|
||||
void drawPlantlikeQuad(const TileSpec &tile, float rotation, float quad_offset = 0,
|
||||
bool offset_top_only = false);
|
||||
void drawPlantlike(bool is_rooted = false);
|
||||
void drawPlantlike(const TileSpec &tile, bool is_rooted = false);
|
||||
|
||||
// firelike-specific
|
||||
void drawFirelikeQuad(float rotation, float opening_angle,
|
||||
void drawFirelikeQuad(const TileSpec &tile, float rotation, float opening_angle,
|
||||
float offset_h, float offset_v = 0.0);
|
||||
|
||||
// drawtypes
|
||||
|
|
|
@ -472,6 +472,8 @@ public:
|
|||
|
||||
const static float object_hit_delay = 0.2;
|
||||
|
||||
const static u16 bbox_debug_flag = scene::EDS_BBOX_ALL;
|
||||
|
||||
/* The reason the following structs are not anonymous structs within the
|
||||
* class is that they are not used by the majority of member functions and
|
||||
* many functions that do require objects of thse types do not modify them
|
||||
|
@ -680,6 +682,8 @@ protected:
|
|||
private:
|
||||
struct Flags {
|
||||
bool disable_camera_update = false;
|
||||
/// 0 = no debug text active, see toggleDebug() for the rest
|
||||
int debug_state = 0;
|
||||
};
|
||||
|
||||
void pauseAnimation();
|
||||
|
@ -782,11 +786,8 @@ private:
|
|||
* (as opposed to the this local caching). This can be addressed in
|
||||
* a later release.
|
||||
*/
|
||||
bool m_cache_disable_escape_sequences;
|
||||
bool m_cache_doubletap_jump;
|
||||
bool m_cache_enable_clouds;
|
||||
bool m_cache_enable_joysticks;
|
||||
bool m_cache_enable_particles;
|
||||
bool m_cache_enable_fog;
|
||||
bool m_cache_enable_noclip;
|
||||
bool m_cache_enable_free_move;
|
||||
|
@ -828,16 +829,10 @@ Game::Game() :
|
|||
{
|
||||
g_settings->registerChangedCallback("chat_log_level",
|
||||
&settingChangedCallback, this);
|
||||
g_settings->registerChangedCallback("disable_escape_sequences",
|
||||
&settingChangedCallback, this);
|
||||
g_settings->registerChangedCallback("doubletap_jump",
|
||||
&settingChangedCallback, this);
|
||||
g_settings->registerChangedCallback("enable_clouds",
|
||||
&settingChangedCallback, this);
|
||||
g_settings->registerChangedCallback("enable_joysticks",
|
||||
&settingChangedCallback, this);
|
||||
g_settings->registerChangedCallback("enable_particles",
|
||||
&settingChangedCallback, this);
|
||||
g_settings->registerChangedCallback("enable_fog",
|
||||
&settingChangedCallback, this);
|
||||
g_settings->registerChangedCallback("mouse_sensitivity",
|
||||
|
@ -937,6 +932,10 @@ bool Game::startup(bool *kill,
|
|||
runData.time_from_last_punch = 10.0;
|
||||
|
||||
m_game_ui->initFlags();
|
||||
if (g_settings->getBool("show_debug")) {
|
||||
m_flags.debug_state = 1;
|
||||
m_game_ui->m_flags.show_minimal_debug = true;
|
||||
}
|
||||
|
||||
m_first_loop_after_window_activation = true;
|
||||
|
||||
|
@ -1175,7 +1174,7 @@ bool Game::init(
|
|||
bool Game::initSound()
|
||||
{
|
||||
#if USE_SOUND
|
||||
if (g_settings->getBool("enable_sound") && g_sound_manager_singleton.get()) {
|
||||
if (g_sound_manager_singleton.get()) {
|
||||
infostream << "Attempting to use OpenAL audio" << std::endl;
|
||||
sound_manager = createOpenALSoundManager(g_sound_manager_singleton.get(),
|
||||
std::make_unique<SoundFallbackPathProvider>());
|
||||
|
@ -1333,8 +1332,7 @@ bool Game::createClient(const GameStartData &start_data)
|
|||
|
||||
/* Clouds
|
||||
*/
|
||||
if (m_cache_enable_clouds)
|
||||
clouds = make_irr<Clouds>(smgr, shader_src, -1, rand());
|
||||
clouds = make_irr<Clouds>(smgr, shader_src, -1, myrand());
|
||||
|
||||
/* Skybox
|
||||
*/
|
||||
|
@ -1708,6 +1706,7 @@ void Game::updateDebugState()
|
|||
hud->disableBlockBounds();
|
||||
if (!has_debug) {
|
||||
draw_control->show_wireframe = false;
|
||||
smgr->setGlobalDebugData(0, bbox_debug_flag);
|
||||
m_flags.disable_camera_update = false;
|
||||
m_game_formspec.disableDebugView();
|
||||
}
|
||||
|
@ -1845,7 +1844,9 @@ void Game::processUserInput(f32 dtime)
|
|||
m_game_focused = true;
|
||||
}
|
||||
|
||||
if (!guienv->hasFocus(gui_chat_console.get()) && gui_chat_console->isOpen()) {
|
||||
if (!guienv->hasFocus(gui_chat_console.get()) && gui_chat_console->isOpen()
|
||||
&& !gui_chat_console->isMyChild(guienv->getFocus()))
|
||||
{
|
||||
gui_chat_console->closeConsoleAtOnce();
|
||||
}
|
||||
|
||||
|
@ -1909,34 +1910,22 @@ void Game::processKeyInput()
|
|||
toggleNoClip();
|
||||
#if USE_SOUND
|
||||
} else if (wasKeyDown(KeyType::MUTE)) {
|
||||
if (g_settings->getBool("enable_sound")) {
|
||||
bool new_mute_sound = !g_settings->getBool("mute_sound");
|
||||
g_settings->setBool("mute_sound", new_mute_sound);
|
||||
if (new_mute_sound)
|
||||
m_game_ui->showTranslatedStatusText("Sound muted");
|
||||
else
|
||||
m_game_ui->showTranslatedStatusText("Sound unmuted");
|
||||
} else {
|
||||
m_game_ui->showTranslatedStatusText("Sound system is disabled");
|
||||
}
|
||||
bool new_mute_sound = !g_settings->getBool("mute_sound");
|
||||
g_settings->setBool("mute_sound", new_mute_sound);
|
||||
if (new_mute_sound)
|
||||
m_game_ui->showTranslatedStatusText("Sound muted");
|
||||
else
|
||||
m_game_ui->showTranslatedStatusText("Sound unmuted");
|
||||
} else if (wasKeyDown(KeyType::INC_VOLUME)) {
|
||||
if (g_settings->getBool("enable_sound")) {
|
||||
float new_volume = g_settings->getFloat("sound_volume", 0.0f, 0.9f) + 0.1f;
|
||||
g_settings->setFloat("sound_volume", new_volume);
|
||||
std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100));
|
||||
m_game_ui->showStatusText(msg);
|
||||
} else {
|
||||
m_game_ui->showTranslatedStatusText("Sound system is disabled");
|
||||
}
|
||||
float new_volume = g_settings->getFloat("sound_volume", 0.0f, 0.9f) + 0.1f;
|
||||
g_settings->setFloat("sound_volume", new_volume);
|
||||
std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100));
|
||||
m_game_ui->showStatusText(msg);
|
||||
} else if (wasKeyDown(KeyType::DEC_VOLUME)) {
|
||||
if (g_settings->getBool("enable_sound")) {
|
||||
float new_volume = g_settings->getFloat("sound_volume", 0.1f, 1.0f) - 0.1f;
|
||||
g_settings->setFloat("sound_volume", new_volume);
|
||||
std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100));
|
||||
m_game_ui->showStatusText(msg);
|
||||
} else {
|
||||
m_game_ui->showTranslatedStatusText("Sound system is disabled");
|
||||
}
|
||||
float new_volume = g_settings->getFloat("sound_volume", 0.1f, 1.0f) - 0.1f;
|
||||
g_settings->setFloat("sound_volume", new_volume);
|
||||
std::wstring msg = fwgettext("Volume changed to %d%%", myround(new_volume * 100));
|
||||
m_game_ui->showStatusText(msg);
|
||||
#else
|
||||
} else if (wasKeyDown(KeyType::MUTE) || wasKeyDown(KeyType::INC_VOLUME)
|
||||
|| wasKeyDown(KeyType::DEC_VOLUME)) {
|
||||
|
@ -2267,45 +2256,44 @@ void Game::toggleDebug()
|
|||
LocalPlayer *player = client->getEnv().getLocalPlayer();
|
||||
bool has_debug = client->checkPrivilege("debug");
|
||||
bool has_basic_debug = has_debug || (player->hud_flags & HUD_FLAG_BASIC_DEBUG);
|
||||
|
||||
// Initial: No debug info
|
||||
// 1x toggle: Debug text
|
||||
// 2x toggle: Debug text with profiler graph
|
||||
// 3x toggle: Debug text and wireframe (needs "debug" priv)
|
||||
// Next toggle: Back to initial
|
||||
// 4x toggle: Debug text and bbox (needs "debug" priv)
|
||||
//
|
||||
// The debug text can be in 2 modes: minimal and basic.
|
||||
// * Minimal: Only technical client info that not gameplay-relevant
|
||||
// * Basic: Info that might give gameplay advantage, e.g. pos, angle
|
||||
// Basic mode is used when player has the debug HUD flag set,
|
||||
// otherwise the Minimal mode is used.
|
||||
if (!m_game_ui->m_flags.show_minimal_debug) {
|
||||
m_game_ui->m_flags.show_minimal_debug = true;
|
||||
if (has_basic_debug)
|
||||
m_game_ui->m_flags.show_basic_debug = true;
|
||||
m_game_ui->m_flags.show_profiler_graph = false;
|
||||
draw_control->show_wireframe = false;
|
||||
|
||||
auto &state = m_flags.debug_state;
|
||||
state = (state + 1) % 5;
|
||||
if (state >= 3 && !has_debug)
|
||||
state = 0;
|
||||
|
||||
m_game_ui->m_flags.show_minimal_debug = state > 0;
|
||||
m_game_ui->m_flags.show_basic_debug = state > 0 && has_basic_debug;
|
||||
m_game_ui->m_flags.show_profiler_graph = state == 2;
|
||||
draw_control->show_wireframe = state == 3;
|
||||
smgr->setGlobalDebugData(state == 4 ? bbox_debug_flag : 0,
|
||||
state == 4 ? 0 : bbox_debug_flag);
|
||||
|
||||
if (state == 1) {
|
||||
m_game_ui->showTranslatedStatusText("Debug info shown");
|
||||
} else if (!m_game_ui->m_flags.show_profiler_graph && !draw_control->show_wireframe) {
|
||||
if (has_basic_debug)
|
||||
m_game_ui->m_flags.show_basic_debug = true;
|
||||
m_game_ui->m_flags.show_profiler_graph = true;
|
||||
} else if (state == 2) {
|
||||
m_game_ui->showTranslatedStatusText("Profiler graph shown");
|
||||
} else if (!draw_control->show_wireframe && client->checkPrivilege("debug")) {
|
||||
if (has_basic_debug)
|
||||
m_game_ui->m_flags.show_basic_debug = true;
|
||||
m_game_ui->m_flags.show_profiler_graph = false;
|
||||
draw_control->show_wireframe = true;
|
||||
m_game_ui->showTranslatedStatusText("Wireframe shown");
|
||||
} else if (state == 3) {
|
||||
if (driver->getDriverType() == video::EDT_OGLES2)
|
||||
m_game_ui->showTranslatedStatusText("Wireframe not supported by video driver");
|
||||
else
|
||||
m_game_ui->showTranslatedStatusText("Wireframe shown");
|
||||
} else if (state == 4) {
|
||||
m_game_ui->showTranslatedStatusText("Bounding boxes shown");
|
||||
} else {
|
||||
m_game_ui->m_flags.show_minimal_debug = false;
|
||||
m_game_ui->m_flags.show_basic_debug = false;
|
||||
m_game_ui->m_flags.show_profiler_graph = false;
|
||||
draw_control->show_wireframe = false;
|
||||
if (has_debug) {
|
||||
m_game_ui->showTranslatedStatusText("Debug info, profiler graph, and wireframe hidden");
|
||||
} else {
|
||||
m_game_ui->showTranslatedStatusText("Debug info and profiler graph hidden");
|
||||
}
|
||||
m_game_ui->showTranslatedStatusText("All debug info hidden");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2896,9 +2884,6 @@ void Game::handleClientEvent_OverrideDayNigthRatio(ClientEvent *event,
|
|||
|
||||
void Game::handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam)
|
||||
{
|
||||
if (!clouds)
|
||||
return;
|
||||
|
||||
clouds->setDensity(event->cloud_params.density);
|
||||
clouds->setColorBright(video::SColor(event->cloud_params.color_bright));
|
||||
clouds->setColorAmbient(video::SColor(event->cloud_params.color_ambient));
|
||||
|
@ -2935,10 +2920,7 @@ void Game::updateChat(f32 dtime)
|
|||
std::vector<LogEntry> entries = m_chat_log_buf.take();
|
||||
for (const auto& entry : entries) {
|
||||
std::string line;
|
||||
if (!m_cache_disable_escape_sequences) {
|
||||
line.append(color_for(entry.level));
|
||||
}
|
||||
line.append(entry.combined);
|
||||
line.append(color_for(entry.level)).append(entry.combined);
|
||||
chat_backend->addMessage(L"", utf8_to_wide(line));
|
||||
}
|
||||
|
||||
|
@ -3023,8 +3005,7 @@ void Game::updateCamera(f32 dtime)
|
|||
client->updateCameraOffset(camera_offset);
|
||||
client->getEnv().updateCameraOffset(camera_offset);
|
||||
|
||||
if (clouds)
|
||||
clouds->updateCameraOffset(camera_offset);
|
||||
clouds->updateCameraOffset(camera_offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3683,10 +3664,8 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
|
|||
} else {
|
||||
runData.dig_time_complete = params.time;
|
||||
|
||||
if (m_cache_enable_particles) {
|
||||
client->getParticleManager()->addNodeParticle(client,
|
||||
player, nodepos, n, features);
|
||||
}
|
||||
client->getParticleManager()->addNodeParticle(client,
|
||||
player, nodepos, n, features);
|
||||
}
|
||||
|
||||
if (!runData.digging) {
|
||||
|
@ -3771,11 +3750,8 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
|
|||
|
||||
client->interact(INTERACT_DIGGING_COMPLETED, pointed);
|
||||
|
||||
if (m_cache_enable_particles) {
|
||||
client->getParticleManager()->addDiggingParticles(client,
|
||||
player, nodepos, n, features);
|
||||
}
|
||||
|
||||
client->getParticleManager()->addDiggingParticles(client,
|
||||
player, nodepos, n, features);
|
||||
|
||||
// Send event to trigger sound
|
||||
client->getEventManager()->put(new NodeDugEvent(nodepos, n));
|
||||
|
@ -3866,8 +3842,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
|
|||
/*
|
||||
Update clouds
|
||||
*/
|
||||
if (clouds)
|
||||
updateClouds(dtime);
|
||||
updateClouds(dtime);
|
||||
|
||||
/*
|
||||
Update particles
|
||||
|
@ -4129,11 +4104,8 @@ void Game::readSettings()
|
|||
}
|
||||
m_chat_log_buf.setLogLevel(chat_log_level);
|
||||
|
||||
m_cache_disable_escape_sequences = g_settings->getBool("disable_escape_sequences");
|
||||
m_cache_doubletap_jump = g_settings->getBool("doubletap_jump");
|
||||
m_cache_enable_clouds = g_settings->getBool("enable_clouds");
|
||||
m_cache_enable_joysticks = g_settings->getBool("enable_joysticks");
|
||||
m_cache_enable_particles = g_settings->getBool("enable_particles");
|
||||
m_cache_enable_fog = g_settings->getBool("enable_fog");
|
||||
m_cache_mouse_sensitivity = g_settings->getFloat("mouse_sensitivity", 0.001f, 10.0f);
|
||||
m_cache_joystick_frustum_sensitivity = std::max(g_settings->getFloat("joystick_frustum_sensitivity"), 0.001f);
|
||||
|
|
|
@ -333,12 +333,11 @@ void GameFormSpec::showPauseMenu()
|
|||
|
||||
#ifndef __ANDROID__
|
||||
#if USE_SOUND
|
||||
if (g_settings->getBool("enable_sound")) {
|
||||
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;"
|
||||
<< strgettext("Sound Volume") << "]";
|
||||
}
|
||||
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_sound;"
|
||||
<< strgettext("Sound Volume") << "]";
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (g_touchcontrols) {
|
||||
os << "button_exit[4," << (ypos++) << ";3,0.5;btn_touchscreen_layout;"
|
||||
<< strgettext("Touchscreen Layout") << "]";
|
||||
|
|
|
@ -215,7 +215,6 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
|
|||
void GameUI::initFlags()
|
||||
{
|
||||
m_flags = GameUI::Flags();
|
||||
m_flags.show_minimal_debug = g_settings->getBool("show_debug");
|
||||
}
|
||||
|
||||
void GameUI::showTranslatedStatusText(const char *str)
|
||||
|
|
|
@ -94,8 +94,7 @@ video::ITexture *guiScalingResizeCached(video::IVideoDriver *driver,
|
|||
auto it_img = g_imgCache.find(origname);
|
||||
video::IImage *srcimg = (it_img != g_imgCache.end()) ? it_img->second : nullptr;
|
||||
if (!srcimg) {
|
||||
if (!g_settings->getBool("gui_scaling_filter_txr2img"))
|
||||
return src;
|
||||
// Download image from GPU
|
||||
srcimg = driver->createImageFromData(src->getColorFormat(),
|
||||
src->getSize(), src->lock(video::ETLM_READ_ONLY), false);
|
||||
src->unlock();
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "irrlichttypes.h"
|
||||
#include "irr_v2d.h"
|
||||
#include "joystick_controller.h"
|
||||
#include <list>
|
||||
#include "keycode.h"
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include <IEventReceiver.h>
|
||||
#include "irrlichttypes.h"
|
||||
|
||||
#include "keys.h"
|
||||
#include <bitset>
|
||||
#include <vector>
|
||||
|
|
|
@ -26,10 +26,14 @@
|
|||
MeshMakeData
|
||||
*/
|
||||
|
||||
MeshMakeData::MeshMakeData(const NodeDefManager *ndef, u16 side_length):
|
||||
side_length(side_length),
|
||||
nodedef(ndef)
|
||||
{}
|
||||
MeshMakeData::MeshMakeData(const NodeDefManager *ndef,
|
||||
u16 side_length, MeshGrid mesh_grid) :
|
||||
m_side_length(side_length),
|
||||
m_mesh_grid(mesh_grid),
|
||||
m_nodedef(ndef)
|
||||
{
|
||||
assert(m_side_length > 0);
|
||||
}
|
||||
|
||||
void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
|
||||
{
|
||||
|
@ -38,8 +42,9 @@ void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
|
|||
v3s16 blockpos_nodes = m_blockpos*MAP_BLOCKSIZE;
|
||||
|
||||
m_vmanip.clear();
|
||||
// extra 1 block thick layer around the mesh
|
||||
VoxelArea voxel_area(blockpos_nodes - v3s16(1,1,1) * MAP_BLOCKSIZE,
|
||||
blockpos_nodes + v3s16(1,1,1) * (side_length + MAP_BLOCKSIZE /* extra layer of blocks around the mesh */) - v3s16(1,1,1));
|
||||
blockpos_nodes + v3s16(1,1,1) * (m_side_length + MAP_BLOCKSIZE) - v3s16(1,1,1));
|
||||
m_vmanip.addArea(voxel_area);
|
||||
}
|
||||
|
||||
|
@ -52,17 +57,30 @@ void MeshMakeData::fillBlockData(const v3s16 &bp, MapNode *data)
|
|||
m_vmanip.copyFrom(data, data_area, v3s16(0,0,0), blockpos_nodes, data_size);
|
||||
}
|
||||
|
||||
void MeshMakeData::fillSingleNode(MapNode data, MapNode padding)
|
||||
{
|
||||
m_blockpos = {0, 0, 0};
|
||||
|
||||
m_vmanip.clear();
|
||||
// area around 0,0,0 so that this positon has neighbors
|
||||
const s16 sz = 3;
|
||||
m_vmanip.addArea({v3s16(-sz), v3s16(sz)});
|
||||
|
||||
u32 count = m_vmanip.m_area.getVolume();
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
m_vmanip.m_data[i] = padding;
|
||||
m_vmanip.m_flags[i] &= ~VOXELFLAG_NO_DATA;
|
||||
}
|
||||
|
||||
m_vmanip.setNodeNoEmerge({0, 0, 0}, data);
|
||||
}
|
||||
|
||||
void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
|
||||
{
|
||||
if (crack_level >= 0)
|
||||
m_crack_pos_relative = crack_pos - m_blockpos*MAP_BLOCKSIZE;
|
||||
}
|
||||
|
||||
void MeshMakeData::setSmoothLighting(bool smooth_lighting)
|
||||
{
|
||||
m_smooth_lighting = smooth_lighting;
|
||||
}
|
||||
|
||||
/*
|
||||
Light and vertex color functions
|
||||
*/
|
||||
|
@ -133,7 +151,7 @@ u16 getFaceLight(MapNode n, MapNode n2, const NodeDefManager *ndef)
|
|||
static u16 getSmoothLightCombined(const v3s16 &p,
|
||||
const std::array<v3s16,8> &dirs, MeshMakeData *data)
|
||||
{
|
||||
const NodeDefManager *ndef = data->nodedef;
|
||||
const NodeDefManager *ndef = data->m_nodedef;
|
||||
|
||||
u16 ambient_occlusion = 0;
|
||||
u16 light_count = 0;
|
||||
|
@ -321,7 +339,7 @@ void final_color_blend(video::SColor *result,
|
|||
*/
|
||||
void getNodeTileN(MapNode mn, const v3s16 &p, u8 tileindex, MeshMakeData *data, TileSpec &tile)
|
||||
{
|
||||
const NodeDefManager *ndef = data->nodedef;
|
||||
const NodeDefManager *ndef = data->m_nodedef;
|
||||
const ContentFeatures &f = ndef->get(mn);
|
||||
tile = f.tiles[tileindex];
|
||||
bool has_crack = p == data->m_crack_pos_relative;
|
||||
|
@ -341,7 +359,7 @@ void getNodeTileN(MapNode mn, const v3s16 &p, u8 tileindex, MeshMakeData *data,
|
|||
*/
|
||||
void getNodeTile(MapNode mn, const v3s16 &p, const v3s16 &dir, MeshMakeData *data, TileSpec &tile)
|
||||
{
|
||||
const NodeDefManager *ndef = data->nodedef;
|
||||
const NodeDefManager *ndef = data->m_nodedef;
|
||||
|
||||
// Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0),
|
||||
// (0,0,1), (0,0,-1) or (0,0,0)
|
||||
|
@ -593,7 +611,7 @@ void PartialMeshBuffer::draw(video::IVideoDriver *driver) const
|
|||
MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offset):
|
||||
m_tsrc(client->getTextureSource()),
|
||||
m_shdrsrc(client->getShaderSource()),
|
||||
m_bounding_sphere_center((data->side_length * 0.5f - 0.5f) * BS),
|
||||
m_bounding_sphere_center((data->m_side_length * 0.5f - 0.5f) * BS),
|
||||
m_animation_force_timer(0), // force initial animation
|
||||
m_last_crack(-1)
|
||||
{
|
||||
|
@ -602,10 +620,12 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
|
|||
for (auto &m : m_mesh)
|
||||
m = make_irr<scene::SMesh>();
|
||||
|
||||
auto mesh_grid = client->getMeshGrid();
|
||||
auto mesh_grid = data->m_mesh_grid;
|
||||
v3s16 bp = data->m_blockpos;
|
||||
// Only generate minimap mapblocks at even coordinates.
|
||||
if (mesh_grid.isMeshPos(bp) && client->getMinimap()) {
|
||||
// Only generate minimap mapblocks at grid aligned coordinates.
|
||||
// FIXME: ^ doesn't really make sense. and in practice, bp is always aligned
|
||||
if (mesh_grid.isMeshPos(bp) && data->m_generate_minimap) {
|
||||
// meshgen area always fits into a grid cell
|
||||
m_minimap_mapblocks.resize(mesh_grid.getCellVolume(), nullptr);
|
||||
v3s16 ofs;
|
||||
|
||||
|
@ -622,17 +642,13 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
|
|||
}
|
||||
}
|
||||
|
||||
// algin vertices to mesh grid, not meshgen area
|
||||
v3f offset = intToFloat((data->m_blockpos - mesh_grid.getMeshPos(data->m_blockpos)) * MAP_BLOCKSIZE, BS);
|
||||
|
||||
MeshCollector collector(m_bounding_sphere_center, offset);
|
||||
/*
|
||||
Add special graphics:
|
||||
- torches
|
||||
- flowing water
|
||||
- fences
|
||||
- whatever
|
||||
*/
|
||||
|
||||
{
|
||||
// Generate everything
|
||||
MapblockMeshGenerator(data, &collector).generate();
|
||||
}
|
||||
|
||||
|
@ -640,9 +656,6 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
|
|||
Convert MeshCollector to SMesh
|
||||
*/
|
||||
|
||||
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++) {
|
||||
|
@ -679,16 +692,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
|
|||
auto &info = m_animation_info[{layer, i}];
|
||||
info.tile = p.layer;
|
||||
info.frame = 0;
|
||||
if (desync_animations) {
|
||||
// Get starting position from noise
|
||||
info.frame_offset =
|
||||
100000 * (2.0 + noise3d(
|
||||
data->m_blockpos.X, data->m_blockpos.Y,
|
||||
data->m_blockpos.Z, 0));
|
||||
} else {
|
||||
// Play all synchronized
|
||||
info.frame_offset = 0;
|
||||
}
|
||||
info.frame_offset = 0;
|
||||
// Replace tile texture with the first animation frame
|
||||
p.layer.texture = (*p.layer.frames)[0].texture;
|
||||
}
|
||||
|
@ -702,6 +706,16 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
|
|||
tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST;
|
||||
tex.MagFilter = video::ETMAGF_NEAREST;
|
||||
});
|
||||
/*
|
||||
* The second layer is for overlays, but uses the same vertex positions
|
||||
* as the first, which quickly leads to z-fighting.
|
||||
* To fix this we can offset the polygons in the direction of the camera.
|
||||
* This only affects the depth buffer and leads to no visual gaps in geometry.
|
||||
*/
|
||||
if (layer == 1) {
|
||||
material.PolygonOffsetSlopeScale = -1;
|
||||
material.PolygonOffsetDepthBias = -1;
|
||||
}
|
||||
|
||||
{
|
||||
material.MaterialType = m_shdrsrc->getShaderInfo(
|
||||
|
@ -738,7 +752,7 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs
|
|||
}
|
||||
}
|
||||
|
||||
m_bsp_tree.buildTree(&m_transparent_triangles, data->side_length);
|
||||
m_bsp_tree.buildTree(&m_transparent_triangles, data->m_side_length);
|
||||
|
||||
// Check if animation is required for this mesh
|
||||
m_has_animation =
|
||||
|
@ -947,21 +961,22 @@ video::SColor encode_light(u16 light, u8 emissive_light)
|
|||
|
||||
u8 get_solid_sides(MeshMakeData *data)
|
||||
{
|
||||
std::unordered_map<v3s16, u8> results;
|
||||
v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
|
||||
const NodeDefManager *ndef = data->nodedef;
|
||||
const NodeDefManager *ndef = data->m_nodedef;
|
||||
|
||||
u8 result = 0x3F; // all sides solid;
|
||||
const u16 side = data->m_side_length;
|
||||
assert(data->m_vmanip.m_area.contains(blockpos_nodes + v3s16(side - 1)));
|
||||
|
||||
for (s16 i = 0; i < data->side_length && result != 0; i++)
|
||||
for (s16 j = 0; j < data->side_length && result != 0; j++) {
|
||||
u8 result = 0x3F; // all sides solid
|
||||
for (s16 i = 0; i < side && result != 0; i++)
|
||||
for (s16 j = 0; j < side && result != 0; j++) {
|
||||
v3s16 positions[6] = {
|
||||
v3s16(0, i, j),
|
||||
v3s16(data->side_length - 1, i, j),
|
||||
v3s16(side - 1, i, j),
|
||||
v3s16(i, 0, j),
|
||||
v3s16(i, data->side_length - 1, j),
|
||||
v3s16(i, side - 1, j),
|
||||
v3s16(i, j, 0),
|
||||
v3s16(i, j, data->side_length - 1)
|
||||
v3s16(i, j, side - 1)
|
||||
};
|
||||
|
||||
for (u8 k = 0; k < 6; k++) {
|
||||
|
|
|
@ -4,8 +4,11 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "irrlichttypes.h"
|
||||
#include "irr_ptr.h"
|
||||
#include "IMesh.h"
|
||||
#include "SMeshBuffer.h"
|
||||
|
||||
#include "util/numeric.h"
|
||||
#include "client/tile.h"
|
||||
#include "voxel.h"
|
||||
|
@ -13,6 +16,10 @@
|
|||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace irr::video {
|
||||
class IVideoDriver;
|
||||
}
|
||||
|
||||
class Client;
|
||||
class NodeDefManager;
|
||||
class IShaderSource;
|
||||
|
@ -29,14 +36,25 @@ struct MinimapMapblock;
|
|||
struct MeshMakeData
|
||||
{
|
||||
VoxelManipulator m_vmanip;
|
||||
|
||||
// base pos of meshgen area, in blocks
|
||||
v3s16 m_blockpos = v3s16(-1337,-1337,-1337);
|
||||
// size of meshgen area, in nodes.
|
||||
// vmanip will have at least an extra 1 node onion layer.
|
||||
// area is expected to fit into mesh grid cell.
|
||||
u16 m_side_length;
|
||||
// vertex positions will be relative to this grid
|
||||
MeshGrid m_mesh_grid;
|
||||
|
||||
// relative to blockpos
|
||||
v3s16 m_crack_pos_relative = v3s16(-1337,-1337,-1337);
|
||||
bool m_generate_minimap = false;
|
||||
bool m_smooth_lighting = false;
|
||||
u16 side_length;
|
||||
bool m_enable_water_reflections = false;
|
||||
|
||||
const NodeDefManager *nodedef;
|
||||
const NodeDefManager *m_nodedef;
|
||||
|
||||
MeshMakeData(const NodeDefManager *ndef, u16 side_length);
|
||||
MeshMakeData(const NodeDefManager *ndef, u16 side_lingth, MeshGrid mesh_grid);
|
||||
|
||||
/*
|
||||
Copy block data manually (to allow optimizations by the caller)
|
||||
|
@ -44,15 +62,15 @@ struct MeshMakeData
|
|||
void fillBlockDataBegin(const v3s16 &blockpos);
|
||||
void fillBlockData(const v3s16 &bp, MapNode *data);
|
||||
|
||||
/*
|
||||
Prepare block data for rendering a single node located at (0,0,0).
|
||||
*/
|
||||
void fillSingleNode(MapNode data, MapNode padding = MapNode(CONTENT_AIR));
|
||||
|
||||
/*
|
||||
Set the (node) position of a crack
|
||||
*/
|
||||
void setCrack(int crack_level, v3s16 crack_pos);
|
||||
|
||||
/*
|
||||
Enable or disable smooth lighting
|
||||
*/
|
||||
void setSmoothLighting(bool smooth_lighting);
|
||||
};
|
||||
|
||||
// represents a triangle as indexes into the vertex buffer in SMeshBuffer
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
|
||||
|
||||
#include "mesh.h"
|
||||
#include "S3DVertex.h"
|
||||
#include "debug.h"
|
||||
#include "log.h"
|
||||
#include <cmath>
|
||||
|
@ -11,6 +10,9 @@
|
|||
#include <IAnimatedMesh.h>
|
||||
#include <SAnimatedMesh.h>
|
||||
#include <IAnimatedMeshSceneNode.h>
|
||||
#include "S3DVertex.h"
|
||||
#include "SMesh.h"
|
||||
#include "SMeshBuffer.h"
|
||||
|
||||
inline static void applyShadeFactor(video::SColor& color, float factor)
|
||||
{
|
||||
|
|
|
@ -4,10 +4,20 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "SColor.h"
|
||||
#include "SMaterialLayer.h"
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "nodedef.h"
|
||||
|
||||
namespace irr {
|
||||
namespace scene {
|
||||
class IAnimatedMesh;
|
||||
class IMesh;
|
||||
class IMeshBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace irr;
|
||||
|
||||
/*!
|
||||
* Applies shading to a color based on the surface's
|
||||
* normal vector.
|
||||
|
|
|
@ -40,6 +40,7 @@ MeshUpdateQueue::MeshUpdateQueue(Client *client):
|
|||
m_client(client)
|
||||
{
|
||||
m_cache_smooth_lighting = g_settings->getBool("smooth_lighting");
|
||||
m_cache_enable_water_reflections = g_settings->getBool("enable_water_reflections");
|
||||
}
|
||||
|
||||
MeshUpdateQueue::~MeshUpdateQueue()
|
||||
|
@ -176,7 +177,8 @@ void MeshUpdateQueue::done(v3s16 pos)
|
|||
void MeshUpdateQueue::fillDataFromMapBlocks(QueuedMeshUpdate *q)
|
||||
{
|
||||
auto mesh_grid = m_client->getMeshGrid();
|
||||
MeshMakeData *data = new MeshMakeData(m_client->ndef(), MAP_BLOCKSIZE * mesh_grid.cell_size);
|
||||
MeshMakeData *data = new MeshMakeData(m_client->ndef(),
|
||||
MAP_BLOCKSIZE * mesh_grid.cell_size, mesh_grid);
|
||||
q->data = data;
|
||||
|
||||
data->fillBlockDataBegin(q->p);
|
||||
|
@ -191,7 +193,9 @@ void MeshUpdateQueue::fillDataFromMapBlocks(QueuedMeshUpdate *q)
|
|||
}
|
||||
|
||||
data->setCrack(q->crack_level, q->crack_pos);
|
||||
data->setSmoothLighting(m_cache_smooth_lighting);
|
||||
data->m_generate_minimap = !!m_client->getMinimap();
|
||||
data->m_smooth_lighting = m_cache_smooth_lighting;
|
||||
data->m_enable_water_reflections = m_cache_enable_water_reflections;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -69,8 +69,9 @@ private:
|
|||
std::unordered_set<v3s16> m_inflight_blocks;
|
||||
std::mutex m_mutex;
|
||||
|
||||
// TODO: Add callback to update these when g_settings changes
|
||||
// TODO: Add callback to update these when g_settings changes, and update all meshes
|
||||
bool m_cache_smooth_lighting;
|
||||
bool m_cache_enable_water_reflections;
|
||||
|
||||
void fillDataFromMapBlocks(QueuedMeshUpdate *q);
|
||||
};
|
||||
|
|
|
@ -41,45 +41,6 @@ void MeshCollector::append(const TileLayer &layer, const video::S3DVertex *verti
|
|||
p.indices.push_back(indices[i] + vertex_count);
|
||||
}
|
||||
|
||||
void MeshCollector::append(const TileSpec &tile, const video::S3DVertex *vertices,
|
||||
u32 numVertices, const u16 *indices, u32 numIndices, v3f pos,
|
||||
video::SColor c, u8 light_source)
|
||||
{
|
||||
for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
|
||||
const TileLayer *layer = &tile.layers[layernum];
|
||||
if (layer->texture_id == 0)
|
||||
continue;
|
||||
append(*layer, vertices, numVertices, indices, numIndices, pos, c,
|
||||
light_source, layernum, tile.world_aligned);
|
||||
}
|
||||
}
|
||||
|
||||
void MeshCollector::append(const TileLayer &layer, const video::S3DVertex *vertices,
|
||||
u32 numVertices, const u16 *indices, u32 numIndices, v3f pos,
|
||||
video::SColor c, u8 light_source, u8 layernum, bool use_scale)
|
||||
{
|
||||
PreMeshBuffer &p = findBuffer(layer, layernum, numVertices);
|
||||
|
||||
f32 scale = 1.0f;
|
||||
if (use_scale)
|
||||
scale = 1.0f / layer.scale;
|
||||
|
||||
u32 vertex_count = p.vertices.size();
|
||||
for (u32 i = 0; i < numVertices; i++) {
|
||||
video::SColor color = c;
|
||||
if (!light_source)
|
||||
applyFacesShading(color, vertices[i].Normal);
|
||||
auto vpos = vertices[i].Pos + pos + offset;
|
||||
p.vertices.emplace_back(vpos, vertices[i].Normal, color,
|
||||
scale * vertices[i].TCoords);
|
||||
m_bounding_radius_sq = std::max(m_bounding_radius_sq,
|
||||
(vpos - m_center_pos).getLengthSQ());
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < numIndices; i++)
|
||||
p.indices.push_back(indices[i] + vertex_count);
|
||||
}
|
||||
|
||||
PreMeshBuffer &MeshCollector::findBuffer(
|
||||
const TileLayer &layer, u8 layernum, u32 numVertices)
|
||||
{
|
||||
|
|
|
@ -35,21 +35,12 @@ struct MeshCollector
|
|||
void append(const TileSpec &material,
|
||||
const video::S3DVertex *vertices, u32 numVertices,
|
||||
const u16 *indices, u32 numIndices);
|
||||
void append(const TileSpec &material,
|
||||
const video::S3DVertex *vertices, u32 numVertices,
|
||||
const u16 *indices, u32 numIndices,
|
||||
v3f pos, video::SColor c, u8 light_source);
|
||||
|
||||
private:
|
||||
void append(const TileLayer &material,
|
||||
const video::S3DVertex *vertices, u32 numVertices,
|
||||
const u16 *indices, u32 numIndices,
|
||||
u8 layernum, bool use_scale = false);
|
||||
void append(const TileLayer &material,
|
||||
const video::S3DVertex *vertices, u32 numVertices,
|
||||
const u16 *indices, u32 numIndices,
|
||||
v3f pos, video::SColor c, u8 light_source,
|
||||
u8 layernum, bool use_scale = false);
|
||||
|
||||
PreMeshBuffer &findBuffer(const TileLayer &layer, u8 layernum, u32 numVertices);
|
||||
};
|
||||
|
|
|
@ -4,18 +4,35 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "../hud.h"
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "irrlichttypes.h"
|
||||
#include "irr_ptr.h"
|
||||
#include "rect.h"
|
||||
#include "SMeshBuffer.h"
|
||||
|
||||
#include "../hud.h"
|
||||
#include "mapnode.h"
|
||||
#include "util/thread.h"
|
||||
#include "voxel.h"
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace irr {
|
||||
namespace video {
|
||||
class IVideoDriver;
|
||||
class IImage;
|
||||
class ITexture;
|
||||
}
|
||||
|
||||
namespace scene {
|
||||
class ISceneNode;
|
||||
}
|
||||
}
|
||||
|
||||
class Client;
|
||||
class NodeDefManager;
|
||||
class ITextureSource;
|
||||
class IShaderSource;
|
||||
class VoxelManipulator;
|
||||
|
||||
#define MINIMAP_MAX_SX 512
|
||||
#define MINIMAP_MAX_SY 512
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include "settings.h"
|
||||
#include "profiler.h"
|
||||
|
||||
#include "SMeshBuffer.h"
|
||||
|
||||
using BlendMode = ParticleParamTypes::BlendMode;
|
||||
|
||||
ClientParticleTexture::ClientParticleTexture(const ServerParticleTexture& p, ITextureSource *tsrc)
|
||||
|
|
|
@ -4,12 +4,21 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "irrlichttypes_bloated.h"
|
||||
#include "irr_ptr.h"
|
||||
#include "ISceneNode.h"
|
||||
#include "S3DVertex.h"
|
||||
#include "SMeshBuffer.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "irr_ptr.h"
|
||||
#include "../particles.h"
|
||||
|
||||
namespace irr::video {
|
||||
class ITexture;
|
||||
}
|
||||
|
||||
struct ClientEvent;
|
||||
class ParticleManager;
|
||||
class ClientEnvironment;
|
||||
|
|
|
@ -18,7 +18,7 @@ void SetColorMaskStep::run(PipelineContext &context)
|
|||
{
|
||||
video::SOverrideMaterial &mat = context.device->getVideoDriver()->getOverrideMaterial();
|
||||
mat.reset();
|
||||
mat.Material.ColorMask = color_mask;
|
||||
mat.Material.ColorMask = static_cast<video::E_COLOR_PLANE>(color_mask);
|
||||
mat.EnableProps = video::EMP_COLOR_MASK;
|
||||
mat.EnablePasses = scene::ESNRP_SKY_BOX | scene::ESNRP_SOLID |
|
||||
scene::ESNRP_TRANSPARENT | scene::ESNRP_TRANSPARENT_EFFECT;
|
||||
|
|
|
@ -21,7 +21,7 @@ PostProcessingStep::PostProcessingStep(u32 _shader_id, const std::vector<u8> &_t
|
|||
void PostProcessingStep::configureMaterial()
|
||||
{
|
||||
material.UseMipMaps = false;
|
||||
material.ZBuffer = true;
|
||||
material.ZBuffer = video::ECFN_LESSEQUAL;
|
||||
material.ZWriteEnable = video::EZW_ON;
|
||||
for (u32 k = 0; k < texture_map.size(); ++k) {
|
||||
material.TextureLayers[k].AnisotropicFilter = 0;
|
||||
|
@ -196,7 +196,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
|
|||
}
|
||||
|
||||
if (enable_volumetric_light) {
|
||||
buffer->setTexture(TEXTURE_VOLUME, scale, "volume", color_format);
|
||||
buffer->setTexture(TEXTURE_VOLUME, scale, "volume", bloom_format);
|
||||
|
||||
shader_id = client->getShaderSource()->getShaderRaw("volumetric_light");
|
||||
auto volume = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { source, TEXTURE_DEPTH });
|
||||
|
|
|
@ -50,8 +50,7 @@ void FpsControl::limit(IrrlichtDevice *device, f32 *dtime, bool assume_paused)
|
|||
|
||||
if (busy_time < frametime_min) {
|
||||
sleep_time = frametime_min - busy_time;
|
||||
if (sleep_time > 0)
|
||||
sleep_us(sleep_time);
|
||||
porting::preciseSleepUs(sleep_time);
|
||||
} else {
|
||||
sleep_time = 0;
|
||||
}
|
||||
|
|
|
@ -687,13 +687,23 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
|
|||
case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
|
||||
case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
|
||||
case TILE_MATERIAL_WAVING_LIQUID_BASIC:
|
||||
case TILE_MATERIAL_LIQUID_TRANSPARENT:
|
||||
shaders_header << "#define MATERIAL_WAVING_LIQUID 1\n";
|
||||
break;
|
||||
default:
|
||||
shaders_header << "#define MATERIAL_WAVING_LIQUID 0\n";
|
||||
break;
|
||||
}
|
||||
switch (material_type) {
|
||||
case TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT:
|
||||
case TILE_MATERIAL_WAVING_LIQUID_OPAQUE:
|
||||
case TILE_MATERIAL_WAVING_LIQUID_BASIC:
|
||||
case TILE_MATERIAL_LIQUID_TRANSPARENT:
|
||||
shaders_header << "#define MATERIAL_WATER_REFLECTIONS 1\n";
|
||||
break;
|
||||
default:
|
||||
shaders_header << "#define MATERIAL_WATER_REFLECTIONS 0\n";
|
||||
break;
|
||||
}
|
||||
|
||||
shaders_header << "#define ENABLE_WAVING_LEAVES " << g_settings->getBool("enable_waving_leaves") << "\n";
|
||||
shaders_header << "#define ENABLE_WAVING_PLANTS " << g_settings->getBool("enable_waving_plants") << "\n";
|
||||
|
|
|
@ -13,18 +13,6 @@
|
|||
|
||||
using m4f = core::matrix4;
|
||||
|
||||
static v3f quantizeDirection(v3f direction, float step)
|
||||
{
|
||||
|
||||
float yaw = std::atan2(direction.Z, direction.X);
|
||||
float pitch = std::asin(direction.Y); // assume look is normalized
|
||||
|
||||
yaw = std::floor(yaw / step) * step;
|
||||
pitch = std::floor(pitch / step) * step;
|
||||
|
||||
return v3f(std::cos(yaw)*std::cos(pitch), std::sin(pitch), std::sin(yaw)*std::cos(pitch));
|
||||
}
|
||||
|
||||
void DirectionalLight::createSplitMatrices(const Camera *cam)
|
||||
{
|
||||
static const float COS_15_DEG = 0.965926f;
|
||||
|
@ -74,7 +62,7 @@ void DirectionalLight::createSplitMatrices(const Camera *cam)
|
|||
v3f boundVec = (cam_pos_scene + farCorner * sfFar) - center_scene;
|
||||
float radius = boundVec.getLength();
|
||||
float length = radius * 3.0f;
|
||||
v3f eye_displacement = quantizeDirection(direction, M_PI / 2880 /*15 seconds*/) * length;
|
||||
v3f eye_displacement = direction * length;
|
||||
|
||||
// we must compute the viewmat with the position - the camera offset
|
||||
// but the future_frustum position must be the actual world position
|
||||
|
|
|
@ -27,7 +27,7 @@ static video::SMaterial baseMaterial()
|
|||
video::SMaterial mat;
|
||||
mat.ZBuffer = video::ECFN_DISABLED;
|
||||
mat.ZWriteEnable = video::EZW_OFF;
|
||||
mat.AntiAliasing = 0;
|
||||
mat.AntiAliasing = video::EAAM_OFF;
|
||||
mat.TextureLayers[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
|
||||
mat.TextureLayers[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
|
||||
mat.BackfaceCulling = false;
|
||||
|
|
|
@ -50,6 +50,11 @@ struct FrameSpec
|
|||
video::ITexture *texture = nullptr;
|
||||
};
|
||||
|
||||
/**
|
||||
* We have two tile layers:
|
||||
* layer 0 = base
|
||||
* layer 1 = overlay
|
||||
*/
|
||||
#define MAX_TILE_LAYERS 2
|
||||
|
||||
//! Defines a layer of a tile.
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
#include <IMeshManipulator.h>
|
||||
#include "client/renderingengine.h"
|
||||
|
||||
#define WIELD_SCALE_FACTOR 30.0
|
||||
#define WIELD_SCALE_FACTOR_EXTRUDED 40.0
|
||||
#define WIELD_SCALE_FACTOR 30.0f
|
||||
#define WIELD_SCALE_FACTOR_EXTRUDED 40.0f
|
||||
|
||||
#define MIN_EXTRUSION_MESH_RESOLUTION 16
|
||||
#define MAX_EXTRUSION_MESH_RESOLUTION 512
|
||||
|
@ -225,18 +225,6 @@ WieldMeshSceneNode::~WieldMeshSceneNode()
|
|||
g_extrusion_mesh_cache = nullptr;
|
||||
}
|
||||
|
||||
void WieldMeshSceneNode::setCube(const ContentFeatures &f,
|
||||
v3f wield_scale)
|
||||
{
|
||||
scene::IMesh *cubemesh = g_extrusion_mesh_cache->createCube();
|
||||
scene::SMesh *copy = cloneMesh(cubemesh);
|
||||
cubemesh->drop();
|
||||
postProcessNodeMesh(copy, f, false, &m_material_type, &m_colors, true);
|
||||
changeToMesh(copy);
|
||||
copy->drop();
|
||||
m_meshnode->setScale(wield_scale * WIELD_SCALE_FACTOR);
|
||||
}
|
||||
|
||||
void WieldMeshSceneNode::setExtruded(const std::string &imagename,
|
||||
const std::string &overlay_name, v3f wield_scale, ITextureSource *tsrc,
|
||||
u8 num_frames)
|
||||
|
@ -251,6 +239,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
|
|||
|
||||
core::dimension2d<u32> dim = texture->getSize();
|
||||
// Detect animation texture and pull off top frame instead of using entire thing
|
||||
// FIXME: this is quite unportable, we should be working with the original TileLayer if there's one
|
||||
if (num_frames > 1) {
|
||||
u32 frame_height = dim.Height / num_frames;
|
||||
dim = core::dimension2d<u32>(dim.Width, frame_height);
|
||||
|
@ -262,11 +251,13 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
|
|||
mesh->getMeshBuffer(0)->getMaterial().setTexture(0,
|
||||
tsrc->getTexture(imagename));
|
||||
if (overlay_texture) {
|
||||
// duplicate the extruded mesh for the overlay
|
||||
scene::IMeshBuffer *copy = cloneMeshBuffer(mesh->getMeshBuffer(0));
|
||||
copy->getMaterial().setTexture(0, overlay_texture);
|
||||
mesh->addMeshBuffer(copy);
|
||||
copy->drop();
|
||||
}
|
||||
mesh->recalculateBoundingBox();
|
||||
changeToMesh(mesh);
|
||||
mesh->drop();
|
||||
|
||||
|
@ -292,14 +283,10 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
|
|||
}
|
||||
}
|
||||
|
||||
static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n,
|
||||
static scene::SMesh *createGenericNodeMesh(Client *client, MapNode n,
|
||||
std::vector<ItemPartColor> *colors, const ContentFeatures &f)
|
||||
{
|
||||
MeshMakeData mesh_make_data(client->ndef(), 1);
|
||||
MeshCollector collector(v3f(0.0f * BS), v3f());
|
||||
mesh_make_data.setSmoothLighting(false);
|
||||
MapblockMeshGenerator gen(&mesh_make_data, &collector);
|
||||
|
||||
n.setParam1(0xff);
|
||||
if (n.getParam2()) {
|
||||
// keep it
|
||||
} else if (f.param_type_2 == CPT2_WALLMOUNTED ||
|
||||
|
@ -313,29 +300,43 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n,
|
|||
} else if (f.drawtype == NDT_SIGNLIKE || f.drawtype == NDT_TORCHLIKE) {
|
||||
n.setParam2(1);
|
||||
}
|
||||
gen.renderSingle(n.getContent(), n.getParam2());
|
||||
|
||||
MeshCollector collector(v3f(0), v3f());
|
||||
{
|
||||
MeshMakeData mmd(client->ndef(), 1, MeshGrid{1});
|
||||
mmd.fillSingleNode(n);
|
||||
MapblockMeshGenerator(&mmd, &collector).generate();
|
||||
}
|
||||
|
||||
colors->clear();
|
||||
scene::SMesh *mesh = new scene::SMesh();
|
||||
for (auto &prebuffers : collector.prebuffers)
|
||||
for (int layer = 0; layer < MAX_TILE_LAYERS; layer++) {
|
||||
auto &prebuffers = collector.prebuffers[layer];
|
||||
for (PreMeshBuffer &p : prebuffers) {
|
||||
if (p.layer.material_flags & MATERIAL_FLAG_ANIMATION) {
|
||||
const FrameSpec &frame = (*p.layer.frames)[0];
|
||||
p.layer.texture = frame.texture;
|
||||
}
|
||||
for (video::S3DVertex &v : p.vertices) {
|
||||
for (video::S3DVertex &v : p.vertices)
|
||||
v.Color.setAlpha(255);
|
||||
}
|
||||
scene::SMeshBuffer *buf = new scene::SMeshBuffer();
|
||||
buf->Material.setTexture(0, p.layer.texture);
|
||||
p.layer.applyMaterialOptions(buf->Material);
|
||||
mesh->addMeshBuffer(buf);
|
||||
|
||||
auto buf = make_irr<scene::SMeshBuffer>();
|
||||
buf->append(&p.vertices[0], p.vertices.size(),
|
||||
&p.indices[0], p.indices.size());
|
||||
buf->drop();
|
||||
colors->push_back(
|
||||
ItemPartColor(p.layer.has_color, p.layer.color));
|
||||
|
||||
// Set up material
|
||||
buf->Material.setTexture(0, p.layer.texture);
|
||||
if (layer == 1) {
|
||||
buf->Material.PolygonOffsetSlopeScale = -1;
|
||||
buf->Material.PolygonOffsetDepthBias = -1;
|
||||
}
|
||||
p.layer.applyMaterialOptions(buf->Material);
|
||||
|
||||
mesh->addMeshBuffer(buf.get());
|
||||
colors->emplace_back(p.layer.has_color, p.layer.color);
|
||||
}
|
||||
}
|
||||
mesh->recalculateBoundingBox();
|
||||
return mesh;
|
||||
}
|
||||
|
||||
|
@ -375,15 +376,12 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
|
|||
}
|
||||
|
||||
// Handle nodes
|
||||
// See also CItemDefManager::createClientCached()
|
||||
if (def.type == ITEM_NODE) {
|
||||
bool cull_backface = f.needsBackfaceCulling();
|
||||
|
||||
// Select rendering method
|
||||
switch (f.drawtype) {
|
||||
case NDT_AIRLIKE:
|
||||
setExtruded("no_texture_airlike.png", "",
|
||||
v3f(1.0, 1.0, 1.0), tsrc, 1);
|
||||
v3f(1), tsrc, 1);
|
||||
break;
|
||||
case NDT_SIGNLIKE:
|
||||
case NDT_TORCHLIKE:
|
||||
|
@ -393,38 +391,33 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
|
|||
v3f wscale = wield_scale;
|
||||
if (f.drawtype == NDT_FLOWINGLIQUID)
|
||||
wscale.Z *= 0.1f;
|
||||
setExtruded(tsrc->getTextureName(f.tiles[0].layers[0].texture_id),
|
||||
tsrc->getTextureName(f.tiles[0].layers[1].texture_id),
|
||||
wscale, tsrc,
|
||||
f.tiles[0].layers[0].animation_frame_count);
|
||||
// Add color
|
||||
const TileLayer &l0 = f.tiles[0].layers[0];
|
||||
m_colors.emplace_back(l0.has_color, l0.color);
|
||||
const TileLayer &l1 = f.tiles[0].layers[1];
|
||||
setExtruded(tsrc->getTextureName(l0.texture_id),
|
||||
tsrc->getTextureName(l1.texture_id),
|
||||
wscale, tsrc,
|
||||
l0.animation_frame_count);
|
||||
// Add color
|
||||
m_colors.emplace_back(l0.has_color, l0.color);
|
||||
m_colors.emplace_back(l1.has_color, l1.color);
|
||||
break;
|
||||
}
|
||||
case NDT_PLANTLIKE_ROOTED: {
|
||||
setExtruded(tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id),
|
||||
"", wield_scale, tsrc,
|
||||
f.special_tiles[0].layers[0].animation_frame_count);
|
||||
// Add color
|
||||
// use the plant tile
|
||||
const TileLayer &l0 = f.special_tiles[0].layers[0];
|
||||
setExtruded(tsrc->getTextureName(l0.texture_id),
|
||||
"", wield_scale, tsrc,
|
||||
l0.animation_frame_count);
|
||||
m_colors.emplace_back(l0.has_color, l0.color);
|
||||
break;
|
||||
}
|
||||
case NDT_NORMAL:
|
||||
case NDT_ALLFACES:
|
||||
case NDT_LIQUID:
|
||||
setCube(f, wield_scale);
|
||||
break;
|
||||
default: {
|
||||
// Render non-trivial drawtypes like the actual node
|
||||
// Render all other drawtypes like the actual node
|
||||
MapNode n(id);
|
||||
if (def.place_param2)
|
||||
n.setParam2(*def.place_param2);
|
||||
|
||||
mesh = createSpecialNodeMesh(client, n, &m_colors, f);
|
||||
mesh = createGenericNodeMesh(client, n, &m_colors, f);
|
||||
changeToMesh(mesh);
|
||||
mesh->drop();
|
||||
m_meshnode->setScale(
|
||||
|
@ -437,9 +430,9 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
|
|||
u32 material_count = m_meshnode->getMaterialCount();
|
||||
for (u32 i = 0; i < material_count; ++i) {
|
||||
video::SMaterial &material = m_meshnode->getMaterial(i);
|
||||
// FIXME: overriding this breaks different alpha modes the mesh may have
|
||||
material.MaterialType = m_material_type;
|
||||
material.MaterialTypeParam = 0.5f;
|
||||
material.BackfaceCulling = cull_backface;
|
||||
material.forEachTexture([this] (auto &tex) {
|
||||
setMaterialFilters(tex, m_bilinear_filter, m_trilinear_filter,
|
||||
m_anisotropic_filter);
|
||||
|
@ -550,8 +543,6 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
|
|||
// Shading is on by default
|
||||
result->needs_shading = true;
|
||||
|
||||
bool cull_backface = f.needsBackfaceCulling();
|
||||
|
||||
// If inventory_image is defined, it overrides everything else
|
||||
const std::string inventory_image = item.getInventoryImage(idef);
|
||||
const std::string inventory_overlay = item.getInventoryOverlay(idef);
|
||||
|
@ -568,51 +559,32 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
|
|||
result->needs_shading = false;
|
||||
} else if (def.type == ITEM_NODE) {
|
||||
switch (f.drawtype) {
|
||||
case NDT_NORMAL:
|
||||
case NDT_ALLFACES:
|
||||
case NDT_LIQUID:
|
||||
case NDT_FLOWINGLIQUID: {
|
||||
scene::IMesh *cube = g_extrusion_mesh_cache->createCube();
|
||||
mesh = cloneMesh(cube);
|
||||
cube->drop();
|
||||
if (f.drawtype == NDT_FLOWINGLIQUID) {
|
||||
scaleMesh(mesh, v3f(1.2, 0.03, 1.2));
|
||||
translateMesh(mesh, v3f(0, -0.57, 0));
|
||||
} else
|
||||
scaleMesh(mesh, v3f(1.2, 1.2, 1.2));
|
||||
// add overlays
|
||||
postProcessNodeMesh(mesh, f, false, nullptr,
|
||||
&result->buffer_colors, true);
|
||||
if (f.drawtype == NDT_ALLFACES)
|
||||
scaleMesh(mesh, v3f(f.visual_scale));
|
||||
break;
|
||||
}
|
||||
case NDT_PLANTLIKE: {
|
||||
mesh = getExtrudedMesh(tsrc,
|
||||
tsrc->getTextureName(f.tiles[0].layers[0].texture_id),
|
||||
tsrc->getTextureName(f.tiles[0].layers[1].texture_id));
|
||||
// Add color
|
||||
const TileLayer &l0 = f.tiles[0].layers[0];
|
||||
result->buffer_colors.emplace_back(l0.has_color, l0.color);
|
||||
const TileLayer &l1 = f.tiles[0].layers[1];
|
||||
mesh = getExtrudedMesh(tsrc,
|
||||
tsrc->getTextureName(l0.texture_id),
|
||||
tsrc->getTextureName(l1.texture_id));
|
||||
// Add color
|
||||
result->buffer_colors.emplace_back(l0.has_color, l0.color);
|
||||
result->buffer_colors.emplace_back(l1.has_color, l1.color);
|
||||
break;
|
||||
}
|
||||
case NDT_PLANTLIKE_ROOTED: {
|
||||
mesh = getExtrudedMesh(tsrc,
|
||||
tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id), "");
|
||||
// Add color
|
||||
// Use the plant tile
|
||||
const TileLayer &l0 = f.special_tiles[0].layers[0];
|
||||
mesh = getExtrudedMesh(tsrc,
|
||||
tsrc->getTextureName(l0.texture_id), "");
|
||||
result->buffer_colors.emplace_back(l0.has_color, l0.color);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
// Render non-trivial drawtypes like the actual node
|
||||
// Render all other drawtypes like the actual node
|
||||
MapNode n(id);
|
||||
if (def.place_param2)
|
||||
n.setParam2(*def.place_param2);
|
||||
|
||||
mesh = createSpecialNodeMesh(client, n, &result->buffer_colors, f);
|
||||
mesh = createGenericNodeMesh(client, n, &result->buffer_colors, f);
|
||||
scaleMesh(mesh, v3f(0.12, 0.12, 0.12));
|
||||
break;
|
||||
}
|
||||
|
@ -621,13 +593,13 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
|
|||
for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) {
|
||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
|
||||
video::SMaterial &material = buf->getMaterial();
|
||||
// FIXME: overriding this breaks different alpha modes the mesh may have
|
||||
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
material.MaterialTypeParam = 0.5f;
|
||||
material.forEachTexture([] (auto &tex) {
|
||||
tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST;
|
||||
tex.MagFilter = video::ETMAGF_NEAREST;
|
||||
});
|
||||
material.BackfaceCulling = cull_backface;
|
||||
}
|
||||
|
||||
rotateMeshXZby(mesh, -45);
|
||||
|
@ -648,7 +620,7 @@ scene::SMesh *getExtrudedMesh(ITextureSource *tsrc,
|
|||
const std::string &imagename, const std::string &overlay_name)
|
||||
{
|
||||
// check textures
|
||||
video::ITexture *texture = tsrc->getTextureForMesh(imagename);
|
||||
video::ITexture *texture = tsrc->getTexture(imagename);
|
||||
if (!texture) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -683,56 +655,7 @@ scene::SMesh *getExtrudedMesh(ITextureSource *tsrc,
|
|||
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
|
||||
material.MaterialTypeParam = 0.5f;
|
||||
}
|
||||
scaleMesh(mesh, v3f(2.0, 2.0, 2.0));
|
||||
scaleMesh(mesh, v3f(2));
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f,
|
||||
bool set_material, const video::E_MATERIAL_TYPE *mattype,
|
||||
std::vector<ItemPartColor> *colors, bool apply_scale)
|
||||
{
|
||||
const u32 mc = mesh->getMeshBufferCount();
|
||||
// Allocate colors for existing buffers
|
||||
colors->clear();
|
||||
colors->resize(mc);
|
||||
|
||||
for (u32 i = 0; i < mc; ++i) {
|
||||
const TileSpec *tile = &(f.tiles[i]);
|
||||
scene::IMeshBuffer *buf = mesh->getMeshBuffer(i);
|
||||
for (int layernum = 0; layernum < MAX_TILE_LAYERS; layernum++) {
|
||||
const TileLayer *layer = &tile->layers[layernum];
|
||||
if (layer->texture_id == 0)
|
||||
continue;
|
||||
if (layernum != 0) {
|
||||
scene::IMeshBuffer *copy = cloneMeshBuffer(buf);
|
||||
copy->getMaterial() = buf->getMaterial();
|
||||
mesh->addMeshBuffer(copy);
|
||||
copy->drop();
|
||||
buf = copy;
|
||||
colors->emplace_back(layer->has_color, layer->color);
|
||||
} else {
|
||||
(*colors)[i] = ItemPartColor(layer->has_color, layer->color);
|
||||
}
|
||||
|
||||
video::SMaterial &material = buf->getMaterial();
|
||||
if (set_material)
|
||||
layer->applyMaterialOptions(material);
|
||||
if (mattype) {
|
||||
material.MaterialType = *mattype;
|
||||
}
|
||||
if (layer->animation_frame_count > 1) {
|
||||
const FrameSpec &animation_frame = (*layer->frames)[0];
|
||||
material.setTexture(0, animation_frame.texture);
|
||||
} else {
|
||||
material.setTexture(0, layer->texture);
|
||||
}
|
||||
|
||||
if (apply_scale && tile->world_aligned) {
|
||||
u32 n = buf->getVertexCount();
|
||||
for (u32 k = 0; k != n; ++k)
|
||||
buf->getTCoords(k) /= layer->scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,6 @@ public:
|
|||
WieldMeshSceneNode(scene::ISceneManager *mgr, s32 id = -1);
|
||||
virtual ~WieldMeshSceneNode();
|
||||
|
||||
void setCube(const ContentFeatures &f, v3f wield_scale);
|
||||
void setExtruded(const std::string &imagename, const std::string &overlay_image,
|
||||
v3f wield_scale, ITextureSource *tsrc, u8 num_frames);
|
||||
void setItem(const ItemStack &item, Client *client,
|
||||
|
@ -143,14 +142,3 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result);
|
|||
|
||||
scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, const std::string &imagename,
|
||||
const std::string &overlay_name);
|
||||
|
||||
/*!
|
||||
* Applies overlays, textures and optionally materials to the given mesh and
|
||||
* extracts tile colors for colorization.
|
||||
* \param mattype overrides the buffer's material type, but can also
|
||||
* be NULL to leave the original material.
|
||||
* \param colors returns the colors of the mesh buffers in the mesh.
|
||||
*/
|
||||
void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f,
|
||||
bool set_material, const video::E_MATERIAL_TYPE *mattype,
|
||||
std::vector<ItemPartColor> *colors, bool apply_scale = false);
|
||||
|
|
|
@ -3,9 +3,8 @@
|
|||
// Copyright (C) 2018 rubenwardy <rw@rubenwardy.com>
|
||||
|
||||
#pragma once
|
||||
#include "config.h"
|
||||
#include "convert_json.h"
|
||||
#include "irrlichttypes.h"
|
||||
#include <string>
|
||||
|
||||
enum class ContentType
|
||||
{
|
||||
|
|
|
@ -47,7 +47,7 @@ void ModConfiguration::addMods(const std::vector<ModSpec> &new_mods)
|
|||
}
|
||||
|
||||
// Add new mods
|
||||
for (int want_from_modpack = 1; want_from_modpack >= 0; --want_from_modpack) {
|
||||
for (bool want_from_modpack : {true, false}) {
|
||||
// First iteration:
|
||||
// Add all the mods that come from modpacks
|
||||
// Second iteration:
|
||||
|
@ -56,9 +56,12 @@ void ModConfiguration::addMods(const std::vector<ModSpec> &new_mods)
|
|||
std::set<std::string> seen_this_iteration;
|
||||
|
||||
for (const ModSpec &mod : new_mods) {
|
||||
if (mod.part_of_modpack != (bool)want_from_modpack)
|
||||
if (mod.part_of_modpack != want_from_modpack)
|
||||
continue;
|
||||
|
||||
// unrelated to this code, but we want to assert it somewhere
|
||||
assert(fs::IsPathAbsolute(mod.path));
|
||||
|
||||
if (existing_mods.count(mod.name) == 0) {
|
||||
// GOOD CASE: completely new mod.
|
||||
m_unsatisfied_mods.push_back(mod);
|
||||
|
|
|
@ -167,6 +167,7 @@ std::map<std::string, ModSpec> getModsInPath(
|
|||
|
||||
mod_path.clear();
|
||||
mod_path.append(path).append(DIR_DELIM).append(modname);
|
||||
mod_path = fs::AbsolutePath(mod_path);
|
||||
|
||||
mod_virtual_path.clear();
|
||||
// Intentionally uses / to keep paths same on different platforms
|
||||
|
@ -174,7 +175,7 @@ std::map<std::string, ModSpec> getModsInPath(
|
|||
|
||||
ModSpec spec(modname, mod_path, part_of_modpack, mod_virtual_path);
|
||||
parseModContents(spec);
|
||||
result.insert(std::make_pair(modname, spec));
|
||||
result[modname] = std::move(spec);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ struct ModSpec
|
|||
{
|
||||
std::string name;
|
||||
std::string author;
|
||||
std::string path;
|
||||
std::string path; // absolute path on disk
|
||||
std::string desc;
|
||||
int release = 0;
|
||||
|
||||
|
|
|
@ -22,9 +22,8 @@
|
|||
namespace
|
||||
{
|
||||
|
||||
bool getGameMinetestConfig(const std::string &game_path, Settings &conf)
|
||||
bool getGameConfig(const std::string &game_path, Settings &conf)
|
||||
{
|
||||
// TODO: rename this
|
||||
std::string conf_path = game_path + DIR_DELIM + "minetest.conf";
|
||||
return conf.readConfigFile(conf_path.c_str());
|
||||
}
|
||||
|
@ -355,7 +354,7 @@ void loadGameConfAndInitWorld(const std::string &path, const std::string &name,
|
|||
game_settings = Settings::createLayer(SL_GAME);
|
||||
}
|
||||
|
||||
getGameMinetestConfig(gamespec.path, *game_settings);
|
||||
getGameConfig(gamespec.path, *game_settings);
|
||||
game_settings->removeSecureSettings();
|
||||
|
||||
infostream << "Initializing world at " << final_path << std::endl;
|
||||
|
|
|
@ -6,8 +6,7 @@
|
|||
|
||||
#include <exception>
|
||||
#include <cassert>
|
||||
#include "gettime.h"
|
||||
#include "log.h"
|
||||
#include "log.h" // unused. for convenience.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define FUNCTION_NAME __FUNCTION__
|
||||
|
|
|
@ -82,7 +82,6 @@ void set_default_settings()
|
|||
|
||||
// Client
|
||||
settings->setDefault("address", "");
|
||||
settings->setDefault("enable_sound", "true");
|
||||
#if defined(__unix__) && !defined(__APPLE__) && !defined (__ANDROID__)
|
||||
// On Linux+X11 (not Linux+Wayland or Linux+XWayland), I've encountered a bug
|
||||
// where fake mouse events were generated from touch events if in relative
|
||||
|
@ -270,7 +269,6 @@ void set_default_settings()
|
|||
settings->setDefault("cinematic", "false");
|
||||
settings->setDefault("camera_smoothing", "0.0");
|
||||
settings->setDefault("cinematic_camera_smoothing", "0.7");
|
||||
settings->setDefault("enable_clouds", "true");
|
||||
settings->setDefault("view_bobbing_amount", "1.0");
|
||||
settings->setDefault("fall_bobbing_amount", "0.03");
|
||||
settings->setDefault("enable_3d_clouds", "true");
|
||||
|
@ -292,14 +290,11 @@ void set_default_settings()
|
|||
settings->setDefault("hud_scaling", "1.0");
|
||||
settings->setDefault("gui_scaling", "1.0");
|
||||
settings->setDefault("gui_scaling_filter", "false");
|
||||
settings->setDefault("gui_scaling_filter_txr2img", "true");
|
||||
settings->setDefault("smooth_scrolling", "true");
|
||||
settings->setDefault("desynchronize_mapblock_texture_animation", "false");
|
||||
settings->setDefault("hud_hotbar_max_width", "1.0");
|
||||
settings->setDefault("enable_local_map_saving", "false");
|
||||
settings->setDefault("show_entity_selectionbox", "false");
|
||||
settings->setDefault("ambient_occlusion_gamma", "1.8");
|
||||
settings->setDefault("enable_particles", "true");
|
||||
settings->setDefault("arm_inertia", "true");
|
||||
settings->setDefault("show_nametag_backgrounds", "true");
|
||||
settings->setDefault("show_block_bounds_radius_near", "4");
|
||||
|
@ -350,7 +345,7 @@ void set_default_settings()
|
|||
settings->setDefault("shadow_map_color", "false");
|
||||
settings->setDefault("shadow_filters", "1");
|
||||
settings->setDefault("shadow_poisson_filter", "true");
|
||||
settings->setDefault("shadow_update_frames", "8");
|
||||
settings->setDefault("shadow_update_frames", "16");
|
||||
settings->setDefault("shadow_soft_radius", "5.0");
|
||||
settings->setDefault("shadow_sky_body_orbit_tilt", "0.0");
|
||||
settings->setDefault("enable_sun_tint", "false");
|
||||
|
@ -420,7 +415,6 @@ void set_default_settings()
|
|||
#endif
|
||||
|
||||
// Server
|
||||
settings->setDefault("disable_escape_sequences", "false");
|
||||
settings->setDefault("strip_color_codes", "false");
|
||||
#ifndef NDEBUG
|
||||
settings->setDefault("random_mod_load_order", "true");
|
||||
|
@ -440,7 +434,6 @@ void set_default_settings()
|
|||
settings->setDefault("protocol_version_min", "1");
|
||||
settings->setDefault("player_transfer_distance", "0");
|
||||
settings->setDefault("max_simultaneous_block_sends_per_client", "40");
|
||||
settings->setDefault("time_send_interval", "5");
|
||||
|
||||
settings->setDefault("motd", "");
|
||||
settings->setDefault("max_users", "15");
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include <mutex>
|
||||
#include "network/networkprotocol.h"
|
||||
#include "irr_v3d.h"
|
||||
#include "util/container.h"
|
||||
#include "util/metricsbackend.h"
|
||||
#include "mapgen/mapgen.h" // for MapgenParams
|
||||
#include "map.h"
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "gettext.h"
|
||||
#include "irrlicht_changes/CGUITTFont.h"
|
||||
#include "util/string.h"
|
||||
#include "guiScrollBar.h"
|
||||
#include <string>
|
||||
|
||||
inline u32 clamp_u8(s32 value)
|
||||
|
@ -28,6 +29,11 @@ inline bool isInCtrlKeys(const irr::EKEY_CODE& kc)
|
|||
return kc == KEY_LCONTROL || kc == KEY_RCONTROL || kc == KEY_CONTROL;
|
||||
}
|
||||
|
||||
inline u32 getScrollbarSize(IGUIEnvironment* env)
|
||||
{
|
||||
return env->getSkin()->getSize(gui::EGDS_SCROLLBAR_SIZE);
|
||||
}
|
||||
|
||||
GUIChatConsole::GUIChatConsole(
|
||||
gui::IGUIEnvironment* env,
|
||||
gui::IGUIElement* parent,
|
||||
|
@ -62,15 +68,14 @@ GUIChatConsole::GUIChatConsole(
|
|||
}
|
||||
|
||||
const u16 chat_font_size = g_settings->getU16("chat_font_size");
|
||||
m_font = g_fontengine->getFont(chat_font_size != 0 ?
|
||||
rangelim(chat_font_size, 5, 72) : FONT_SIZE_UNSPECIFIED, FM_Mono);
|
||||
m_font.grab(g_fontengine->getFont(chat_font_size != 0 ?
|
||||
rangelim(chat_font_size, 5, 72) : FONT_SIZE_UNSPECIFIED, FM_Mono));
|
||||
|
||||
if (!m_font) {
|
||||
errorstream << "GUIChatConsole: Unable to load mono font" << std::endl;
|
||||
} else {
|
||||
core::dimension2d<u32> dim = m_font->getDimension(L"M");
|
||||
m_fontsize = v2u32(dim.Width, dim.Height);
|
||||
m_font->grab();
|
||||
}
|
||||
m_fontsize.X = MYMAX(m_fontsize.X, 1);
|
||||
m_fontsize.Y = MYMAX(m_fontsize.Y, 1);
|
||||
|
@ -81,12 +86,11 @@ GUIChatConsole::GUIChatConsole(
|
|||
// track ctrl keys for mouse event
|
||||
m_is_ctrl_down = false;
|
||||
m_cache_clickable_chat_weblinks = g_settings->getBool("clickable_chat_weblinks");
|
||||
}
|
||||
|
||||
GUIChatConsole::~GUIChatConsole()
|
||||
{
|
||||
if (m_font)
|
||||
m_font->drop();
|
||||
m_scrollbar.reset(new GUIScrollBar(env, this, -1, core::rect<s32>(0, 0, 30, m_height), false, true, tsrc));
|
||||
m_scrollbar->setSubElement(true);
|
||||
m_scrollbar->setLargeStep(1);
|
||||
m_scrollbar->setSmallStep(1);
|
||||
}
|
||||
|
||||
void GUIChatConsole::openConsole(f32 scale)
|
||||
|
@ -121,6 +125,7 @@ void GUIChatConsole::closeConsole()
|
|||
m_open = false;
|
||||
Environment->removeFocus(this);
|
||||
m_menumgr->deletingMenu(this);
|
||||
m_scrollbar->setVisible(false);
|
||||
}
|
||||
|
||||
void GUIChatConsole::closeConsoleAtOnce()
|
||||
|
@ -180,6 +185,10 @@ void GUIChatConsole::draw()
|
|||
m_screensize = screensize;
|
||||
m_desired_height = m_desired_height_fraction * m_screensize.Y;
|
||||
reformatConsole();
|
||||
} else if (!m_scrollbar->getAbsolutePosition().isPointInside(core::vector2di(screensize.X, m_height))) {
|
||||
// the height of the chat window is no longer the height of the scrollbar
|
||||
// happens while opening/closing the window
|
||||
updateScrollbar(true);
|
||||
}
|
||||
|
||||
// Animation
|
||||
|
@ -204,6 +213,9 @@ void GUIChatConsole::reformatConsole()
|
|||
s32 rows = m_desired_height / m_fontsize.Y - 1; // make room for the input prompt
|
||||
if (cols <= 0 || rows <= 0)
|
||||
cols = rows = 0;
|
||||
|
||||
updateScrollbar(true);
|
||||
|
||||
recalculateConsolePosition();
|
||||
m_chat_backend->reformat(cols, rows);
|
||||
}
|
||||
|
@ -293,10 +305,17 @@ void GUIChatConsole::drawBackground()
|
|||
|
||||
void GUIChatConsole::drawText()
|
||||
{
|
||||
if (m_font == NULL)
|
||||
if (!m_font)
|
||||
return;
|
||||
|
||||
ChatBuffer& buf = m_chat_backend->getConsoleBuffer();
|
||||
|
||||
core::recti rect;
|
||||
if (m_scrollbar->isVisible())
|
||||
rect = core::rect<s32> (0, 0, m_screensize.X - getScrollbarSize(Environment), m_height);
|
||||
else
|
||||
rect = AbsoluteClippingRect;
|
||||
|
||||
for (u32 row = 0; row < buf.getRows(); ++row)
|
||||
{
|
||||
const ChatFormattedLine& line = buf.getFormattedLine(row);
|
||||
|
@ -315,13 +334,13 @@ void GUIChatConsole::drawText()
|
|||
|
||||
if (m_font->getType() == irr::gui::EGFT_CUSTOM) {
|
||||
// Draw colored text if possible
|
||||
gui::CGUITTFont *tmp = static_cast<gui::CGUITTFont*>(m_font);
|
||||
auto *tmp = static_cast<gui::CGUITTFont*>(m_font.get());
|
||||
tmp->draw(
|
||||
fragment.text,
|
||||
destrect,
|
||||
false,
|
||||
false,
|
||||
&AbsoluteClippingRect);
|
||||
&rect);
|
||||
} else {
|
||||
// Otherwise use standard text
|
||||
m_font->draw(
|
||||
|
@ -330,10 +349,12 @@ void GUIChatConsole::drawText()
|
|||
video::SColor(255, 255, 255, 255),
|
||||
false,
|
||||
false,
|
||||
&AbsoluteClippingRect);
|
||||
&rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateScrollbar();
|
||||
}
|
||||
|
||||
void GUIChatConsole::drawPrompt()
|
||||
|
@ -680,6 +701,11 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
|||
prompt.input(std::wstring(event.StringInput.Str->c_str()));
|
||||
return true;
|
||||
}
|
||||
else if (event.EventType == EET_GUI_EVENT && event.GUIEvent.EventType == EGET_SCROLL_BAR_CHANGED &&
|
||||
(void*) event.GUIEvent.Caller == (void*) m_scrollbar.get())
|
||||
{
|
||||
m_chat_backend->getConsoleBuffer().scrollAbsolute(m_scrollbar->getPos());
|
||||
}
|
||||
|
||||
return Parent ? Parent->OnEvent(event) : false;
|
||||
}
|
||||
|
@ -692,6 +718,7 @@ void GUIChatConsole::setVisible(bool visible)
|
|||
m_height = 0;
|
||||
recalculateConsolePosition();
|
||||
}
|
||||
m_scrollbar->setVisible(visible);
|
||||
}
|
||||
|
||||
bool GUIChatConsole::weblinkClick(s32 col, s32 row)
|
||||
|
@ -763,3 +790,18 @@ void GUIChatConsole::updatePrimarySelection()
|
|||
std::string selected = wide_to_utf8(wselected);
|
||||
Environment->getOSOperator()->copyToPrimarySelection(selected.c_str());
|
||||
}
|
||||
|
||||
void GUIChatConsole::updateScrollbar(bool update_size)
|
||||
{
|
||||
ChatBuffer &buf = m_chat_backend->getConsoleBuffer();
|
||||
m_scrollbar->setMin(buf.getTopScrollPos());
|
||||
m_scrollbar->setMax(buf.getBottomScrollPos());
|
||||
m_scrollbar->setPos(buf.getScrollPosition());
|
||||
m_scrollbar->setPageSize(m_fontsize.Y * buf.getLineCount());
|
||||
m_scrollbar->setVisible(m_scrollbar->getMin() != m_scrollbar->getMax());
|
||||
|
||||
if (update_size) {
|
||||
const core::rect<s32> rect (m_screensize.X - getScrollbarSize(Environment), 0, m_screensize.X, m_height);
|
||||
m_scrollbar->setRelativePosition(rect);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,8 +8,10 @@
|
|||
#include "modalMenu.h"
|
||||
#include "chat.h"
|
||||
#include "config.h"
|
||||
#include "irr_ptr.h"
|
||||
|
||||
class Client;
|
||||
class GUIScrollBar;
|
||||
|
||||
class GUIChatConsole : public gui::IGUIElement
|
||||
{
|
||||
|
@ -20,7 +22,6 @@ public:
|
|||
ChatBackend* backend,
|
||||
Client* client,
|
||||
IMenuManager* menumgr);
|
||||
virtual ~GUIChatConsole();
|
||||
|
||||
// Open the console (height = desired fraction of screen size)
|
||||
// This doesn't open immediately but initiates an animation.
|
||||
|
@ -76,10 +77,13 @@ private:
|
|||
// If the selected text changed, we need to update the (X11) primary selection.
|
||||
void updatePrimarySelection();
|
||||
|
||||
void updateScrollbar(bool update_size = false);
|
||||
|
||||
private:
|
||||
ChatBackend* m_chat_backend;
|
||||
Client* m_client;
|
||||
IMenuManager* m_menumgr;
|
||||
irr_ptr<GUIScrollBar> m_scrollbar;
|
||||
|
||||
// current screen size
|
||||
v2u32 m_screensize;
|
||||
|
@ -116,7 +120,7 @@ private:
|
|||
video::SColor m_background_color = video::SColor(255, 0, 0, 0);
|
||||
|
||||
// font
|
||||
gui::IGUIFont *m_font = nullptr;
|
||||
irr_ptr<gui::IGUIFont> m_font;
|
||||
v2u32 m_fontsize;
|
||||
|
||||
// Enable clickable chat weblinks
|
||||
|
|
|
@ -130,7 +130,7 @@ GUIEngine::GUIEngine(JoystickController *joystick,
|
|||
|
||||
// create soundmanager
|
||||
#if USE_SOUND
|
||||
if (g_settings->getBool("enable_sound") && g_sound_manager_singleton.get()) {
|
||||
if (g_sound_manager_singleton.get()) {
|
||||
m_sound_manager = createOpenALSoundManager(g_sound_manager_singleton.get(),
|
||||
std::make_unique<MenuMusicFetcher>());
|
||||
}
|
||||
|
|
|
@ -11,6 +11,12 @@
|
|||
#include <cassert>
|
||||
#include <list>
|
||||
|
||||
#include "IGUIEnvironment.h"
|
||||
|
||||
namespace irr::gui {
|
||||
class IGUIStaticText;
|
||||
}
|
||||
|
||||
class IGameCallback
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "IGUIElement.h"
|
||||
#include "irrlichttypes_bloated.h"
|
||||
#include "irr_ptr.h"
|
||||
|
||||
#include "util/string.h"
|
||||
#ifdef __ANDROID__
|
||||
#include <porting_android.h>
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
class ISimpleTextureSource;
|
||||
namespace irr::gui
|
||||
{
|
||||
class IGUIButton;
|
||||
class IGUIImage;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
// Luanti
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// Copyright (C) 2021 x2048, Dmitry Kostenko <codeforsmile@gmail.com>
|
||||
|
||||
#include "lighting.h"
|
||||
|
||||
AutoExposure::AutoExposure()
|
||||
: luminance_min(-3.f),
|
||||
luminance_max(-3.f),
|
||||
exposure_correction(0.0f),
|
||||
speed_dark_bright(1000.f),
|
||||
speed_bright_dark(1000.f),
|
||||
center_weight_power(1.f)
|
||||
{}
|
|
@ -29,7 +29,14 @@ struct AutoExposure
|
|||
/// @brief Power value for center-weighted metering. Value of 1.0 measures entire screen uniformly
|
||||
float center_weight_power;
|
||||
|
||||
AutoExposure();
|
||||
constexpr AutoExposure()
|
||||
: luminance_min(-3.f),
|
||||
luminance_max(-3.f),
|
||||
exposure_correction(0.0f),
|
||||
speed_dark_bright(1000.f),
|
||||
speed_bright_dark(1000.f),
|
||||
center_weight_power(1.f)
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
17
src/map.cpp
17
src/map.cpp
|
@ -752,17 +752,12 @@ MMVManip::MMVManip(Map *map):
|
|||
assert(map);
|
||||
}
|
||||
|
||||
void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
|
||||
bool load_if_inexistent)
|
||||
void MMVManip::initialEmerge(v3s16 p_min, v3s16 p_max, bool load_if_inexistent)
|
||||
{
|
||||
TimeTaker timer1("initialEmerge", &emerge_time);
|
||||
|
||||
assert(m_map);
|
||||
|
||||
// Units of these are MapBlocks
|
||||
v3s16 p_min = blockpos_min;
|
||||
v3s16 p_max = blockpos_max;
|
||||
|
||||
VoxelArea block_area_nodes
|
||||
(p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
|
||||
|
||||
|
@ -775,6 +770,7 @@ void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
|
|||
infostream<<std::endl;
|
||||
}
|
||||
|
||||
const bool all_new = m_area.hasEmptyExtent() || block_area_nodes.contains(m_area);
|
||||
addArea(block_area_nodes);
|
||||
|
||||
for(s32 z=p_min.Z; z<=p_max.Z; z++)
|
||||
|
@ -812,16 +808,12 @@ void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
|
|||
setFlags(a, VOXELFLAG_NO_DATA);
|
||||
}
|
||||
}
|
||||
/*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
|
||||
{
|
||||
// Mark that block was loaded as blank
|
||||
flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
|
||||
}*/
|
||||
|
||||
m_loaded_blocks[p] = flags;
|
||||
}
|
||||
|
||||
m_is_dirty = false;
|
||||
if (all_new)
|
||||
m_is_dirty = false;
|
||||
}
|
||||
|
||||
void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
|
||||
|
@ -834,6 +826,7 @@ void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
|
|||
/*
|
||||
Copy data of all blocks
|
||||
*/
|
||||
assert(!m_loaded_blocks.empty());
|
||||
for (auto &loaded_block : m_loaded_blocks) {
|
||||
v3s16 p = loaded_block.first;
|
||||
MapBlock *block = m_map->getBlockNoCreateNoEx(p);
|
||||
|
|
|
@ -298,9 +298,6 @@ protected:
|
|||
u32 needed_count);
|
||||
};
|
||||
|
||||
#define VMANIP_BLOCK_DATA_INEXIST 1
|
||||
#define VMANIP_BLOCK_CONTAINS_CIGNORE 2
|
||||
|
||||
class MMVManip : public VoxelManipulator
|
||||
{
|
||||
public:
|
||||
|
@ -344,4 +341,8 @@ protected:
|
|||
value = flags describing the block
|
||||
*/
|
||||
std::map<v3s16, u8> m_loaded_blocks;
|
||||
|
||||
enum : u8 {
|
||||
VMANIP_BLOCK_DATA_INEXIST = 1 << 0,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -73,6 +73,12 @@ MapBlock::~MapBlock()
|
|||
porting::TrackFreedMemory(sizeof(MapNode) * nodecount);
|
||||
}
|
||||
|
||||
static inline size_t get_max_objects_per_block()
|
||||
{
|
||||
u16 ret = g_settings->getU16("max_objects_per_block");
|
||||
return MYMAX(256, ret);
|
||||
}
|
||||
|
||||
bool MapBlock::onObjectsActivation()
|
||||
{
|
||||
// Ignore if no stored objects (to not set changed flag)
|
||||
|
@ -84,7 +90,7 @@ bool MapBlock::onObjectsActivation()
|
|||
<< "activating " << count << " objects in block " << getPos()
|
||||
<< std::endl;
|
||||
|
||||
if (count > g_settings->getU16("max_objects_per_block")) {
|
||||
if (count > get_max_objects_per_block()) {
|
||||
errorstream << "suspiciously large amount of objects detected: "
|
||||
<< count << " in " << getPos() << "; removing all of them."
|
||||
<< std::endl;
|
||||
|
@ -99,7 +105,7 @@ bool MapBlock::onObjectsActivation()
|
|||
|
||||
bool MapBlock::saveStaticObject(u16 id, const StaticObject &obj, u32 reason)
|
||||
{
|
||||
if (m_static_objects.getStoredSize() >= g_settings->getU16("max_objects_per_block")) {
|
||||
if (m_static_objects.getStoredSize() >= get_max_objects_per_block()) {
|
||||
warningstream << "MapBlock::saveStaticObject(): Trying to store id = " << id
|
||||
<< " statically but block " << getPos() << " already contains "
|
||||
<< m_static_objects.getStoredSize() << " objects."
|
||||
|
|
180
src/mapnode.cpp
180
src/mapnode.cpp
|
@ -179,130 +179,52 @@ void transformNodeBox(const MapNode &n, const NodeBox &nodebox,
|
|||
if (nodebox.type == NODEBOX_FIXED || nodebox.type == NODEBOX_LEVELED) {
|
||||
const auto &fixed = nodebox.fixed;
|
||||
int facedir = n.getFaceDir(nodemgr, true);
|
||||
u8 axisdir = facedir>>2;
|
||||
facedir&=0x03;
|
||||
u8 axisdir = facedir >> 2;
|
||||
facedir &= 0x03;
|
||||
|
||||
boxes.reserve(boxes.size() + fixed.size());
|
||||
for (aabb3f box : fixed) {
|
||||
if (nodebox.type == NODEBOX_LEVELED)
|
||||
box.MaxEdge.Y = (-0.5f + n.getLevel(nodemgr) / 64.0f) * BS;
|
||||
|
||||
if(facedir == 1) {
|
||||
box.MinEdge.rotateXZBy(-90);
|
||||
box.MaxEdge.rotateXZBy(-90);
|
||||
} else if(facedir == 2) {
|
||||
box.MinEdge.rotateXZBy(180);
|
||||
box.MaxEdge.rotateXZBy(180);
|
||||
} else if(facedir == 3) {
|
||||
box.MinEdge.rotateXZBy(90);
|
||||
box.MaxEdge.rotateXZBy(90);
|
||||
}
|
||||
|
||||
switch (axisdir) {
|
||||
case 0:
|
||||
if(facedir == 1)
|
||||
{
|
||||
box.MinEdge.rotateXZBy(-90);
|
||||
box.MaxEdge.rotateXZBy(-90);
|
||||
}
|
||||
else if(facedir == 2)
|
||||
{
|
||||
box.MinEdge.rotateXZBy(180);
|
||||
box.MaxEdge.rotateXZBy(180);
|
||||
}
|
||||
else if(facedir == 3)
|
||||
{
|
||||
box.MinEdge.rotateXZBy(90);
|
||||
box.MaxEdge.rotateXZBy(90);
|
||||
}
|
||||
break;
|
||||
case 1: // z+
|
||||
box.MinEdge.rotateYZBy(90);
|
||||
box.MaxEdge.rotateYZBy(90);
|
||||
if(facedir == 1)
|
||||
{
|
||||
box.MinEdge.rotateXYBy(90);
|
||||
box.MaxEdge.rotateXYBy(90);
|
||||
}
|
||||
else if(facedir == 2)
|
||||
{
|
||||
box.MinEdge.rotateXYBy(180);
|
||||
box.MaxEdge.rotateXYBy(180);
|
||||
}
|
||||
else if(facedir == 3)
|
||||
{
|
||||
box.MinEdge.rotateXYBy(-90);
|
||||
box.MaxEdge.rotateXYBy(-90);
|
||||
}
|
||||
break;
|
||||
case 2: //z-
|
||||
box.MinEdge.rotateYZBy(-90);
|
||||
box.MaxEdge.rotateYZBy(-90);
|
||||
if(facedir == 1)
|
||||
{
|
||||
box.MinEdge.rotateXYBy(-90);
|
||||
box.MaxEdge.rotateXYBy(-90);
|
||||
}
|
||||
else if(facedir == 2)
|
||||
{
|
||||
box.MinEdge.rotateXYBy(180);
|
||||
box.MaxEdge.rotateXYBy(180);
|
||||
}
|
||||
else if(facedir == 3)
|
||||
{
|
||||
box.MinEdge.rotateXYBy(90);
|
||||
box.MaxEdge.rotateXYBy(90);
|
||||
}
|
||||
break;
|
||||
case 3: //x+
|
||||
box.MinEdge.rotateXYBy(-90);
|
||||
box.MaxEdge.rotateXYBy(-90);
|
||||
if(facedir == 1)
|
||||
{
|
||||
box.MinEdge.rotateYZBy(90);
|
||||
box.MaxEdge.rotateYZBy(90);
|
||||
}
|
||||
else if(facedir == 2)
|
||||
{
|
||||
box.MinEdge.rotateYZBy(180);
|
||||
box.MaxEdge.rotateYZBy(180);
|
||||
}
|
||||
else if(facedir == 3)
|
||||
{
|
||||
box.MinEdge.rotateYZBy(-90);
|
||||
box.MaxEdge.rotateYZBy(-90);
|
||||
}
|
||||
break;
|
||||
case 4: //x-
|
||||
box.MinEdge.rotateXYBy(90);
|
||||
box.MaxEdge.rotateXYBy(90);
|
||||
if(facedir == 1)
|
||||
{
|
||||
box.MinEdge.rotateYZBy(-90);
|
||||
box.MaxEdge.rotateYZBy(-90);
|
||||
}
|
||||
else if(facedir == 2)
|
||||
{
|
||||
box.MinEdge.rotateYZBy(180);
|
||||
box.MaxEdge.rotateYZBy(180);
|
||||
}
|
||||
else if(facedir == 3)
|
||||
{
|
||||
box.MinEdge.rotateYZBy(90);
|
||||
box.MaxEdge.rotateYZBy(90);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
box.MinEdge.rotateXYBy(-180);
|
||||
box.MaxEdge.rotateXYBy(-180);
|
||||
if(facedir == 1)
|
||||
{
|
||||
box.MinEdge.rotateXZBy(90);
|
||||
box.MaxEdge.rotateXZBy(90);
|
||||
}
|
||||
else if(facedir == 2)
|
||||
{
|
||||
box.MinEdge.rotateXZBy(180);
|
||||
box.MaxEdge.rotateXZBy(180);
|
||||
}
|
||||
else if(facedir == 3)
|
||||
{
|
||||
box.MinEdge.rotateXZBy(-90);
|
||||
box.MaxEdge.rotateXZBy(-90);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
box.repair();
|
||||
boxes.push_back(box);
|
||||
}
|
||||
|
@ -419,57 +341,47 @@ void transformNodeBox(const MapNode &n, const NodeBox &nodebox,
|
|||
|
||||
boxes.reserve(boxes_size);
|
||||
|
||||
#define BOXESPUSHBACK(c) \
|
||||
for (std::vector<aabb3f>::const_iterator \
|
||||
it = (c).begin(); \
|
||||
it != (c).end(); ++it) \
|
||||
(boxes).push_back(*it);
|
||||
auto boxes_insert = [&](const std::vector<aabb3f> &boxes_src) {
|
||||
boxes.insert(boxes.end(), boxes_src.begin(), boxes_src.end());
|
||||
};
|
||||
|
||||
BOXESPUSHBACK(nodebox.fixed);
|
||||
boxes_insert(nodebox.fixed);
|
||||
|
||||
if (neighbors & 1) {
|
||||
BOXESPUSHBACK(c.connect_top);
|
||||
} else {
|
||||
BOXESPUSHBACK(c.disconnected_top);
|
||||
}
|
||||
if (neighbors & 1)
|
||||
boxes_insert(c.connect_top);
|
||||
else
|
||||
boxes_insert(c.disconnected_top);
|
||||
|
||||
if (neighbors & 2) {
|
||||
BOXESPUSHBACK(c.connect_bottom);
|
||||
} else {
|
||||
BOXESPUSHBACK(c.disconnected_bottom);
|
||||
}
|
||||
if (neighbors & 2)
|
||||
boxes_insert(c.connect_bottom);
|
||||
else
|
||||
boxes_insert(c.disconnected_bottom);
|
||||
|
||||
if (neighbors & 4) {
|
||||
BOXESPUSHBACK(c.connect_front);
|
||||
} else {
|
||||
BOXESPUSHBACK(c.disconnected_front);
|
||||
}
|
||||
if (neighbors & 4)
|
||||
boxes_insert(c.connect_front);
|
||||
else
|
||||
boxes_insert(c.disconnected_front);
|
||||
|
||||
if (neighbors & 8) {
|
||||
BOXESPUSHBACK(c.connect_left);
|
||||
} else {
|
||||
BOXESPUSHBACK(c.disconnected_left);
|
||||
}
|
||||
if (neighbors & 8)
|
||||
boxes_insert(c.connect_left);
|
||||
else
|
||||
boxes_insert(c.disconnected_left);
|
||||
|
||||
if (neighbors & 16) {
|
||||
BOXESPUSHBACK(c.connect_back);
|
||||
} else {
|
||||
BOXESPUSHBACK(c.disconnected_back);
|
||||
}
|
||||
if (neighbors & 16)
|
||||
boxes_insert(c.connect_back);
|
||||
else
|
||||
boxes_insert(c.disconnected_back);
|
||||
|
||||
if (neighbors & 32) {
|
||||
BOXESPUSHBACK(c.connect_right);
|
||||
} else {
|
||||
BOXESPUSHBACK(c.disconnected_right);
|
||||
}
|
||||
if (neighbors & 32)
|
||||
boxes_insert(c.connect_right);
|
||||
else
|
||||
boxes_insert(c.disconnected_right);
|
||||
|
||||
if (neighbors == 0) {
|
||||
BOXESPUSHBACK(c.disconnected);
|
||||
}
|
||||
if (neighbors == 0)
|
||||
boxes_insert(c.disconnected);
|
||||
|
||||
if (neighbors < 4) {
|
||||
BOXESPUSHBACK(c.disconnected_sides);
|
||||
}
|
||||
if (neighbors < 4)
|
||||
boxes_insert(c.disconnected_sides);
|
||||
|
||||
}
|
||||
else // NODEBOX_REGULAR
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "version.h"
|
||||
#include "irrlicht_changes/printing.h"
|
||||
#include "network/connection.h"
|
||||
#include "network/networkpacket.h"
|
||||
#include "network/networkprotocol.h"
|
||||
#include "network/serveropcodes.h"
|
||||
#include "server/player_sao.h"
|
||||
|
|
|
@ -474,21 +474,6 @@ struct ContentFeatures
|
|||
}
|
||||
}
|
||||
|
||||
bool needsBackfaceCulling() const
|
||||
{
|
||||
switch (drawtype) {
|
||||
case NDT_TORCHLIKE:
|
||||
case NDT_SIGNLIKE:
|
||||
case NDT_FIRELIKE:
|
||||
case NDT_RAILLIKE:
|
||||
case NDT_PLANTLIKE:
|
||||
case NDT_PLANTLIKE_ROOTED:
|
||||
case NDT_MESH:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool isLiquid() const{
|
||||
return (liquid_type != LIQUID_NONE);
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
#include "util/numeric.h"
|
||||
#include "log.h"
|
||||
#include "gamedef.h"
|
||||
#include "porting.h" // strcasecmp
|
||||
|
||||
#include <cassert>
|
||||
|
||||
ObjDefManager::ObjDefManager(IGameDef *gamedef, ObjDefType type)
|
||||
{
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "util/basic_macros.h"
|
||||
#include "porting.h"
|
||||
#include "util/basic_macros.h" // DISABLE_CLASS_COPY
|
||||
#include "irrlichttypes.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class IGameDef;
|
||||
|
|
|
@ -32,12 +32,16 @@
|
|||
#define sleep_ms(x) Sleep(x)
|
||||
#define sleep_us(x) Sleep((x)/1000)
|
||||
|
||||
#define SLEEP_ACCURACY_US 2000
|
||||
|
||||
#define setenv(n,v,o) _putenv_s(n,v)
|
||||
#define unsetenv(n) _putenv_s(n,"")
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <cstdlib> // setenv
|
||||
|
||||
#define SLEEP_ACCURACY_US 200
|
||||
|
||||
#define sleep_ms(x) usleep((x)*1000)
|
||||
#define sleep_us(x) usleep(x)
|
||||
#endif
|
||||
|
@ -220,6 +224,21 @@ inline u64 getDeltaMs(u64 old_time_ms, u64 new_time_ms)
|
|||
return (old_time_ms - new_time_ms);
|
||||
}
|
||||
|
||||
inline void preciseSleepUs(u64 sleep_time)
|
||||
{
|
||||
if (sleep_time > 0)
|
||||
{
|
||||
u64 target_time = porting::getTimeUs() + sleep_time;
|
||||
if (sleep_time > SLEEP_ACCURACY_US)
|
||||
sleep_us(sleep_time - SLEEP_ACCURACY_US);
|
||||
|
||||
// Busy-wait the remaining time to adjust for sleep inaccuracies
|
||||
// The target - now > 0 construct will handle overflow gracefully (even though it should
|
||||
// never happen)
|
||||
while ((s64)(target_time - porting::getTimeUs()) > 0) {}
|
||||
}
|
||||
}
|
||||
|
||||
inline const char *getPlatformName()
|
||||
{
|
||||
return
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "util/container.h"
|
||||
#include "irrlichttypes_bloated.h"
|
||||
#include "irrlichttypes.h"
|
||||
#include "irr_v3d.h"
|
||||
|
||||
class NodeDefManager;
|
||||
class Map;
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <algorithm>
|
||||
#include "irr_v2d.h"
|
||||
#include "network/connection.h"
|
||||
#include "network/networkpacket.h"
|
||||
#include "network/networkprotocol.h"
|
||||
#include "network/serveropcodes.h"
|
||||
#include "server/ban.h"
|
||||
|
@ -624,6 +625,11 @@ void Server::AsyncRunStep(float dtime, bool initial_step)
|
|||
ZoneScoped;
|
||||
auto framemarker = FrameMarker("Server::AsyncRunStep()-frame").started();
|
||||
|
||||
if (!m_async_fatal_error.get().empty()) {
|
||||
infostream << "Refusing server step in error state" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
// Send blocks to clients
|
||||
SendBlocks(dtime);
|
||||
|
@ -649,9 +655,10 @@ void Server::AsyncRunStep(float dtime, bool initial_step)
|
|||
Send to clients at constant intervals
|
||||
*/
|
||||
|
||||
static const float time_send_interval = 5.0f;
|
||||
m_time_of_day_send_timer -= dtime;
|
||||
if (m_time_of_day_send_timer < 0.0) {
|
||||
m_time_of_day_send_timer = g_settings->getFloat("time_send_interval");
|
||||
if (m_time_of_day_send_timer < 0) {
|
||||
m_time_of_day_send_timer = time_send_interval;
|
||||
u16 time = m_env->getTimeOfDay();
|
||||
float time_speed = g_settings->getFloat("time_speed");
|
||||
SendTimeOfDay(PEER_ID_INEXISTENT, time, time_speed);
|
||||
|
@ -3862,6 +3869,14 @@ std::string Server::getBuiltinLuaPath()
|
|||
return porting::path_share + DIR_DELIM + "builtin";
|
||||
}
|
||||
|
||||
void Server::setAsyncFatalError(const std::string &error)
|
||||
{
|
||||
m_async_fatal_error.set(error);
|
||||
// make sure server steps stop happening immediately
|
||||
if (m_thread)
|
||||
m_thread->stop();
|
||||
}
|
||||
|
||||
// Not thread-safe.
|
||||
void Server::addShutdownError(const ModError &e)
|
||||
{
|
||||
|
|
|
@ -344,8 +344,7 @@ public:
|
|||
void setStepSettings(StepSettings spdata) { m_step_settings.store(spdata); }
|
||||
StepSettings getStepSettings() { return m_step_settings.load(); }
|
||||
|
||||
inline void setAsyncFatalError(const std::string &error)
|
||||
{ m_async_fatal_error.set(error); }
|
||||
void setAsyncFatalError(const std::string &error);
|
||||
inline void setAsyncFatalError(const LuaError &e)
|
||||
{
|
||||
setAsyncFatalError(std::string("Lua: ") + e.what());
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "clientiface.h"
|
||||
#include "debug.h"
|
||||
#include "network/connection.h"
|
||||
#include "network/networkpacket.h"
|
||||
#include "network/serveropcodes.h"
|
||||
#include "remoteplayer.h"
|
||||
#include "serialization.h" // SER_FMT_VER_INVALID
|
||||
|
|
|
@ -6,25 +6,25 @@
|
|||
|
||||
#include "irr_v3d.h" // for irrlicht datatypes
|
||||
|
||||
#include "constants.h"
|
||||
#include "network/networkpacket.h"
|
||||
#include "network/networkprotocol.h"
|
||||
#include "network/address.h"
|
||||
#include "network/networkprotocol.h" // session_t
|
||||
#include "porting.h"
|
||||
#include "threading/mutex_auto_lock.h"
|
||||
#include "clientdynamicinfo.h"
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
class MapBlock;
|
||||
class ServerEnvironment;
|
||||
class EmergeManager;
|
||||
class MapBlock;
|
||||
class NetworkPacket;
|
||||
class ServerEnvironment;
|
||||
|
||||
/*
|
||||
* State Transitions
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
#include <memory>
|
||||
|
||||
#include "map.h"
|
||||
#include "util/container.h"
|
||||
#include "util/metricsbackend.h"
|
||||
#include "util/container.h" // UniqueQueue
|
||||
#include "util/metricsbackend.h" // ptr typedefs
|
||||
#include "map_settings_manager.h"
|
||||
|
||||
class Settings;
|
||||
|
|
|
@ -212,8 +212,6 @@ bool run_tests()
|
|||
u64 t1 = porting::getTimeMs();
|
||||
TestGameDef gamedef;
|
||||
|
||||
g_logger.setLevelSilenced(LL_ERROR, true);
|
||||
|
||||
u32 num_modules_failed = 0;
|
||||
u32 num_total_tests_failed = 0;
|
||||
u32 num_total_tests_run = 0;
|
||||
|
@ -243,11 +241,9 @@ bool run_tests()
|
|||
|
||||
u64 tdiff = porting::getTimeMs() - t1;
|
||||
|
||||
g_logger.setLevelSilenced(LL_ERROR, false);
|
||||
|
||||
const char *overall_status = (num_modules_failed == 0) ? "PASSED" : "FAILED";
|
||||
|
||||
rawstream
|
||||
rawstream << "\n"
|
||||
<< "++++++++++++++++++++++++++++++++++++++++"
|
||||
<< "++++++++++++++++++++++++++++++++++++++++" << std::endl
|
||||
<< "Unit Test Results: " << overall_status << std::endl
|
||||
|
@ -283,17 +279,15 @@ bool run_tests(const std::string &module_name)
|
|||
return catch_test_failures == 0;
|
||||
}
|
||||
|
||||
g_logger.setLevelSilenced(LL_ERROR, true);
|
||||
u64 t1 = porting::getTimeMs();
|
||||
|
||||
bool ok = testmod->testModule(&gamedef);
|
||||
|
||||
u64 tdiff = porting::getTimeMs() - t1;
|
||||
g_logger.setLevelSilenced(LL_ERROR, false);
|
||||
|
||||
const char *overall_status = ok ? "PASSED" : "FAILED";
|
||||
|
||||
rawstream
|
||||
rawstream << "\n"
|
||||
<< "++++++++++++++++++++++++++++++++++++++++"
|
||||
<< "++++++++++++++++++++++++++++++++++++++++" << std::endl
|
||||
<< "Unit Test Results: " << overall_status << std::endl
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "irrlichttypes_bloated.h"
|
||||
#include "porting.h"
|
||||
#include "filesys.h"
|
||||
#include "mapnode.h"
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
#include <sstream>
|
||||
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "log.h"
|
||||
#include "serialization.h"
|
||||
#include "nodedef.h"
|
||||
|
|
|
@ -38,8 +38,10 @@ public:
|
|||
|
||||
MeshMakeData makeSingleNodeMMD(bool smooth_lighting = true)
|
||||
{
|
||||
MeshMakeData data{ndef(), 1};
|
||||
data.setSmoothLighting(smooth_lighting);
|
||||
MeshMakeData data{ndef(), 1, MeshGrid{1}};
|
||||
data.m_generate_minimap = false;
|
||||
data.m_smooth_lighting = smooth_lighting;
|
||||
data.m_enable_water_reflections = false;
|
||||
data.m_blockpos = {0, 0, 0};
|
||||
for (s16 x = -1; x <= 1; x++)
|
||||
for (s16 y = -1; y <= 1; y++)
|
||||
|
|
|
@ -98,10 +98,12 @@ void TestVoxelArea::test_addarea()
|
|||
void TestVoxelArea::test_pad()
|
||||
{
|
||||
VoxelArea v1(v3s16(-1447, -9547, -875), v3s16(-147, 8854, 669));
|
||||
auto old_extent = v1.getExtent();
|
||||
v1.pad(v3s16(100, 200, 300));
|
||||
|
||||
UASSERT(v1.MinEdge == v3s16(-1547, -9747, -1175));
|
||||
UASSERT(v1.MaxEdge == v3s16(-47, 9054, 969));
|
||||
UASSERT(v1.getExtent() > old_extent);
|
||||
}
|
||||
|
||||
void TestVoxelArea::test_extent()
|
||||
|
@ -165,6 +167,12 @@ void TestVoxelArea::test_contains_point()
|
|||
UASSERTEQ(bool, v1.contains(v3s16(-100, 100, 10000)), false);
|
||||
UASSERTEQ(bool, v1.contains(v3s16(-100, 100, -10000)), false);
|
||||
UASSERTEQ(bool, v1.contains(v3s16(10000, 100, 10)), false);
|
||||
|
||||
VoxelArea v2;
|
||||
UASSERTEQ(bool, v2.contains(v3s16(-200, 10, 10)), false);
|
||||
UASSERTEQ(bool, v2.contains(v3s16(0, 0, 0)), false);
|
||||
UASSERTEQ(bool, v2.contains(v3s16(1, 1, 1)), false);
|
||||
UASSERTEQ(bool, v2.contains(v3s16(-1, -1, -1)), false);
|
||||
}
|
||||
|
||||
void TestVoxelArea::test_contains_i()
|
||||
|
@ -180,6 +188,12 @@ void TestVoxelArea::test_contains_i()
|
|||
UASSERTEQ(bool, v2.contains(10), true);
|
||||
UASSERTEQ(bool, v2.contains(0), true);
|
||||
UASSERTEQ(bool, v2.contains(-1), false);
|
||||
|
||||
VoxelArea v3;
|
||||
UASSERTEQ(bool, v3.contains(0), false);
|
||||
UASSERTEQ(bool, v3.contains(-1), false);
|
||||
UASSERTEQ(bool, v3.contains(1), false);
|
||||
UASSERTEQ(bool, v3.contains(2), false);
|
||||
}
|
||||
|
||||
void TestVoxelArea::test_equal()
|
||||
|
@ -244,6 +258,7 @@ void TestVoxelArea::test_intersect()
|
|||
VoxelArea v3({11, 11, 11}, {11, 11, 11});
|
||||
VoxelArea v4({-11, -2, -10}, {10, 2, 11});
|
||||
UASSERT(v2.intersect(v1) == v2);
|
||||
UASSERT(!v2.intersect(v1).hasEmptyExtent());
|
||||
UASSERT(v1.intersect(v2) == v2.intersect(v1));
|
||||
UASSERT(v1.intersect(v3).hasEmptyExtent());
|
||||
UASSERT(v3.intersect(v1) == v1.intersect(v3));
|
||||
|
|
|
@ -113,6 +113,20 @@ void VoxelManipulator::print(std::ostream &o, const NodeDefManager *ndef,
|
|||
}
|
||||
}
|
||||
|
||||
static inline void checkArea(const VoxelArea &a)
|
||||
{
|
||||
// won't overflow since cbrt(2^64) > 2^16
|
||||
u64 real_volume = static_cast<u64>(a.getExtent().X) * a.getExtent().Y * a.getExtent().Z;
|
||||
|
||||
// Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
|
||||
// Note: the hard limit is somewhere around 2^31 due to s32 type
|
||||
constexpr u64 MAX_ALLOWED = 4096000;
|
||||
if (real_volume > MAX_ALLOWED) {
|
||||
throw BaseException("VoxelManipulator: "
|
||||
"Area volume exceeds allowed value of " + std::to_string(MAX_ALLOWED));
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelManipulator::addArea(const VoxelArea &area)
|
||||
{
|
||||
// Cancel if requested area has zero volume
|
||||
|
@ -124,18 +138,10 @@ void VoxelManipulator::addArea(const VoxelArea &area)
|
|||
return;
|
||||
|
||||
// Calculate new area
|
||||
VoxelArea new_area;
|
||||
// New area is the requested area if m_area has zero volume
|
||||
if(m_area.hasEmptyExtent())
|
||||
{
|
||||
new_area = area;
|
||||
}
|
||||
// Else add requested area to m_area
|
||||
else
|
||||
{
|
||||
new_area = m_area;
|
||||
new_area.addArea(area);
|
||||
}
|
||||
VoxelArea new_area = m_area;
|
||||
new_area.addArea(area);
|
||||
|
||||
checkArea(new_area);
|
||||
|
||||
u32 new_size = new_area.getVolume();
|
||||
|
||||
|
|
|
@ -103,6 +103,7 @@ public:
|
|||
{
|
||||
MinEdge -= d;
|
||||
MaxEdge += d;
|
||||
cacheExtent();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -188,6 +189,7 @@ public:
|
|||
ret.MaxEdge.Y = std::min(a.MaxEdge.Y, MaxEdge.Y);
|
||||
ret.MinEdge.Z = std::max(a.MinEdge.Z, MinEdge.Z);
|
||||
ret.MaxEdge.Z = std::min(a.MaxEdge.Z, MaxEdge.Z);
|
||||
ret.cacheExtent();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -457,7 +459,9 @@ public:
|
|||
{
|
||||
if(!m_area.contains(p))
|
||||
return false;
|
||||
m_data[m_area.index(p)] = n;
|
||||
const s32 index = m_area.index(p);
|
||||
m_data[index] = n;
|
||||
m_flags[index] &= ~VOXELFLAG_NO_DATA;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue