From bafc4779199a0544303290efa7be82ba1be9d5ee Mon Sep 17 00:00:00 2001 From: grorp Date: Fri, 8 Nov 2024 11:17:15 +0100 Subject: [PATCH 001/136] Revert "2D rendering: Enable bilinear filter for downscaling textures" (#15385) This reverts commit minetest/irrlicht@fb7a0e4298356a2d339c5ebf23152b441dc06a8f. --- irr/src/CNullDriver.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/irr/src/CNullDriver.cpp b/irr/src/CNullDriver.cpp index c7b296b57..74e8cb0f4 100644 --- a/irr/src/CNullDriver.cpp +++ b/irr/src/CNullDriver.cpp @@ -108,9 +108,7 @@ CNullDriver::CNullDriver(io::IFileSystem *io, const core::dimension2d &scre InitMaterial2D.ZBuffer = video::ECFN_DISABLED; InitMaterial2D.UseMipMaps = false; InitMaterial2D.forEachTexture([](auto &tex) { - // Using ETMINF_LINEAR_MIPMAP_NEAREST (bilinear) for 2D graphics looks - // much better and doesn't have any downsides (e.g. regarding pixel art). - tex.MinFilter = video::ETMINF_LINEAR_MIPMAP_NEAREST; + tex.MinFilter = video::ETMINF_NEAREST_MIPMAP_NEAREST; tex.MagFilter = video::ETMAGF_NEAREST; tex.TextureWrapU = video::ETC_REPEAT; tex.TextureWrapV = video::ETC_REPEAT; From fced6ff2401dfb0504064ee164bc625eac49c4b9 Mon Sep 17 00:00:00 2001 From: grorp Date: Thu, 7 Nov 2024 20:43:05 +0100 Subject: [PATCH 002/136] Fix ECF_D32 support in ogles2 video driver OES_depth32 only talks about support for render buffers, not textures, so it's not relevant here: https://github.com/KhronosGroup/OpenGL-Registry/blob/main/extensions/OES/OES_depth32.txt This fixes the scene being black with "video_driver = ogles2" and "enable_post_processing = true" on my desktop computer. --- irr/src/OpenGLES2/Driver.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/irr/src/OpenGLES2/Driver.cpp b/irr/src/OpenGLES2/Driver.cpp index 249b6caef..9a99601fd 100644 --- a/irr/src/OpenGLES2/Driver.cpp +++ b/irr/src/OpenGLES2/Driver.cpp @@ -57,8 +57,12 @@ void COpenGLES2Driver::initFeatures() else if (FeatureAvailable[IRR_GL_APPLE_texture_format_BGRA8888]) TextureFormats[ECF_A8R8G8B8] = {BGRA8_EXT, GL_BGRA, GL_UNSIGNED_BYTE}; - if (FeatureAvailable[IRR_GL_OES_depth32]) - TextureFormats[ECF_D32] = {GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}; + // OpenGL ES 3 doesn't include a GL_DEPTH_COMPONENT32, so still use + // OES_depth_texture for 32-bit depth texture support. + // OpenGL ES 3 would allow {GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT}, + // but I guess that would have to be called ECF_D32F... + if (FeatureAvailable[IRR_GL_OES_depth_texture]) + TextureFormats[ECF_D32] = {GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}; } else { // NOTE These are *texture* formats. They may or may not be suitable // for render targets. The specs only talks on *sized* formats for the @@ -98,8 +102,9 @@ void COpenGLES2Driver::initFeatures() if (FeatureAvailable[IRR_GL_OES_depth_texture]) { TextureFormats[ECF_D16] = {GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; - if (FeatureAvailable[IRR_GL_OES_depth32]) - TextureFormats[ECF_D32] = {GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}; + // OES_depth_texture includes 32-bit depth texture support. + TextureFormats[ECF_D32] = {GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}; + if (FeatureAvailable[IRR_GL_OES_packed_depth_stencil]) TextureFormats[ECF_D24S8] = {GL_DEPTH_STENCIL, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}; } From 50b75233364c89235ec2f8f77fb54767a228e395 Mon Sep 17 00:00:00 2001 From: grorp Date: Thu, 7 Nov 2024 20:12:37 +0100 Subject: [PATCH 003/136] ogles 2 driver: Delete some dead code grepping for IRR_COMPILE_GLES2_COMMON gives no other results COGLESCoreExtensionHandler is only used through COpenGL3ExtensionHandler --- irr/src/COGLESCoreExtensionHandler.h | 92 +--------------------------- irr/src/COpenGLCoreTexture.h | 1 + 2 files changed, 2 insertions(+), 91 deletions(-) diff --git a/irr/src/COGLESCoreExtensionHandler.h b/irr/src/COGLESCoreExtensionHandler.h index 4c691aaf9..80a7bb061 100644 --- a/irr/src/COGLESCoreExtensionHandler.h +++ b/irr/src/COGLESCoreExtensionHandler.h @@ -24,39 +24,21 @@ public: enum EOGLESFeatures { // If you update this enum also update the corresponding OGLESFeatureStrings string-array - IRR_GL_APPLE_texture_2D_limited_npot, IRR_GL_APPLE_texture_format_BGRA8888, IRR_GL_EXT_blend_minmax, - IRR_GL_EXT_read_format_bgra, - IRR_GL_EXT_texture_filter_anisotropic, IRR_GL_EXT_texture_format_BGRA8888, - IRR_GL_EXT_texture_lod_bias, IRR_GL_EXT_texture_rg, - IRR_GL_IMG_read_format, - IRR_GL_IMG_texture_format_BGRA8888, - IRR_GL_IMG_user_clip_plane, - IRR_GL_OES_blend_func_separate, - IRR_GL_OES_blend_subtract, IRR_GL_OES_depth_texture, - IRR_GL_OES_depth24, - IRR_GL_OES_depth32, IRR_GL_OES_element_index_uint, - IRR_GL_OES_framebuffer_object, IRR_GL_OES_packed_depth_stencil, - IRR_GL_OES_point_size_array, - IRR_GL_OES_point_sprite, - IRR_GL_OES_read_format, - IRR_GL_OES_stencil_wrap, IRR_GL_OES_texture_float, IRR_GL_OES_texture_half_float, - IRR_GL_OES_texture_mirrored_repeat, - IRR_GL_OES_texture_npot, IRR_OGLES_Feature_Count }; COGLESCoreExtensionHandler() : - Version(0), MaxAnisotropy(1), MaxIndices(0xffff), + MaxAnisotropy(1), MaxIndices(0xffff), MaxTextureSize(1), MaxTextureLODBias(0.f), StencilBuffer(false) { for (u32 i = 0; i < IRR_OGLES_Feature_Count; ++i) @@ -81,99 +63,27 @@ public: os::Printer::log(getFeatureString(i), FeatureAvailable[i] ? " true" : " false"); } - bool queryGLESFeature(EOGLESFeatures feature) const - { - return FeatureAvailable[feature]; - } - protected: const char *getFeatureString(size_t index) const { // One for each EOGLESFeatures static const char *const OGLESFeatureStrings[IRR_OGLES_Feature_Count] = { - "GL_APPLE_texture_2D_limited_npot", "GL_APPLE_texture_format_BGRA8888", "GL_EXT_blend_minmax", - "GL_EXT_read_format_bgra", - "GL_EXT_texture_filter_anisotropic", "GL_EXT_texture_format_BGRA8888", - "GL_EXT_texture_lod_bias", "GL_EXT_texture_rg", - "GL_IMG_read_format", - "GL_IMG_texture_format_BGRA8888", - "GL_IMG_user_clip_plane", - "GL_OES_blend_func_separate", - "GL_OES_blend_subtract", "GL_OES_depth_texture", - "GL_OES_depth24", - "GL_OES_depth32", "GL_OES_element_index_uint", - "GL_OES_framebuffer_object", "GL_OES_packed_depth_stencil", - "GL_OES_point_size_array", - "GL_OES_point_sprite", - "GL_OES_read_format", - "GL_OES_stencil_wrap", "GL_OES_texture_float", "GL_OES_texture_half_float", - "GL_OES_texture_mirrored_repeat", - "GL_OES_texture_npot", }; return OGLESFeatureStrings[index]; } - void getGLVersion() - { - Version = 0; - s32 multiplier = 100; - - core::stringc version(glGetString(GL_VERSION)); - - for (u32 i = 0; i < version.size(); ++i) { - if (version[i] >= '0' && version[i] <= '9') { - if (multiplier > 1) { - Version += static_cast(core::floor32(atof(&(version[i]))) * multiplier); - multiplier /= 10; - } else { - break; - } - } - } - } - - void getGLExtensions() - { - core::stringc extensions = glGetString(GL_EXTENSIONS); - os::Printer::log(extensions.c_str()); - - const u32 size = extensions.size() + 1; - c8 *str = new c8[size]; - strncpy(str, extensions.c_str(), extensions.size()); - str[extensions.size()] = ' '; - c8 *p = str; - - for (u32 i = 0; i < size; ++i) { - if (str[i] == ' ') { - str[i] = 0; - if (*p) - for (size_t j = 0; j < IRR_OGLES_Feature_Count; ++j) { - if (!strcmp(getFeatureString(j), p)) { - FeatureAvailable[j] = true; - break; - } - } - - p = p + strlen(p) + 1; - } - } - - delete[] str; - } - COpenGLCoreFeature Feature; - u16 Version; u8 MaxAnisotropy; u32 MaxIndices; u32 MaxTextureSize; diff --git a/irr/src/COpenGLCoreTexture.h b/irr/src/COpenGLCoreTexture.h index 95cac4c22..86ed4f73a 100644 --- a/irr/src/COpenGLCoreTexture.h +++ b/irr/src/COpenGLCoreTexture.h @@ -297,6 +297,7 @@ public: delete[] tmpBuffer; } #elif defined(IRR_COMPILE_GLES2_COMMON) + // TODO: revive this code COpenGLCoreTexture *tmpTexture = new COpenGLCoreTexture("OGL_CORE_LOCK_TEXTURE", Size, ETT_2D, ColorFormat, Driver); GLuint tmpFBO = 0; From cce4fe5a3fb574de20303b227ba4bedba5a57b7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Sat, 9 Nov 2024 17:57:37 +0100 Subject: [PATCH 004/136] Fix wrongly documented glTF frame number restriction The frame numbers can very well be floats since 06907aa --- doc/lua_api.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index 6db358c85..864b4539b 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -312,9 +312,7 @@ due to their space savings. This means that many glTF features are not supported *yet*, including: * Animations - * Only a single animation is supported, - use frame ranges within this animation. - * Only integer frames are supported. + * Only a single animation is supported, use frame ranges within this animation. * Cameras * Materials * Only base color textures are supported From 77e78193a00c2591a1dcb01eef7a69e3bfa1549b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Sat, 9 Nov 2024 18:13:36 +0100 Subject: [PATCH 005/136] Fix `set_bone_override` documentation (#15353) --- doc/lua_api.md | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index 864b4539b..e27964fc5 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -8244,7 +8244,13 @@ child will follow movement and rotation of that bone. object. * `set_detach()`: Detaches object. No-op if object was not attached. * `set_bone_position([bone, position, rotation])` - * Shorthand for `set_bone_override(bone, {position = position, rotation = rotation:apply(math.rad)})` using absolute values. + * Sets absolute bone overrides, e.g. it is equivalent to + ```lua + obj:set_bone_override(bone, { + position = {vec = position, absolute = true}, + rotation = {vec = rotation:apply(math.rad), absolute = true} + }) + ``` * **Note:** Rotation is in degrees, not radians. * **Deprecated:** Use `set_bone_override` instead. * `get_bone_position(bone)`: returns the previously set position and rotation of the bone @@ -8254,15 +8260,18 @@ child will follow movement and rotation of that bone. * `set_bone_override(bone, override)` * `bone`: string * `override`: `{ position = property, rotation = property, scale = property }` or `nil` - * `property`: `{ vec = vector, interpolation = 0, absolute = false}` or `nil`; - * `vec` is in the same coordinate system as the model, and in degrees for rotation - * `property = nil` is equivalent to no override on that property - * `absolute`: If set to `false`, the override will be relative to the animated property: - * Transposition in the case of `position`; - * Composition in the case of `rotation`; - * Multiplication in the case of `scale` - * `interpolation`: Old and new values are interpolated over this timeframe (in seconds) * `override = nil` (including omission) is shorthand for `override = {}` which clears the override + * Each `property` is a table of the form + `{ vec = vector, interpolation = 0, absolute = false }` or `nil` + * `vec` is in the same coordinate system as the model, and in radians for rotation. + It defaults to `vector.zero()` for translation and rotation and `vector.new(1, 1, 1)` for scale. + * `interpolation`: The old and new overrides are interpolated over this timeframe (in seconds). + * `absolute`: If set to `false` (which is the default), + the override will be relative to the animated property: + * Translation in the case of `position`; + * Composition in the case of `rotation`; + * Per-axis multiplication in the case of `scale` + * `property = nil` is equivalent to no override on that property * **Note:** Unlike `set_bone_position`, the rotation is in radians, not degrees. * Compatibility note: Clients prior to 5.9.0 only support absolute position and rotation. All values are treated as absolute and are set immediately (no interpolation). From 0391d91e5db3b3d0108b9851f09b4a556a57f59c Mon Sep 17 00:00:00 2001 From: Lars Mueller Date: Sat, 9 Nov 2024 17:25:56 +0100 Subject: [PATCH 006/136] Improve error messages for failed mesh loading --- irr/src/CGLTFMeshFileLoader.cpp | 2 +- irr/src/CSceneManager.cpp | 21 +++++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/irr/src/CGLTFMeshFileLoader.cpp b/irr/src/CGLTFMeshFileLoader.cpp index e727b0410..fe67228a7 100644 --- a/irr/src/CGLTFMeshFileLoader.cpp +++ b/irr/src/CGLTFMeshFileLoader.cpp @@ -669,7 +669,7 @@ void SelfType::MeshExtractor::loadAnimation(const std::size_t animIdx) const auto &sampler = anim.samplers.at(channel.sampler); if (sampler.interpolation != tiniergltf::AnimationSampler::Interpolation::LINEAR) - throw std::runtime_error("unsupported interpolation"); + throw std::runtime_error("unsupported interpolation, only linear interpolation is supported"); const auto inputAccessor = Accessor::make(m_gltf_model, sampler.input); const auto n_frames = inputAccessor.getCount(); diff --git a/irr/src/CSceneManager.cpp b/irr/src/CSceneManager.cpp index c75a28a48..d75abc284 100644 --- a/irr/src/CSceneManager.cpp +++ b/irr/src/CSceneManager.cpp @@ -140,28 +140,29 @@ IAnimatedMesh *CSceneManager::getMesh(io::IReadFile *file) // load and create a mesh which we know already isn't in the cache and put it in there IAnimatedMesh *CSceneManager::getUncachedMesh(io::IReadFile *file, const io::path &filename, const io::path &cachename) { - IAnimatedMesh *msh = 0; - // iterate the list in reverse order so user-added loaders can override the built-in ones + + bool unsupported = true; for (auto it = MeshLoaderList.rbegin(); it != MeshLoaderList.rend(); it++) { if ((*it)->isALoadableFileExtension(filename)) { + unsupported = false; // reset file to avoid side effects of previous calls to createMesh file->seek(0); - msh = (*it)->createMesh(file); + IAnimatedMesh *msh = (*it)->createMesh(file); if (msh) { MeshCache->addMesh(cachename, msh); msh->drop(); - break; + os::Printer::log("Loaded mesh", filename, ELL_DEBUG); + return msh; } } } - if (!msh) - os::Printer::log("Could not load mesh, file format seems to be unsupported", filename, ELL_ERROR); - else - os::Printer::log("Loaded mesh", filename, ELL_DEBUG); - - return msh; + os::Printer::log(unsupported + ? "Could not load mesh, file format seems to be unsupported" + : "Attempt to load mesh failed", + filename, ELL_ERROR); + return nullptr; } //! returns the video driver From 4bb9c8c61b36b16720ead745d920d4a6ea5afe0e Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Sun, 10 Nov 2024 13:20:30 +0100 Subject: [PATCH 007/136] Revert "Fix collisions with long dtime, in particular with bouncing" (#15400) This reverts commit cb6c8eb2f013edfe127ce18f760c432aee5aba01. --- src/collision.cpp | 257 +++++++++++++++++++++------------------------- 1 file changed, 119 insertions(+), 138 deletions(-) diff --git a/src/collision.cpp b/src/collision.cpp index 6bad618d8..dcb318b0f 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -70,14 +70,6 @@ inline v3f truncate(const v3f vec, const f32 factor) ); } -inline v3f rangelimv(const v3f vec, const f32 low, const f32 high) -{ - return v3f( - rangelim(vec.X, low, high), - rangelim(vec.Y, low, high), - rangelim(vec.Z, low, high) - ); -} } // Helper function: @@ -341,10 +333,6 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, collisionMoveResult result; - // Assume no collisions when no velocity and no acceleration - if (*speed_f == v3f() && accel_f == v3f()) - return result; - /* Calculate new velocity */ @@ -359,19 +347,30 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, time_notification_done = false; } - // Average speed - v3f aspeed_f = *speed_f + accel_f * 0.5f * dtime; - // Limit speed for avoiding hangs - aspeed_f = truncate(rangelimv(aspeed_f, -5000.0f, 5000.0f), 10000.0f); + v3f dpos_f = (*speed_f + accel_f * 0.5f * dtime) * dtime; + v3f newpos_f = *pos_f + dpos_f; + *speed_f += accel_f * dtime; - // Collect node boxes in movement range + // If the object is static, there are no collisions + if (dpos_f == v3f()) + return result; + + // Limit speed for avoiding hangs + speed_f->Y = rangelim(speed_f->Y, -5000, 5000); + speed_f->X = rangelim(speed_f->X, -5000, 5000); + speed_f->Z = rangelim(speed_f->Z, -5000, 5000); + + *speed_f = truncate(*speed_f, 10000.0f); + + /* + Collect node boxes in movement range + */ // cached allocation thread_local std::vector cinfo; cinfo.clear(); + { - // Movement if no collisions - v3f newpos_f = *pos_f + aspeed_f * dtime; v3f minpos_f( MYMIN(pos_f->X, newpos_f.X), MYMIN(pos_f->Y, newpos_f.Y) + 0.01f * BS, // bias rounding, player often at +/-n.5 @@ -397,16 +396,26 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, } } - // Collect object boxes in movement range + /* + Collect object boxes in movement range + */ if (collide_with_objects) { - add_object_boxes(env, box_0, dtime, *pos_f, aspeed_f, self, cinfo); - } + add_object_boxes(env, box_0, dtime, *pos_f, *speed_f, self, cinfo); + } + + /* + Collision detection + */ - // Collision detection f32 d = 0.0f; - for (int loopcount = 0;; loopcount++) { + + int loopcount = 0; + + while(dtime > BS * 1e-10f) { + // Avoid infinite loop + loopcount++; if (loopcount >= 100) { - warningstream << "collisionMoveSimple: Loop count exceeded, aborting to avoid infinite loop" << std::endl; + warningstream << "collisionMoveSimple: Loop count exceeded, aborting to avoid infiniite loop" << std::endl; break; } @@ -418,7 +427,9 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, f32 nearest_dtime = dtime; int nearest_boxindex = -1; - // Go through every nodebox, find nearest collision + /* + Go through every nodebox, find nearest collision + */ for (u32 boxindex = 0; boxindex < cinfo.size(); boxindex++) { const NearbyCollisionInfo &box_info = cinfo[boxindex]; // Ignore if already stepped up this nodebox. @@ -428,7 +439,8 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, // Find nearest collision of the two boxes (raytracing-like) f32 dtime_tmp = nearest_dtime; CollisionAxis collided = axisAlignedCollision(box_info.box, - movingbox, aspeed_f, &dtime_tmp); + movingbox, *speed_f, &dtime_tmp); + if (collided == -1 || dtime_tmp >= nearest_dtime) continue; @@ -439,127 +451,96 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, if (nearest_collided == COLLISION_AXIS_NONE) { // No collision with any collision box. - *pos_f += truncate(aspeed_f * dtime, 100.0f); - // Final speed: - *speed_f += accel_f * dtime; - // Limit speed for avoiding hangs - *speed_f = truncate(rangelimv(*speed_f, -5000.0f, 5000.0f), 10000.0f); - break; - } - // Otherwise, a collision occurred. - NearbyCollisionInfo &nearest_info = cinfo[nearest_boxindex]; - const aabb3f& cbox = nearest_info.box; + *pos_f += truncate(*speed_f * dtime, 100.0f); + dtime = 0; // Set to 0 to avoid "infinite" loop due to small FP numbers + } else { + // Otherwise, a collision occurred. + NearbyCollisionInfo &nearest_info = cinfo[nearest_boxindex]; + const aabb3f& cbox = nearest_info.box; - //movingbox except moved to the horizontal position it would be after step up - bool step_up = false; - if (nearest_collided != COLLISION_AXIS_Y) { + //movingbox except moved to the horizontal position it would be after step up aabb3f stepbox = movingbox; - // Look slightly ahead for checking the height when stepping - // to ensure we also check above the node we collided with - // otherwise, might allow glitches such as a stack of stairs - float extra_dtime = nearest_dtime + 0.1f * fabsf(dtime - nearest_dtime); - stepbox.MinEdge.X += aspeed_f.X * extra_dtime; - stepbox.MinEdge.Z += aspeed_f.Z * extra_dtime; - stepbox.MaxEdge.X += aspeed_f.X * extra_dtime; - stepbox.MaxEdge.Z += aspeed_f.Z * extra_dtime; + stepbox.MinEdge.X += speed_f->X * dtime; + stepbox.MinEdge.Z += speed_f->Z * dtime; + stepbox.MaxEdge.X += speed_f->X * dtime; + stepbox.MaxEdge.Z += speed_f->Z * dtime; // Check for stairs. - step_up = (movingbox.MinEdge.Y < cbox.MaxEdge.Y) && - (movingbox.MinEdge.Y + stepheight > cbox.MaxEdge.Y) && - (!wouldCollideWithCeiling(cinfo, stepbox, - cbox.MaxEdge.Y - movingbox.MinEdge.Y, - d)); - } + bool step_up = (nearest_collided != COLLISION_AXIS_Y) && // must not be Y direction + (movingbox.MinEdge.Y < cbox.MaxEdge.Y) && + (movingbox.MinEdge.Y + stepheight > cbox.MaxEdge.Y) && + (!wouldCollideWithCeiling(cinfo, stepbox, + cbox.MaxEdge.Y - movingbox.MinEdge.Y, + d)); - // Get bounce multiplier - float bounce = -(float)nearest_info.bouncy / 100.0f; + // Get bounce multiplier + float bounce = -(float)nearest_info.bouncy / 100.0f; - // Move to the point of collision and reduce dtime by nearest_dtime - if (nearest_dtime < 0) { - // Handle negative nearest_dtime - // This largely means an "instant" collision, e.g., with the floor. - // We use aspeed and nearest_dtime to be consistent with above and resolve this collision - if (!step_up) { - if (nearest_collided == COLLISION_AXIS_X) - pos_f->X += aspeed_f.X * nearest_dtime; - if (nearest_collided == COLLISION_AXIS_Y) - pos_f->Y += aspeed_f.Y * nearest_dtime; - if (nearest_collided == COLLISION_AXIS_Z) - pos_f->Z += aspeed_f.Z * nearest_dtime; - } - } else if (nearest_dtime > 0) { - // updated average speed for the sub-interval up to nearest_dtime - aspeed_f = *speed_f + accel_f * 0.5f * nearest_dtime; - *pos_f += truncate(aspeed_f * nearest_dtime, 100.0f); - // Speed at (approximated) collision: - *speed_f += accel_f * nearest_dtime; - // Limit speed for avoiding hangs - *speed_f = truncate(rangelimv(*speed_f, -5000.0f, 5000.0f), 10000.0f); - dtime -= nearest_dtime; - } - - bool is_collision = true; - if (nearest_info.is_unloaded) - is_collision = false; - - CollisionInfo info; - if (nearest_info.isObject()) - info.type = COLLISION_OBJECT; - else - info.type = COLLISION_NODE; - - info.node_p = nearest_info.position; - info.object = nearest_info.obj; - info.new_pos = *pos_f; - info.old_speed = *speed_f; - info.plane = nearest_collided; - - // Set the speed component that caused the collision to zero - if (step_up) { - // Special case: Handle stairs - nearest_info.is_step_up = true; - is_collision = false; - } else if (nearest_collided == COLLISION_AXIS_X) { - if (bounce < -1e-4 && fabsf(speed_f->X) > BS * 3) { - speed_f->X *= bounce; + // Move to the point of collision and reduce dtime by nearest_dtime + if (nearest_dtime < 0) { + // Handle negative nearest_dtime + if (!step_up) { + if (nearest_collided == COLLISION_AXIS_X) + pos_f->X += speed_f->X * nearest_dtime; + if (nearest_collided == COLLISION_AXIS_Y) + pos_f->Y += speed_f->Y * nearest_dtime; + if (nearest_collided == COLLISION_AXIS_Z) + pos_f->Z += speed_f->Z * nearest_dtime; + } } else { - speed_f->X = 0; - accel_f.X = 0; + *pos_f += truncate(*speed_f * nearest_dtime, 100.0f); + dtime -= nearest_dtime; } - result.collides = true; - } else if (nearest_collided == COLLISION_AXIS_Y) { - if(bounce < -1e-4 && fabsf(speed_f->Y) > BS * 3) { - speed_f->Y *= bounce; - } else { - speed_f->Y = 0; - accel_f.Y = 0; + + bool is_collision = true; + if (nearest_info.is_unloaded) + is_collision = false; + + CollisionInfo info; + if (nearest_info.isObject()) + info.type = COLLISION_OBJECT; + else + info.type = COLLISION_NODE; + + info.node_p = nearest_info.position; + info.object = nearest_info.obj; + info.new_pos = *pos_f; + info.old_speed = *speed_f; + info.plane = nearest_collided; + + // Set the speed component that caused the collision to zero + if (step_up) { + // Special case: Handle stairs + nearest_info.is_step_up = true; + is_collision = false; + } else if (nearest_collided == COLLISION_AXIS_X) { + if (fabs(speed_f->X) > BS * 3) + speed_f->X *= bounce; + else + speed_f->X = 0; + result.collides = true; + } else if (nearest_collided == COLLISION_AXIS_Y) { + if(fabs(speed_f->Y) > BS * 3) + speed_f->Y *= bounce; + else + speed_f->Y = 0; + result.collides = true; + } else if (nearest_collided == COLLISION_AXIS_Z) { + if (fabs(speed_f->Z) > BS * 3) + speed_f->Z *= bounce; + else + speed_f->Z = 0; + result.collides = true; } - result.collides = true; - } else if (nearest_collided == COLLISION_AXIS_Z) { - if (bounce < -1e-4 && fabsf(speed_f->Z) > BS * 3) { - speed_f->Z *= bounce; - } else { - speed_f->Z = 0; - accel_f.Z = 0; + + info.new_speed = *speed_f; + if (info.new_speed.getDistanceFrom(info.old_speed) < 0.1f * BS) + is_collision = false; + + if (is_collision) { + info.axis = nearest_collided; + result.collisions.push_back(std::move(info)); } - result.collides = true; } - - info.new_speed = *speed_f; - if (info.new_speed.getDistanceFrom(info.old_speed) < 0.1f * BS) - is_collision = false; - - if (is_collision) { - info.axis = nearest_collided; - result.collisions.push_back(info); - } - - if (dtime < BS * 1e-10f) - break; - - // Speed for finding the next collision - aspeed_f = *speed_f + accel_f * 0.5f * dtime; - // Limit speed for avoiding hangs - aspeed_f = truncate(rangelimv(aspeed_f, -5000.0f, 5000.0f), 10000.0f); } /* From 122b2d70d94bdd070bcb840e89d3b936f376f5ac Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 9 Nov 2024 12:12:01 +0100 Subject: [PATCH 008/136] Re-fix CAO mesh lighting with shaders disabled previously: 65af606729f7e3c162bf0b77a02570697f784c66 --- src/client/content_cao.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 5a8e1222f..16ceda4ec 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -741,7 +741,8 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) }); } else if (m_prop.visual == "mesh") { grabMatrixNode(); - scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true); + // can't cache mesh if shaders disabled, since we modify vertices + scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, m_enable_shaders); if (mesh) { if (!checkMeshNormals(mesh)) { infostream << "GenericCAO: recalculating normals for mesh " From 7557a287e53a796e61c2287fda9c72a5ac1f32c6 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 9 Nov 2024 12:33:47 +0100 Subject: [PATCH 009/136] Update credits for 5.10.0 --- builtin/mainmenu/credits.json | 32 +++++++++++++++----------------- util/gather_git_credits.py | 2 +- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/builtin/mainmenu/credits.json b/builtin/mainmenu/credits.json index 1e35cc6b3..8a946893c 100644 --- a/builtin/mainmenu/credits.json +++ b/builtin/mainmenu/credits.json @@ -13,7 +13,9 @@ "Desour/DS", "srifqi", "Gregor Parzefall (grorp)", - "Lars Müller (luatic)" + "Lars Müller (luatic)", + "cx384", + "sfence" ], "previous_core_developers": [ "BlockMen", @@ -44,30 +46,25 @@ ], "#": "For updating active/previous contributors, see the script in ./util/gather_git_credits.py", "contributors": [ - "cx384", - "numzero", - "AFCMS", - "sfence", - "Wuzzy", - "ROllerozxa", "JosiahWI", - "OgelGames", - "David Heidelberg", "1F616EMO", - "HybridDog", - "Bradley Pierce (Thresher)", - "savilli", - "Stvk imension", "y5nw", + "Erich Schubert", + "numzero", + "red-001 ", + "David Heidelberg", + "Wuzzy", + "paradust7", + "HybridDog", + "Zemtzov7", + "kromka-chleba", + "AFCMS", "chmodsayshello", - "jordan4ibanez", - "superfloh247" + "OgelGames" ], "previous_contributors": [ "Ælla Chiana Moskopp (erle) [Logo]", - "red-001 ", "Giuseppe Bilotta", - "HybridDog", "ClobberXD", "Dániel Juhász (juhdanad) ", "MirceaKitsune ", @@ -75,6 +72,7 @@ "MoNTE48", "Constantin Wenger (SpeedProg)", "Ciaran Gultnieks (CiaranG)", + "ROllerozxa", "Paul Ouellette (pauloue)", "stujones11", "Rogier ", diff --git a/util/gather_git_credits.py b/util/gather_git_credits.py index cb0f42dde..d531f81cb 100755 --- a/util/gather_git_credits.py +++ b/util/gather_git_credits.py @@ -6,7 +6,7 @@ from collections import defaultdict codefiles = r"(\.[ch](pp)?|\.lua|\.md|\.cmake|\.java|\.gradle|Makefile|CMakeLists\.txt)$" # two minor versions back, for "Active Contributors" -REVS_ACTIVE = "5.7.0..HEAD" +REVS_ACTIVE = "5.8.0..HEAD" # all time, for "Previous Contributors" REVS_PREVIOUS = "HEAD" From 8b27340b2eb30cd4efdbf50803af8b03170b22bd Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 10 Nov 2024 13:11:02 +0100 Subject: [PATCH 010/136] Work around Intel driver bug on Win 8.1 and older --- irr/src/COpenGLSLMaterialRenderer.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/irr/src/COpenGLSLMaterialRenderer.cpp b/irr/src/COpenGLSLMaterialRenderer.cpp index 556405d7b..27393adeb 100644 --- a/irr/src/COpenGLSLMaterialRenderer.cpp +++ b/irr/src/COpenGLSLMaterialRenderer.cpp @@ -401,8 +401,10 @@ bool COpenGLSLMaterialRenderer::linkProgram() #endif if (maxlen == 0) { - os::Printer::log("GLSL (> 2.x): failed to retrieve uniform information", ELL_ERROR); - return false; + // Intel driver bug that seems to primarily happen on Win 8.1 or older: + // There are >0 uniforms yet the driver reports a max name length of 0. + os::Printer::log("GLSL (> 2.x): failed to retrieve uniform information", ELL_WARNING); + maxlen = 256; // hope that this is enough } // seems that some implementations use an extra null terminator @@ -471,8 +473,10 @@ bool COpenGLSLMaterialRenderer::linkProgram() #endif if (maxlen == 0) { - os::Printer::log("GLSL: failed to retrieve uniform information", ELL_ERROR); - return false; + // Intel driver bug that seems to primarily happen on Win 8.1 or older: + // There are >0 uniforms yet the driver reports a max name length of 0. + os::Printer::log("GLSL: failed to retrieve uniform information", ELL_WARNING); + maxlen = 256; // hope that this is enough } // seems that some implementations use an extra null terminator From 2424c6409906a838869e619f6d2a7cb5f25b3954 Mon Sep 17 00:00:00 2001 From: grorp Date: Fri, 1 Nov 2024 14:00:28 +0000 Subject: [PATCH 011/136] Translated using Weblate (German) Currently translated at 99.7% (1380 of 1383 strings) --- po/de/luanti.po | 178 ++++++++++++++++++++++-------------------------- 1 file changed, 81 insertions(+), 97 deletions(-) diff --git a/po/de/luanti.po b/po/de/luanti.po index fab6cd4f9..fc68a06f3 100644 --- a/po/de/luanti.po +++ b/po/de/luanti.po @@ -3,8 +3,8 @@ msgstr "" "Project-Id-Version: German (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-07-12 14:09+0000\n" -"Last-Translator: Wuzzy \n" +"PO-Revision-Date: 2024-11-01 15:20+0000\n" +"Last-Translator: grorp \n" "Language-Team: German \n" "Language: de\n" @@ -12,7 +12,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.7-dev\n" +"X-Generator: Weblate 5.8.2-dev\n" #: builtin/client/chatcommands.lua msgid "Clear the out chat queue" @@ -159,7 +159,7 @@ msgstr "$1 laden herunter…" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "All" -msgstr "" +msgstr "Alle" #: builtin/mainmenu/content/dlg_contentdb.lua #: builtin/mainmenu/content/dlg_package.lua @@ -168,10 +168,8 @@ msgid "Back" msgstr "Zurück" #: builtin/mainmenu/content/dlg_contentdb.lua -#, fuzzy msgid "ContentDB is not available when Luanti was compiled without cURL" -msgstr "" -"ContentDB ist nicht verfügbar, wenn Minetest ohne cURL kompiliert wurde" +msgstr "ContentDB ist nicht verfügbar, wenn Luanti ohne cURL kompiliert wurde" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Downloading..." @@ -215,7 +213,6 @@ msgid "Queued" msgstr "Eingereiht" #: builtin/mainmenu/content/dlg_contentdb.lua -#, fuzzy msgid "Texture Packs" msgstr "Texturenpakete" @@ -269,9 +266,8 @@ msgid "Dependencies:" msgstr "Abhängigkeiten:" #: builtin/mainmenu/content/dlg_install.lua -#, fuzzy msgid "Error getting dependencies for package $1" -msgstr "Fehler beim Holen der Abhängigkeiten für Paket" +msgstr "Fehler beim Laden der Abhängigkeiten für Paket $1" #: builtin/mainmenu/content/dlg_install.lua msgid "Install" @@ -307,44 +303,40 @@ msgid "Overwrite" msgstr "Überschreiben" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "ContentDB page" -msgstr "ContentDB-URL" +msgstr "ContentDB-Seite" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Description" -msgstr "Serverbeschreibung" +msgstr "Beschreibung" #: builtin/mainmenu/content/dlg_package.lua msgid "Donate" -msgstr "" +msgstr "Spenden" #: builtin/mainmenu/content/dlg_package.lua msgid "Forum Topic" msgstr "" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Information" -msgstr "Information:" +msgstr "Informationen" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Install [$1]" -msgstr "$1 installieren" +msgstr "Installieren [$1]" #: builtin/mainmenu/content/dlg_package.lua msgid "Issue Tracker" -msgstr "" +msgstr "Issue-Tracker" #: builtin/mainmenu/content/dlg_package.lua msgid "Source" -msgstr "" +msgstr "Quellcode" #: builtin/mainmenu/content/dlg_package.lua msgid "Translate" -msgstr "" +msgstr "Übersetzen" #: builtin/mainmenu/content/dlg_package.lua builtin/mainmenu/tab_content.lua msgid "Uninstall" @@ -355,13 +347,12 @@ msgid "Update" msgstr "Updaten" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Website" -msgstr "Webseite besuchen" +msgstr "Webseite" #: builtin/mainmenu/content/dlg_package.lua msgid "by $1 — $2 downloads — +$3 / $4 / -$5" -msgstr "" +msgstr "von $1 — $2 Downloads — +$3 / $4 / -$5" #: builtin/mainmenu/content/pkgmgr.lua msgid "$1 (Enabled)" @@ -726,14 +717,13 @@ msgid "Dismiss" msgstr "Ablehnen" #: builtin/mainmenu/dlg_reinstall_mtg.lua -#, fuzzy msgid "" "For a long time, Luanti shipped with a default game called \"Minetest " "Game\". Since version 5.8.0, Luanti ships without a default game." msgstr "" -"Für eine lange Zeit wurde die Minetest-Engine mit einem Standardspiel namens " -"„Minetest Game“ ausgeliefert. Seit Minetest 5.8.0 wird Minetest ohne ein " -"Standardspiel ausgeliefert." +"Für eine lange Zeit wurde Luanti mit einem Standardspiel namens „Minetest " +"Game“ ausgeliefert. Seit Version 5.8.0 wird Luanti ohne ein Standardspiel " +"ausgeliefert." #: builtin/mainmenu/dlg_reinstall_mtg.lua msgid "" @@ -895,19 +885,16 @@ msgid "eased" msgstr "weich (eased)" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable automatic exposure as well)" -msgstr "(Das Spiel muss ebenfalls Schatten aktivieren)" +msgstr "(Das Spiel muss ebenfalls automatische Belichtung aktivieren)" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable bloom as well)" -msgstr "(Das Spiel muss ebenfalls Schatten aktivieren)" +msgstr "(Das Spiel muss ebenfalls Bloom aktivieren)" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable volumetric lighting as well)" -msgstr "(Das Spiel muss ebenfalls Schatten aktivieren)" +msgstr "(Das Spiel muss ebenfalls volumetrisches Licht aktivieren)" #: builtin/mainmenu/settings/dlg_settings.lua msgid "(Use system language)" @@ -919,7 +906,7 @@ msgstr "Barrierefreiheit" #: builtin/mainmenu/settings/dlg_settings.lua msgid "Auto" -msgstr "" +msgstr "Automatisch" #: builtin/mainmenu/settings/dlg_settings.lua src/gui/guiKeyChangeMenu.cpp #: src/gui/touchcontrols.cpp src/settings_translation_file.cpp @@ -985,18 +972,16 @@ msgid "Content: Mods" msgstr "Inhalt: Mods" #: builtin/mainmenu/settings/shader_warning_component.lua -#, fuzzy msgid "Enable" msgstr "Aktiviert" #: builtin/mainmenu/settings/shader_warning_component.lua -#, fuzzy msgid "Shaders are disabled." -msgstr "Kameraaktualisierung deaktiviert" +msgstr "Shader sind deaktiviert." #: builtin/mainmenu/settings/shader_warning_component.lua msgid "This is not a recommended configuration." -msgstr "" +msgstr "Dies ist keine empfohlene Konfiguration." #: builtin/mainmenu/settings/shadows_component.lua msgid "(The game will need to enable shadows as well)" @@ -1156,17 +1141,15 @@ msgid "Install games from ContentDB" msgstr "Spiele aus ContentDB installieren" #: builtin/mainmenu/tab_local.lua -#, fuzzy msgid "Luanti doesn't come with a game by default." -msgstr "Minetest wird standardmäßig nicht mehr mit einem Spiel ausgeliefert." +msgstr "Luanti wird standardmäßig nicht mit einem Spiel ausgeliefert." #: builtin/mainmenu/tab_local.lua -#, fuzzy msgid "" "Luanti is a game-creation platform that allows you to play many different " "games." msgstr "" -"Minetest ist eine Spielerschaffungsplattform, welche es Ihnen ermöglicht, " +"Luanti ist eine Spielerschaffungsplattform, welche es Ihnen ermöglicht, " "viele verschiedene Spiele zu spielen." #: builtin/mainmenu/tab_local.lua @@ -2272,18 +2255,16 @@ msgid "Sound Volume: %d%%" msgstr "Tonlautstärke: %d%%" #: src/gui/touchcontrols.cpp -#, fuzzy msgid "Joystick" -msgstr "Joystick-ID" +msgstr "Joystick" #: src/gui/touchcontrols.cpp msgid "Overflow menu" -msgstr "" +msgstr "Überlauf-Menü" #: src/gui/touchcontrols.cpp -#, fuzzy msgid "Toggle debug" -msgstr "Nebel an/aus" +msgstr "Debug an/aus" #: src/network/clientpackethandler.cpp msgid "" @@ -2294,15 +2275,16 @@ msgstr "" #: src/network/clientpackethandler.cpp msgid "Empty passwords are disallowed. Set a password and try again." msgstr "" +"Leere Passwörter sind nicht erlaubt. Legen Sie ein Passwort fest und " +"versuchen Sie es erneut." #: src/network/clientpackethandler.cpp msgid "Internal server error" -msgstr "" +msgstr "Interner Serverfehler" #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Invalid password" -msgstr "Altes Passwort" +msgstr "Falsches Passwort" #. ~ DO NOT TRANSLATE THIS LITERALLY! #. This is a special string which needs to contain the translation's @@ -2325,46 +2307,51 @@ msgstr "Name ist belegt. Bitte einen anderen Namen wählen" #: src/network/clientpackethandler.cpp msgid "Player name contains disallowed characters" -msgstr "" +msgstr "Spielername enthält nicht erlaubte Zeichen" #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Player name not allowed" -msgstr "Der Spielername ist zu lang." +msgstr "Spielername nicht erlaubt" #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Server shutting down" -msgstr "Herunterfahren …" +msgstr "Server fährt herunter" #: src/network/clientpackethandler.cpp msgid "" "The server has experienced an internal error. You will now be disconnected." msgstr "" +"Auf dem Server ist ein interner Fehler aufgetreten. Die Verbindung wird " +"jetzt getrennt." #: src/network/clientpackethandler.cpp msgid "The server is running in singleplayer mode. You cannot connect." msgstr "" +"Der Server läuft im Einzelspielermodus. Sie können sich nicht verbinden." #: src/network/clientpackethandler.cpp msgid "Too many users" -msgstr "" +msgstr "Zu viele Benutzer" #: src/network/clientpackethandler.cpp msgid "Unknown disconnect reason." -msgstr "" +msgstr "Unbekannter Grund für die Trennung der Verbindung." #: src/network/clientpackethandler.cpp msgid "" "Your client sent something the server didn't expect. Try reconnecting or " "updating your client." msgstr "" +"Ihr Client hat etwas gesendet, das der Server nicht erwartet hat. Versuchen " +"Sie, sich erneut zu verbinden oder Ihren Client zu aktualisieren." #: src/network/clientpackethandler.cpp msgid "" "Your client's version is not supported.\n" "Please contact the server administrator." msgstr "" +"Ihre Client-Version wird nicht unterstützt.\n" +"Bitte kontaktieren Sie den Server-Administrator." #: src/server.cpp #, c-format @@ -2674,11 +2661,11 @@ msgstr "Kantenglättungsmethode" #: src/settings_translation_file.cpp msgid "Anticheat flags" -msgstr "" +msgstr "Anticheat-Flags" #: src/settings_translation_file.cpp msgid "Anticheat movement tolerance" -msgstr "" +msgstr "Anticheat-Bewegungs-Toleranz" #: src/settings_translation_file.cpp msgid "Append item name" @@ -2832,9 +2819,8 @@ msgid "Biome noise" msgstr "Biomrauschen" #: src/settings_translation_file.cpp -#, fuzzy msgid "Block bounds HUD radius" -msgstr "Blockgrenzen" +msgstr "Radius für Blockgrenzen-HUD" #: src/settings_translation_file.cpp msgid "Block cull optimize distance" @@ -3050,7 +3036,6 @@ msgstr "" "für Details." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Comma-separated list of flags to hide in the content repository.\n" "\"nonfree\" can be used to hide packages which do not qualify as 'free " @@ -3060,13 +3045,13 @@ msgid "" "These flags are independent from Luanti versions,\n" "so see a full list at https://content.minetest.net/help/content_flags/" msgstr "" -"Kommagetrennte Liste von Flags für Dinge, die im Inhaltespeicher verborgen " +"Kommagetrennte Liste von Flags für Dinge, die im Inhalte-Browser verborgen " "werden sollten.\n" "„nonfree“ kann benutzt werden, um Pakete, die nicht als „freie Software“ " "nach\n" "der Definition der Free Software Foundation gelten, zu verbergen.\n" "Sie können auch Inhaltseinstufungen festlegen.\n" -"Diese Flags sind von Minetestversionen unabhängig,\n" +"Diese Flags sind von Luanti-Versionen unabhängig,\n" "für eine vollständige Liste gehen Sie auf:\n" "https://content.minetest.net/help/content_flags/" @@ -3276,7 +3261,6 @@ msgstr "" "aber dies verbraucht auch mehr Ressourcen." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Define the oldest clients allowed to connect.\n" "Older clients are compatible in the sense that they will not crash when " @@ -3288,17 +3272,16 @@ msgid "" "Luanti still enforces its own internal minimum, and enabling\n" "strict_protocol_version_checking will effectively override this." msgstr "" -"Hier festlegen, welches die ältesten Clients sind, die sich verbinden " -"dürfen.\n" +"Hier festlegen, welches die ältesten Clients sind, die sich verbinden dürfen." +"\n" "Ältere Clients sind kompatibel in der Hinsicht, dass sie beim Verbinden zu " "neuen\n" "Servern nicht abstürzen, aber sie könnten nicht alle neuen Funktionen, die " "Sie\n" "erwarten, unterstützen.\n" -"Das ermöglicht eine genauere Kontrolle als " -"strict_protocol_version_checking.\n" -"Minetest wird immer noch ein internes Minimum erzwingen, und die " -"Aktivierung\n" +"Das ermöglicht eine genauere Kontrolle als strict_protocol_version_checking." +"\n" +"Luanti wird immer noch ein internes Minimum erzwingen, und die Aktivierung\n" "von strict_protocol_version_checking wird dies überschreiben." #: src/settings_translation_file.cpp @@ -3439,7 +3422,6 @@ msgid "Display Density Scaling Factor" msgstr "Anzeigendichtenskalierungsfaktor" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Distance in nodes at which transparency depth sorting is enabled.\n" "Use this to limit the performance impact of transparency depth sorting.\n" @@ -3448,7 +3430,8 @@ msgstr "" "Entfernung in Nodes, bei welcher die Transparenztiefensortierung aktiviert " "ist.\n" "Dies benutzen, um die Performanzeinbußen der Transparenztiefensortierung zu " -"begrenzen" +"begrenzen.\n" +"Auf 0 setzen, um sie vollständig zu deaktivieren." #: src/settings_translation_file.cpp msgid "Domain name of server, to be displayed in the serverlist." @@ -3479,9 +3462,8 @@ msgid "Dungeon noise" msgstr "Verliesrauschen" #: src/settings_translation_file.cpp -#, fuzzy msgid "Effects" -msgstr "Grafikeffekte" +msgstr "Effekte" #: src/settings_translation_file.cpp msgid "Enable Automatic Exposure" @@ -3588,11 +3570,8 @@ msgid "Enable random user input (only used for testing)." msgstr "Schaltet zufällige Steuerung ein (nur zum Testen verwendet)." #: src/settings_translation_file.cpp -#, fuzzy msgid "Enable smooth lighting with simple ambient occlusion." -msgstr "" -"Weiches Licht mit einfacher Ambient-Occlusion aktivieren.\n" -"Für bessere Performanz oder anderes Aussehen deaktivieren." +msgstr "Weiches Licht mit einfacher Ambient-Occlusion aktivieren." #: src/settings_translation_file.cpp msgid "Enable split login/register" @@ -3615,7 +3594,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Enable updates available indicator on content tab" -msgstr "" +msgstr "Update-Indikator auf dem „Inhalt“-Tab aktivieren" #: src/settings_translation_file.cpp msgid "" @@ -3667,22 +3646,21 @@ msgid "Enables animation of inventory items." msgstr "Aktiviert die Animation von Inventargegenständen." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Enables caching of facedir rotated meshes.\n" "This is only effective with shaders disabled." msgstr "" "Aktiviert das Zwischenspeichern von 3-D-Modellen, die mittels facedir " -"rotiert werden." +"rotiert werden.\n" +"Dies hat nur einen Effekt, wenn Shader deaktiviert sind." #: src/settings_translation_file.cpp msgid "Enables debug and error-checking in the OpenGL driver." msgstr "Aktiviert Debug und Fehlerprüfungen im OpenGL-Treiber." #: src/settings_translation_file.cpp -#, fuzzy msgid "Enables smooth scrolling." -msgstr "Nachbearbeitung aktivieren" +msgstr "Weiches Scrollen aktivieren" #: src/settings_translation_file.cpp msgid "Enables the post processing pipeline." @@ -3695,6 +3673,11 @@ msgid "" "\"auto\" means that the touchscreen controls will be enabled and disabled\n" "automatically depending on the last used input method." msgstr "" +"Aktiviert die Touchscreen-Steuerung, so dass Sie das Spiel mit einem " +"Touchscreen spielen können.\n" +"„Automatisch“ bedeutet, dass die Touchscreen-Steuerung automatisch aktiviert " +"und deaktiviert wird,\n" +"basierend auf dem zuletzt verwendeten Eingabegerät." #: src/settings_translation_file.cpp msgid "" @@ -4289,6 +4272,9 @@ msgid "" "ContentDB to\n" "check for package updates when opening the mainmenu." msgstr "" +"Wenn dies aktiviert ist und Sie ContentDB-Pakete installiert haben, kann " +"Luanti beim Öffnen\n" +"des Hauptmenüs ContentDB kontaktieren, um nach Updates zu suchen." #: src/settings_translation_file.cpp msgid "" @@ -4433,13 +4419,12 @@ msgid "Instrument chat commands on registration." msgstr "Chatbefehle bei ihrer Registrierung instrumentieren." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Instrument global callback functions on registration.\n" "(anything you pass to a core.register_*() function)" msgstr "" "Globale Rückruffunktionen bei ihrer Registrierung instrumentieren\n" -"(alles, was man einer Funktion wie minetest.register_*() übergibt)." +"(alles, was man einer Funktion wie core.register_*() übergibt)." #: src/settings_translation_file.cpp msgid "" @@ -4650,7 +4635,6 @@ msgid "Leaves style" msgstr "Blätterstil" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Leaves style:\n" "- Fancy: all faces visible\n" @@ -4659,12 +4643,10 @@ msgid "" msgstr "" "Blätterstil:\n" "- Fancy: Alle Seiten sind sichtbar\n" -"- Simple: Nur äußere Seiten, falls definierte special_tiles benutzt " -"werden\n" +"- Simple: Nur äußere Seiten\n" "- Opaque: Transparenz deaktivieren" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Length of a server tick (the interval at which everything is generally " "updated),\n" @@ -4673,10 +4655,13 @@ msgid "" "This is a lower bound, i.e. server steps may not be shorter than this, but\n" "they are often longer." msgstr "" -"Länge eines Servertakts (dem Intervall, wo grundsätzlich alles aktualisiert " -"wird),\n" +"Länge eines Servertakts (dem Intervall, in dem grundsätzlich alles " +"aktualisiert wird),\n" "in Sekunden.\n" -"Wirkt sich nicht auf Sitzungen aus, die vom Clientmenü gestartet wurden." +"Wirkt sich nicht auf Sitzungen aus, die mit dem Hauptmenü gestartet wurden.\n" +"Dies ist eine Untergrenze, d.h. Server-Schritte dürfen nicht kürzer als " +"dieser Wert sein,\n" +"sind aber oft länger." #: src/settings_translation_file.cpp msgid "Length of liquid waves." @@ -4792,9 +4777,8 @@ msgid "Liquid queue purge time" msgstr "Aufräumzeit für Flüssigkeitswarteschlange" #: src/settings_translation_file.cpp -#, fuzzy msgid "Liquid reflections" -msgstr "Flüssigkeitswiderstand" +msgstr "Flüssigkeits-Reflexionen" #: src/settings_translation_file.cpp msgid "Liquid sinking" From 5891d0f5ec3b70bf2173652670e7495c549db877 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Fri, 1 Nov 2024 15:10:13 +0000 Subject: [PATCH 012/136] Translated using Weblate (German) Currently translated at 99.7% (1380 of 1383 strings) --- po/de/luanti.po | 81 +++++++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/po/de/luanti.po b/po/de/luanti.po index fc68a06f3..7fecb8b93 100644 --- a/po/de/luanti.po +++ b/po/de/luanti.po @@ -3,8 +3,8 @@ msgstr "" "Project-Id-Version: German (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-11-01 15:20+0000\n" -"Last-Translator: grorp \n" +"PO-Revision-Date: 2024-11-01 16:26+0000\n" +"Last-Translator: Wuzzy \n" "Language-Team: German \n" "Language: de\n" @@ -177,7 +177,7 @@ msgstr "Herunterladen …" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Featured" -msgstr "" +msgstr "Vorgestellt" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Games" @@ -316,7 +316,7 @@ msgstr "Spenden" #: builtin/mainmenu/content/dlg_package.lua msgid "Forum Topic" -msgstr "" +msgstr "Forumthema" #: builtin/mainmenu/content/dlg_package.lua msgid "Information" @@ -2271,6 +2271,8 @@ msgid "" "Another client is connected with this name. If your client closed " "unexpectedly, try again in a minute." msgstr "" +"Ein anderer Client ist mit diesem Namen verbunden. Falls Ihr Client " +"unerwartet geschlossen wurde, versuchen Sie es in einer Minute erneut." #: src/network/clientpackethandler.cpp msgid "Empty passwords are disallowed. Set a password and try again." @@ -2700,7 +2702,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Apply specular shading to nodes." -msgstr "" +msgstr "Specular-Shading auf Nodes anwenden." #: src/settings_translation_file.cpp msgid "Arm inertia" @@ -3660,7 +3662,7 @@ msgstr "Aktiviert Debug und Fehlerprüfungen im OpenGL-Treiber." #: src/settings_translation_file.cpp msgid "Enables smooth scrolling." -msgstr "Weiches Scrollen aktivieren" +msgstr "Weiches Scrollen aktivieren." #: src/settings_translation_file.cpp msgid "Enables the post processing pipeline." @@ -5124,6 +5126,10 @@ msgid "" "You generally don't need to change this, however busy servers may benefit " "from a higher number." msgstr "" +"Maximale Anzahl der Pakete, die jeden Server-Step im Low-Level-Netzwerkcode " +"gesendet werden.\n" +"Sie brauchen das normalerweise nicht ändern, jedoch können ausgelastete " +"Server von einer höheren Zahl profitieren." #: src/settings_translation_file.cpp msgid "Maximum number of players that can be connected simultaneously." @@ -5364,7 +5370,7 @@ msgstr "Blockhervorhebung" #: src/settings_translation_file.cpp msgid "Node specular" -msgstr "" +msgstr "Node-Specular" #: src/settings_translation_file.cpp msgid "NodeTimer interval" @@ -5421,14 +5427,13 @@ msgstr "" "darf." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Number of threads to use for mesh generation.\n" "Value of 0 (default) will let Luanti autodetect the number of available " "threads." msgstr "" "Anzahl der Threads, die für die Meshgenerierung benutzt werden.\n" -"Der Wert 0 (Standard) sorgt dafür, dass Minetest die Anzahl verfügbarer " +"Der Wert 0 (Standard) sorgt dafür, dass Luanti die Anzahl verfügbarer " "Threads automatisch ermittelt." #: src/settings_translation_file.cpp @@ -5460,18 +5465,16 @@ msgid "OpenGL debug" msgstr "OpenGL-Debug" #: src/settings_translation_file.cpp -#, fuzzy msgid "Optimize GUI for touchscreens" -msgstr "Fadenkreuz für Touchscreen benutzen" +msgstr "GUI für Touchscreens optimieren" #: src/settings_translation_file.cpp msgid "Optional override for chat weblink color." msgstr "Optionaler manueller Wert für die Farbe von Chat-Weblinks." #: src/settings_translation_file.cpp -#, fuzzy msgid "Other Effects" -msgstr "Grafikeffekte" +msgstr "Andere Effekte" #: src/settings_translation_file.cpp msgid "" @@ -5589,7 +5592,6 @@ msgid "Prometheus listener address" msgstr "Prometheus-Lauschadresse" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Prometheus listener address.\n" "If Luanti is compiled with ENABLE_PROMETHEUS option enabled,\n" @@ -5597,7 +5599,7 @@ msgid "" "Metrics can be fetched on http://127.0.0.1:30000/metrics" msgstr "" "Prometheus-Lauschadresse.\n" -"Falls Minetest mit der ENABLE_PROMETEUS-Option kompiliert wurde,\n" +"Falls Luanti mit der ENABLE_PROMETEUS-Option kompiliert wurde,\n" "wird dies den Metriklauscher für Prometheus auf dieser Adresse aktivieren.\n" "Metriken können von http://127.0.0.1:30000/metrics abgegriffen werden." @@ -5626,6 +5628,8 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Radius to use when the block bounds HUD feature is set to near blocks." msgstr "" +"Der zu verwendende Radius, wenn sich die Blockbegrenzungs-HUD-Funktion im " +"Modus „Blöcke in Nähe“ befindet." #: src/settings_translation_file.cpp msgid "Raises terrain to make valleys around the rivers." @@ -5952,11 +5956,12 @@ msgid "" "Send names of online players to the serverlist. If disabled only the player " "count is revealed." msgstr "" +"Name von Spielern, die online sind, an die Serverliste senden. Fall " +"deaktiviert, wird nur die Anzahl der Spieler offengelegt." #: src/settings_translation_file.cpp -#, fuzzy msgid "Send player names to the server list" -msgstr "Zu dieser Serverliste ankündigen." +msgstr "Spielernamen an die Serverliste senden" #: src/settings_translation_file.cpp msgid "Server" @@ -5984,6 +5989,9 @@ msgid "" "Flags are positive. Uncheck the flag to disable corresponding anticheat " "module." msgstr "" +"Server-Anticheat-Konfiguration.\n" +"Flags sind positiv. Das Kreuzchen beim jeweiligen Flag entfernen, um das " +"dazugehörige Anticheatmodul zu deaktivieren." #: src/settings_translation_file.cpp msgid "Server description" @@ -6140,6 +6148,8 @@ msgid "" "Shaders are a fundamental part of rendering and enable advanced visual " "effects." msgstr "" +"Shader sind ein fundamentaler Teil des Renderns und aktivieren erweiterte " +"visuelle Effekte." #: src/settings_translation_file.cpp msgid "Shadow filter quality" @@ -6211,6 +6221,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Simulate translucency when looking at foliage in the sunlight." msgstr "" +"Transluzenz simulieren, wenn auf Blattwerk im Sonnenlicht geblickt wird." #: src/settings_translation_file.cpp msgid "" @@ -6264,9 +6275,8 @@ msgid "Smooth lighting" msgstr "Weiches Licht" #: src/settings_translation_file.cpp -#, fuzzy msgid "Smooth scrolling" -msgstr "Weiches Licht" +msgstr "Weiches Scrollen" #: src/settings_translation_file.cpp msgid "" @@ -6294,9 +6304,8 @@ msgid "Sneaking speed, in nodes per second." msgstr "Schleichgeschwindigkeit, in Blöcken pro Sekunde." #: src/settings_translation_file.cpp -#, fuzzy msgid "Soft clouds" -msgstr "3-D-Wolken" +msgstr "Weiche Wolken" #: src/settings_translation_file.cpp msgid "Soft shadow radius" @@ -6533,7 +6542,6 @@ msgstr "" "Der Dateipfad relativ zu Ihrem Weltpfad, in dem Profile abgespeichert werden." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "The gesture for punching players/entities.\n" "This can be overridden by games and mods.\n" @@ -6553,7 +6561,7 @@ msgstr "" "sollen.\n" "\n" "* long_tap\n" -"Bekannt aus der klassischen Mineteststeuerung für mobile Endgeräte.\n" +"Bekannt aus der klassischen Luantisteuerung für mobile Endgeräte.\n" "Der Kampf ist mehr oder weniger unmöglich." #: src/settings_translation_file.cpp @@ -6620,7 +6628,6 @@ msgstr "" "konfiguriert werden." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "The rendering back-end.\n" "Note: A restart is required after changing this!\n" @@ -6629,8 +6636,7 @@ msgstr "" "Das Renderer-Backend.\n" "Anmerkung: Ein Neustart ist nach einer Änderung notwendig!\n" "Auf Desktopsystemen ist OpenGL die Standardeinstellung. Bei Android ist " -"OGLES2 die Standardeinstellung.\n" -"Shader werden von allem außer OGLES1 unterstützt." +"OGLES2 die Standardeinstellung." #: src/settings_translation_file.cpp msgid "" @@ -6760,6 +6766,8 @@ msgid "" "Tolerance of movement cheat detector.\n" "Increase the value if players experience stuttery movement." msgstr "" +"Toleranz des Bewegungs-Cheaterkenners.\n" +"Erhöhen Sie den Wert, falls Spieler bei Bewegungen ein Stottern feststellen." #: src/settings_translation_file.cpp msgid "Tooltip delay" @@ -6770,9 +6778,8 @@ msgid "Touchscreen" msgstr "Touchscreen" #: src/settings_translation_file.cpp -#, fuzzy msgid "Touchscreen controls" -msgstr "Touchscreenschwellwert" +msgstr "Touchscreensteuerung" #: src/settings_translation_file.cpp msgid "Touchscreen sensitivity" @@ -6787,9 +6794,8 @@ msgid "Tradeoffs for performance" msgstr "Kompromisse für Performanz" #: src/settings_translation_file.cpp -#, fuzzy msgid "Translucent foliage" -msgstr "Transluzente Flüssigkeiten" +msgstr "Transluzentes Blattwerk" #: src/settings_translation_file.cpp msgid "Translucent liquids" @@ -6842,14 +6848,13 @@ msgstr "" "haben." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "URL to JSON file which provides information about the newest Luanti " "release.\n" "If this is empty the engine will never check for updates." msgstr "" -"URL zu einer JSON-Datei, welche Informationen über das neueste Minetest-" -"Release enthält\n" +"URL zu einer JSON-Datei, welche Informationen über das neueste Luanti-" +"Release enthält.\n" "Wenn dies leer ist, wird die Engine nie nach Updates suchen." #: src/settings_translation_file.cpp @@ -6952,7 +6957,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Use smooth cloud shading." -msgstr "" +msgstr "Weiches Wolken-Shading benutzen." #: src/settings_translation_file.cpp msgid "" @@ -7162,13 +7167,16 @@ msgstr "Weblinkfarbe" #: src/settings_translation_file.cpp msgid "When enabled, liquid reflections are simulated." -msgstr "" +msgstr "Falls aktiviert, werden Flüssigkeitsreflextionen simuliert." #: src/settings_translation_file.cpp msgid "" "When enabled, the GUI is optimized to be more usable on touchscreens.\n" "Whether this is enabled by default depends on your hardware form-factor." msgstr "" +"Falls aktiviert, wird die GUI optimiert, damit sie für Touchscreens " +"benutzbarer wird.\n" +"Die Standardeinstellung hängt von ihrem Hardware-Formfaktor ab." #: src/settings_translation_file.cpp msgid "" @@ -7290,13 +7298,12 @@ msgid "Window maximized" msgstr "Fenster maximiert" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Windows systems only: Start Luanti with the command line window in the " "background.\n" "Contains the same information as the file debug.txt (default name)." msgstr "" -"Nur für Windows-Systeme: Startet Minetest mit dem Kommandozeilenfenster im\n" +"Nur für Windows-Systeme: Startet Luanti mit dem Kommandozeilenfenster im\n" "Hintergrund. Enthält die selbe Information wie die Datei debug.txt " "(Standardname)." From e1be22a6ffde4a23a6b71fba2aa6bf2ddc898e9d Mon Sep 17 00:00:00 2001 From: BreadW Date: Fri, 1 Nov 2024 15:10:46 +0000 Subject: [PATCH 013/136] Translated using Weblate (Japanese) Currently translated at 94.5% (1308 of 1383 strings) --- po/ja/luanti.po | 365 +++++++++++++++++++++++------------------------- 1 file changed, 173 insertions(+), 192 deletions(-) diff --git a/po/ja/luanti.po b/po/ja/luanti.po index 79eebeb7c..2146c2304 100644 --- a/po/ja/luanti.po +++ b/po/ja/luanti.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: Japanese (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-08-08 13:09+0000\n" +"PO-Revision-Date: 2024-11-04 01:00+0000\n" "Last-Translator: BreadW \n" "Language-Team: Japanese \n" @@ -12,7 +12,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 5.7-dev\n" +"X-Generator: Weblate 5.8.2\n" #: builtin/client/chatcommands.lua msgid "Clear the out chat queue" @@ -159,7 +159,7 @@ msgstr "$1 ダウンロード中..." #: builtin/mainmenu/content/dlg_contentdb.lua msgid "All" -msgstr "" +msgstr "すべて" #: builtin/mainmenu/content/dlg_contentdb.lua #: builtin/mainmenu/content/dlg_package.lua @@ -168,9 +168,8 @@ msgid "Back" msgstr "戻る" #: builtin/mainmenu/content/dlg_contentdb.lua -#, fuzzy msgid "ContentDB is not available when Luanti was compiled without cURL" -msgstr "MinetestがcURLなしでコンパイルされた場合、コンテンツDBは使用できません" +msgstr "LuantiがcURLなしでコンパイルされたとき、コンテンツDBは利用できません" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Downloading..." @@ -178,7 +177,7 @@ msgstr "ダウンロード中..." #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Featured" -msgstr "" +msgstr "注目作" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Games" @@ -214,7 +213,6 @@ msgid "Queued" msgstr "待機中" #: builtin/mainmenu/content/dlg_contentdb.lua -#, fuzzy msgid "Texture Packs" msgstr "テクスチャパック" @@ -268,9 +266,8 @@ msgid "Dependencies:" msgstr "依存MOD:" #: builtin/mainmenu/content/dlg_install.lua -#, fuzzy msgid "Error getting dependencies for package $1" -msgstr "パッケージの依存関係を取得するエラー" +msgstr "パッケージ $1 の依存関係を取得するエラー" #: builtin/mainmenu/content/dlg_install.lua msgid "Install" @@ -305,44 +302,40 @@ msgid "Overwrite" msgstr "上書き" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "ContentDB page" -msgstr "コンテンツDBのURL" +msgstr "コンテンツDBページ" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Description" -msgstr "サーバーの説明" +msgstr "説明" #: builtin/mainmenu/content/dlg_package.lua msgid "Donate" -msgstr "" +msgstr "寄付" #: builtin/mainmenu/content/dlg_package.lua msgid "Forum Topic" -msgstr "" +msgstr "フォーラムトピック" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Information" -msgstr "情報:" +msgstr "情報" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Install [$1]" -msgstr "$1 のインストール" +msgstr "入手 [$1]" #: builtin/mainmenu/content/dlg_package.lua msgid "Issue Tracker" -msgstr "" +msgstr "問題追跡" #: builtin/mainmenu/content/dlg_package.lua msgid "Source" -msgstr "" +msgstr "ソース" #: builtin/mainmenu/content/dlg_package.lua msgid "Translate" -msgstr "" +msgstr "翻訳" #: builtin/mainmenu/content/dlg_package.lua builtin/mainmenu/tab_content.lua msgid "Uninstall" @@ -353,13 +346,12 @@ msgid "Update" msgstr "更新" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Website" -msgstr "ウェブサイトを見る" +msgstr "ウェブサイト" #: builtin/mainmenu/content/dlg_package.lua msgid "by $1 — $2 downloads — +$3 / $4 / -$5" -msgstr "" +msgstr "by $1 — $2 ダウンロード — +$3 / $4 / -$5" #: builtin/mainmenu/content/pkgmgr.lua msgid "$1 (Enabled)" @@ -618,7 +610,7 @@ msgstr "Seed値" #: builtin/mainmenu/dlg_create_world.lua msgid "Smooth transition between biomes" -msgstr "バイオーム間の円滑な移行" +msgstr "バイオーム間の滑らかな移行" #: builtin/mainmenu/dlg_create_world.lua msgid "" @@ -719,13 +711,13 @@ msgid "Dismiss" msgstr "免責事項" #: builtin/mainmenu/dlg_reinstall_mtg.lua -#, fuzzy msgid "" "For a long time, Luanti shipped with a default game called \"Minetest " "Game\". Since version 5.8.0, Luanti ships without a default game." msgstr "" -"長い間、Minetestエンジンは「Minetest Game」と呼ばれる基本のゲームとともに提供" -"してきました。Minetest 5.8.0 からはゲームなしで提供します。" +"長い間、Luantiは「Minetest " +"Game」と呼ばれるデフォルトのゲームとともに提供してきました。バージョン 5.8.0 " +"以降のLuantiはデフォルトゲームなしで提供します。" #: builtin/mainmenu/dlg_reinstall_mtg.lua msgid "" @@ -885,19 +877,16 @@ msgid "eased" msgstr "緩和する" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable automatic exposure as well)" -msgstr "(ゲームは影を有効にする必要があります)" +msgstr "(ゲームも自動露出を有効にする必要があります)" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable bloom as well)" -msgstr "(ゲームは影を有効にする必要があります)" +msgstr "(ゲームもブルームを有効にする必要があります)" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable volumetric lighting as well)" -msgstr "(ゲームは影を有効にする必要があります)" +msgstr "(ゲームもボリュームライティングを有効にする必要があります)" #: builtin/mainmenu/settings/dlg_settings.lua msgid "(Use system language)" @@ -909,7 +898,7 @@ msgstr "アクセシビリティ" #: builtin/mainmenu/settings/dlg_settings.lua msgid "Auto" -msgstr "" +msgstr "自動" #: builtin/mainmenu/settings/dlg_settings.lua src/gui/guiKeyChangeMenu.cpp #: src/gui/touchcontrols.cpp src/settings_translation_file.cpp @@ -918,7 +907,7 @@ msgstr "チャット" #: builtin/mainmenu/settings/dlg_settings.lua builtin/mainmenu/tab_online.lua msgid "Clear" -msgstr "Clear" +msgstr "クリア" #: builtin/mainmenu/settings/dlg_settings.lua src/client/game.cpp #: src/settings_translation_file.cpp @@ -975,18 +964,16 @@ msgid "Content: Mods" msgstr "コンテンツ: MOD" #: builtin/mainmenu/settings/shader_warning_component.lua -#, fuzzy msgid "Enable" msgstr "有効" #: builtin/mainmenu/settings/shader_warning_component.lua -#, fuzzy msgid "Shaders are disabled." -msgstr "カメラ更新 無効" +msgstr "シェーダーは無効です。" #: builtin/mainmenu/settings/shader_warning_component.lua msgid "This is not a recommended configuration." -msgstr "" +msgstr "推奨されている設定ではありません。" #: builtin/mainmenu/settings/shadows_component.lua msgid "(The game will need to enable shadows as well)" @@ -1023,7 +1010,7 @@ msgstr "とても弱く" #: builtin/mainmenu/tab_about.lua msgid "About" -msgstr "ContentDBについて" +msgstr "私たちについて" #: builtin/mainmenu/tab_about.lua msgid "Active Contributors" @@ -1146,18 +1133,14 @@ msgid "Install games from ContentDB" msgstr "コンテンツDBからゲームをインストール" #: builtin/mainmenu/tab_local.lua -#, fuzzy msgid "Luanti doesn't come with a game by default." -msgstr "Minetest は初期状態でゲームが付属していません。" +msgstr "Luantiはデフォルトではゲームが付属していません。" #: builtin/mainmenu/tab_local.lua -#, fuzzy msgid "" "Luanti is a game-creation platform that allows you to play many different " "games." -msgstr "" -"Minetestは、さまざまなゲームで遊ぶことを可能にするゲーム制作プラットフォーム" -"です." +msgstr "Luantiは、多くの異なるゲームを遊ぶことができるゲーム制作プラットフォームです." #: builtin/mainmenu/tab_local.lua msgid "New" @@ -1963,7 +1946,7 @@ msgstr "Shiftキー" #: src/client/keycode.cpp msgid "Sleep" -msgstr "Sleep" +msgstr "スリープ" #: src/client/keycode.cpp msgid "Snapshot" @@ -2219,7 +2202,7 @@ msgstr "開く" #: src/gui/guiOpenURL.cpp msgid "Open URL?" -msgstr "URLを開く?" +msgstr "このURLを開きますか?" #: src/gui/guiOpenURL.cpp msgid "Unable to open URL" @@ -2255,37 +2238,35 @@ msgid "Sound Volume: %d%%" msgstr "音量: %d%%" #: src/gui/touchcontrols.cpp -#, fuzzy msgid "Joystick" -msgstr "ジョイスティックID" +msgstr "ジョイスティック" #: src/gui/touchcontrols.cpp msgid "Overflow menu" -msgstr "" +msgstr "オーバーフローメニュー" #: src/gui/touchcontrols.cpp -#, fuzzy msgid "Toggle debug" -msgstr "霧表示切替" +msgstr "デバッグ切替" #: src/network/clientpackethandler.cpp msgid "" "Another client is connected with this name. If your client closed " "unexpectedly, try again in a minute." -msgstr "" +msgstr "別のクライアントがこの名前で接続されています。 " +"クライアントが予期せず終了した場合はもう一度お試しください。" #: src/network/clientpackethandler.cpp msgid "Empty passwords are disallowed. Set a password and try again." -msgstr "" +msgstr "パスワードが未入力です。 パスワードを設定し、もう一度お試しください。" #: src/network/clientpackethandler.cpp msgid "Internal server error" -msgstr "" +msgstr "内部サーバーエラー" #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Invalid password" -msgstr "古いパスワード" +msgstr "無効なパスワード" #. ~ DO NOT TRANSLATE THIS LITERALLY! #. This is a special string which needs to contain the translation's @@ -2298,9 +2279,8 @@ msgstr "ja" #: src/network/clientpackethandler.cpp msgid "" "Name is not registered. To create an account on this server, click 'Register'" -msgstr "" -"名前が登録されていません。このサーバーにアカウントを作成するには「登録」をク" -"リック。" +msgstr "名前が登録されていません。このサーバーにアカウントを作成するには「登録」をク" +"リック" #: src/network/clientpackethandler.cpp msgid "Name is taken. Please choose another name" @@ -2308,46 +2288,47 @@ msgstr "名前は使われています。他の名前に変えてください" #: src/network/clientpackethandler.cpp msgid "Player name contains disallowed characters" -msgstr "" +msgstr "プレイヤー名に無効の文字が含まれている" #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Player name not allowed" -msgstr "プレイヤー名が長過ぎます。" +msgstr "プレイヤー名 不可" #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Server shutting down" -msgstr "終了中..." +msgstr "サーバのシャットダウン" #: src/network/clientpackethandler.cpp msgid "" "The server has experienced an internal error. You will now be disconnected." -msgstr "" +msgstr "サーバーで内部エラーが発生しました。 接続が切断されます。" #: src/network/clientpackethandler.cpp msgid "The server is running in singleplayer mode. You cannot connect." -msgstr "" +msgstr "サーバーはシングルプレイヤーモードで実行されています。 接続できません。" #: src/network/clientpackethandler.cpp msgid "Too many users" -msgstr "" +msgstr "多すぎるユーザー" #: src/network/clientpackethandler.cpp msgid "Unknown disconnect reason." -msgstr "" +msgstr "未知の切断理由です。" #: src/network/clientpackethandler.cpp msgid "" "Your client sent something the server didn't expect. Try reconnecting or " "updating your client." -msgstr "" +msgstr "クライアントはサーバーが予期しないものを送信しました。 " +"再接続するか、クライアントを更新してください。" #: src/network/clientpackethandler.cpp msgid "" "Your client's version is not supported.\n" "Please contact the server administrator." msgstr "" +"クライアントのバージョンはサポートされていません。\n" +"サーバーの管理者に問い合わせてください。" #: src/server.cpp #, c-format @@ -2511,7 +2492,7 @@ msgstr "サーバークラッシュ時にすべてのクライアントへ表示 #: src/settings_translation_file.cpp msgid "A message to be displayed to all clients when the server shuts down." -msgstr "サーバー終了時にすべてのクライアントへ表示するメッセージ。" +msgstr "サーバー終了時にすべてのクライアントへ表示するメッセージです。" #: src/settings_translation_file.cpp msgid "ABM interval" @@ -2551,7 +2532,7 @@ msgstr "アクティブなオブジェクトの送信範囲" #: src/settings_translation_file.cpp msgid "Adds particles when digging a node." -msgstr "ノードを掘る際にパーティクルを追加します。" +msgstr "ノード掘削時にパーティクルを追加します。" #: src/settings_translation_file.cpp msgid "Adjust the detected display density, used for scaling UI elements." @@ -2633,11 +2614,11 @@ msgstr "アンチエイリアス方式" #: src/settings_translation_file.cpp msgid "Anticheat flags" -msgstr "" +msgstr "アンチチートフラグ" #: src/settings_translation_file.cpp msgid "Anticheat movement tolerance" -msgstr "" +msgstr "アンチチート動作耐性" #: src/settings_translation_file.cpp msgid "Append item name" @@ -2675,7 +2656,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Apply specular shading to nodes." -msgstr "" +msgstr "ノードにスペキュラーシェーディングを適用します。" #: src/settings_translation_file.cpp msgid "Arm inertia" @@ -2712,7 +2693,7 @@ msgstr "" "洞窟で正しく描画されません)。\n" "max_block_send_distance より大きい値に設定すると、この最適化は\n" "無効になります。 \n" -"マップブロック(16ノード)で表記。" +"マップブロック(16ノード)で表記します。" #: src/settings_translation_file.cpp msgid "" @@ -2791,9 +2772,8 @@ msgid "Biome noise" msgstr "バイオームノイズ" #: src/settings_translation_file.cpp -#, fuzzy msgid "Block bounds HUD radius" -msgstr "ブロック境界線表示切替" +msgstr "ブロック境界 HUD 半径" #: src/settings_translation_file.cpp msgid "Block cull optimize distance" @@ -3008,7 +2988,6 @@ msgstr "" "テストのために有用です。 詳細は al_extensions.[h,cpp] を参照してください。" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Comma-separated list of flags to hide in the content repository.\n" "\"nonfree\" can be used to hide packages which do not qualify as 'free " @@ -3018,13 +2997,12 @@ msgid "" "These flags are independent from Luanti versions,\n" "so see a full list at https://content.minetest.net/help/content_flags/" msgstr "" -"コンテンツリポジトリで非表示にするフラグのカンマ区切りリスト。\n" -"「nonfree」は、フリーソフトウェア財団によって定義されている\n" -"フリーソフトウェアとして認定されていないパッケージを隠すために\n" -"使うことができます。\n" +"コンテンツリポジトリで非表示にするフラグのカンマ区切りリストです。\n" +"『nonfree』を使用すると、フリーソフトウェア財団によって定義されている\n" +"「フリーソフトウェア」として認定されていないパッケージを非表示にできます。\n" "コンテンツの評価を指定することもできます。\n" -"これらのフラグはMinetestのバージョンから独立しています、\n" -"https://content.minetest.net/help/content_flags/ にある完全なリスト参照" +"これらのフラグはLuantiのバージョンとは無関係です。完全なリストについては\n" +"https://content.minetest.net/help/content_flags/ を参照してください。" #: src/settings_translation_file.cpp msgid "" @@ -3032,7 +3010,7 @@ msgid "" "allow them to upload and download data to/from the internet." msgstr "" "HTTP APIへのアクセスが許可され、インターネットでデータをアップロード\n" -"およびダウンロードできるようにするModのコンマ区切りリスト。" +"およびダウンロードできるようにするModのカンマ区切りリストです。" #: src/settings_translation_file.cpp msgid "" @@ -3041,7 +3019,7 @@ msgid "" msgstr "" "MODのセキュリティが有効の場合でも (request_insecure_environment() \n" "を介して) 安全でない機能へのアクセスが許可されている信頼できる\n" -"MODのコンマ区切りリスト。" +"MODのカンマ区切りリストです。" #: src/settings_translation_file.cpp msgid "" @@ -3227,7 +3205,6 @@ msgstr "" "しかし、より多くのリソースを消費します。" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Define the oldest clients allowed to connect.\n" "Older clients are compatible in the sense that they will not crash when " @@ -3240,13 +3217,15 @@ msgid "" "strict_protocol_version_checking will effectively override this." msgstr "" "接続を許可する最も古いクライアントを定義します。\n" -"古いクライアントは、新しいサーバーに接続するときにクラッシュしないという意味" -"では\n" -"互換性がありますが、期待されるすべての新機能をサポートしているわけではない可" -"能性があります。\n" -"これにより、strict_protocol_version_checking よりも細かい管理ができます。\n" -"Minetest は依然として独自の内部最小値を強制しており、\n" -"strict_protocol_version_checking はこれをが効果的に上書きします。" +"古いクライアントは、" +"新しいサーバーに接続するときにクラッシュしないという意味では\n" +"互換性がありますが、期待するすべての新機能をサポートしていない可能性がありま" +"す。\n" +"これにより、strict_protocol_version_checking " +"よりきめ細かい制御が可能になります。\n" +"Luantiは独自の内部最小値を強制しますが、\n" +"strict_protocol_version_checking " +"を有効にすると、実質的にこれが上書きされます。" #: src/settings_translation_file.cpp msgid "Defines areas where trees have apples." @@ -3377,14 +3356,15 @@ msgid "Display Density Scaling Factor" msgstr "ディスプレイ密度スケーリング係数" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Distance in nodes at which transparency depth sorting is enabled.\n" "Use this to limit the performance impact of transparency depth sorting.\n" "Set to 0 to disable it entirely." msgstr "" -"透明度の深さの並べ替えが有効になっているノードの距離\n" -"これを使用して、透明度の深さの並べ替えによるパフォーマンスへの影響を制限" +"透明度の深さの並べ替えが有効になっているノードの距離です。\n" +"透明度の深さの並べ替えがパフォーマンスへの影響を制限するためにこれを使用しま" +"す。\n" +"完全に無効にするには 0 に設定します。" #: src/settings_translation_file.cpp msgid "Domain name of server, to be displayed in the serverlist." @@ -3415,9 +3395,8 @@ msgid "Dungeon noise" msgstr "ダンジョンノイズ" #: src/settings_translation_file.cpp -#, fuzzy msgid "Effects" -msgstr "グラフィック効果" +msgstr "効果" #: src/settings_translation_file.cpp msgid "Enable Automatic Exposure" @@ -3521,11 +3500,8 @@ msgid "Enable random user input (only used for testing)." msgstr "ランダムなユーザー入力を有効にします (テストにのみ使用)。" #: src/settings_translation_file.cpp -#, fuzzy msgid "Enable smooth lighting with simple ambient occlusion." -msgstr "" -"シンプルなアンビエントオクルージョンで滑らかな照明を有効にします。\n" -"速度や異なる見た目のために無効にしてください。" +msgstr "シンプルなアンビエントオクルージョンで滑らかな照明を実現にします。" #: src/settings_translation_file.cpp msgid "Enable split login/register" @@ -3546,7 +3522,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Enable updates available indicator on content tab" -msgstr "" +msgstr "コンテンツタブで利用可能な更新インジケーターを有効にする" #: src/settings_translation_file.cpp msgid "" @@ -3555,8 +3531,8 @@ msgid "" "textures)\n" "when connecting to the server." msgstr "" -"リモートメディアサーバーの使用を有効にします (サーバーによって提供\n" -"されている場合)。\n" +"リモートメディアサーバーの使用を有効にします " +"(サーバーによって提供されている場合)。\n" "リモートサーバはサーバーに接続するときにメディア (例えば、テクスチャ) を\n" "ダウンロードするための非常に高速な方法を提供します。" @@ -3595,20 +3571,20 @@ msgid "Enables animation of inventory items." msgstr "インベントリのアイテムのアニメーションを有効にします。" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Enables caching of facedir rotated meshes.\n" "This is only effective with shaders disabled." -msgstr "facedir回転メッシュのキャッシングを有効にします。" +msgstr "" +"facesir回転メッシュのキャッシュを有効にします。\n" +"これはシェーダーが無効になっている場合にのみ有効です。" #: src/settings_translation_file.cpp msgid "Enables debug and error-checking in the OpenGL driver." msgstr "OpenGL ドライバでデバッグとエラーチェックを有効にします。" #: src/settings_translation_file.cpp -#, fuzzy msgid "Enables smooth scrolling." -msgstr "後処理有効" +msgstr "滑らかなスクロールを有効にします。" #: src/settings_translation_file.cpp msgid "Enables the post processing pipeline." @@ -3621,6 +3597,10 @@ msgid "" "\"auto\" means that the touchscreen controls will be enabled and disabled\n" "automatically depending on the last used input method." msgstr "" +"タッチスクリーン制御を有効にして、タッチスクリーンでゲームをプレイできるよう" +"にします。\n" +"\"auto\" は、最後に使用した入力方法に応じて、タッチスクリーン制御が自動的に\n" +"有効または無効になることを意味します。" #: src/settings_translation_file.cpp msgid "" @@ -3956,7 +3936,7 @@ msgid "" "In Mapgen v6 the 'decorations' flag controls all decorations except trees\n" "and jungle grass, in all other mapgens this flag controls all decorations." msgstr "" -"全体的なマップ生成属性。\n" +"全体的なマップ生成属性です。\n" "マップジェネレータv6では、'decorations' フラグで木とジャングルの草を\n" "除くすべての装飾を制御しますが、他のすべてのマップジェネレータでは\n" "このフラグがすべての装飾を制御します。" @@ -4191,6 +4171,10 @@ msgid "" "ContentDB to\n" "check for package updates when opening the mainmenu." msgstr "" +"有効になっていて、コンテンツDBのパッケージがインストールされている場合、" +"Luantiは\n" +"メインメニューを開いたときにコンテンツDBに接続してパッケージの更新を確認する" +"ことがあります。" #: src/settings_translation_file.cpp msgid "" @@ -4321,13 +4305,12 @@ msgid "Instrument chat commands on registration." msgstr "チャットコマンドが登録されるとすぐに計測します。" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Instrument global callback functions on registration.\n" "(anything you pass to a core.register_*() function)" msgstr "" -"グローバルコールバック関数が登録されるとすぐに計測します。\n" -"(あなたが minetest.register_*() 関数に渡すもの)" +"登録時にグローバルコールバック関数を測定します。\n" +"(core.register_*() 関数に渡すものすべて)" #: src/settings_translation_file.cpp msgid "" @@ -4531,7 +4514,6 @@ msgid "Leaves style" msgstr "葉のスタイル" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Leaves style:\n" "- Fancy: all faces visible\n" @@ -4540,11 +4522,10 @@ msgid "" msgstr "" "葉のスタイル:\n" "- Fancy: すべての面が見える\n" -"- Simple: special_tiles が定義されている場合は外側の面のみ\n" -"- Opaque: 透明性を無効化" +"- Simple: 外側の面のみ\n" +"- Opaque: 不透明" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Length of a server tick (the interval at which everything is generally " "updated),\n" @@ -4553,8 +4534,11 @@ msgid "" "This is a lower bound, i.e. server steps may not be shorter than this, but\n" "they are often longer." msgstr "" -"サーバーが時を刻む長さ (通常、すべてが更新される間隔) を秒単位で定めます。\n" -"クライアント メニューからホストされるセッションには適用されません。" +"サーバーが時を刻む長さ(すべてが通常更新される間隔)を、\n" +"秒単位で指定します。\n" +"クライアントメニューからホストされるセッションには適用されません。\n" +"これは下限値で、サーバーのステップがこれより短くなることはありませんが、\n" +"長くなることはよくあります。" #: src/settings_translation_file.cpp msgid "Length of liquid waves." @@ -4668,9 +4652,8 @@ msgid "Liquid queue purge time" msgstr "液体キューのパージ時間" #: src/settings_translation_file.cpp -#, fuzzy msgid "Liquid reflections" -msgstr "液体の流動性" +msgstr "液体の反射" #: src/settings_translation_file.cpp msgid "Liquid sinking" @@ -4678,7 +4661,7 @@ msgstr "液体中の沈降" #: src/settings_translation_file.cpp msgid "Liquid update interval in seconds." -msgstr "液体の秒単位の更新間隔。" +msgstr "液体の秒単位の更新間隔です。" #: src/settings_translation_file.cpp msgid "Liquid update tick" @@ -4903,7 +4886,7 @@ msgstr "ブロック送信最大距離" #: src/settings_translation_file.cpp msgid "Max liquids processed per step." -msgstr "ステップあたりの液体の最大処理。" +msgstr "ステップあたりの液体の最大処理数です。" #: src/settings_translation_file.cpp msgid "Max. clearobjects extra blocks" @@ -4947,7 +4930,7 @@ msgstr "マップチャンクあたりの小さな洞窟の乱数の最大値。 msgid "" "Maximum liquid resistance. Controls deceleration when entering liquid at\n" "high speed." -msgstr "最大の液体抵抗。高速で液体に入る際の減速を制御します。" +msgstr "液体抵抗の最大値です。高速で液体に入るさいの減速を制御します。" #: src/settings_translation_file.cpp msgid "" @@ -5004,6 +4987,10 @@ msgid "" "You generally don't need to change this, however busy servers may benefit " "from a higher number." msgstr "" +"低レベルのネットワーク " +"コードで送信ステップごとに送信されるパケットの最大数です。\n" +"通常、これを変更する必要はありませんが、ビジー状態のサーバーでは、数値を大き" +"くするとメリットが得られる場合があります。" #: src/settings_translation_file.cpp msgid "Maximum number of players that can be connected simultaneously." @@ -5079,7 +5066,7 @@ msgstr "接続中のプレイヤーに表示されるその日のメッセージ #: src/settings_translation_file.cpp msgid "Method used to highlight selected object." -msgstr "選択したオブジェクトを強調表示するために使用される方法。" +msgstr "選択したオブジェクトを強調表示するために使用される方法です。" #: src/settings_translation_file.cpp msgid "Minimal level of logging to be written to chat." @@ -5199,9 +5186,9 @@ msgid "" "When running a server, clients connecting with this name are admins.\n" "When starting from the main menu, this is overridden." msgstr "" -"プレイヤーの名前。\n" -"サーバーを実行している場合、この名前で接続しているクライアントは管理者\n" -"です。\n" +"プレイヤーの名前です。\n" +"サーバーを実行している場合、この名前で接続しているクライアントは\n" +"管理者です。\n" "メインメニューから起動すると、これは上書きされます。" #: src/settings_translation_file.cpp @@ -5235,7 +5222,7 @@ msgstr "ノードをハイライト" #: src/settings_translation_file.cpp msgid "Node specular" -msgstr "" +msgstr "ノード スペキュラー" #: src/settings_translation_file.cpp msgid "NodeTimer interval" @@ -5288,15 +5275,13 @@ msgid "Number of messages a player may send per 10 seconds." msgstr "プレイヤーが10秒間に送信できるメッセージの数です。" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Number of threads to use for mesh generation.\n" "Value of 0 (default) will let Luanti autodetect the number of available " "threads." msgstr "" -"メッシュ生成に使用するスレッド数。\n" -"値 0 (既定値) を指定すると、Minetest は使用可能なスレッドの数を自動検出しま" -"す。" +"メッシュ生成に使用するスレッドの数です。\n" +"値 0 (既定値) を指定すると、Luantiは使用可能なスレッドの数を自動検出します。" #: src/settings_translation_file.cpp msgid "Occlusion Culler" @@ -5325,18 +5310,16 @@ msgid "OpenGL debug" msgstr "OpenGLのデバッグ" #: src/settings_translation_file.cpp -#, fuzzy msgid "Optimize GUI for touchscreens" -msgstr "タッチスクリーンに十字カーソルを使用する" +msgstr "タッチスクリーン用にGUIを最適化する" #: src/settings_translation_file.cpp msgid "Optional override for chat weblink color." msgstr "チャットのウェブリンクの色を上書きするオプションです。" #: src/settings_translation_file.cpp -#, fuzzy msgid "Other Effects" -msgstr "グラフィック効果" +msgstr "その他の効果" #: src/settings_translation_file.cpp msgid "" @@ -5360,7 +5343,7 @@ msgid "" "Path to shader directory. If no path is defined, default location will be " "used." msgstr "" -"シェーダーディレクトリへのパス。パスが定義されていない場合は、\n" +"シェーダーディレクトリへのパスです。パスが定義されていない場合は、\n" "既定の場所が使用されます。" #: src/settings_translation_file.cpp @@ -5448,17 +5431,15 @@ msgid "Prometheus listener address" msgstr "プロメテウスリスナーのアドレス" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Prometheus listener address.\n" "If Luanti is compiled with ENABLE_PROMETHEUS option enabled,\n" "enable metrics listener for Prometheus on that address.\n" "Metrics can be fetched on http://127.0.0.1:30000/metrics" msgstr "" -"プロメテウスリスナーのアドレス。\n" -"Minetest が ENABLE_PROMETHEUS オプションを有効にしてコンパイルされている場" -"合、\n" -"そのアドレスのプロメテウスのメトリックスリスナーを有効にします。\n" +"プロメテウスリスナーのアドレスです。\n" +"Luantiが ENABLE_PROMETHEUS オプションを有効にしてコンパイルされている場合、\n" +"そのアドレスでプロメテウスのメトリックスリスナーを有効にします。\n" "メトリックスは http://127.0.0.1:30000/metrics で取得可能" #: src/settings_translation_file.cpp @@ -5484,7 +5465,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Radius to use when the block bounds HUD feature is set to near blocks." -msgstr "" +msgstr "ブロック境界HUD機能がブロックの近くに設定されている場合に使う半径です。" #: src/settings_translation_file.cpp msgid "Raises terrain to make valleys around the rivers." @@ -5519,9 +5500,8 @@ msgid "" "Remove color codes from incoming chat messages\n" "Use this to stop players from being able to use color in their messages" msgstr "" -"チャットメッセージから色コードを取り除きます\n" -"これを使用して、プレイヤーが自分のメッセージに色を使用できない\n" -"ようにします" +"チャットメッセージから色コードを取り除く\n" +"プレイヤーが自分のメッセージに色を使用できないようにする" #: src/settings_translation_file.cpp msgid "Replaces the default main menu with a custom one." @@ -5803,12 +5783,12 @@ msgstr "" msgid "" "Send names of online players to the serverlist. If disabled only the player " "count is revealed." -msgstr "" +msgstr "オンラインプレイヤーの名前をサーバー一覧に送信します。無効にすると、プレイヤ" +"ー数のみが表示されます。" #: src/settings_translation_file.cpp -#, fuzzy msgid "Send player names to the server list" -msgstr "このサーバー一覧に告知します。" +msgstr "プレイヤー名をサーバー一覧に送信する" #: src/settings_translation_file.cpp msgid "Server" @@ -5836,6 +5816,8 @@ msgid "" "Flags are positive. Uncheck the flag to disable corresponding anticheat " "module." msgstr "" +"サーバーのアンチチート設定です。\n" +"フラグのチェックを外すと対応するアンチチートモジュールを無効にします。" #: src/settings_translation_file.cpp msgid "Server description" @@ -5987,7 +5969,7 @@ msgstr "シェーダー" msgid "" "Shaders are a fundamental part of rendering and enable advanced visual " "effects." -msgstr "" +msgstr "シェーダーはレンダリングの基本的な部分であり、高度な視覚効果を有効にします。" #: src/settings_translation_file.cpp msgid "Shadow filter quality" @@ -6056,7 +6038,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Simulate translucency when looking at foliage in the sunlight." -msgstr "" +msgstr "日光の下で葉を見るときの半透明感をシミュレートします。" #: src/settings_translation_file.cpp msgid "" @@ -6108,17 +6090,15 @@ msgid "Smooth lighting" msgstr "滑らかな照明" #: src/settings_translation_file.cpp -#, fuzzy msgid "Smooth scrolling" -msgstr "滑らかな照明" +msgstr "滑らかなスクロール" #: src/settings_translation_file.cpp msgid "" "Smooths rotation of camera when in cinematic mode, 0 to disable. Enter " "cinematic mode by using the key set in Controls." -msgstr "" -"シネマティックモードでのカメラの旋回を滑らかにし、0 で無効にします。\n" -"キー割り当てで設定されたキーを使用してシネマティックモードに切替えます。" +msgstr "シネマティックモードでのカメラの旋回を滑らかにし、0 で無効にします。キー割り" +"当てで設定されたキーを使用してシネマティックモードに切替えます。" #: src/settings_translation_file.cpp msgid "" @@ -6137,9 +6117,8 @@ msgid "Sneaking speed, in nodes per second." msgstr "スニーク時の速度、1秒あたりのノード数です。" #: src/settings_translation_file.cpp -#, fuzzy msgid "Soft clouds" -msgstr "立体な雲" +msgstr "柔らかい雲" #: src/settings_translation_file.cpp msgid "Soft shadow radius" @@ -6366,7 +6345,6 @@ msgid "" msgstr "観測記録が保存されるワールドパスに対する相対的なファイルパスです。" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "The gesture for punching players/entities.\n" "This can be overridden by games and mods.\n" @@ -6385,7 +6363,7 @@ msgstr "" "使いやすく、名前は挙げませんが他のゲームでもよく知られています。\n" "\n" "* ロングタップ\n" -"古典的な Minetest のモバイル版操作として知られています。\n" +"古典的なLuantiのモバイル版操作として知られています。\n" "戦闘はほぼ不可能です。" #: src/settings_translation_file.cpp @@ -6447,7 +6425,6 @@ msgstr "" "これは active_object_send_range_blocks と一緒に設定する必要があります。" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "The rendering back-end.\n" "Note: A restart is required after changing this!\n" @@ -6455,14 +6432,15 @@ msgid "" msgstr "" "レンダリングのバックエンドです。\n" "注:これを変更した後は再起動が必要です!\n" -"デスクトップでは OpenGL が、Android では OGLES2 が規定です。\n" -"シェーダーは OGLES1 以外のすべてでサポートされています。" +"デスクトップではOpenGLが、AndroidではOGLES2が規定です。" #: src/settings_translation_file.cpp msgid "" "The sensitivity of the joystick axes for moving the\n" "in-game view frustum around." -msgstr "ゲーム内の視錐台を動かすためのジョイスティック軸の感度。" +msgstr "" +"ゲーム内の視錐台を動かすための\n" +"ジョイスティック軸の感度です。" #: src/settings_translation_file.cpp msgid "" @@ -6471,7 +6449,7 @@ msgid "" "setting is 0.25 to 4.0 inclusive. If the value is out of range it will be\n" "set to the nearest valid value." msgstr "" -"ノードのアンビエントオクルージョンシェーディングの強度 (暗さ)。\n" +"ノードのアンビエントオクルージョンシェーディングの強度 (暗さ)です。\n" "低いほど暗く、高いほど明るくなります。設定の有効範囲は 0.25~4.0 です。\n" "値が範囲外の場合は、最も近い有効な値に設定されます。" @@ -6481,8 +6459,9 @@ msgid "" "capacity until an attempt is made to decrease its size by dumping old queue\n" "items. A value of 0 disables the functionality." msgstr "" -"古いキューアイテムを出力してサイズを減らそうとするまでに、液体キューが\n" -"処理能力を超えて拡張できる時間(秒単位)。値 0 は機能を無効にします。" +"古いキューアイテムを出力してサイズを減らそうとするまでに、\n" +"液体キューが処理能力を超えて拡張できる時間(秒単位)です。\n" +"値 0 は機能を無効にします。" #: src/settings_translation_file.cpp msgid "" @@ -6504,7 +6483,7 @@ msgstr "" msgid "" "The time in seconds it takes between repeated node placements when holding\n" "the place button." -msgstr "設置ボタンを押したままノードの設置を繰り返す秒単位の間隔。" +msgstr "設置ボタンを押したままノードの設置を繰り返す秒単位の間隔です。" #: src/settings_translation_file.cpp msgid "The type of joystick" @@ -6562,14 +6541,16 @@ msgid "" "node." msgstr "" "ラグを減らすために、プレーヤーが何かを設置しているときブロック転送は\n" -"遅くなります。\n" -"これはノードを設置または破壊した後にどれくらい遅くなるかを決定します。" +"遅くなります。ノードを設置または破壊した後にどれくらい遅くなるかを決定します" +"。" #: src/settings_translation_file.cpp msgid "" "Tolerance of movement cheat detector.\n" "Increase the value if players experience stuttery movement." msgstr "" +"チートな動きの検出許容度です。\n" +"プレイヤーの動きがカクつく場合は値を増やします。" #: src/settings_translation_file.cpp msgid "Tooltip delay" @@ -6580,9 +6561,8 @@ msgid "Touchscreen" msgstr "タッチスクリーン" #: src/settings_translation_file.cpp -#, fuzzy msgid "Touchscreen controls" -msgstr "タッチスクリーンのしきい値" +msgstr "タッチスクリーン制御" #: src/settings_translation_file.cpp msgid "Touchscreen sensitivity" @@ -6597,9 +6577,8 @@ msgid "Tradeoffs for performance" msgstr "パフォーマンスのためのトレードオフ" #: src/settings_translation_file.cpp -#, fuzzy msgid "Translucent foliage" -msgstr "半透明な液体" +msgstr "半透明な葉" #: src/settings_translation_file.cpp msgid "Translucent liquids" @@ -6648,14 +6627,13 @@ msgstr "" "パフォーマンスの問題がある場合のみ、この設定を変更する必要があります。" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "URL to JSON file which provides information about the newest Luanti " "release.\n" "If this is empty the engine will never check for updates." msgstr "" -"最新の Minetest リリースに関する情報を提供する JSON ファイルへの URL\n" -"これが空の場合、エンジンは更新をチェックしません。" +"最新のLuantiリリースに関する情報を提供するJSONファイルへの URLです。\n" +"空にするとエンジンの更新が確認されることはありません。" #: src/settings_translation_file.cpp msgid "URL to the server list displayed in the Multiplayer Tab." @@ -6748,7 +6726,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Use smooth cloud shading." -msgstr "" +msgstr "滑らかな雲を使用します。" #: src/settings_translation_file.cpp msgid "" @@ -6954,13 +6932,17 @@ msgstr "ウェブリンクの色" #: src/settings_translation_file.cpp msgid "When enabled, liquid reflections are simulated." -msgstr "" +msgstr "有効にすると、液体の反射がシミュレートされます。" #: src/settings_translation_file.cpp msgid "" "When enabled, the GUI is optimized to be more usable on touchscreens.\n" "Whether this is enabled by default depends on your hardware form-factor." msgstr "" +"有効にすると、タッチスクリーンでより使いやすくなるように GUI " +"が最適化されます。\n" +"デフォルトで有効になっているかどうかは、ハードウェアのフォームファクタに依存" +"します。" #: src/settings_translation_file.cpp msgid "" @@ -7064,7 +7046,7 @@ msgid "" "Whether to show the client debug info (has the same effect as hitting F5)." msgstr "" "クライアントのデバッグ情報を表示するかどうかの設定です\n" -"(F5を押すのと同じ効果)。" +"(F5キーを押すのと同じ効果)。" #: src/settings_translation_file.cpp msgid "Width component of the initial window size." @@ -7079,23 +7061,22 @@ msgid "Window maximized" msgstr "ウィンドウの最大化" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Windows systems only: Start Luanti with the command line window in the " "background.\n" "Contains the same information as the file debug.txt (default name)." msgstr "" -"Windowsのみ: Minetestと一緒にバックグランドでコマンドプロンプトを\n" -"起動します。\n" -"debug.txt (既定の名前) と同じ情報を含んでいます。" +"Windowsのみ: コマンドライン ウィンドウをバックグラウンドで使用して Luanti " +"を起動します。\n" +"ファイル debug.txt (デフォルト名) と同じ情報が含まれます。" #: src/settings_translation_file.cpp msgid "" "World directory (everything in the world is stored here).\n" "Not needed if starting from the main menu." msgstr "" -"ワールドを保存するディレクトリです(全てのワールドはここに保存\n" -"されます)。\n" +"ワールドを保存するディレクトリです(すべてのワールドは\n" +"ここに保存されます)。\n" "メインメニューから開始する場合必要ありません。" #: src/settings_translation_file.cpp From f25eaf126144b8e2aa85a3daa26dd632467151e2 Mon Sep 17 00:00:00 2001 From: BlackImpostor Date: Fri, 1 Nov 2024 15:12:57 +0000 Subject: [PATCH 014/136] Translated using Weblate (Russian) Currently translated at 94.7% (1310 of 1383 strings) --- .../app/src/main/res/values-ru/strings.xml | 11 + po/ru/luanti.po | 279 +++++++++--------- 2 files changed, 146 insertions(+), 144 deletions(-) create mode 100644 android/app/src/main/res/values-ru/strings.xml diff --git a/android/app/src/main/res/values-ru/strings.xml b/android/app/src/main/res/values-ru/strings.xml new file mode 100644 index 000000000..77748a9f6 --- /dev/null +++ b/android/app/src/main/res/values-ru/strings.xml @@ -0,0 +1,11 @@ + + + Загрузка Luanti + Меньше чам за 1 минуту… + Готово + Luаnti + Уведомления от Luanti + Основные уведомления + Загрузка… + Не найдено веб-браузера + \ No newline at end of file diff --git a/po/ru/luanti.po b/po/ru/luanti.po index ea7e0e1c2..4e55cc69b 100644 --- a/po/ru/luanti.po +++ b/po/ru/luanti.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: Russian (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-10-19 17:16+0000\n" +"PO-Revision-Date: 2024-11-01 17:58+0000\n" "Last-Translator: BlackImpostor \n" "Language-Team: Russian \n" @@ -13,7 +13,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Weblate 5.8-rc\n" +"X-Generator: Weblate 5.8.2-dev\n" #: builtin/client/chatcommands.lua msgid "Clear the out chat queue" @@ -160,7 +160,7 @@ msgstr "$1 скачивается…" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "All" -msgstr "" +msgstr "Всё" #: builtin/mainmenu/content/dlg_contentdb.lua #: builtin/mainmenu/content/dlg_package.lua @@ -169,9 +169,8 @@ msgid "Back" msgstr "Назад" #: builtin/mainmenu/content/dlg_contentdb.lua -#, fuzzy msgid "ContentDB is not available when Luanti was compiled without cURL" -msgstr "ContentDB недоступен, когда Minetest скомпилирован без cURL" +msgstr "ContentDB недоступен, когда Luanti скомпилирован без cURL" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Downloading..." @@ -179,7 +178,7 @@ msgstr "Загрузка…" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Featured" -msgstr "" +msgstr "Рекомендуемое" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Games" @@ -215,9 +214,8 @@ msgid "Queued" msgstr "В очереди" #: builtin/mainmenu/content/dlg_contentdb.lua -#, fuzzy msgid "Texture Packs" -msgstr "Наборы текстур" +msgstr "Наборы Текстур" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "The package $1 was not found." @@ -269,9 +267,8 @@ msgid "Dependencies:" msgstr "Зависимости:" #: builtin/mainmenu/content/dlg_install.lua -#, fuzzy msgid "Error getting dependencies for package $1" -msgstr "Ошибка при получении зависимостей для дополнения" +msgstr "Ошибка при получении зависимостей для дополнения $1" #: builtin/mainmenu/content/dlg_install.lua msgid "Install" @@ -306,44 +303,40 @@ msgid "Overwrite" msgstr "Перезаписать" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "ContentDB page" -msgstr "Ссылка ContentDB" +msgstr "Страница ContentDB" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Description" -msgstr "Описание сервера" +msgstr "Описание" #: builtin/mainmenu/content/dlg_package.lua msgid "Donate" -msgstr "" +msgstr "Пожертвовать" #: builtin/mainmenu/content/dlg_package.lua msgid "Forum Topic" -msgstr "" +msgstr "Страница на Форуме" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Information" -msgstr "Информация:" +msgstr "Информация" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Install [$1]" -msgstr "Установить $1" +msgstr "Установить [$1]" #: builtin/mainmenu/content/dlg_package.lua msgid "Issue Tracker" -msgstr "" +msgstr "Треккер Проблем" #: builtin/mainmenu/content/dlg_package.lua msgid "Source" -msgstr "" +msgstr "Источник" #: builtin/mainmenu/content/dlg_package.lua msgid "Translate" -msgstr "" +msgstr "Перевести" #: builtin/mainmenu/content/dlg_package.lua builtin/mainmenu/tab_content.lua msgid "Uninstall" @@ -354,13 +347,12 @@ msgid "Update" msgstr "Обновить" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Website" -msgstr "Посетить вебсайт" +msgstr "Веб-сайт" #: builtin/mainmenu/content/dlg_package.lua msgid "by $1 — $2 downloads — +$3 / $4 / -$5" -msgstr "" +msgstr "сделано $1 — $2 загрузок — +$3 / $4 / -$5" #: builtin/mainmenu/content/pkgmgr.lua msgid "$1 (Enabled)" @@ -722,14 +714,13 @@ msgid "Dismiss" msgstr "Пропустить" #: builtin/mainmenu/dlg_reinstall_mtg.lua -#, fuzzy msgid "" "For a long time, Luanti shipped with a default game called \"Minetest " "Game\". Since version 5.8.0, Luanti ships without a default game." msgstr "" -"Долгое время движок Minetest поставлялся вместе с игрой по умолчанию под " -"названием «Minetest Game». Начиная с Minetest 5.8.0, Minetest поставляется " -"без игры по умолчанию." +"Долгое время движок Luanti поставлялся вместе с игрой по умолчанию под " +"названием «Minetest Game». Начиная с версии 5.8.0, Luanti поставляется без " +"игры по умолчанию." #: builtin/mainmenu/dlg_reinstall_mtg.lua msgid "" @@ -890,19 +881,16 @@ msgid "eased" msgstr "cглаженный" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable automatic exposure as well)" -msgstr "(В игре также необходимо будет включить тени)" +msgstr "(В игре также необходимо будет включить автоматическую экспозицию)" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable bloom as well)" -msgstr "(В игре также необходимо будет включить тени)" +msgstr "(В игре также нужно будет включить функцию размытия)" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable volumetric lighting as well)" -msgstr "(В игре также необходимо будет включить тени)" +msgstr "(В игре также необходимо будет включить объемное освещение)" #: builtin/mainmenu/settings/dlg_settings.lua msgid "(Use system language)" @@ -914,7 +902,7 @@ msgstr "Доступность" #: builtin/mainmenu/settings/dlg_settings.lua msgid "Auto" -msgstr "" +msgstr "Авто" #: builtin/mainmenu/settings/dlg_settings.lua src/gui/guiKeyChangeMenu.cpp #: src/gui/touchcontrols.cpp src/settings_translation_file.cpp @@ -945,7 +933,7 @@ msgstr "Основной" #: builtin/mainmenu/settings/dlg_settings.lua msgid "Movement" -msgstr "Движение" +msgstr "Перемещение" #: builtin/mainmenu/settings/dlg_settings.lua msgid "Reset setting to default" @@ -980,18 +968,16 @@ msgid "Content: Mods" msgstr "Контент: Дополнения" #: builtin/mainmenu/settings/shader_warning_component.lua -#, fuzzy msgid "Enable" -msgstr "Включено" +msgstr "Включить" #: builtin/mainmenu/settings/shader_warning_component.lua -#, fuzzy msgid "Shaders are disabled." -msgstr "Обновление камеры выключено" +msgstr "Шейдеры выключены." #: builtin/mainmenu/settings/shader_warning_component.lua msgid "This is not a recommended configuration." -msgstr "" +msgstr "Это конфигурация не рекомендуется." #: builtin/mainmenu/settings/shadows_component.lua msgid "(The game will need to enable shadows as well)" @@ -1028,7 +1014,7 @@ msgstr "Очень низкие" #: builtin/mainmenu/tab_about.lua msgid "About" -msgstr "Узнать подробнее" +msgstr "Подробней" #: builtin/mainmenu/tab_about.lua msgid "Active Contributors" @@ -1151,17 +1137,15 @@ msgid "Install games from ContentDB" msgstr "Установить игры с ContentDB" #: builtin/mainmenu/tab_local.lua -#, fuzzy msgid "Luanti doesn't come with a game by default." -msgstr "Minetest Game больше не стоит по умолчанию." +msgstr "Luanti больше не стоит по умолчанию." #: builtin/mainmenu/tab_local.lua -#, fuzzy msgid "" "Luanti is a game-creation platform that allows you to play many different " "games." msgstr "" -"Minetest - это платформа для создания модификаций, которая позволяет вам " +"Luanti - это платформа для создания модификаций, которая позволяет вам " "играть во множество различных игр и устанавливать дополнения." #: builtin/mainmenu/tab_local.lua @@ -1219,7 +1203,7 @@ msgstr "Избранное" #: builtin/mainmenu/tab_online.lua msgid "Incompatible Servers" -msgstr "Несовместимые серверы" +msgstr "Несовместимые Сервера" #: builtin/mainmenu/tab_online.lua msgid "Join Game" @@ -2261,37 +2245,36 @@ msgid "Sound Volume: %d%%" msgstr "Громкость звука: %d%%" #: src/gui/touchcontrols.cpp -#, fuzzy msgid "Joystick" -msgstr "ID контроллера" +msgstr "Джойстик" #: src/gui/touchcontrols.cpp msgid "Overflow menu" -msgstr "" +msgstr "Переполненное меню" #: src/gui/touchcontrols.cpp -#, fuzzy msgid "Toggle debug" -msgstr "Вкл/откл туман" +msgstr "Переключать отладку" #: src/network/clientpackethandler.cpp msgid "" "Another client is connected with this name. If your client closed " "unexpectedly, try again in a minute." msgstr "" +"Другой клиент уже подключён с таким именем. Если ваш клиент неожиданно " +"закрылся, повторите попытку через минуту." #: src/network/clientpackethandler.cpp msgid "Empty passwords are disallowed. Set a password and try again." -msgstr "" +msgstr "Пустые пароли не принимаются. Установите пароль и повторите попытку." #: src/network/clientpackethandler.cpp msgid "Internal server error" -msgstr "" +msgstr "Внутренняя ошибка сервера" #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Invalid password" -msgstr "Старый пароль" +msgstr "Неверный пароль" #. ~ DO NOT TRANSLATE THIS LITERALLY! #. This is a special string which needs to contain the translation's @@ -2314,46 +2297,48 @@ msgstr "Имя занято. Пожалуйста, выберите другое #: src/network/clientpackethandler.cpp msgid "Player name contains disallowed characters" -msgstr "" +msgstr "Имя игрока содержит запрещенные символы" #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Player name not allowed" -msgstr "Имя игрока слишком длинное." +msgstr "Имя игрока запрещено" #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Server shutting down" -msgstr "Завершение…" +msgstr "Сервер завершает работу" #: src/network/clientpackethandler.cpp msgid "" "The server has experienced an internal error. You will now be disconnected." -msgstr "" +msgstr "У сервера произошла внутренняя ошибка. Вы будете отключены от сети." #: src/network/clientpackethandler.cpp msgid "The server is running in singleplayer mode. You cannot connect." -msgstr "" +msgstr "Сервер работает в одиночном режиме. Вам не удается подключиться." #: src/network/clientpackethandler.cpp msgid "Too many users" -msgstr "" +msgstr "Слишком много пользователей" #: src/network/clientpackethandler.cpp msgid "Unknown disconnect reason." -msgstr "" +msgstr "Неизвестная причина отключения." #: src/network/clientpackethandler.cpp msgid "" "Your client sent something the server didn't expect. Try reconnecting or " "updating your client." msgstr "" +"Ваш клиент отправил то, чего сервер не ожидал. Попробуйте повторно " +"подключиться или обновить свой клиент." #: src/network/clientpackethandler.cpp msgid "" "Your client's version is not supported.\n" "Please contact the server administrator." msgstr "" +"Версия вашего клиента не поддерживается.\n" +"Пожалуйста, свяжитесь с администратором сервера." #: src/server.cpp #, c-format @@ -2647,11 +2632,11 @@ msgstr "Метод сглаживания" #: src/settings_translation_file.cpp msgid "Anticheat flags" -msgstr "" +msgstr "Флаги Анти-чита" #: src/settings_translation_file.cpp msgid "Anticheat movement tolerance" -msgstr "" +msgstr "Допуск движения Анти-чита" #: src/settings_translation_file.cpp msgid "Append item name" @@ -2688,7 +2673,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Apply specular shading to nodes." -msgstr "" +msgstr "Применить зеркальное затенение к блокам." #: src/settings_translation_file.cpp msgid "Arm inertia" @@ -2809,9 +2794,8 @@ msgid "Biome noise" msgstr "Шум биомов" #: src/settings_translation_file.cpp -#, fuzzy msgid "Block bounds HUD radius" -msgstr "Границы мапблока" +msgstr "Радиус ограничения HUD блока" #: src/settings_translation_file.cpp msgid "Block cull optimize distance" @@ -3028,7 +3012,6 @@ msgstr "" "cpp]." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Comma-separated list of flags to hide in the content repository.\n" "\"nonfree\" can be used to hide packages which do not qualify as 'free " @@ -3038,12 +3021,13 @@ msgid "" "These flags are independent from Luanti versions,\n" "so see a full list at https://content.minetest.net/help/content_flags/" msgstr "" -"Список меток, разделённый запятыми, для скрытия в репозитории контента.\n" -"«nonfree» скрывает дополнения не являющиеся «свободным ПО»\n" -"по определению Фонда свободного программного обеспечения.\n" -"Вы также можете указать рейтинг дополнений.\n" -"Эти метки не зависят от версии Minetest,\n" -"узнать полный список можно на https://content.minetest.net/help/" +"Список разделенных запятыми флажков для скрытия в хранилище контента.\n" +"\"nonfree\" может использоваться для скрытия пакетов,\n" +"которые не подпадают под категорию Free Software Foundation,\n" +"как это определено Фондом свободного программного обеспечения.\n" +"Вы также можете указать рейтинг контента. Эти флаги не зависят от версий " +"Luanti,\n" +"поэтому смотрите полный список по адресу https://content.minetest.net/help/" "content_flags/" #: src/settings_translation_file.cpp @@ -3249,7 +3233,6 @@ msgstr "" "но также использует больше ресурсов." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Define the oldest clients allowed to connect.\n" "Older clients are compatible in the sense that they will not crash when " @@ -3263,14 +3246,12 @@ msgid "" msgstr "" "Определите, к каким самым старым клиентам разрешено подключаться.\n" "Старые клиенты совместимы в том смысле, что они не будут выходить из строя " -"при подключении\n" -"к новым серверам, но они могут поддерживать не все новые функции, которые вы " -"ожидаете.\n" +"при подключении к новым серверам,\n" +"но они могут поддерживать не все новые функции, которые вы ожидаете.\n" "Это позволяет осуществлять более детальный контроль, чем " "strict_protocol_version_checking.\n" -"Minetest по-прежнему применяет свой собственный внутренний минимум, и " -"включение\n" -"strict_protocol_version_checking эффективно отменит это." +"Luanti по-прежнему применяет свой собственный внутренний минимум,\n" +"и включение strict_protocol_version_checking эффективно отменит это." #: src/settings_translation_file.cpp msgid "Defines areas where trees have apples." @@ -3406,14 +3387,16 @@ msgid "Display Density Scaling Factor" msgstr "Коэффициент масштабирования плотности отображения" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Distance in nodes at which transparency depth sorting is enabled.\n" "Use this to limit the performance impact of transparency depth sorting.\n" "Set to 0 to disable it entirely." msgstr "" -"Расстояние в нодах на котором включено разделение по глубине прозрачности\n" -"Используйте это, чтобы ограничить его влияние на производительность" +"Расстояние в блоках, на котором включена сортировка по глубине прозрачности." +"\n" +"Используйте это значение, чтобы ограничить влияние сортировки по глубине " +"прозрачности на производительность.\n" +"Задайте значение 0, чтобы полностью отключить ее." #: src/settings_translation_file.cpp msgid "Domain name of server, to be displayed in the serverlist." @@ -3444,9 +3427,8 @@ msgid "Dungeon noise" msgstr "Шум подземелий" #: src/settings_translation_file.cpp -#, fuzzy msgid "Effects" -msgstr "Графические эффекты" +msgstr "Эффекты" #: src/settings_translation_file.cpp msgid "Enable Automatic Exposure" @@ -3553,11 +3535,8 @@ msgid "Enable random user input (only used for testing)." msgstr "Включить случайный ввод пользователя (только для тестов)." #: src/settings_translation_file.cpp -#, fuzzy msgid "Enable smooth lighting with simple ambient occlusion." -msgstr "" -"Включить мягкое освещение с простым глобальным затенением.\n" -"Отключите для более высокой скорости или другого вида." +msgstr "Включить плавное освещение с помощью простой внешней окклюзии." #: src/settings_translation_file.cpp msgid "Enable split login/register" @@ -3579,7 +3558,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Enable updates available indicator on content tab" -msgstr "" +msgstr "Включить индикатор доступности обновлений на вкладке «Контент»" #: src/settings_translation_file.cpp msgid "" @@ -3629,20 +3608,20 @@ msgid "Enables animation of inventory items." msgstr "Включить анимацию предметов в инвентаре." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Enables caching of facedir rotated meshes.\n" "This is only effective with shaders disabled." -msgstr "Включает кэширование повёрнутых мешей." +msgstr "" +"Включает кэширование повернутых сеток facedir.\n" +"Это работает только при отключенных шейдерах." #: src/settings_translation_file.cpp msgid "Enables debug and error-checking in the OpenGL driver." msgstr "Включает отладку и проверку ошибок в драйвере OpenGL." #: src/settings_translation_file.cpp -#, fuzzy msgid "Enables smooth scrolling." -msgstr "Включить Постобработку" +msgstr "Обеспечивает плавную прокрутку." #: src/settings_translation_file.cpp msgid "Enables the post processing pipeline." @@ -3655,6 +3634,11 @@ msgid "" "\"auto\" means that the touchscreen controls will be enabled and disabled\n" "automatically depending on the last used input method." msgstr "" +"Включает сенсорные элементы управления, позволяя вам играть в игру с помощью " +"сенсорного экрана.\n" +"\"auto\" означает, что сенсорные элементы управления будут включаться и " +"отключаться\n" +"автоматически в зависимости от последнего использованного метода ввода." #: src/settings_translation_file.cpp msgid "" @@ -4225,6 +4209,9 @@ msgid "" "ContentDB to\n" "check for package updates when opening the mainmenu." msgstr "" +"Если включено и у вас установлены пакеты ContentDB, Luanti может связаться с " +"ContentDB,\n" +"чтобы проверить наличие обновлений пакетов при открытии главного меню." #: src/settings_translation_file.cpp msgid "" @@ -4356,13 +4343,12 @@ msgid "Instrument chat commands on registration." msgstr "Замерять команды чата при регистрации." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Instrument global callback functions on registration.\n" "(anything you pass to a core.register_*() function)" msgstr "" -"Замерять глобальные обратные вызовы\n" -"(всё, что вы передаёте в функции вида minetest.register_*())" +"Функции глобального обратного вызова инструмента при регистрации.\n" +"(все, что вы передаете в функцию core.register_*())" #: src/settings_translation_file.cpp msgid "" @@ -4565,7 +4551,6 @@ msgid "Leaves style" msgstr "Стиль листвы" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Leaves style:\n" "- Fancy: all faces visible\n" @@ -4574,11 +4559,10 @@ msgid "" msgstr "" "Стили листвы:\n" "- Fancy: видны все стороны\n" -"- Simple: видны внешние стороны, если используется special_tiles\n" -"- Opaque: прозачность отключена" +"- Simple: видны внешние стороны\n" +"- Opaque: отключённая прозрачность" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Length of a server tick (the interval at which everything is generally " "updated),\n" @@ -4587,9 +4571,12 @@ msgid "" "This is a lower bound, i.e. server steps may not be shorter than this, but\n" "they are often longer." msgstr "" -"Длительность тика сервера (интервал, с которым обычно все обновляется),\n" +"Длительность тика сервера (интервал, с которым обычно обновляется вся " +"информация),\n" "указанная в секундах.\n" -"Не применяется к сеансам, размещенным из клиентского меню." +"Не применяется к сеансам, размещаемым из клиентского меню.\n" +"Это нижняя граница, т.е. шаги сервера могут быть не короче этого значения,\n" +"но часто они длиннее." #: src/settings_translation_file.cpp msgid "Length of liquid waves." @@ -4704,9 +4691,8 @@ msgid "Liquid queue purge time" msgstr "Время очистки очереди жидкостей" #: src/settings_translation_file.cpp -#, fuzzy msgid "Liquid reflections" -msgstr "Текучесть жидкости" +msgstr "Отражения жидкости" #: src/settings_translation_file.cpp msgid "Liquid sinking" @@ -5043,6 +5029,10 @@ msgid "" "You generally don't need to change this, however busy servers may benefit " "from a higher number." msgstr "" +"Максимальное количество пакетов, отправляемых на шаг отправки в коде " +"низкоуровневой сети.\n" +"Обычно это не требуется изменять, однако для загруженных серверов может быть " +"полезно большее количество." #: src/settings_translation_file.cpp msgid "Maximum number of players that can be connected simultaneously." @@ -5272,7 +5262,7 @@ msgstr "Подсветка нод" #: src/settings_translation_file.cpp msgid "Node specular" -msgstr "" +msgstr "Зеркальный блок" #: src/settings_translation_file.cpp msgid "NodeTimer interval" @@ -5328,14 +5318,13 @@ msgstr "" "Количество сообщений, которые игрок может отправить в течении 10 секунд." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Number of threads to use for mesh generation.\n" "Value of 0 (default) will let Luanti autodetect the number of available " "threads." msgstr "" "Количество потоков, используемых для генерации мешей.\n" -"Значение 0 (по умолчанию) позволит Minetest автоматически определять " +"Значение 0 (по умолчанию) позволит Luanti автоматически определять " "количество доступных потоков." #: src/settings_translation_file.cpp @@ -5365,18 +5354,16 @@ msgid "OpenGL debug" msgstr "Отладка OpenGL" #: src/settings_translation_file.cpp -#, fuzzy msgid "Optimize GUI for touchscreens" -msgstr "Использовать перекрестие для сенсорного экрана" +msgstr "Оптимизирует графический интерфейс для сенсорных экранов" #: src/settings_translation_file.cpp msgid "Optional override for chat weblink color." msgstr "Опциональное переопределение цвета ссылки в чате." #: src/settings_translation_file.cpp -#, fuzzy msgid "Other Effects" -msgstr "Графические эффекты" +msgstr "Другие Эффекты" #: src/settings_translation_file.cpp msgid "" @@ -5492,7 +5479,6 @@ msgid "Prometheus listener address" msgstr "Адрес прослушивания Prometheus" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Prometheus listener address.\n" "If Luanti is compiled with ENABLE_PROMETHEUS option enabled,\n" @@ -5500,7 +5486,7 @@ msgid "" "Metrics can be fetched on http://127.0.0.1:30000/metrics" msgstr "" "Адрес прослушивания Prometheus.\n" -"Если Minetest скомпилирован с опцией ENABLE_PROMETHEUS,\n" +"Если Luanti скомпилирован с опцией ENABLE_PROMETHEUS,\n" "включить прослушивание метрик для Prometheus по этому адресу.\n" "Метрики можно получить на http://127.0.0.1:30000/metrics" @@ -5528,6 +5514,8 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Radius to use when the block bounds HUD feature is set to near blocks." msgstr "" +"Радиус, используемый, когда функция отображения границ блоков установлена на " +"ближние блоки." #: src/settings_translation_file.cpp msgid "Raises terrain to make valleys around the rivers." @@ -5851,11 +5839,12 @@ msgid "" "Send names of online players to the serverlist. If disabled only the player " "count is revealed." msgstr "" +"Отправлять имена онлайн-игроков в список серверов. Если этот параметр " +"отключен, отображается только количество игроков." #: src/settings_translation_file.cpp -#, fuzzy msgid "Send player names to the server list" -msgstr "Анонсировать в этот список серверов." +msgstr "Отправлять имена игроков на список серверов" #: src/settings_translation_file.cpp msgid "Server" @@ -5883,6 +5872,9 @@ msgid "" "Flags are positive. Uncheck the flag to disable corresponding anticheat " "module." msgstr "" +"Конфигурация Ати-чита сервера.\n" +"Флажки являются положительными. Снимите флажок, чтобы отключить " +"соответствующий модуль анти-чита." #: src/settings_translation_file.cpp msgid "Server description" @@ -6037,6 +6029,8 @@ msgid "" "Shaders are a fundamental part of rendering and enable advanced visual " "effects." msgstr "" +"Шейдеры являются фундаментальной частью рендеринга и обеспечивают " +"расширенные визуальные эффекты." #: src/settings_translation_file.cpp msgid "Shadow filter quality" @@ -6107,7 +6101,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Simulate translucency when looking at foliage in the sunlight." -msgstr "" +msgstr "Имитировать прозрачность при взгляде на листву в солнечном свете." #: src/settings_translation_file.cpp msgid "" @@ -6161,9 +6155,8 @@ msgid "Smooth lighting" msgstr "Мягкое освещение" #: src/settings_translation_file.cpp -#, fuzzy msgid "Smooth scrolling" -msgstr "Мягкое освещение" +msgstr "Плавная прокрутка" #: src/settings_translation_file.cpp msgid "" @@ -6191,9 +6184,8 @@ msgid "Sneaking speed, in nodes per second." msgstr "Скорость ходьбы украдкой, в нодах в секунду." #: src/settings_translation_file.cpp -#, fuzzy msgid "Soft clouds" -msgstr "Объёмные облака" +msgstr "Мягкие облака" #: src/settings_translation_file.cpp msgid "Soft shadow radius" @@ -6431,7 +6423,6 @@ msgstr "" "Путь к файлу, куда будут сохранены профили, относительно пути к вашему миру." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "The gesture for punching players/entities.\n" "This can be overridden by games and mods.\n" @@ -6451,7 +6442,7 @@ msgstr "" "указываются.\n" "\n" "* длинный удар\n" -"Известен по классическому мобильному элементу управления Minetest.\n" +"Известен по классическому мобильному элементу управления Luanti.\n" "Сражение более или менее невозможно." #: src/settings_translation_file.cpp @@ -6516,7 +6507,6 @@ msgstr "" "Это должно быть настроено вместе с active_object_send_range_blocks." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "The rendering back-end.\n" "Note: A restart is required after changing this!\n" @@ -6525,8 +6515,7 @@ msgstr "" "Серверная часть рендеринга.\n" "Примечание: После изменения этого параметра требуется перезагрузка!\n" "По умолчанию для настольных компьютеров используется OpenGL, а для Android - " -"OGLES2.\n" -"Шейдеры поддерживаются всеми, кроме OGLES1." +"OGLES2." #: src/settings_translation_file.cpp msgid "" @@ -6651,6 +6640,8 @@ msgid "" "Tolerance of movement cheat detector.\n" "Increase the value if players experience stuttery movement." msgstr "" +"Детектор читерства \"Устойчивость к движению\".\n" +"Увеличьте значение, если игроки начинают неуверенно двигаться." #: src/settings_translation_file.cpp msgid "Tooltip delay" @@ -6661,9 +6652,8 @@ msgid "Touchscreen" msgstr "Сенсорный экран" #: src/settings_translation_file.cpp -#, fuzzy msgid "Touchscreen controls" -msgstr "Порог сенсорного экрана" +msgstr "Сенсорное управление" #: src/settings_translation_file.cpp msgid "Touchscreen sensitivity" @@ -6678,9 +6668,8 @@ msgid "Tradeoffs for performance" msgstr "Компромиссы для производительности" #: src/settings_translation_file.cpp -#, fuzzy msgid "Translucent foliage" -msgstr "Полупрозрачные жидкости" +msgstr "Полупрозрачная листва" #: src/settings_translation_file.cpp msgid "Translucent liquids" @@ -6731,14 +6720,13 @@ msgstr "" "производительностью." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "URL to JSON file which provides information about the newest Luanti " "release.\n" "If this is empty the engine will never check for updates." msgstr "" "URL-адрес файла JSON, который предоставляет информацию о последней версии " -"Minetest\n" +"Luanti.\n" "Если поле не заполнено, движок никогда не будет проверять наличие обновлений." #: src/settings_translation_file.cpp @@ -6838,7 +6826,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Use smooth cloud shading." -msgstr "" +msgstr "Используйте плавный шейдинг облаков." #: src/settings_translation_file.cpp msgid "" @@ -7046,13 +7034,17 @@ msgstr "Цвет ссылки" #: src/settings_translation_file.cpp msgid "When enabled, liquid reflections are simulated." -msgstr "" +msgstr "При включении имитируются отражения от жидкости." #: src/settings_translation_file.cpp msgid "" "When enabled, the GUI is optimized to be more usable on touchscreens.\n" "Whether this is enabled by default depends on your hardware form-factor." msgstr "" +"Если этот параметр будет включен, графический интерфейс оптимизирован для " +"более удобного использования на сенсорных экранах.\n" +"Будет ли он включен по умолчанию, зависит от форм-фактора вашего " +"оборудования." #: src/settings_translation_file.cpp msgid "" @@ -7167,15 +7159,14 @@ msgid "Window maximized" msgstr "Окно развёрнуто" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Windows systems only: Start Luanti with the command line window in the " "background.\n" "Contains the same information as the file debug.txt (default name)." msgstr "" -"Только для Windows: запускать Minetest с окном командной строки на заднем " -"плане\n" -"Содержит ту же информацию, что и файл debug.txt (имя файла по умолчанию)." +"Только для систем Windows: Запустите Luanti с помощью окна командной строки " +"в фоновом режиме.\n" +"Содержит ту же информацию, что и файл debug.txt (имя по умолчанию)." #: src/settings_translation_file.cpp msgid "" From eed109c72450a1b44e8ea1027fe2f834f37d8240 Mon Sep 17 00:00:00 2001 From: chocomint Date: Fri, 1 Nov 2024 16:58:32 +0000 Subject: [PATCH 015/136] Translated using Weblate (Spanish) Currently translated at 96.6% (1337 of 1383 strings) --- po/es/luanti.po | 166 +++++++++++++++++++++--------------------------- 1 file changed, 72 insertions(+), 94 deletions(-) diff --git a/po/es/luanti.po b/po/es/luanti.po index 966f234db..749e4f320 100644 --- a/po/es/luanti.po +++ b/po/es/luanti.po @@ -3,8 +3,8 @@ msgstr "" "Project-Id-Version: Spanish (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-10-12 03:08+0000\n" -"Last-Translator: gallegonovato \n" +"PO-Revision-Date: 2024-11-01 22:24+0000\n" +"Last-Translator: chocomint \n" "Language-Team: Spanish \n" "Language: es\n" @@ -12,7 +12,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.8-dev\n" +"X-Generator: Weblate 5.8.2-dev\n" #: builtin/client/chatcommands.lua msgid "Clear the out chat queue" @@ -159,7 +159,7 @@ msgstr "$1 descargando..." #: builtin/mainmenu/content/dlg_contentdb.lua msgid "All" -msgstr "" +msgstr "Todo" #: builtin/mainmenu/content/dlg_contentdb.lua #: builtin/mainmenu/content/dlg_package.lua @@ -168,10 +168,8 @@ msgid "Back" msgstr "Atrás" #: builtin/mainmenu/content/dlg_contentdb.lua -#, fuzzy msgid "ContentDB is not available when Luanti was compiled without cURL" -msgstr "" -"ContentDB no se encuentra disponible cuando Minetest se compiló sin cURL" +msgstr "ContentDB no se encuentra disponible cuando Luanti se compiló sin cURL" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Downloading..." @@ -179,7 +177,7 @@ msgstr "Descargando..." #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Featured" -msgstr "" +msgstr "Destacado" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Games" @@ -215,9 +213,8 @@ msgid "Queued" msgstr "En cola" #: builtin/mainmenu/content/dlg_contentdb.lua -#, fuzzy msgid "Texture Packs" -msgstr "Paq. de texturas" +msgstr "Paquetes de texturas" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "The package $1 was not found." @@ -269,9 +266,8 @@ msgid "Dependencies:" msgstr "Dependencias:" #: builtin/mainmenu/content/dlg_install.lua -#, fuzzy msgid "Error getting dependencies for package $1" -msgstr "Error obteniendo dependencias para el paquete" +msgstr "Error obteniendo dependencias para el paquete $1" #: builtin/mainmenu/content/dlg_install.lua msgid "Install" @@ -306,44 +302,40 @@ msgid "Overwrite" msgstr "Sobreescribir" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "ContentDB page" -msgstr "URL de ContentDB" +msgstr "Página de ContentDB" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Description" -msgstr "Descripción del servidor" +msgstr "Descripción" #: builtin/mainmenu/content/dlg_package.lua msgid "Donate" -msgstr "" +msgstr "Donar" #: builtin/mainmenu/content/dlg_package.lua msgid "Forum Topic" -msgstr "" +msgstr "Tema del foro" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Information" -msgstr "Información:" +msgstr "Información" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Install [$1]" -msgstr "Instalar $1" +msgstr "Instalar [$1]" #: builtin/mainmenu/content/dlg_package.lua msgid "Issue Tracker" -msgstr "" +msgstr "Rastreador de problemas" #: builtin/mainmenu/content/dlg_package.lua msgid "Source" -msgstr "" +msgstr "Fuente" #: builtin/mainmenu/content/dlg_package.lua msgid "Translate" -msgstr "" +msgstr "Traducir" #: builtin/mainmenu/content/dlg_package.lua builtin/mainmenu/tab_content.lua msgid "Uninstall" @@ -354,13 +346,12 @@ msgid "Update" msgstr "Actualizar" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Website" -msgstr "Visitar el sitio web" +msgstr "Sitio web" #: builtin/mainmenu/content/dlg_package.lua msgid "by $1 — $2 downloads — +$3 / $4 / -$5" -msgstr "" +msgstr "por $1 — $2 descargas — +$3 / $4 / -$5" #: builtin/mainmenu/content/pkgmgr.lua msgid "$1 (Enabled)" @@ -725,13 +716,12 @@ msgid "Dismiss" msgstr "Descartar" #: builtin/mainmenu/dlg_reinstall_mtg.lua -#, fuzzy msgid "" "For a long time, Luanti shipped with a default game called \"Minetest " "Game\". Since version 5.8.0, Luanti ships without a default game." msgstr "" -"Por un largo tiempo, el motor de Minetest incluía un juego default llamado " -"\"Minetest Game\". Desde Minetest 5.8.0, Minetest se incluye sin un juego " +"Por un largo tiempo, Luanti incluía un juego predeterminado llamado " +"'Minetest Game'. Desde la versión 5.8.0, Luanti se incluye sin un juego " "predeterminado." #: builtin/mainmenu/dlg_reinstall_mtg.lua @@ -894,19 +884,16 @@ msgid "eased" msgstr "Suavizado" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable automatic exposure as well)" -msgstr "(El juego necesitará habilitar las sombras también)" +msgstr "(El juego necesitará habilitar la exposición automática también)" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable bloom as well)" -msgstr "(El juego necesitará habilitar las sombras también)" +msgstr "(El juego necesitará habilitar el efecto de bloom también)" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable volumetric lighting as well)" -msgstr "(El juego necesitará habilitar las sombras también)" +msgstr "(El juego necesitará habilitar la iluminación volumétrica también)" #: builtin/mainmenu/settings/dlg_settings.lua msgid "(Use system language)" @@ -918,7 +905,7 @@ msgstr "Accesibilidad" #: builtin/mainmenu/settings/dlg_settings.lua msgid "Auto" -msgstr "" +msgstr "Automático" #: builtin/mainmenu/settings/dlg_settings.lua src/gui/guiKeyChangeMenu.cpp #: src/gui/touchcontrols.cpp src/settings_translation_file.cpp @@ -984,18 +971,16 @@ msgid "Content: Mods" msgstr "Contenido: Mods" #: builtin/mainmenu/settings/shader_warning_component.lua -#, fuzzy msgid "Enable" -msgstr "Activado" +msgstr "Habilitar" #: builtin/mainmenu/settings/shader_warning_component.lua -#, fuzzy msgid "Shaders are disabled." -msgstr "Actualización de la cámara desactivada" +msgstr "Los Shaders están deshabilitados." #: builtin/mainmenu/settings/shader_warning_component.lua msgid "This is not a recommended configuration." -msgstr "" +msgstr "Esta no es una configuración recomendada." #: builtin/mainmenu/settings/shadows_component.lua msgid "(The game will need to enable shadows as well)" @@ -1155,18 +1140,16 @@ msgid "Install games from ContentDB" msgstr "Instalar juegos desde ContentDB" #: builtin/mainmenu/tab_local.lua -#, fuzzy msgid "Luanti doesn't come with a game by default." -msgstr "Minetest no viene con un juego por defecto." +msgstr "Luanti no viene con un juego por defecto." #: builtin/mainmenu/tab_local.lua -#, fuzzy msgid "" "Luanti is a game-creation platform that allows you to play many different " "games." msgstr "" -"Minetest es una plataforma de creación de juegos que te permite jugar a " -"muchos juegos diferentes." +"Luanti es una plataforma de creación de juegos que te permite jugar a muchos " +"diferentes juegos." #: builtin/mainmenu/tab_local.lua msgid "New" @@ -2273,37 +2256,38 @@ msgid "Sound Volume: %d%%" msgstr "Volumen del sonido: %d%%" #: src/gui/touchcontrols.cpp -#, fuzzy msgid "Joystick" -msgstr "ID de Joystick" +msgstr "Joystick" #: src/gui/touchcontrols.cpp msgid "Overflow menu" -msgstr "" +msgstr "Menú de desborde" #: src/gui/touchcontrols.cpp -#, fuzzy msgid "Toggle debug" -msgstr "Alternar la niebla" +msgstr "Alternar depuración" #: src/network/clientpackethandler.cpp msgid "" "Another client is connected with this name. If your client closed " "unexpectedly, try again in a minute." msgstr "" +"Otro cliente está conectado con este nombre. Si su cliente se cerró " +"inesperadamente, intente nuevamente en un minuto." #: src/network/clientpackethandler.cpp msgid "Empty passwords are disallowed. Set a password and try again." msgstr "" +"Las contraseñas vacías no están permitidas. Establezca una contraseña y " +"vuelva a intentarlo." #: src/network/clientpackethandler.cpp msgid "Internal server error" -msgstr "" +msgstr "Error interno del servidor" #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Invalid password" -msgstr "Contraseña anterior" +msgstr "Contraseña inválida" #. ~ DO NOT TRANSLATE THIS LITERALLY! #. This is a special string which needs to contain the translation's @@ -2326,30 +2310,30 @@ msgstr "El nombre ya ha sido tomado. Por favor, elegir otro nombre" #: src/network/clientpackethandler.cpp msgid "Player name contains disallowed characters" -msgstr "" +msgstr "El nombre del jugador contiene caracteres no permitidos" #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Player name not allowed" -msgstr "Nombre de jugador demasiado largo." +msgstr "Nombre de jugador no permitido" #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Server shutting down" -msgstr "Cerrando..." +msgstr "El servidor se está cerrando" #: src/network/clientpackethandler.cpp msgid "" "The server has experienced an internal error. You will now be disconnected." msgstr "" +"El servidor ha experimentado un error interno. Ahora serás desconectado." #: src/network/clientpackethandler.cpp msgid "The server is running in singleplayer mode. You cannot connect." msgstr "" +"El servidor está funcionando en modo un jugador. No puedes conectarte." #: src/network/clientpackethandler.cpp msgid "Too many users" -msgstr "" +msgstr "Muchos usuarios" #: src/network/clientpackethandler.cpp msgid "Unknown disconnect reason." @@ -2831,9 +2815,8 @@ msgid "Biome noise" msgstr "Ruido del bioma" #: src/settings_translation_file.cpp -#, fuzzy msgid "Block bounds HUD radius" -msgstr "Límites de bloque" +msgstr "Radio de límites de bloque en HUD" #: src/settings_translation_file.cpp msgid "Block cull optimize distance" @@ -3049,7 +3032,6 @@ msgstr "" "Útil para pruebas. Ver al_extensions.[h,cpp] para más detalles." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Comma-separated list of flags to hide in the content repository.\n" "\"nonfree\" can be used to hide packages which do not qualify as 'free " @@ -3059,14 +3041,14 @@ msgid "" "These flags are independent from Luanti versions,\n" "so see a full list at https://content.minetest.net/help/content_flags/" msgstr "" -"Lista separada por comas de etiquetas a ocultar en el repositorio de " +"Lista de banderas separadas por comas para ocultar en el repositorio de " "contenido.\n" -"Se puede usar la etiqueta 'nonfree' para ocultar paquetes que no califican\n" -"como \"software libre\", tal como es definido por la Fundación de Software " -"Libre (FSF).\n" +"\"nonfree\" se puede usar para ocultar paquetes que no califican como " +"'software libre',\n" +"según lo definido por la Free Software Foundation.\n" "También puedes especificar clasificaciones de contenido.\n" -"Estas etiquetas son independientes de la versión de Minetest.\n" -"Si quieres ver una lista completa visita https://content.minetest.net/help/" +"Estas banderas son independientes de las versiones de Luanti,\n" +"así que consulta una lista completa en https://content.minetest.net/help/" "content_flags/" #: src/settings_translation_file.cpp @@ -3273,7 +3255,6 @@ msgstr "" "pero tambien utiliza más recursos." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Define the oldest clients allowed to connect.\n" "Older clients are compatible in the sense that they will not crash when " @@ -3285,15 +3266,15 @@ msgid "" "Luanti still enforces its own internal minimum, and enabling\n" "strict_protocol_version_checking will effectively override this." msgstr "" -"Definir los clientes más antiguos con permiso para conectarse.\n" -"Los clientes más antiguos no se colgarán al intento de conectarse\n" -"a nuevos servidores, pero no soportarán todas las nuevas características que " -"espera.\n" -"Esto permite un control mucho más ajustado que " -"strict_protocol_version_checking.\n" -"Aún así, Minetest sigue forzando su minimo interno, y activar\n" -"strict_protocol_version_checking ignorará efectivamente todos los parámetros " -"que haya definido." +"Define los clientes más antiguos permitidos para conectarse.\n" +"Los clientes más antiguos son compatibles en el sentido de que no se " +"bloquearán al conectarse\n" +"a nuevos servidores, pero pueden no soportar todas las nuevas " +"características que esperas.\n" +"Esto permite un control más detallado que la verificación estricta de la " +"versión del protocolo.\n" +"Luanti aún aplica su propio mínimo interno, y habilitar la verificación " +"estricta de la versión del protocolo anulará efectivamente esto." #: src/settings_translation_file.cpp msgid "Defines areas where trees have apples." @@ -3432,16 +3413,16 @@ msgid "Display Density Scaling Factor" msgstr "Factor del Escalado de la Densidad de Visualización" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Distance in nodes at which transparency depth sorting is enabled.\n" "Use this to limit the performance impact of transparency depth sorting.\n" "Set to 0 to disable it entirely." msgstr "" "Distancia en nodos a la que se activa la clasificación por profundidad de " -"transparencia\n" +"transparencia.\n" "Utilice esto para limitar el impacto en el rendimiento de la clasificación " -"por profundidad de transparencia" +"por profundidad de transparencia.\n" +"Establezca en 0 para desactivarlo por completo." #: src/settings_translation_file.cpp msgid "Domain name of server, to be displayed in the serverlist." @@ -3473,9 +3454,8 @@ msgid "Dungeon noise" msgstr "Ruido de mazmorra" #: src/settings_translation_file.cpp -#, fuzzy msgid "Effects" -msgstr "Efectos gráficos" +msgstr "Efectos" #: src/settings_translation_file.cpp msgid "Enable Automatic Exposure" @@ -3584,11 +3564,8 @@ msgid "Enable random user input (only used for testing)." msgstr "Habilitar entrada aleatoria (solo usar para pruebas)." #: src/settings_translation_file.cpp -#, fuzzy msgid "Enable smooth lighting with simple ambient occlusion." -msgstr "" -"Habilita iluminación suave con oclusión ambiental simple.\n" -"Deshabilítalo para mayor velocidad o una vista diferente." +msgstr "Habilita iluminación suave con oclusión ambiental simple." #: src/settings_translation_file.cpp msgid "Enable split login/register" @@ -3659,20 +3636,21 @@ msgid "Enables animation of inventory items." msgstr "Habilita la animación de objetos en el inventario." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Enables caching of facedir rotated meshes.\n" "This is only effective with shaders disabled." -msgstr "Habilitar cacheado de mallas giradas." +msgstr "" +"Habilita el almacenamiento en caché de mallas rotadas por dirección de cara." +"\n" +"Esto solo es efectivo con los shaders desactivados." #: src/settings_translation_file.cpp msgid "Enables debug and error-checking in the OpenGL driver." msgstr "Activa depuración y comprobación de errores en el driver OpenGL." #: src/settings_translation_file.cpp -#, fuzzy msgid "Enables smooth scrolling." -msgstr "Habilitar posprocesamiento" +msgstr "Habilita el desplazamiento suave." #: src/settings_translation_file.cpp msgid "Enables the post processing pipeline." From c96455b2e4591fdccebd639387cb2927ec108b81 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Fri, 1 Nov 2024 18:11:21 +0000 Subject: [PATCH 016/136] Translated using Weblate (Spanish) Currently translated at 98.6% (1365 of 1383 strings) --- po/es/luanti.po | 73 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 20 deletions(-) diff --git a/po/es/luanti.po b/po/es/luanti.po index 749e4f320..cb6444177 100644 --- a/po/es/luanti.po +++ b/po/es/luanti.po @@ -3,8 +3,8 @@ msgstr "" "Project-Id-Version: Spanish (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-11-01 22:24+0000\n" -"Last-Translator: chocomint \n" +"PO-Revision-Date: 2024-11-01 22:25+0000\n" +"Last-Translator: gallegonovato \n" "Language-Team: Spanish \n" "Language: es\n" @@ -347,7 +347,7 @@ msgstr "Actualizar" #: builtin/mainmenu/content/dlg_package.lua msgid "Website" -msgstr "Sitio web" +msgstr "Página web" #: builtin/mainmenu/content/dlg_package.lua msgid "by $1 — $2 downloads — +$3 / $4 / -$5" @@ -720,8 +720,8 @@ msgid "" "For a long time, Luanti shipped with a default game called \"Minetest " "Game\". Since version 5.8.0, Luanti ships without a default game." msgstr "" -"Por un largo tiempo, Luanti incluía un juego predeterminado llamado " -"'Minetest Game'. Desde la versión 5.8.0, Luanti se incluye sin un juego " +"Durante mucho tiempo, Luanti se entregó con un juego predeterminado llamado " +"\"Minetest Game\". Desde la versión 5.8.0, Luanti se entrega sin un juego " "predeterminado." #: builtin/mainmenu/dlg_reinstall_mtg.lua @@ -729,16 +729,16 @@ msgid "" "If you want to continue playing in your Minetest Game worlds, you need to " "reinstall Minetest Game." msgstr "" -"Si quieres continuar jugando en tus mundos de Minetest, necesitarás " -"reinstalar Minetest Game." +"Si deseas seguir jugando en los mundos de Minetest Game, deberás reinstalar " +"Minetest Game." #: builtin/mainmenu/dlg_reinstall_mtg.lua msgid "Minetest Game is no longer installed by default" -msgstr "Minetest Game ya no es instalado por predeterminado" +msgstr "Minetest Game ya no se instala de forma predeterminada" #: builtin/mainmenu/dlg_reinstall_mtg.lua msgid "Reinstall Minetest Game" -msgstr "Reinstala Minetest Game" +msgstr "Reinstalar Minetest Game" #: builtin/mainmenu/dlg_rename_modpack.lua msgid "Accept" @@ -893,7 +893,7 @@ msgstr "(El juego necesitará habilitar el efecto de bloom también)" #: builtin/mainmenu/settings/dlg_settings.lua msgid "(The game will need to enable volumetric lighting as well)" -msgstr "(El juego necesitará habilitar la iluminación volumétrica también)" +msgstr "(El juego también deberá habilitar la iluminación volumétrica)" #: builtin/mainmenu/settings/dlg_settings.lua msgid "(Use system language)" @@ -2333,23 +2333,27 @@ msgstr "" #: src/network/clientpackethandler.cpp msgid "Too many users" -msgstr "Muchos usuarios" +msgstr "Demasiados usuarios" #: src/network/clientpackethandler.cpp msgid "Unknown disconnect reason." -msgstr "" +msgstr "Motivo de desconexión desconocido." #: src/network/clientpackethandler.cpp msgid "" "Your client sent something the server didn't expect. Try reconnecting or " "updating your client." msgstr "" +"Su cliente envió algo que el servidor no esperaba. Intente reconectarse o " +"actualizar su cliente." #: src/network/clientpackethandler.cpp msgid "" "Your client's version is not supported.\n" "Please contact the server administrator." msgstr "" +"La versión de su cliente no es compatible.\n" +"Por favor, póngase en contacto con el administrador del servidor." #: src/server.cpp #, c-format @@ -2654,11 +2658,11 @@ msgstr "Método de suavizado" #: src/settings_translation_file.cpp msgid "Anticheat flags" -msgstr "" +msgstr "Banderas antitrampas" #: src/settings_translation_file.cpp msgid "Anticheat movement tolerance" -msgstr "" +msgstr "Tolerancia al movimiento antitrampas" #: src/settings_translation_file.cpp msgid "Append item name" @@ -2695,7 +2699,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Apply specular shading to nodes." -msgstr "" +msgstr "Aplique la sombra especulativa a los nodos." #: src/settings_translation_file.cpp msgid "Arm inertia" @@ -3587,6 +3591,8 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Enable updates available indicator on content tab" msgstr "" +"Habilitar el indicador de actualizaciones disponibles en la pestaña de " +"contenido" #: src/settings_translation_file.cpp msgid "" @@ -3650,11 +3656,11 @@ msgstr "Activa depuración y comprobación de errores en el driver OpenGL." #: src/settings_translation_file.cpp msgid "Enables smooth scrolling." -msgstr "Habilita el desplazamiento suave." +msgstr "Activar el desplazamiento suave." #: src/settings_translation_file.cpp msgid "Enables the post processing pipeline." -msgstr "Activas el proceso de posprocesamiento." +msgstr "Habilita la canalización para el posprocesamiento." #: src/settings_translation_file.cpp msgid "" @@ -3663,6 +3669,11 @@ msgid "" "\"auto\" means that the touchscreen controls will be enabled and disabled\n" "automatically depending on the last used input method." msgstr "" +"Habilita los controles de pantalla táctil, lo que te permite jugar el juego " +"con una pantalla táctil.\n" +"\"auto\" significa que los controles de la pantalla táctil se habilitarán y " +"deshabilitarán\n" +"automáticamente dependiendo del último método de entrada utilizado." #: src/settings_translation_file.cpp msgid "" @@ -4248,6 +4259,9 @@ msgid "" "ContentDB to\n" "check for package updates when opening the mainmenu." msgstr "" +"Si está habilitado y tiene paquetes ContentDB instalados, Luanti puede " +"comunicarse con ContentDB para\n" +"Compruebe si hay actualizaciones del paquete al abrir el menú principal." #: src/settings_translation_file.cpp msgid "" @@ -5099,6 +5113,10 @@ msgid "" "You generally don't need to change this, however busy servers may benefit " "from a higher number." msgstr "" +"Número máximo de paquetes enviados por paso de envío en el código de red de " +"bajo nivel.\n" +"Generalmente no es necesario cambiar esto, sin embargo los servidores " +"ocupados pueden beneficiarse de un número mayor." #: src/settings_translation_file.cpp msgid "Maximum number of players that can be connected simultaneously." @@ -5597,6 +5615,8 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Radius to use when the block bounds HUD feature is set to near blocks." msgstr "" +"El radio que se utilizará cuando la función HUD de límite de bloque está en " +"el modo Bloques cercanos." #: src/settings_translation_file.cpp msgid "Raises terrain to make valleys around the rivers." @@ -5928,6 +5948,8 @@ msgid "" "Send names of online players to the serverlist. If disabled only the player " "count is revealed." msgstr "" +"Envía los nombres de los jugadores en línea a la lista de servidores. Si " +"está deshabilitada, solo se revela el número de jugadores." #: src/settings_translation_file.cpp #, fuzzy @@ -5960,6 +5982,9 @@ msgid "" "Flags are positive. Uncheck the flag to disable corresponding anticheat " "module." msgstr "" +"Configuración antitrampas del servidor.\n" +"Las banderas son positivas. Desmarque la bandera para desactivar el módulo " +"antitrampas correspondiente." #: src/settings_translation_file.cpp msgid "Server description" @@ -6120,6 +6145,8 @@ msgid "" "Shaders are a fundamental part of rendering and enable advanced visual " "effects." msgstr "" +"Los Shaders son una parte fundamental del renderizado y permiten efectos " +"visuales avanzados." #: src/settings_translation_file.cpp msgid "Shadow filter quality" @@ -6192,7 +6219,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Simulate translucency when looking at foliage in the sunlight." -msgstr "" +msgstr "Simule la translucidez al mirar el follaje a la luz del sol." #: src/settings_translation_file.cpp msgid "" @@ -6746,6 +6773,8 @@ msgid "" "Tolerance of movement cheat detector.\n" "Increase the value if players experience stuttery movement." msgstr "" +"Detector de trampas de tolerancia de movimiento.\n" +"Aumente el valor si los jugadores experimentan movimientos entrecortados." #: src/settings_translation_file.cpp msgid "Tooltip delay" @@ -6931,7 +6960,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Use smooth cloud shading." -msgstr "" +msgstr "Utilice un sombreado de nubes suave." #: src/settings_translation_file.cpp msgid "" @@ -7140,13 +7169,17 @@ msgstr "Color de los enlaces web" #: src/settings_translation_file.cpp msgid "When enabled, liquid reflections are simulated." -msgstr "" +msgstr "Cuando está habilitado, se simulan reflejos de líquidos." #: src/settings_translation_file.cpp msgid "" "When enabled, the GUI is optimized to be more usable on touchscreens.\n" "Whether this is enabled by default depends on your hardware form-factor." msgstr "" +"Cuando está habilitada, la GUI se optimiza para que sea más fácil de usar en " +"pantallas táctiles.\n" +"Si esta opción está habilitada de manera predeterminada depende del factor " +"de forma de su hardware." #: src/settings_translation_file.cpp msgid "" From 112c0719cde3dadf19e5cdfdff5707bc98840e39 Mon Sep 17 00:00:00 2001 From: y5nw Date: Fri, 1 Nov 2024 19:43:19 +0000 Subject: [PATCH 017/136] Translated using Weblate (Chinese (Simplified Han script)) Currently translated at 91.7% (1269 of 1383 strings) --- po/zh_CN/luanti.po | 51 +++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/po/zh_CN/luanti.po b/po/zh_CN/luanti.po index 12789f9dc..6fdf6bbec 100644 --- a/po/zh_CN/luanti.po +++ b/po/zh_CN/luanti.po @@ -3,16 +3,16 @@ msgstr "" "Project-Id-Version: Chinese (Simplified) (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-07-31 22:09+0000\n" +"PO-Revision-Date: 2024-11-01 22:24+0000\n" "Last-Translator: y5nw \n" -"Language-Team: Chinese (Simplified) \n" +"Language-Team: Chinese (Simplified Han script) \n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 5.7-dev\n" +"X-Generator: Weblate 5.8.2-dev\n" #: builtin/client/chatcommands.lua msgid "Clear the out chat queue" @@ -267,9 +267,8 @@ msgid "Dependencies:" msgstr "依赖项:" #: builtin/mainmenu/content/dlg_install.lua -#, fuzzy msgid "Error getting dependencies for package $1" -msgstr "无法获取这个包的依赖项" +msgstr "无法获取$1的依赖项" #: builtin/mainmenu/content/dlg_install.lua msgid "Install" @@ -309,9 +308,8 @@ msgid "ContentDB page" msgstr "ContentDB网址" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Description" -msgstr "服务器描述" +msgstr "描述" #: builtin/mainmenu/content/dlg_package.lua msgid "Donate" @@ -324,7 +322,7 @@ msgstr "" #: builtin/mainmenu/content/dlg_package.lua #, fuzzy msgid "Information" -msgstr "信息:" +msgstr "信息" #: builtin/mainmenu/content/dlg_package.lua #, fuzzy @@ -337,11 +335,11 @@ msgstr "" #: builtin/mainmenu/content/dlg_package.lua msgid "Source" -msgstr "" +msgstr "源代码" #: builtin/mainmenu/content/dlg_package.lua msgid "Translate" -msgstr "" +msgstr "翻译" #: builtin/mainmenu/content/dlg_package.lua builtin/mainmenu/tab_content.lua msgid "Uninstall" @@ -352,9 +350,8 @@ msgid "Update" msgstr "更新" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Website" -msgstr "访问网站" +msgstr "网站" #: builtin/mainmenu/content/dlg_package.lua msgid "by $1 — $2 downloads — +$3 / $4 / -$5" @@ -718,8 +715,8 @@ msgid "" "For a long time, Luanti shipped with a default game called \"Minetest " "Game\". Since version 5.8.0, Luanti ships without a default game." msgstr "" -"一直以来,Minetest 游戏引擎默认已经自带了“Minetest Game”这个子游戏。但是从 " -"Minetest 5.8.0 版本起,Minetest 将不再自带任何子游戏。" +"一直以来,Luanti 游戏引擎默认自带了“Minetest Game”这个子游戏。但是从 5.8.0 " +"版本起,Luanti 不再自带任何子游戏。" #: builtin/mainmenu/dlg_reinstall_mtg.lua msgid "" @@ -1140,7 +1137,7 @@ msgstr "从 ContentDB 安装游戏" #: builtin/mainmenu/tab_local.lua #, fuzzy msgid "Luanti doesn't come with a game by default." -msgstr "Minetest Game 不再是默认自带的子游戏了" +msgstr "Luanti 不自带任何子游戏。" #: builtin/mainmenu/tab_local.lua msgid "" @@ -1181,7 +1178,6 @@ msgid "Start Game" msgstr "启动游戏" #: builtin/mainmenu/tab_local.lua -#, fuzzy msgid "You need to install a game before you can create a world." msgstr "您需要先安装一个子游戏才能创建新的世界。" @@ -2207,12 +2203,10 @@ msgid "Open" msgstr "打开" #: src/gui/guiOpenURL.cpp -#, fuzzy msgid "Open URL?" msgstr "是否打开网页?" #: src/gui/guiOpenURL.cpp -#, fuzzy msgid "Unable to open URL" msgstr "无法打开网页" @@ -2296,18 +2290,19 @@ msgid "Name is taken. Please choose another name" msgstr "名称已被占用。请选择其他名称" #: src/network/clientpackethandler.cpp +#, fuzzy msgid "Player name contains disallowed characters" -msgstr "" +msgstr "玩家名称包含不允许使用的字符" #: src/network/clientpackethandler.cpp #, fuzzy msgid "Player name not allowed" -msgstr "玩家名称过长。" +msgstr "不允许使用该玩家名称" #: src/network/clientpackethandler.cpp #, fuzzy msgid "Server shutting down" -msgstr "关闭中..." +msgstr "服务器正在关闭" #: src/network/clientpackethandler.cpp msgid "" @@ -2337,6 +2332,8 @@ msgid "" "Your client's version is not supported.\n" "Please contact the server administrator." msgstr "" +"服务器不支持这个客户端版本。\n" +"请联系管理员。" #: src/server.cpp #, c-format @@ -5735,15 +5732,15 @@ msgstr "" "18 = 4D \"Mandelbulb\" 朱利亚集." #: src/settings_translation_file.cpp +#, fuzzy msgid "" "Send names of online players to the serverlist. If disabled only the player " "count is revealed." -msgstr "" +msgstr "向服务器列表发送在线玩家的名称。如果禁用此设置,服务器只发送玩家数量。" #: src/settings_translation_file.cpp -#, fuzzy msgid "Send player names to the server list" -msgstr "向服务器表公开服务器。" +msgstr "向服务器列表公开玩家名称" #: src/settings_translation_file.cpp msgid "Server" @@ -6574,7 +6571,9 @@ msgid "" "URL to JSON file which provides information about the newest Luanti " "release.\n" "If this is empty the engine will never check for updates." -msgstr "提供最新 Minetest 版本信息的 JSON 文件的 URL" +msgstr "" +"提供最新 Luanti 版本信息的 JSON 文件的 URL。\n" +"如果设置为空,Luanti 不会查找新版本。" #: src/settings_translation_file.cpp msgid "URL to the server list displayed in the Multiplayer Tab." From 62bee9f502aeca59daa960b16873341450b0b1ff Mon Sep 17 00:00:00 2001 From: chocomint Date: Fri, 1 Nov 2024 22:24:24 +0000 Subject: [PATCH 018/136] Translated using Weblate (Spanish) Currently translated at 98.7% (1366 of 1383 strings) --- po/es/luanti.po | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/po/es/luanti.po b/po/es/luanti.po index cb6444177..725f0e45d 100644 --- a/po/es/luanti.po +++ b/po/es/luanti.po @@ -4,7 +4,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" "PO-Revision-Date: 2024-11-01 22:25+0000\n" -"Last-Translator: gallegonovato \n" +"Last-Translator: chocomint \n" "Language-Team: Spanish \n" "Language: es\n" @@ -4406,13 +4406,12 @@ msgid "Instrument chat commands on registration." msgstr "Instrumento de comandos del chat al registrarse." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Instrument global callback functions on registration.\n" "(anything you pass to a core.register_*() function)" msgstr "" -"Funciones de devolución de llamada global del instrumento en el registro.\n" -"(Cualquier cosa que pase a una función minetest.register _ * ())" +"Manejar funciones de devolución de llamada global en el registro.\n" +"(Cualquier cosa que pase a una función core.register_*())" #: src/settings_translation_file.cpp msgid "" From 31c50c470c9e39b7854c101db2152618476e0fa5 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Fri, 1 Nov 2024 22:26:00 +0000 Subject: [PATCH 019/136] Translated using Weblate (Spanish) Currently translated at 99.1% (1371 of 1383 strings) --- po/es/luanti.po | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/po/es/luanti.po b/po/es/luanti.po index 725f0e45d..df4380769 100644 --- a/po/es/luanti.po +++ b/po/es/luanti.po @@ -3,8 +3,8 @@ msgstr "" "Project-Id-Version: Spanish (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-11-01 22:25+0000\n" -"Last-Translator: chocomint \n" +"PO-Revision-Date: 2024-11-01 22:28+0000\n" +"Last-Translator: gallegonovato \n" "Language-Team: Spanish \n" "Language: es\n" @@ -4410,21 +4410,21 @@ msgid "" "Instrument global callback functions on registration.\n" "(anything you pass to a core.register_*() function)" msgstr "" -"Manejar funciones de devolución de llamada global en el registro.\n" -"(Cualquier cosa que pase a una función core.register_*())" +"Instrumentar funciones callback globales en el registro.\n" +"(cualquier cosa que se pase a una función core.register_*())" #: src/settings_translation_file.cpp msgid "" "Instrument the action function of Active Block Modifiers on registration." msgstr "" -"Instrumenta la función de acción de los Modificadores de Bloque Activos en " +"Instrumentar la función de acción de los modificadores de bloque activo en " "el registro." #: src/settings_translation_file.cpp msgid "" "Instrument the action function of Loading Block Modifiers on registration." msgstr "" -"Instrumenta la función de acción de Carga de Modificadores de Bloque en el " +"Instrumentar la función de acción de Cargar modificadores de bloque en el " "registro." #: src/settings_translation_file.cpp From 0c61461b07d128a8723bd9ba56b42ef3b82fba8d Mon Sep 17 00:00:00 2001 From: chocomint Date: Fri, 1 Nov 2024 22:26:03 +0000 Subject: [PATCH 020/136] Translated using Weblate (Spanish) Currently translated at 99.1% (1371 of 1383 strings) --- po/es/luanti.po | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/po/es/luanti.po b/po/es/luanti.po index df4380769..87ab0f095 100644 --- a/po/es/luanti.po +++ b/po/es/luanti.po @@ -4,7 +4,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" "PO-Revision-Date: 2024-11-01 22:28+0000\n" -"Last-Translator: gallegonovato \n" +"Last-Translator: chocomint \n" "Language-Team: Spanish \n" "Language: es\n" @@ -4619,7 +4619,6 @@ msgid "Leaves style" msgstr "Estilo de las hojas" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Leaves style:\n" "- Fancy: all faces visible\n" @@ -4627,12 +4626,11 @@ msgid "" "- Opaque: disable transparency" msgstr "" "Estilo de hojas:\n" -"- Fabuloso: Todas las caras son visibles\n" -"- Simple: Solo caras externas, si se utilizan special_tiles definidos\n" -"- Opaco: Transparencia desactivada" +"- Fabuloso: todas las caras son visibles\n" +"- Simple: solo caras externas\n" +"- Opaco: desactivar transparencia" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Length of a server tick (the interval at which everything is generally " "updated),\n" @@ -4644,7 +4642,10 @@ msgstr "" "Duración de un tick del servidor (el intervalo en el que todo es " "actualizado),\n" "expresado en segundos.\n" -"No se aplica a las sesiones iniciadas desde el menú del cliente." +"No se aplica a las sesiones iniciadas desde el menú del cliente.\n" +"Esta es una cota inferior, es decir, los pasos del servidor no pueden ser " +"más cortos que esto, pero\n" +"a menudo son más largos." #: src/settings_translation_file.cpp msgid "Length of liquid waves." @@ -4766,9 +4767,8 @@ msgid "Liquid queue purge time" msgstr "Tiempo de purga de colas de líquidos" #: src/settings_translation_file.cpp -#, fuzzy msgid "Liquid reflections" -msgstr "Fluidez líquida" +msgstr "Reflejos líquidos" #: src/settings_translation_file.cpp msgid "Liquid sinking" @@ -5353,7 +5353,7 @@ msgstr "Resaltado de los nodos" #: src/settings_translation_file.cpp msgid "Node specular" -msgstr "" +msgstr "Nodo especular" #: src/settings_translation_file.cpp msgid "NodeTimer interval" @@ -5409,15 +5409,14 @@ msgid "Number of messages a player may send per 10 seconds." msgstr "Número de mensajes que un jugador puede enviar cada 10 segundos." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Number of threads to use for mesh generation.\n" "Value of 0 (default) will let Luanti autodetect the number of available " "threads." msgstr "" -"Numero de hilos del procesador a usar para la generación de mayas.\n" -"Un valor de 0 (default) dejará que Minetest detecte automáticamente el " -"número de hilos disponibles." +"Número de hilos a utilizar para la generación de mallas.\n" +"Un valor de 0 (predeterminado) permitirá que Luanti detecte automáticamente " +"el número de hilos disponibles." #: src/settings_translation_file.cpp msgid "Occlusion Culler" From aaf487773093fcc5a5c763273591ff4774348d5a Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Fri, 1 Nov 2024 22:28:53 +0000 Subject: [PATCH 021/136] Translated using Weblate (Spanish) Currently translated at 99.3% (1374 of 1383 strings) --- po/es/luanti.po | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/po/es/luanti.po b/po/es/luanti.po index 87ab0f095..43eaf1f14 100644 --- a/po/es/luanti.po +++ b/po/es/luanti.po @@ -3,8 +3,8 @@ msgstr "" "Project-Id-Version: Spanish (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-11-01 22:28+0000\n" -"Last-Translator: chocomint \n" +"PO-Revision-Date: 2024-11-01 22:30+0000\n" +"Last-Translator: gallegonovato \n" "Language-Team: Spanish \n" "Language: es\n" @@ -4625,10 +4625,10 @@ msgid "" "- Simple: only outer faces\n" "- Opaque: disable transparency" msgstr "" -"Estilo de hojas:\n" -"- Fabuloso: todas las caras son visibles\n" -"- Simple: solo caras externas\n" -"- Opaco: desactivar transparencia" +"Estilo de las hojas:\n" +"- Elegante: todas las caras visibles\n" +"- Simple: solo las caras exteriores\n" +"- Opaco: desactivar la transparencia" #: src/settings_translation_file.cpp msgid "" @@ -4639,12 +4639,12 @@ msgid "" "This is a lower bound, i.e. server steps may not be shorter than this, but\n" "they are often longer." msgstr "" -"Duración de un tick del servidor (el intervalo en el que todo es " -"actualizado),\n" -"expresado en segundos.\n" -"No se aplica a las sesiones iniciadas desde el menú del cliente.\n" -"Esta es una cota inferior, es decir, los pasos del servidor no pueden ser " -"más cortos que esto, pero\n" +"Duración de un tick del servidor (intervalo en el que generalmente se " +"actualiza todo),\n" +"indicada en segundos.\n" +"No se aplica a las sesiones alojadas desde el menú cliente.\n" +"Se trata de un límite inferior, es decir, los pasos del servidor no pueden " +"ser más cortos que esto, pero\n" "a menudo son más largos." #: src/settings_translation_file.cpp From 000f0c78bc766037655b939aa31162c6b61e350b Mon Sep 17 00:00:00 2001 From: chocomint Date: Fri, 1 Nov 2024 22:29:02 +0000 Subject: [PATCH 022/136] Translated using Weblate (Spanish) Currently translated at 99.3% (1374 of 1383 strings) --- po/es/luanti.po | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/po/es/luanti.po b/po/es/luanti.po index 43eaf1f14..c4b5236d0 100644 --- a/po/es/luanti.po +++ b/po/es/luanti.po @@ -4,7 +4,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" "PO-Revision-Date: 2024-11-01 22:30+0000\n" -"Last-Translator: gallegonovato \n" +"Last-Translator: chocomint \n" "Language-Team: Spanish \n" "Language: es\n" @@ -5448,18 +5448,16 @@ msgid "OpenGL debug" msgstr "Depuración OpenGL" #: src/settings_translation_file.cpp -#, fuzzy msgid "Optimize GUI for touchscreens" -msgstr "Usar retícula en pantalla táctil" +msgstr "Optimizar la interfaz gráfica de usuario para pantallas táctiles" #: src/settings_translation_file.cpp msgid "Optional override for chat weblink color." msgstr "Anulación opcional del color de un enlace web en el chat." #: src/settings_translation_file.cpp -#, fuzzy msgid "Other Effects" -msgstr "Efectos gráficos" +msgstr "Otros Efectos" #: src/settings_translation_file.cpp msgid "" @@ -5576,16 +5574,15 @@ msgid "Prometheus listener address" msgstr "Dirección del receptor \"Prometheus\"" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Prometheus listener address.\n" "If Luanti is compiled with ENABLE_PROMETHEUS option enabled,\n" "enable metrics listener for Prometheus on that address.\n" "Metrics can be fetched on http://127.0.0.1:30000/metrics" msgstr "" -"Dirección de escucha de \"Prometheus\".\n" -"Si Minetest se compila con la opción 'ENABLE_PROMETHEUS' activada,\n" -"se habilitará el detector de métricas para \"Prometheus\" en esa dirección.\n" +"Dirección de escucha de Prometheus.\n" +"Si Luanti se compila con la opción ENABLE_PROMETHEUS activada,\n" +"habilite el detector de métricas para Prometheus en esa dirección.\n" "Las métricas pueden obtenerse en http://127.0.0.1:30000/metrics" #: src/settings_translation_file.cpp From 58ebe0a58f7b4a06f948ad96e71047b4b172cd5c Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Fri, 1 Nov 2024 22:30:48 +0000 Subject: [PATCH 023/136] Translated using Weblate (Spanish) Currently translated at 99.7% (1380 of 1383 strings) --- po/es/luanti.po | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/po/es/luanti.po b/po/es/luanti.po index c4b5236d0..e994d2149 100644 --- a/po/es/luanti.po +++ b/po/es/luanti.po @@ -3,8 +3,8 @@ msgstr "" "Project-Id-Version: Spanish (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-11-01 22:30+0000\n" -"Last-Translator: chocomint \n" +"PO-Revision-Date: 2024-11-01 22:34+0000\n" +"Last-Translator: gallegonovato \n" "Language-Team: Spanish \n" "Language: es\n" @@ -5449,15 +5449,15 @@ msgstr "Depuración OpenGL" #: src/settings_translation_file.cpp msgid "Optimize GUI for touchscreens" -msgstr "Optimizar la interfaz gráfica de usuario para pantallas táctiles" +msgstr "Optimización de la interfaz gráfica para pantallas táctiles" #: src/settings_translation_file.cpp msgid "Optional override for chat weblink color." -msgstr "Anulación opcional del color de un enlace web en el chat." +msgstr "Cambio opcional del color del enlace web del chat." #: src/settings_translation_file.cpp msgid "Other Effects" -msgstr "Otros Efectos" +msgstr "Otros efectos" #: src/settings_translation_file.cpp msgid "" @@ -5582,12 +5582,12 @@ msgid "" msgstr "" "Dirección de escucha de Prometheus.\n" "Si Luanti se compila con la opción ENABLE_PROMETHEUS activada,\n" -"habilite el detector de métricas para Prometheus en esa dirección.\n" -"Las métricas pueden obtenerse en http://127.0.0.1:30000/metrics" +"habilita la escucha de métricas para Prometheus en esa dirección.\n" +"Las métricas se pueden obtener en http://127.0.0.1:30000/metrics" #: src/settings_translation_file.cpp msgid "Proportion of large caves that contain liquid." -msgstr "Proporción de cuevas grandes que contienen líquido." +msgstr "Proporción de grandes cuevas que contienen líquido." #: src/settings_translation_file.cpp msgid "Protocol version minimum" @@ -6544,7 +6544,6 @@ msgstr "" "los perfiles." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "The gesture for punching players/entities.\n" "This can be overridden by games and mods.\n" @@ -6556,14 +6555,14 @@ msgid "" "Known from the classic Luanti mobile controls.\n" "Combat is more or less impossible." msgstr "" -"El gesto para golpear jugadores/entidades.\n" -"Los juegos y mods pueden ignorar esto.\n" +"El gesto para golpear a jugadores/entidades.\n" +"Esto puede ser anulado por juegos y mods.\n" "\n" -"* sort_tap\n" -"Fácil de usar y muy conocido por otros juegos que no se mencionarán.\n" +"* short_tap\n" +"Fácil de usar y bien conocido de otros juegos que no deben ser nombrados.\n" "\n" "* long_tap\n" -"Conocido por los controles clásicos para móviles de Minetest.\n" +"Conocido por los controles clásicos del móvil Luanti.\n" "El combate es más o menos imposible." #: src/settings_translation_file.cpp @@ -6630,16 +6629,14 @@ msgstr "" "Esto debe configurarse junto con active_object_send_range_blocks." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "The rendering back-end.\n" "Note: A restart is required after changing this!\n" "OpenGL is the default for desktop, and OGLES2 for Android." msgstr "" "El back-end de renderizado.\n" -"Nota: ¡se debe reiniciar después de cambiar esto!\n" -"OpenGL es el predeterminado para PC, y OGLES2 para Android.\n" -"Los shaders son compatibles con todos los sistemas excepto OGLES1." +"Nota: ¡es necesario reiniciar después de cambiar esto!\n" +"OpenGL es el predeterminado para escritorio, y OGLES2 para Android." #: src/settings_translation_file.cpp msgid "" @@ -6780,9 +6777,8 @@ msgid "Touchscreen" msgstr "Pantalla táctil" #: src/settings_translation_file.cpp -#, fuzzy msgid "Touchscreen controls" -msgstr "Umbral de la pantalla táctil" +msgstr "Controles táctiles" #: src/settings_translation_file.cpp msgid "Touchscreen sensitivity" From e23c191232f9d8f2d637cd7300036ba93a1177c4 Mon Sep 17 00:00:00 2001 From: chocomint Date: Fri, 1 Nov 2024 22:31:49 +0000 Subject: [PATCH 024/136] Translated using Weblate (Spanish) Currently translated at 99.7% (1380 of 1383 strings) --- po/es/luanti.po | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/po/es/luanti.po b/po/es/luanti.po index e994d2149..0a85da8fb 100644 --- a/po/es/luanti.po +++ b/po/es/luanti.po @@ -3,8 +3,8 @@ msgstr "" "Project-Id-Version: Spanish (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-11-01 22:34+0000\n" -"Last-Translator: gallegonovato \n" +"PO-Revision-Date: 2024-11-01 22:36+0000\n" +"Last-Translator: chocomint \n" "Language-Team: Spanish \n" "Language: es\n" @@ -5947,9 +5947,8 @@ msgstr "" "está deshabilitada, solo se revela el número de jugadores." #: src/settings_translation_file.cpp -#, fuzzy msgid "Send player names to the server list" -msgstr "Anunciar en esta lista de servidores." +msgstr "Enviar nombres de los jugadores a la lista de servidores" #: src/settings_translation_file.cpp msgid "Server" @@ -6269,9 +6268,8 @@ msgid "Smooth lighting" msgstr "Iluminación suave" #: src/settings_translation_file.cpp -#, fuzzy msgid "Smooth scrolling" -msgstr "Iluminación suave" +msgstr "Desplazado suave" #: src/settings_translation_file.cpp msgid "" @@ -6298,9 +6296,8 @@ msgid "Sneaking speed, in nodes per second." msgstr "Velocidad agachado, en nodos por segundo." #: src/settings_translation_file.cpp -#, fuzzy msgid "Soft clouds" -msgstr "Nubes 3D" +msgstr "Nubes suaves" #: src/settings_translation_file.cpp msgid "Soft shadow radius" @@ -6562,7 +6559,7 @@ msgstr "" "Fácil de usar y bien conocido de otros juegos que no deben ser nombrados.\n" "\n" "* long_tap\n" -"Conocido por los controles clásicos del móvil Luanti.\n" +"Conocido por los controles clásicos de móvil en Luanti.\n" "El combate es más o menos imposible." #: src/settings_translation_file.cpp @@ -6634,9 +6631,9 @@ msgid "" "Note: A restart is required after changing this!\n" "OpenGL is the default for desktop, and OGLES2 for Android." msgstr "" -"El back-end de renderizado.\n" -"Nota: ¡es necesario reiniciar después de cambiar esto!\n" -"OpenGL es el predeterminado para escritorio, y OGLES2 para Android." +"El renderizado de back-end.\n" +"Nota: ¡Se requiere un reinicio después de cambiar esto!\n" +"OpenGL es el predeterminado para el escritorio, y OGLES2 para Android." #: src/settings_translation_file.cpp msgid "" @@ -6778,7 +6775,7 @@ msgstr "Pantalla táctil" #: src/settings_translation_file.cpp msgid "Touchscreen controls" -msgstr "Controles táctiles" +msgstr "Controles de pantalla táctil" #: src/settings_translation_file.cpp msgid "Touchscreen sensitivity" From 2d6592a8044c5461ebae0dbbaf8a0d415e461d10 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Fri, 1 Nov 2024 22:34:21 +0000 Subject: [PATCH 025/136] Translated using Weblate (Spanish) Currently translated at 100.0% (1383 of 1383 strings) --- po/es/luanti.po | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/po/es/luanti.po b/po/es/luanti.po index 0a85da8fb..0d9225609 100644 --- a/po/es/luanti.po +++ b/po/es/luanti.po @@ -4,7 +4,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" "PO-Revision-Date: 2024-11-01 22:36+0000\n" -"Last-Translator: chocomint \n" +"Last-Translator: gallegonovato \n" "Language-Team: Spanish \n" "Language: es\n" @@ -6790,9 +6790,8 @@ msgid "Tradeoffs for performance" msgstr "Contrapartidas para el rendimiento" #: src/settings_translation_file.cpp -#, fuzzy msgid "Translucent foliage" -msgstr "Líquidos translúcidos" +msgstr "Follaje translúcido" #: src/settings_translation_file.cpp msgid "Translucent liquids" @@ -6842,14 +6841,13 @@ msgstr "" "Esta configuración solo debe cambiarse si tiene problemas de rendimiento." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "URL to JSON file which provides information about the newest Luanti " "release.\n" "If this is empty the engine will never check for updates." msgstr "" -"URL del archivo JSON que proporciona información sobre la última versión de " -"Minetest\n" +"Dirección URL al archivo JSON que proporciona información sobre la última " +"versión de Luanti.\n" "Si está vacío, el motor nunca buscará actualizaciones." #: src/settings_translation_file.cpp @@ -7293,15 +7291,14 @@ msgid "Window maximized" msgstr "Ventana maximizada" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Windows systems only: Start Luanti with the command line window in the " "background.\n" "Contains the same information as the file debug.txt (default name)." msgstr "" -"Solo para sistemas Windows: Iniciar Minetest con la ventana de la linea de " -"comandos en el fondo.\n" -"Contiene la misma información que el archivo debug.txt (Nombre por defecto)." +"Solo sistemas Windows: Inicia Luanti con la ventana de línea de comandos en " +"segundo plano.\n" +"Contiene la misma información que el archivo debug.txt (nombre por defecto)." #: src/settings_translation_file.cpp msgid "" From 812abba33be63f89691d6c5c5f2eef46123623b2 Mon Sep 17 00:00:00 2001 From: chocomint Date: Fri, 1 Nov 2024 22:39:49 +0000 Subject: [PATCH 026/136] Translated using Weblate (Spanish) Currently translated at 100.0% (1383 of 1383 strings) --- po/es/luanti.po | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/po/es/luanti.po b/po/es/luanti.po index 0d9225609..5be7c093a 100644 --- a/po/es/luanti.po +++ b/po/es/luanti.po @@ -3,8 +3,8 @@ msgstr "" "Project-Id-Version: Spanish (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-11-01 22:36+0000\n" -"Last-Translator: gallegonovato \n" +"PO-Revision-Date: 2024-11-01 22:40+0000\n" +"Last-Translator: chocomint \n" "Language-Team: Spanish \n" "Language: es\n" @@ -3052,7 +3052,7 @@ msgstr "" "según lo definido por la Free Software Foundation.\n" "También puedes especificar clasificaciones de contenido.\n" "Estas banderas son independientes de las versiones de Luanti,\n" -"así que consulta una lista completa en https://content.minetest.net/help/" +"así que consulta una lista completa en https://content.luanti.org/help/" "content_flags/" #: src/settings_translation_file.cpp @@ -6846,9 +6846,9 @@ msgid "" "release.\n" "If this is empty the engine will never check for updates." msgstr "" -"Dirección URL al archivo JSON que proporciona información sobre la última " -"versión de Luanti.\n" -"Si está vacío, el motor nunca buscará actualizaciones." +"URL al archivo JSON que proporciona información sobre la nueva versión de " +"Luanti.\n" +"Si esto está vacío el motor nunca comprobará las actualizaciones." #: src/settings_translation_file.cpp msgid "URL to the server list displayed in the Multiplayer Tab." From 0be1fe11ca68aea1fdecb95adc75ccf48286defa Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Fri, 1 Nov 2024 22:38:02 +0000 Subject: [PATCH 027/136] Translated using Weblate (Spanish) Currently translated at 100.0% (1383 of 1383 strings) --- po/es/luanti.po | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/po/es/luanti.po b/po/es/luanti.po index 5be7c093a..91b10e486 100644 --- a/po/es/luanti.po +++ b/po/es/luanti.po @@ -3,8 +3,8 @@ msgstr "" "Project-Id-Version: Spanish (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-11-01 22:40+0000\n" -"Last-Translator: chocomint \n" +"PO-Revision-Date: 2024-11-02 23:00+0000\n" +"Last-Translator: gallegonovato \n" "Language-Team: Spanish \n" "Language: es\n" @@ -12,7 +12,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.8.2-dev\n" +"X-Generator: Weblate 5.8.2\n" #: builtin/client/chatcommands.lua msgid "Clear the out chat queue" @@ -3052,7 +3052,7 @@ msgstr "" "según lo definido por la Free Software Foundation.\n" "También puedes especificar clasificaciones de contenido.\n" "Estas banderas son independientes de las versiones de Luanti,\n" -"así que consulta una lista completa en https://content.luanti.org/help/" +"así que consulta una lista completa en https://content.minetest.net/help/" "content_flags/" #: src/settings_translation_file.cpp @@ -6631,9 +6631,9 @@ msgid "" "Note: A restart is required after changing this!\n" "OpenGL is the default for desktop, and OGLES2 for Android." msgstr "" -"El renderizado de back-end.\n" -"Nota: ¡Se requiere un reinicio después de cambiar esto!\n" -"OpenGL es el predeterminado para el escritorio, y OGLES2 para Android." +"El back-end de renderizado.\n" +"Nota: ¡Es necesario reiniciar después de cambiar esto!\n" +"OpenGL es el predeterminado para escritorio y OGLES2 para Android." #: src/settings_translation_file.cpp msgid "" @@ -6775,7 +6775,7 @@ msgstr "Pantalla táctil" #: src/settings_translation_file.cpp msgid "Touchscreen controls" -msgstr "Controles de pantalla táctil" +msgstr "Controles en pantalla táctil" #: src/settings_translation_file.cpp msgid "Touchscreen sensitivity" @@ -6846,9 +6846,9 @@ msgid "" "release.\n" "If this is empty the engine will never check for updates." msgstr "" -"URL al archivo JSON que proporciona información sobre la nueva versión de " -"Luanti.\n" -"Si esto está vacío el motor nunca comprobará las actualizaciones." +"URL del archivo JSON que proporciona información sobre la versión más " +"reciente de Luanti.\n" +"Si está vacío, el motor nunca buscará actualizaciones." #: src/settings_translation_file.cpp msgid "URL to the server list displayed in the Multiplayer Tab." From 66a5ddca258c4e460b9339dac4405fcf31b6496f Mon Sep 17 00:00:00 2001 From: grorp Date: Sat, 2 Nov 2024 12:48:21 +0000 Subject: [PATCH 028/136] Translated using Weblate (German) Currently translated at 100.0% (1383 of 1383 strings) --- po/de/luanti.po | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/po/de/luanti.po b/po/de/luanti.po index 7fecb8b93..f22502be5 100644 --- a/po/de/luanti.po +++ b/po/de/luanti.po @@ -3,8 +3,8 @@ msgstr "" "Project-Id-Version: German (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-11-01 16:26+0000\n" -"Last-Translator: Wuzzy \n" +"PO-Revision-Date: 2024-11-02 23:00+0000\n" +"Last-Translator: grorp \n" "Language-Team: German \n" "Language: de\n" @@ -12,7 +12,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.8.2-dev\n" +"X-Generator: Weblate 5.8.2\n" #: builtin/client/chatcommands.lua msgid "Clear the out chat queue" @@ -6532,8 +6532,8 @@ msgid "" "The delay in milliseconds after which a touch interaction is considered a " "long tap." msgstr "" -"Die Verzögerung in Millisekunden, nachdem eine Berührungsinteraktion als " -"langes Antippen zählt." +"Die Verzögerung in Millisekunden, nach der eine Touch-Interaktion als langes " +"Antippen zählt." #: src/settings_translation_file.cpp msgid "" @@ -6553,16 +6553,16 @@ msgid "" "Known from the classic Luanti mobile controls.\n" "Combat is more or less impossible." msgstr "" -"Die Geste für für das Schlagen von Spielern/Entitys.\n" +"Die Geste für das Schlagen von Spielern/Entitys.\n" "Dies kann von Spielen und Mods überschrieben werden.\n" "\n" "* short_tap\n" -"Leicht zu benutzen und bekannt von anderen Spielen, die nicht genannt werden " +"Leicht zu benutzen und bekannt aus anderen Spielen, die nicht genannt werden " "sollen.\n" "\n" "* long_tap\n" -"Bekannt aus der klassischen Luantisteuerung für mobile Endgeräte.\n" -"Der Kampf ist mehr oder weniger unmöglich." +"Bekannt aus der klassischen Luanti-Touchscreen-Steuerung.\n" +"Kämpfen ist mehr oder weniger unmöglich." #: src/settings_translation_file.cpp msgid "The identifier of the joystick to use" @@ -6572,7 +6572,7 @@ msgstr "Die Kennung des zu verwendeten Joysticks" msgid "" "The length in pixels after which a touch interaction is considered movement." msgstr "" -"Die Länge in Pixeln, die benötigt wird, damit die Touch-Interaktion als " +"Die Länge in Pixeln, die benötigt wird, damit eine Touch-Interaktion als " "Bewegung zählt." #: src/settings_translation_file.cpp @@ -6779,15 +6779,15 @@ msgstr "Touchscreen" #: src/settings_translation_file.cpp msgid "Touchscreen controls" -msgstr "Touchscreensteuerung" +msgstr "Touchscreen-Steuerung" #: src/settings_translation_file.cpp msgid "Touchscreen sensitivity" -msgstr "Touchscreenempfindlichkeit" +msgstr "Touchscreen-Empfindlichkeit" #: src/settings_translation_file.cpp msgid "Touchscreen sensitivity multiplier." -msgstr "Faktor für die Touchscreenempfindlichkeit." +msgstr "Faktor für die Touchscreen-Empfindlichkeit." #: src/settings_translation_file.cpp msgid "Tradeoffs for performance" From d9df06cda31d835664264e639ef554036a5672df Mon Sep 17 00:00:00 2001 From: ninjum Date: Sat, 2 Nov 2024 12:09:36 +0000 Subject: [PATCH 029/136] Translated using Weblate (Galician) Currently translated at 100.0% (1383 of 1383 strings) --- po/gl/luanti.po | 308 +++++++++++++++++++++++------------------------- 1 file changed, 149 insertions(+), 159 deletions(-) diff --git a/po/gl/luanti.po b/po/gl/luanti.po index f0c163f00..90dba133f 100644 --- a/po/gl/luanti.po +++ b/po/gl/luanti.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: minetest\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-08-14 04:09+0000\n" +"PO-Revision-Date: 2024-11-02 23:00+0000\n" "Last-Translator: ninjum \n" "Language-Team: Galician \n" @@ -12,7 +12,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.7-dev\n" +"X-Generator: Weblate 5.8.2\n" #: builtin/client/chatcommands.lua msgid "Clear the out chat queue" @@ -159,7 +159,7 @@ msgstr "Descargando $1..." #: builtin/mainmenu/content/dlg_contentdb.lua msgid "All" -msgstr "" +msgstr "Todo" #: builtin/mainmenu/content/dlg_contentdb.lua #: builtin/mainmenu/content/dlg_package.lua @@ -168,7 +168,6 @@ msgid "Back" msgstr "Voltar" #: builtin/mainmenu/content/dlg_contentdb.lua -#, fuzzy msgid "ContentDB is not available when Luanti was compiled without cURL" msgstr "ContentDB non está dispoñible cando Minetest compilouse sen cURL" @@ -178,7 +177,7 @@ msgstr "Descargando..." #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Featured" -msgstr "" +msgstr "Destacado" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Games" @@ -214,7 +213,6 @@ msgid "Queued" msgstr "En cola" #: builtin/mainmenu/content/dlg_contentdb.lua -#, fuzzy msgid "Texture Packs" msgstr "Paquetes de texturas" @@ -268,9 +266,8 @@ msgid "Dependencies:" msgstr "Dependencias:" #: builtin/mainmenu/content/dlg_install.lua -#, fuzzy msgid "Error getting dependencies for package $1" -msgstr "Produciuse un erro ao obter dependencias para o paquete" +msgstr "Produciuse un erro ao obter dependencias para o paquete $1" #: builtin/mainmenu/content/dlg_install.lua msgid "Install" @@ -305,44 +302,40 @@ msgid "Overwrite" msgstr "Sobrescribir" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "ContentDB page" -msgstr "Ligazón URL de ContentDB" +msgstr "Ligazón de ContentDB" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Description" -msgstr "Descripción do servidor" +msgstr "Descripción" #: builtin/mainmenu/content/dlg_package.lua msgid "Donate" -msgstr "" +msgstr "Doar" #: builtin/mainmenu/content/dlg_package.lua msgid "Forum Topic" -msgstr "" +msgstr "Tema do foro" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Information" -msgstr "Información:" +msgstr "Información" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Install [$1]" -msgstr "Instalar $1" +msgstr "Instalar [$1]" #: builtin/mainmenu/content/dlg_package.lua msgid "Issue Tracker" -msgstr "" +msgstr "Rastrexador de Problemas" #: builtin/mainmenu/content/dlg_package.lua msgid "Source" -msgstr "" +msgstr "Fonte" #: builtin/mainmenu/content/dlg_package.lua msgid "Translate" -msgstr "" +msgstr "Traducir" #: builtin/mainmenu/content/dlg_package.lua builtin/mainmenu/tab_content.lua msgid "Uninstall" @@ -353,13 +346,12 @@ msgid "Update" msgstr "Actualizar" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Website" -msgstr "Visitar sitio web" +msgstr "Páxina web" #: builtin/mainmenu/content/dlg_package.lua msgid "by $1 — $2 downloads — +$3 / $4 / -$5" -msgstr "" +msgstr "por $1 — $2 descargas — +$3 / $4 / -$5" #: builtin/mainmenu/content/pkgmgr.lua msgid "$1 (Enabled)" @@ -723,14 +715,12 @@ msgid "Dismiss" msgstr "Descartar" #: builtin/mainmenu/dlg_reinstall_mtg.lua -#, fuzzy msgid "" "For a long time, Luanti shipped with a default game called \"Minetest " "Game\". Since version 5.8.0, Luanti ships without a default game." msgstr "" -"Durante moito tempo, o motor Minetest incluía un xogo predeterminado chamado " -"\"Minetest Game\". Dende Minetest 5.8.0, Minetest inclúese sen un xogo " -"predeterminado." +"Durante moito tempo, Luanti incluía un xogo por defecto chamado 'Minetest " +"Game'. Desde a versión 5.8.0, Luanti distribúese sen un xogo por defecto." #: builtin/mainmenu/dlg_reinstall_mtg.lua msgid "" @@ -892,19 +882,16 @@ msgid "eased" msgstr "Suavizado" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable automatic exposure as well)" -msgstr "(O xogo tamén precisará activar as sombras)" +msgstr "(O xogo tamén necesitará habilitar a exposición automática.)" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable bloom as well)" -msgstr "(O xogo tamén precisará activar as sombras)" +msgstr "(O xogo tamén necesitará habilitar efecto de bloom.)" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable volumetric lighting as well)" -msgstr "(O xogo tamén precisará activar as sombras)" +msgstr "(O xogo tamén necesitará habilitar a iluminación volumétrica.)" #: builtin/mainmenu/settings/dlg_settings.lua msgid "(Use system language)" @@ -916,7 +903,7 @@ msgstr "Accesibilidade" #: builtin/mainmenu/settings/dlg_settings.lua msgid "Auto" -msgstr "" +msgstr "Automático" #: builtin/mainmenu/settings/dlg_settings.lua src/gui/guiKeyChangeMenu.cpp #: src/gui/touchcontrols.cpp src/settings_translation_file.cpp @@ -982,18 +969,16 @@ msgid "Content: Mods" msgstr "Contido: modificacións" #: builtin/mainmenu/settings/shader_warning_component.lua -#, fuzzy msgid "Enable" -msgstr "Activado" +msgstr "Habilitar" #: builtin/mainmenu/settings/shader_warning_component.lua -#, fuzzy msgid "Shaders are disabled." -msgstr "Actualización da cámara desactivada" +msgstr "Os sombreadores están deshabilitados." #: builtin/mainmenu/settings/shader_warning_component.lua msgid "This is not a recommended configuration." -msgstr "" +msgstr "Esta non é unha configuración recomendada." #: builtin/mainmenu/settings/shadows_component.lua msgid "(The game will need to enable shadows as well)" @@ -1154,18 +1139,16 @@ msgid "Install games from ContentDB" msgstr "Instalar xogos do ContentDB" #: builtin/mainmenu/tab_local.lua -#, fuzzy msgid "Luanti doesn't come with a game by default." -msgstr "Minetest non trae un xogo por defecto." +msgstr "Luanti non vén cun xogo por defecto." #: builtin/mainmenu/tab_local.lua -#, fuzzy msgid "" "Luanti is a game-creation platform that allows you to play many different " "games." msgstr "" -"Minetest é unha plataforma de creación de xogos que che permite xogar a " -"moitos xogos diferentes." +"Luanti é unha plataforma de creación de xogos que che permite xogar a moitos " +"xogos diferentes." #: builtin/mainmenu/tab_local.lua msgid "New" @@ -2269,37 +2252,38 @@ msgid "Sound Volume: %d%%" msgstr "Son: %d%%" #: src/gui/touchcontrols.cpp -#, fuzzy msgid "Joystick" -msgstr "ID do joystick" +msgstr "Joystick" #: src/gui/touchcontrols.cpp msgid "Overflow menu" -msgstr "" +msgstr "Menú de desbordamento" #: src/gui/touchcontrols.cpp -#, fuzzy msgid "Toggle debug" -msgstr "Alt. néboa" +msgstr "Activar/desactivar depuración" #: src/network/clientpackethandler.cpp msgid "" "Another client is connected with this name. If your client closed " "unexpectedly, try again in a minute." msgstr "" +"Outro cliente está conectado con este nome. Se o seu cliente pechouse " +"inesperadamente, tenteo de novo nun minuto." #: src/network/clientpackethandler.cpp msgid "Empty passwords are disallowed. Set a password and try again." msgstr "" +"Non se permiten contrasinais baleiros. Estableza un contrasinal e intente " +"de novo." #: src/network/clientpackethandler.cpp msgid "Internal server error" -msgstr "" +msgstr "Erro interno do servidor" #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Invalid password" -msgstr "Anterior contrasinal" +msgstr "Contrasinal non válido" #. ~ DO NOT TRANSLATE THIS LITERALLY! #. This is a special string which needs to contain the translation's @@ -2322,46 +2306,48 @@ msgstr "O nome está en uso. Por favor, escolle outro nome" #: src/network/clientpackethandler.cpp msgid "Player name contains disallowed characters" -msgstr "" +msgstr "O nome do xogador contén caracteres non permitidos" #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Player name not allowed" -msgstr "Nome do xogador demasiado longo." +msgstr "Nome de xogador non permitido" #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Server shutting down" -msgstr "Cerrando..." +msgstr "O Servidor tase pechando" #: src/network/clientpackethandler.cpp msgid "" "The server has experienced an internal error. You will now be disconnected." -msgstr "" +msgstr "O servidor experimentou un erro interno. Agora será desconectado." #: src/network/clientpackethandler.cpp msgid "The server is running in singleplayer mode. You cannot connect." -msgstr "" +msgstr "O servidor está en modo un xogador. Non pode conectar." #: src/network/clientpackethandler.cpp msgid "Too many users" -msgstr "" +msgstr "Demasiados usuarios" #: src/network/clientpackethandler.cpp msgid "Unknown disconnect reason." -msgstr "" +msgstr "Razón da desconexión descoñecida." #: src/network/clientpackethandler.cpp msgid "" "Your client sent something the server didn't expect. Try reconnecting or " "updating your client." msgstr "" +"O seu cliente enviou algo que o servidor non esperaba. Tente volver " +"conectar ou actualizar o seu cliente." #: src/network/clientpackethandler.cpp msgid "" "Your client's version is not supported.\n" "Please contact the server administrator." msgstr "" +"A versión do seu cliente non é compatible.\n" +"Por favor, contacte co administrador do servidor." #: src/server.cpp #, c-format @@ -2660,11 +2646,11 @@ msgstr "Método de suavizado (antialiasing)" #: src/settings_translation_file.cpp msgid "Anticheat flags" -msgstr "" +msgstr "Bandeiras antitrampas" #: src/settings_translation_file.cpp msgid "Anticheat movement tolerance" -msgstr "" +msgstr "Tolerancia ao movemento antitrampas" #: src/settings_translation_file.cpp msgid "Append item name" @@ -2699,7 +2685,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Apply specular shading to nodes." -msgstr "" +msgstr "Aplique sombreado especular aos nodos." #: src/settings_translation_file.cpp msgid "Arm inertia" @@ -2819,9 +2805,8 @@ msgid "Biome noise" msgstr "Ruído de bioma" #: src/settings_translation_file.cpp -#, fuzzy msgid "Block bounds HUD radius" -msgstr "Lím. bloques" +msgstr "Raio de límites de bloques no HUD" #: src/settings_translation_file.cpp msgid "Block cull optimize distance" @@ -3036,7 +3021,6 @@ msgstr "" "Útil para probas. Vexa al_extensions.[h,cpp] para máis detalles." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Comma-separated list of flags to hide in the content repository.\n" "\"nonfree\" can be used to hide packages which do not qualify as 'free " @@ -3046,13 +3030,14 @@ msgid "" "These flags are independent from Luanti versions,\n" "so see a full list at https://content.minetest.net/help/content_flags/" msgstr "" -"Lista de marcas separadas por comas para ocultar no repositorio de contido.\n" -"\"Non libre\" pódese usar para ocultar paquetes que non sexan \"software " -"libre\",\n" -"segundo a definición da Free Software Foundation.\n" -"Tamén podes especificar clasificacións de contido.\n" -"Estas marcas son independentes das versións de Minetest,\n" -"así que consulta unha lista completa en https://content.minetest.net/help/" +"Lista de bandeiras separadas por comas que se ocultarán no repositorio de " +"contido.\n" +"\"nonfree\" pódese usar para ocultar paquetes que non cualifican como " +"'software libre',\n" +"tal como o define a Free Software Foundation.\n" +"Tamén podes especificar valoracións de contido.\n" +"Estas bandeiras son independentes das versións de Luanti,\n" +"así que consulta a lista completa en https://content.minetest.net/help/" "content_flags/" #: src/settings_translation_file.cpp @@ -3257,7 +3242,6 @@ msgstr "" "pero tamén consume máis recursos." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Define the oldest clients allowed to connect.\n" "Older clients are compatible in the sense that they will not crash when " @@ -3269,16 +3253,15 @@ msgid "" "Luanti still enforces its own internal minimum, and enabling\n" "strict_protocol_version_checking will effectively override this." msgstr "" -"Define os clientes máis antigos aos que se permite conectarse.\n" -"Os clientes máis antigos son compatibles no sentido de que non fallarán ao " -"conectarse\n" -"a novos servidores, pero é posible que non admitan todas as novas " -"características que esperas.\n" +"Define os clientes máis antigos permitidos para conectarse.\n" +"Os clientes máis antigos son compatibles no sentido de que non se bloquearán " +"ao conectarse\n" +"a servidores novos, pero poden non soportar todas as novas características " +"que esperas.\n" "Isto permite un control máis detallado que a verificación estrita da versión " "do protocolo.\n" -"Minetest segue aplicando o seu propio mínimo interno, e habilitar a\n" -"verificación estrita da versión do protocolo sobreporá efectivamente esta " -"configuración." +"Luanti sigue aplicando o seu mínimo interno, e habilitar\n" +"a verificación estrita da versión do protocolo anulará efectivamente isto." #: src/settings_translation_file.cpp msgid "Defines areas where trees have apples." @@ -3417,16 +3400,16 @@ msgid "Display Density Scaling Factor" msgstr "Factor de escala de densidade de exposición" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Distance in nodes at which transparency depth sorting is enabled.\n" "Use this to limit the performance impact of transparency depth sorting.\n" "Set to 0 to disable it entirely." msgstr "" -"Distancia en nodos á que se habilita a ordenación de profundidade de " -"transparencia\n" -"Usa isto para limitar o impacto no rendemento da ordenación de profundidade " -"de transparencia" +"Distancia en nodos na que se habilita a ordenación de profundidade da " +"translucidez.\n" +"Usa isto para limitar o impacto na rendibilidade da ordenación de " +"profundidade da translucidez.\n" +"Establece a 0 para deshabilitalo completamente." #: src/settings_translation_file.cpp msgid "Domain name of server, to be displayed in the serverlist." @@ -3457,9 +3440,8 @@ msgid "Dungeon noise" msgstr "Sonido de calabozos" #: src/settings_translation_file.cpp -#, fuzzy msgid "Effects" -msgstr "Efectos gráficos" +msgstr "Efectos" #: src/settings_translation_file.cpp msgid "Enable Automatic Exposure" @@ -3570,11 +3552,8 @@ msgid "Enable random user input (only used for testing)." msgstr "Activar a entrada de comandos aleatoria (só para tests)." #: src/settings_translation_file.cpp -#, fuzzy msgid "Enable smooth lighting with simple ambient occlusion." -msgstr "" -"Activar a iluminación suave con oclusión de ambiente simple.\n" -"Desactivar para velocidade ou vistas diferentes." +msgstr "Habilitar iluminación suave cunha oclusión ambiental simple." #: src/settings_translation_file.cpp msgid "Enable split login/register" @@ -3596,6 +3575,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Enable updates available indicator on content tab" msgstr "" +"Habilitar o indicador de actualizacións dispoñibles na lapela de contido" #: src/settings_translation_file.cpp msgid "" @@ -3644,11 +3624,12 @@ msgid "Enables animation of inventory items." msgstr "Activa a animación de obxectos no inventario." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Enables caching of facedir rotated meshes.\n" "This is only effective with shaders disabled." -msgstr "Activa o rexistro de mallas xiradas." +msgstr "" +"Habilita a caché de mallas rotadas por cara.\n" +"Isto só é efectivo cos sombreadores deshabilitados." #: src/settings_translation_file.cpp msgid "Enables debug and error-checking in the OpenGL driver." @@ -3656,9 +3637,8 @@ msgstr "" "Habilita a depuración e a verificación de erros no controlador de OpenGL." #: src/settings_translation_file.cpp -#, fuzzy msgid "Enables smooth scrolling." -msgstr "Habilitar o postprocesado" +msgstr "Habilita o desprazamento suave." #: src/settings_translation_file.cpp msgid "Enables the post processing pipeline." @@ -3671,6 +3651,11 @@ msgid "" "\"auto\" means that the touchscreen controls will be enabled and disabled\n" "automatically depending on the last used input method." msgstr "" +"Habilita os controis de pantalla táctil, permitindo que xogues ao xogo cunha " +"pantalla táctil.\n" +"\"auto\" significa que os controis de pantalla táctil serán habilitados e " +"deshabilitados\n" +"automaticamente, dependendo do último método de entrada utilizado." #: src/settings_translation_file.cpp msgid "" @@ -4254,6 +4239,9 @@ msgid "" "ContentDB to\n" "check for package updates when opening the mainmenu." msgstr "" +"Se está habilitado e ten instalados paquetes de ContentDB, Luanti pode " +"contactar con ContentDB para\n" +"comprobar se hai actualizacións de paquetes ao abrir o menú principal." #: src/settings_translation_file.cpp msgid "" @@ -4391,13 +4379,12 @@ msgid "Instrument chat commands on registration." msgstr "Instrumento de comandos do chat no rexistro." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Instrument global callback functions on registration.\n" "(anything you pass to a core.register_*() function)" msgstr "" -"Instrumentación das funcións de chamadas de retorno globais no rexistro.\n" -"(todo o que pasee a unha función minetest.register_*())" +"Instrumentar funcións de devolución de chamada globais ao rexistrarse.\n" +"(calquera cousa que pases a unha función core.register_*())" #: src/settings_translation_file.cpp msgid "" @@ -4603,21 +4590,18 @@ msgid "Leaves style" msgstr "Apariencia das follas" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Leaves style:\n" "- Fancy: all faces visible\n" "- Simple: only outer faces\n" "- Opaque: disable transparency" msgstr "" -"Apariencia das follas:\n" -"- Detalladas: todas as caras son visibles\n" -"- Simples: só vense as caras externas, cando se utilizan special_tiles " -"definidos\n" -"- Opacas: desactiva a transparencia" +"Estilo das follas:\n" +"- Elegante: todas as caras son visibles\n" +"- Simple: só as caras exteriores\n" +"- Opaco: desactiva a transparencia" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Length of a server tick (the interval at which everything is generally " "updated),\n" @@ -4626,10 +4610,13 @@ msgid "" "This is a lower bound, i.e. server steps may not be shorter than this, but\n" "they are often longer." msgstr "" -"Duración dun tick de servidor (o intervalo no que xeralmente se actualiza " -"todo),\n" -"indicado en segundos.\n" -"Non se aplica ás sesións aloxadas desde o menú do cliente." +"Lonxitude dun tick do servidor (o intervalo no que todo se actualiza en " +"xeral),\n" +"expresada en segundos.\n" +"Non se aplica a sesións hospedadas desde o menú do cliente.\n" +"Este é un límite inferior, é dicir, os pasos do servidor non poden ser máis " +"curtos que isto, pero\n" +"a miúdo son máis longos." #: src/settings_translation_file.cpp msgid "Length of liquid waves." @@ -4749,9 +4736,8 @@ msgid "Liquid queue purge time" msgstr "Tempo para eliminar filas de líquidos" #: src/settings_translation_file.cpp -#, fuzzy msgid "Liquid reflections" -msgstr "Fluidez dos líquidos" +msgstr "Reflexións de líquidos" #: src/settings_translation_file.cpp msgid "Liquid sinking" @@ -5093,6 +5079,10 @@ msgid "" "You generally don't need to change this, however busy servers may benefit " "from a higher number." msgstr "" +"Número máximo de paquetes enviados por cada paso de envío no código de redes " +"de baixo nivel.\n" +"Xeralmente, non é necesario cambiar isto; con todo, os servidores moi " +"ocupados poden beneficiarse dun número máis alto." #: src/settings_translation_file.cpp msgid "Maximum number of players that can be connected simultaneously." @@ -5327,7 +5317,7 @@ msgstr "Resaltado dos nós" #: src/settings_translation_file.cpp msgid "Node specular" -msgstr "" +msgstr "Nodo especular" #: src/settings_translation_file.cpp msgid "NodeTimer interval" @@ -5381,14 +5371,13 @@ msgid "Number of messages a player may send per 10 seconds." msgstr "Cantidade de mensaxes que un xogador pode enviar por cada 10 segundos." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Number of threads to use for mesh generation.\n" "Value of 0 (default) will let Luanti autodetect the number of available " "threads." msgstr "" -"Número de fíos a usar para xeración de mallas.\n" -"O valor 0 (predeterminado) permitirá a Minetest detectar automaticamente o " +"Número de fíos a utilizar para a xeración de mallas.\n" +"Un valor de 0 (por defecto) permitirá que Luanti detecte automaticamente o " "número de fíos dispoñibles." #: src/settings_translation_file.cpp @@ -5421,18 +5410,16 @@ msgid "OpenGL debug" msgstr "Depuración de OpenGL" #: src/settings_translation_file.cpp -#, fuzzy msgid "Optimize GUI for touchscreens" -msgstr "Usar retículo para pantalla táctil" +msgstr "Optimizar a GUI para pantallas táctiles" #: src/settings_translation_file.cpp msgid "Optional override for chat weblink color." msgstr "Substitución opcional da cor da ligazón web do chat." #: src/settings_translation_file.cpp -#, fuzzy msgid "Other Effects" -msgstr "Efectos gráficos" +msgstr "Outros efectos" #: src/settings_translation_file.cpp msgid "" @@ -5548,17 +5535,16 @@ msgid "Prometheus listener address" msgstr "Enderezo do Prometheus" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Prometheus listener address.\n" "If Luanti is compiled with ENABLE_PROMETHEUS option enabled,\n" "enable metrics listener for Prometheus on that address.\n" "Metrics can be fetched on http://127.0.0.1:30000/metrics" msgstr "" -"Enderezo do Prometheus.\n" -"Se Minetest se compila coa opción ENABLE_PROMETHEUS activada,\n" -"habilita a obteción de métricas para Prometheus nese enderezo.\n" -"As métricas pódense obter en http://127.0.0.1:30000/metrics" +"Enderezo do escoitador de Prometheus.\n" +"Se Luanti está compilado coa opción ENABLE_PROMETHEUS habilitada,\n" +"habilita a escoita de métricas para Prometheus nese enderezo.\n" +"As métricas poden ser obtidas en http://127.0.0.1:30000/metrics" #: src/settings_translation_file.cpp msgid "Proportion of large caves that contain liquid." @@ -5585,6 +5571,8 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Radius to use when the block bounds HUD feature is set to near blocks." msgstr "" +"Raio a utilizar cando a función de HUD de límites de bloques está " +"configurada para bloques próximos." #: src/settings_translation_file.cpp msgid "Raises terrain to make valleys around the rivers." @@ -5906,11 +5894,12 @@ msgid "" "Send names of online players to the serverlist. If disabled only the player " "count is revealed." msgstr "" +"Enviar os nomes dos xogadores en liña á lista de servidores. Se está " +"deshabilitado, só se revela o número de xogadores." #: src/settings_translation_file.cpp -#, fuzzy msgid "Send player names to the server list" -msgstr "Anuncar en esta lista de servidores." +msgstr "Enviar os nomes dos xogadores á lista de servidores" #: src/settings_translation_file.cpp msgid "Server" @@ -5938,6 +5927,9 @@ msgid "" "Flags are positive. Uncheck the flag to disable corresponding anticheat " "module." msgstr "" +"Configuración antitrampas do servidor.\n" +"As bandeiras son positivas. Desmarque a bandeira para deshabilitar o módulo " +"antitrampas correspondente." #: src/settings_translation_file.cpp msgid "Server description" @@ -6096,6 +6088,8 @@ msgid "" "Shaders are a fundamental part of rendering and enable advanced visual " "effects." msgstr "" +"Os sombreadores son unha parte fundamental do renderizado e permiten efectos " +"visuais avanzados." #: src/settings_translation_file.cpp msgid "Shadow filter quality" @@ -6166,7 +6160,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Simulate translucency when looking at foliage in the sunlight." -msgstr "" +msgstr "Simular a translucidez ao mirar a follaxe á luz do sol." #: src/settings_translation_file.cpp msgid "" @@ -6220,9 +6214,8 @@ msgid "Smooth lighting" msgstr "Iluminación suave" #: src/settings_translation_file.cpp -#, fuzzy msgid "Smooth scrolling" -msgstr "Iluminación suave" +msgstr "Desprazamento suave" #: src/settings_translation_file.cpp msgid "" @@ -6249,9 +6242,8 @@ msgid "Sneaking speed, in nodes per second." msgstr "Velocidade ao se agachar, en nós por segundo." #: src/settings_translation_file.cpp -#, fuzzy msgid "Soft clouds" -msgstr "Nubes 3D" +msgstr "Nubes suaves" #: src/settings_translation_file.cpp msgid "Soft shadow radius" @@ -6492,7 +6484,6 @@ msgstr "" "O camiño do ficheiro relativa ao camiño do mundo onde se gardarán os perfís." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "The gesture for punching players/entities.\n" "This can be overridden by games and mods.\n" @@ -6504,14 +6495,14 @@ msgid "" "Known from the classic Luanti mobile controls.\n" "Combat is more or less impossible." msgstr "" -"O xesto para golpear xogadores/entidades.\n" -"Isto pode ser anulado por xogos e modificacións.\n" +"A xesto para golpear xogadores/entidades.\n" +"Isto pode ser substituído por xogos e mods.\n" "\n" -"* toque_curto\n" -"Fácil de usar e coñecido doutros xogos que non deben ser nomeados.\n" +"* toque curto\n" +"Fácil de usar e ben coñecido doutros xogos que non se deben nomear.\n" "\n" -"* toque_longo\n" -"Coñecido polos controis móbiles clásicos de Minetest.\n" +"* toque longo\n" +"Coñecido polos controis móbiles clásicos en Luanti.\n" "O combate é máis ou menos imposible." #: src/settings_translation_file.cpp @@ -6577,16 +6568,14 @@ msgstr "" "Isto debería configurarse xunto con active_object_send_range_blocks." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "The rendering back-end.\n" "Note: A restart is required after changing this!\n" "OpenGL is the default for desktop, and OGLES2 for Android." msgstr "" "O backend de renderizado.\n" -"Nota: É preciso reiniciar despois de cambiar isto!\n" -"OpenGL é o predeterminado para escritorio, e OGLES2 para Android.\n" -"Os sombreadores son compatibles con todo menos con OGLES1." +"Nota: É necesario reiniciar despois de cambiar isto!\n" +"OpenGL é o predeterminado para escritorio, e OGLES2 para Android" #: src/settings_translation_file.cpp msgid "" @@ -6714,6 +6703,8 @@ msgid "" "Tolerance of movement cheat detector.\n" "Increase the value if players experience stuttery movement." msgstr "" +"Tolerancia do detector de trampas de movemento.\n" +"Aumenta o valor se os xogadores experimentan movementos entrecortados." #: src/settings_translation_file.cpp msgid "Tooltip delay" @@ -6724,9 +6715,8 @@ msgid "Touchscreen" msgstr "Pantalla táctil" #: src/settings_translation_file.cpp -#, fuzzy msgid "Touchscreen controls" -msgstr "Límite da pantalla táctil" +msgstr "Controis de pantalla táctil" #: src/settings_translation_file.cpp msgid "Touchscreen sensitivity" @@ -6741,9 +6731,8 @@ msgid "Tradeoffs for performance" msgstr "Compensacións para o rendemento" #: src/settings_translation_file.cpp -#, fuzzy msgid "Translucent foliage" -msgstr "Líquidos translúcidos" +msgstr "Follaxe translúcida" #: src/settings_translation_file.cpp msgid "Translucent liquids" @@ -6793,15 +6782,14 @@ msgstr "" "Esta configuración só debe ser cambiada se tes problemas de rendemento." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "URL to JSON file which provides information about the newest Luanti " "release.\n" "If this is empty the engine will never check for updates." msgstr "" -"Enderezo para ficheiro JSON que proporciona información sobre a versión máis " -"recente de Minetest\n" -"Se está baleiro, o motor nunca buscará actualizacións." +"URL do arquivo JSON que proporciona información sobre a versión máis nova de " +"Luanti.\n" +"Se isto está baleiro, o motor nunca comprobará se hai actualizacións." #: src/settings_translation_file.cpp msgid "URL to the server list displayed in the Multiplayer Tab." @@ -6897,7 +6885,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Use smooth cloud shading." -msgstr "" +msgstr "Usar sombreado suave das nubes." #: src/settings_translation_file.cpp msgid "" @@ -7105,13 +7093,16 @@ msgstr "Cor de ligazóns web" #: src/settings_translation_file.cpp msgid "When enabled, liquid reflections are simulated." -msgstr "" +msgstr "Unha vez habilitado, simúlase a reflexión de líquidos." #: src/settings_translation_file.cpp msgid "" "When enabled, the GUI is optimized to be more usable on touchscreens.\n" "Whether this is enabled by default depends on your hardware form-factor." msgstr "" +"Unha vez habilitado, a GUI está optimizada para ser máis sinxelo de usar en " +"pantallas táctiles.\n" +"Se isto está habilitado por defecto depende do formato do seu hardware." #: src/settings_translation_file.cpp msgid "" @@ -7233,15 +7224,14 @@ msgid "Window maximized" msgstr "Xanela maximizada" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Windows systems only: Start Luanti with the command line window in the " "background.\n" "Contains the same information as the file debug.txt (default name)." msgstr "" -"Só sistemas Windows: Inicia Minetest coa xanela da liña de comandos en " +"Só Sistemas Windows: Iniciar Luanti coa xanela da liña de comandos en " "segundo plano.\n" -"Contén a mesma información que o ficheiro debug.txt (nome por defecto)." +"Contén a mesma información co arquivo debug.txt (nome por defecto)." #: src/settings_translation_file.cpp msgid "" From cf76dac464708013233aa708e23461776c8945e5 Mon Sep 17 00:00:00 2001 From: Yof Date: Sun, 3 Nov 2024 17:28:05 +0000 Subject: [PATCH 030/136] Translated using Weblate (Ukrainian) Currently translated at 94.6% (1309 of 1383 strings) --- po/uk/luanti.po | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/po/uk/luanti.po b/po/uk/luanti.po index 972ccfc16..5a281c7ec 100644 --- a/po/uk/luanti.po +++ b/po/uk/luanti.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: Ukrainian (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-08-04 22:09+0000\n" +"PO-Revision-Date: 2024-11-04 01:00+0000\n" "Last-Translator: Yof \n" "Language-Team: Ukrainian \n" @@ -13,7 +13,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Weblate 5.7-dev\n" +"X-Generator: Weblate 5.8.2\n" #: builtin/client/chatcommands.lua msgid "Clear the out chat queue" @@ -160,7 +160,7 @@ msgstr "$1 завантажується..." #: builtin/mainmenu/content/dlg_contentdb.lua msgid "All" -msgstr "" +msgstr "Все" #: builtin/mainmenu/content/dlg_contentdb.lua #: builtin/mainmenu/content/dlg_package.lua @@ -169,9 +169,8 @@ msgid "Back" msgstr "Назад" #: builtin/mainmenu/content/dlg_contentdb.lua -#, fuzzy msgid "ContentDB is not available when Luanti was compiled without cURL" -msgstr "ContentDB недоступний, якщо Minetest було скомпільовано без cURL" +msgstr "ContentDB недоступний, якщо Luanti скомпільовано без cURL" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Downloading..." @@ -215,7 +214,6 @@ msgid "Queued" msgstr "У черзі" #: builtin/mainmenu/content/dlg_contentdb.lua -#, fuzzy msgid "Texture Packs" msgstr "Набори текстур" @@ -269,9 +267,8 @@ msgid "Dependencies:" msgstr "Залежності:" #: builtin/mainmenu/content/dlg_install.lua -#, fuzzy msgid "Error getting dependencies for package $1" -msgstr "Помилка при отриманні залежностей для пакунку" +msgstr "Помилка при отриманні залежностей для пакунку $1" #: builtin/mainmenu/content/dlg_install.lua msgid "Install" @@ -306,32 +303,28 @@ msgid "Overwrite" msgstr "Перезаписати" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "ContentDB page" -msgstr "Адреса ContentDB" +msgstr "Сторінка ContentDB" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Description" -msgstr "Опис сервера" +msgstr "Опис" #: builtin/mainmenu/content/dlg_package.lua msgid "Donate" -msgstr "" +msgstr "Пожертвувати" #: builtin/mainmenu/content/dlg_package.lua msgid "Forum Topic" -msgstr "" +msgstr "Тема на форумі" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Information" -msgstr "Інформація:" +msgstr "Інформація" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Install [$1]" -msgstr "Встановити $1" +msgstr "Встановити [$1]" #: builtin/mainmenu/content/dlg_package.lua msgid "Issue Tracker" @@ -944,7 +937,7 @@ msgstr "Загальне" #: builtin/mainmenu/settings/dlg_settings.lua msgid "Movement" -msgstr "Переміщення" +msgstr "Рух" #: builtin/mainmenu/settings/dlg_settings.lua msgid "Reset setting to default" From c2e89c5b6fd6961616ae11ae96190e7c95d89cb5 Mon Sep 17 00:00:00 2001 From: waxtatect Date: Wed, 6 Nov 2024 15:36:05 +0000 Subject: [PATCH 031/136] Translated using Weblate (French) Currently translated at 100.0% (1383 of 1383 strings) --- po/fr/luanti.po | 411 +++++++++++++++++++++++------------------------- 1 file changed, 201 insertions(+), 210 deletions(-) diff --git a/po/fr/luanti.po b/po/fr/luanti.po index 59c09ea79..ed71726ba 100644 --- a/po/fr/luanti.po +++ b/po/fr/luanti.po @@ -3,7 +3,7 @@ msgstr "" "Project-Id-Version: French (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-07-14 21:24+0000\n" +"PO-Revision-Date: 2024-11-06 18:04+0000\n" "Last-Translator: waxtatect \n" "Language-Team: French \n" @@ -12,7 +12,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 5.7-dev\n" +"X-Generator: Weblate 5.8.2\n" #: builtin/client/chatcommands.lua msgid "Clear the out chat queue" @@ -64,7 +64,7 @@ msgstr "Commande non disponible : " #: builtin/common/chatcommands.lua msgid "Get help for commands (-t: output in chat)" -msgstr "Obtenir de l'aide pour les commandes (-t : afficher dans le tchat)" +msgstr "Obtenir de l'aide pour les commandes (-t : afficher dans le tchat)" #: builtin/common/chatcommands.lua msgid "" @@ -103,7 +103,7 @@ msgstr "Se reconnecter" #: builtin/fstk/ui.lua msgid "The server has requested a reconnect:" -msgstr "Le serveur a demandé une reconnexion :" +msgstr "Le serveur a demandé une reconnexion :" #: builtin/mainmenu/common.lua msgid "Protocol version mismatch. " @@ -136,7 +136,7 @@ msgstr "Échec du téléchargement de « $1 »" #: builtin/mainmenu/content/contentdb.lua msgid "Failed to download $1" -msgstr "Échec du téléchargement de $1" +msgstr "Échec du téléchargement de « $1 »" #: builtin/mainmenu/content/contentdb.lua msgid "" @@ -160,7 +160,7 @@ msgstr "Téléchargement de $1…" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "All" -msgstr "" +msgstr "Tout" #: builtin/mainmenu/content/dlg_contentdb.lua #: builtin/mainmenu/content/dlg_package.lua @@ -169,9 +169,8 @@ msgid "Back" msgstr "Retour" #: builtin/mainmenu/content/dlg_contentdb.lua -#, fuzzy msgid "ContentDB is not available when Luanti was compiled without cURL" -msgstr "ContentDB n'est pas disponible quand Minetest est compilé sans cURL" +msgstr "ContentDB n'est pas disponible quand Luanti est compilé sans cURL" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Downloading..." @@ -179,7 +178,7 @@ msgstr "Téléchargement…" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Featured" -msgstr "" +msgstr "Mis en avant" #: builtin/mainmenu/content/dlg_contentdb.lua msgid "Games" @@ -215,7 +214,6 @@ msgid "Queued" msgstr "En attente" #: builtin/mainmenu/content/dlg_contentdb.lua -#, fuzzy msgid "Texture Packs" msgstr "Packs de textures" @@ -269,9 +267,8 @@ msgid "Dependencies:" msgstr "Dépend de :" #: builtin/mainmenu/content/dlg_install.lua -#, fuzzy msgid "Error getting dependencies for package $1" -msgstr "Erreur d'obtention des dépendances pour le paquet" +msgstr "Erreur d'obtention des dépendances pour le paquet « $1 »" #: builtin/mainmenu/content/dlg_install.lua msgid "Install" @@ -306,44 +303,40 @@ msgid "Overwrite" msgstr "Écraser" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "ContentDB page" -msgstr "URL de ContentDB" +msgstr "Page ContentDB" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Description" -msgstr "Description du serveur" +msgstr "Description" #: builtin/mainmenu/content/dlg_package.lua msgid "Donate" -msgstr "" +msgstr "Faire un don" #: builtin/mainmenu/content/dlg_package.lua msgid "Forum Topic" -msgstr "" +msgstr "Sujet du forum" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Information" -msgstr "Informations :" +msgstr "Informations" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Install [$1]" -msgstr "Installer $1" +msgstr "Installer [$1]" #: builtin/mainmenu/content/dlg_package.lua msgid "Issue Tracker" -msgstr "" +msgstr "Suivi des problèmes" #: builtin/mainmenu/content/dlg_package.lua msgid "Source" -msgstr "" +msgstr "Source" #: builtin/mainmenu/content/dlg_package.lua msgid "Translate" -msgstr "" +msgstr "Traduire" #: builtin/mainmenu/content/dlg_package.lua builtin/mainmenu/tab_content.lua msgid "Uninstall" @@ -354,13 +347,12 @@ msgid "Update" msgstr "Mettre à jour" #: builtin/mainmenu/content/dlg_package.lua -#, fuzzy msgid "Website" -msgstr "Visiter le site web" +msgstr "Site web" #: builtin/mainmenu/content/dlg_package.lua msgid "by $1 — $2 downloads — +$3 / $4 / -$5" -msgstr "" +msgstr "de $1 — $2 téléchargements — +$3 / $4 / -$5" #: builtin/mainmenu/content/pkgmgr.lua msgid "$1 (Enabled)" @@ -727,14 +719,13 @@ msgid "Dismiss" msgstr "Refuser" #: builtin/mainmenu/dlg_reinstall_mtg.lua -#, fuzzy msgid "" "For a long time, Luanti shipped with a default game called \"Minetest " "Game\". Since version 5.8.0, Luanti ships without a default game." msgstr "" -"Pendant longtemps, le moteur Minetest était livré avec un jeu par défaut " -"appelé « Minetest Game ». Depuis Minetest version 5.8.0, Minetest est livré " -"sans jeu par défaut." +"Pendant longtemps, Luanti était livré avec un jeu par défaut appelé « " +"Minetest Game ». Depuis la version 5.8.0, Luanti est livré sans jeu par " +"défaut." #: builtin/mainmenu/dlg_reinstall_mtg.lua msgid "" @@ -896,19 +887,16 @@ msgid "eased" msgstr "Lissé" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable automatic exposure as well)" -msgstr "(Le jeu doit également activer les ombres)" +msgstr "(Le jeu doit également activer l'exposition automatique)" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable bloom as well)" -msgstr "(Le jeu doit également activer les ombres)" +msgstr "(Le jeu doit également activer le flou lumineux)" #: builtin/mainmenu/settings/dlg_settings.lua -#, fuzzy msgid "(The game will need to enable volumetric lighting as well)" -msgstr "(Le jeu doit également activer les ombres)" +msgstr "(Le jeu doit également activer l'éclairage volumétrique)" #: builtin/mainmenu/settings/dlg_settings.lua msgid "(Use system language)" @@ -920,7 +908,7 @@ msgstr "Accessibilité" #: builtin/mainmenu/settings/dlg_settings.lua msgid "Auto" -msgstr "" +msgstr "Automatique" #: builtin/mainmenu/settings/dlg_settings.lua src/gui/guiKeyChangeMenu.cpp #: src/gui/touchcontrols.cpp src/settings_translation_file.cpp @@ -986,18 +974,16 @@ msgid "Content: Mods" msgstr "Contenu : Mods" #: builtin/mainmenu/settings/shader_warning_component.lua -#, fuzzy msgid "Enable" -msgstr "Activé" +msgstr "Activer" #: builtin/mainmenu/settings/shader_warning_component.lua -#, fuzzy msgid "Shaders are disabled." -msgstr "Mise à jour de la caméra désactivée" +msgstr "Les nuanceurs sont désactivés." #: builtin/mainmenu/settings/shader_warning_component.lua msgid "This is not a recommended configuration." -msgstr "" +msgstr "Cette configuration n'est pas recommandée." #: builtin/mainmenu/settings/shadows_component.lua msgid "(The game will need to enable shadows as well)" @@ -1158,17 +1144,15 @@ msgid "Install games from ContentDB" msgstr "Installer des jeux à partir de ContentDB" #: builtin/mainmenu/tab_local.lua -#, fuzzy msgid "Luanti doesn't come with a game by default." -msgstr "Minetest est livré sans jeu par défaut." +msgstr "Luanti est livré sans jeu par défaut." #: builtin/mainmenu/tab_local.lua -#, fuzzy msgid "" "Luanti is a game-creation platform that allows you to play many different " "games." msgstr "" -"Minetest est une plateforme de création avec laquelle découvrir de nombreux " +"Luanti est une plateforme de création avec laquelle découvrir de nombreux " "jeux différents." #: builtin/mainmenu/tab_local.lua @@ -1348,7 +1332,7 @@ msgstr "Une erreur de sérialisation est survenue :" #: src/client/game.cpp #, c-format msgid "Access denied. Reason: %s" -msgstr "Accès refusé. Raison : %s" +msgstr "Accès refusé. Raison : %s" #: src/client/game.cpp msgid "Automatic forward disabled" @@ -1409,11 +1393,11 @@ msgstr "Connexion au serveur…" #: src/client/game.cpp msgid "Connection error (timed out?)" -msgstr "Erreur de connexion (délai expiré ?)" +msgstr "Erreur de connexion (délai expiré ?)." #: src/client/game.cpp msgid "Connection failed for unknown reason" -msgstr "La connexion a échoué pour une raison inconnue" +msgstr "La connexion a échoué pour une raison inconnue." #: src/client/game.cpp msgid "Continue" @@ -1434,20 +1418,20 @@ msgid "" "- touch&drag, tap 2nd finger\n" " --> place single item to slot\n" msgstr "" -"Contrôles :\n" -"Sans menu ouvert :\n" -"– glissement du doigt : regarder autour\n" -"– appui : placer/frapper/utiliser (par défaut)\n" -"– appui long : creuser/utiliser (par défaut)\n" -"Menu/Inventaire ouvert :\n" -"– double-appui (en dehors) : fermer\n" -"– appui sur objets dans l'inventaire : déplacer\n" -"– appui, glissement et appui : pose d'un seul objet par emplacement\n" +"Contrôles :\n" +"Sans menu ouvert :\n" +"– glissement du doigt : regarder autour\n" +"– appui : placer/frapper/utiliser (par défaut)\n" +"– appui long : creuser/utiliser (par défaut)\n" +"Menu/Inventaire ouvert :\n" +"– double-appui (en dehors) : fermer\n" +"– appui sur objets dans l'inventaire : déplacer\n" +"– appui, glissement et appui : pose d'un seul objet par emplacement\n" #: src/client/game.cpp #, c-format msgid "Couldn't resolve address: %s" -msgstr "Impossible de résoudre l'adresse : %s" +msgstr "Impossible de résoudre l'adresse : %s." #: src/client/game.cpp msgid "Creating client..." @@ -1472,7 +1456,7 @@ msgstr "Informations de débogage, graphique du profileur et fils de fer cachés #: src/client/game.cpp #, c-format msgid "Error creating client: %s" -msgstr "Erreur de création du client : %s" +msgstr "Erreur de création du client : %s." #: src/client/game.cpp msgid "Exit to Menu" @@ -1636,7 +1620,7 @@ msgstr "Le serveur utilise probablement une version différente de %s." #: src/client/game.cpp #, c-format msgid "Unable to connect to %s because IPv6 is disabled" -msgstr "Impossible de se connecter à %s car IPv6 est désactivé" +msgstr "Impossible de se connecter à %s car IPv6 est désactivé." #: src/client/game.cpp #, c-format @@ -1751,7 +1735,7 @@ msgstr "Attente" #: src/client/keycode.cpp msgid "Caps Lock" -msgstr "Verr. Maj." +msgstr "Verr. maj." #: src/client/keycode.cpp msgid "Clear Key" @@ -2055,7 +2039,7 @@ msgid "" "Note: this may be caused by a dependency cycle, in which case try updating " "the mods." msgstr "" -"Note : cela peut être dû à un cycle de dépendances, dans ce cas essayer de " +"Note : ceci peut être dû à un cycle de dépendances, dans ce cas essayer de " "mettre à jour les mods." #: src/content/mod_configuration.cpp @@ -2272,37 +2256,38 @@ msgid "Sound Volume: %d%%" msgstr "Volume du son : %d %%" #: src/gui/touchcontrols.cpp -#, fuzzy msgid "Joystick" -msgstr "ID de manette" +msgstr "Manette" #: src/gui/touchcontrols.cpp msgid "Overflow menu" -msgstr "" +msgstr "Menu de débordement" #: src/gui/touchcontrols.cpp -#, fuzzy msgid "Toggle debug" -msgstr "Brouillard" +msgstr "Infos de débogage" #: src/network/clientpackethandler.cpp msgid "" "Another client is connected with this name. If your client closed " "unexpectedly, try again in a minute." msgstr "" +"Un autre client est connecté avec ce nom. Si votre client s'est fermé " +"inopinément, réessayer dans une minute." #: src/network/clientpackethandler.cpp msgid "Empty passwords are disallowed. Set a password and try again." msgstr "" +"Les mots de passe vides sont refusés. Définissez un mot de passe et " +"réessayez." #: src/network/clientpackethandler.cpp msgid "Internal server error" -msgstr "" +msgstr "Erreur interne du serveur." #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Invalid password" -msgstr "Ancien mot de passe" +msgstr "Mot de passe incorrect." #. ~ DO NOT TRANSLATE THIS LITERALLY! #. This is a special string which needs to contain the translation's @@ -2325,46 +2310,50 @@ msgstr "Le nom est pris. Veuillez choisir un autre nom." #: src/network/clientpackethandler.cpp msgid "Player name contains disallowed characters" -msgstr "" +msgstr "Le nom de joueur contient des caractères non autorisés." #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Player name not allowed" -msgstr "Nom du joueur trop long." +msgstr "Le nom de joueur est non autorisé." #: src/network/clientpackethandler.cpp -#, fuzzy msgid "Server shutting down" -msgstr "Fermeture du jeu…" +msgstr "Arrêt du serveur." #: src/network/clientpackethandler.cpp msgid "" "The server has experienced an internal error. You will now be disconnected." msgstr "" +"Le serveur a rencontré une erreur interne. Vous allez maintenant être " +"déconnecté." #: src/network/clientpackethandler.cpp msgid "The server is running in singleplayer mode. You cannot connect." -msgstr "" +msgstr "Le serveur fonctionne en mode solo. Vous ne pouvez pas vous connecter." #: src/network/clientpackethandler.cpp msgid "Too many users" -msgstr "" +msgstr "Trop de joueurs." #: src/network/clientpackethandler.cpp msgid "Unknown disconnect reason." -msgstr "" +msgstr "Raison de déconnexion inconnue." #: src/network/clientpackethandler.cpp msgid "" "Your client sent something the server didn't expect. Try reconnecting or " "updating your client." msgstr "" +"Votre client a envoyé quelque chose que le serveur n'attendait pas. Essayez " +"de vous reconnecter ou de mettre à jour votre client." #: src/network/clientpackethandler.cpp msgid "" "Your client's version is not supported.\n" "Please contact the server administrator." msgstr "" +"La version de votre client n'est pas prise en charge.\n" +"Veuillez contacter l'administrateur du serveur." #: src/server.cpp #, c-format @@ -2479,8 +2468,9 @@ msgid "" msgstr "" "Bruit 3D pour la structures des terrains flottants.\n" "Si la valeur par défaut est changée, le bruit « d'échelle » (0,7 par défaut) " -"peut demander à être ajustée. L'effilage des terrains flottants fonctionne " -"mieux quand le bruit a une valeur autour de -2,0 à 2,0." +"peut demander à être ajustée.\n" +"L'effilage des terrains flottants fonctionne mieux quand le bruit a une " +"valeur autour de -2,0 à 2,0." #: src/settings_translation_file.cpp msgid "3D noise defining structure of river canyon walls." @@ -2512,14 +2502,14 @@ msgid "" "Note that the interlaced mode requires shaders to be enabled." msgstr "" "Prise en charge de la 3D.\n" -"Actuellement disponible :\n" -"– aucun : pas de sortie 3D.\n" -"– anaglyphe : 3D en couleur cyan/magenta.\n" -"– entrelacé : prise en charge de l'écran avec polarisation basée sur les " +"Actuellement disponible :\n" +"– aucun : pas de sortie 3D.\n" +"– anaglyphe : 3D en couleur cyan/magenta.\n" +"– entrelacé : prise en charge de l'écran avec polarisation basée sur les " "lignes paires/impaires.\n" -"– haut-bas : partage haut et bas de l'écran.\n" -"– côte-à-côte : partage côte à côte de l'écran.\n" -"– vision croisée : vision croisée 3D.\n" +"– haut-bas : partage haut et bas de l'écran.\n" +"– côte-à-côte : partage côte à côte de l'écran.\n" +"– vision croisée : vision croisée 3D.\n" "Noter que le mode entrelacé nécessite que les nuanceurs soient activés." #: src/settings_translation_file.cpp @@ -2625,7 +2615,7 @@ msgstr "" "Des valeurs plus élevées rendent les niveaux de lumière moyens et inférieurs " "plus lumineux.\n" "La valeur « 1,0 » laisse la courbe de lumière intacte.\n" -"Cela a un effet significatif seulement sur la lumière du jour et la lumière " +"Ceci a un effet significatif seulement sur la lumière du jour et la lumière " "artificielle, et a très peu d'effet sur la lumière naturelle nocturne." #: src/settings_translation_file.cpp @@ -2662,11 +2652,11 @@ msgstr "Méthode de l'anticrénelage" #: src/settings_translation_file.cpp msgid "Anticheat flags" -msgstr "" +msgstr "Options anti-triche" #: src/settings_translation_file.cpp msgid "Anticheat movement tolerance" -msgstr "" +msgstr "Tolérance de mouvement anti-triche" #: src/settings_translation_file.cpp msgid "Append item name" @@ -2697,12 +2687,12 @@ msgstr "" "effectue un tramage supplémentaire ou si les canaux de couleur ne sont pas " "quantifiés à 8 bits.\n" "Avec OpenGL ES, le tramage fonctionne seulement si les nuanceurs prennent en " -"charge une précision élevée en virgule flottante et cela peut avoir un " +"charge une précision élevée en virgule flottante et ceci peut avoir un " "impact plus important sur les performances." #: src/settings_translation_file.cpp msgid "Apply specular shading to nodes." -msgstr "" +msgstr "Appliquer un ombrage spéculaire aux nœuds." #: src/settings_translation_file.cpp msgid "Arm inertia" @@ -2821,9 +2811,8 @@ msgid "Biome noise" msgstr "Bruit des biomes" #: src/settings_translation_file.cpp -#, fuzzy msgid "Block bounds HUD radius" -msgstr "Limites des blocs" +msgstr "Rayon de l'ATH des limites des blocs" #: src/settings_translation_file.cpp msgid "Block cull optimize distance" @@ -3040,7 +3029,6 @@ msgstr "" "Utile pour les tests. Voir « al_extensions.[h, cpp] » pour plus de détails." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Comma-separated list of flags to hide in the content repository.\n" "\"nonfree\" can be used to hide packages which do not qualify as 'free " @@ -3055,8 +3043,8 @@ msgstr "" "« nonfree » peut être utilisé pour cacher les paquets non libres, comme " "défini par la « Free Software Foundation ».\n" "Vous pouvez aussi spécifier des classifications de contenu.\n" -"Ces étiquettes sont indépendants des versions de Minetest, consulter la " -"liste complète à l'adresse https://content.minetest.net/help/content_flags/." +"Ces étiquettes sont indépendantes des versions de Luanti, consulter la liste " +"complète à l'adresse https://content.luanti.org/help/content_flags/." #: src/settings_translation_file.cpp msgid "" @@ -3257,12 +3245,11 @@ msgid "" "This simulates the soft shadows effect by applying a PCF or Poisson disk\n" "but also uses more resources." msgstr "" -"Définit la qualité du filtrage des ombres. Cela simule l'effet d'ombres " -"douces en appliquant un disque PCF ou Poisson mais utilise également plus de " -"ressources." +"Définir la qualité du filtrage des ombres.\n" +"Ceci simule l'effet d'ombres douces en appliquant un disque PCF ou Poisson " +"mais utilise également plus de ressources." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Define the oldest clients allowed to connect.\n" "Older clients are compatible in the sense that they will not crash when " @@ -3274,14 +3261,14 @@ msgid "" "Luanti still enforces its own internal minimum, and enabling\n" "strict_protocol_version_checking will effectively override this." msgstr "" -"Définit les clients les plus anciens autorisés à se connecter.\n" -"Les anciens clients sont compatibles dans le sens où ils ne s'interrompent " -"pas lors de la connexion aux serveurs récents,\n" +"Définir les clients les plus anciens autorisés à se connecter.\n" +"Les anciens clients sont compatibles dans le sens où ils ne plantent pas " +"lors de la connexion aux serveurs récents,\n" "mais ils peuvent ne pas prendre en charge certaines fonctionnalités.\n" -"Cela permet un contrôle plus précis que " -"« strict_protocol_version_checking ».\n" -"Minetest applique toujours son propre minimum interne, activer " -"« strict_protocol_version_checking » le remplace." +"Ceci permet un contrôle plus précis que « strict_protocol_version_checking »." +"\n" +"Luanti applique toujours son propre minimum interne, activer « " +"strict_protocol_version_checking » le remplace." #: src/settings_translation_file.cpp msgid "Defines areas where trees have apples." @@ -3325,8 +3312,7 @@ msgstr "Définit la profondeur des canaux de rivières." #: src/settings_translation_file.cpp msgid "Defines the maximal player transfer distance in blocks (0 = unlimited)." msgstr "" -"Détermine la distance maximale de transfert du joueur en blocs (0 = " -"illimité)." +"Définit la distance maximale de transfert du joueur en blocs (0 = illimité)." #: src/settings_translation_file.cpp msgid "" @@ -3421,7 +3407,6 @@ msgid "Display Density Scaling Factor" msgstr "Facteur d'échelle de la densité d'affichage" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Distance in nodes at which transparency depth sorting is enabled.\n" "Use this to limit the performance impact of transparency depth sorting.\n" @@ -3430,7 +3415,8 @@ msgstr "" "Distance en nœuds à laquelle le tri de profondeur de la transparence est " "activé.\n" "Utiliser cette option pour limiter l'impact sur les performances du tri de " -"profondeur de la transparence." +"profondeur de la transparence.\n" +"Définir à 0 pour désactiver complètement." #: src/settings_translation_file.cpp msgid "Domain name of server, to be displayed in the serverlist." @@ -3461,9 +3447,8 @@ msgid "Dungeon noise" msgstr "Bruit de donjons" #: src/settings_translation_file.cpp -#, fuzzy msgid "Effects" -msgstr "Effets graphiques" +msgstr "Effets" #: src/settings_translation_file.cpp msgid "Enable Automatic Exposure" @@ -3494,7 +3479,7 @@ msgid "" "Enable Lua modding support on client.\n" "This support is experimental and API can change." msgstr "" -"Active la prise en charge des mods Lua du client.\n" +"Activer la prise en charge des mods Lua du client.\n" "Cette option est expérimentale et l'API peut changer." #: src/settings_translation_file.cpp @@ -3503,7 +3488,7 @@ msgid "" "On true uses Poisson disk to make \"soft shadows\". Otherwise uses PCF " "filtering." msgstr "" -"Active le filtrage par disque de Poisson.\n" +"Activer le filtrage par disque de Poisson.\n" "Si activé, utilise le disque de Poisson pour créer des « ombres douces ». " "Sinon, utilise le filtrage PCF." @@ -3522,7 +3507,7 @@ msgid "" "automatically adjust to the brightness of the scene,\n" "simulating the behavior of human eye." msgstr "" -"Active la correction automatique de l'exposition, lorsque cette option est " +"Activer la correction automatique de l'exposition, lorsque cette option est " "activée,\n" "le moteur de post-traitement s'adapte automatiquement à la luminosité de la " "scène,\n" @@ -3533,7 +3518,7 @@ msgid "" "Enable colored shadows.\n" "On true translucent nodes cast colored shadows. This is expensive." msgstr "" -"Active les ombres colorées.\n" +"Activer les ombres colorées.\n" "Sur les nœuds vraiment transparents, projette des ombres colorées. Ceci est " "coûteux." @@ -3547,7 +3532,7 @@ msgstr "Activer les manettes" #: src/settings_translation_file.cpp msgid "Enable joysticks. Requires a restart to take effect" -msgstr "Active les manettes. Nécessite un redémarrage pour prendre effet." +msgstr "Activer les manettes. Nécessite un redémarrage pour prendre effet." #: src/settings_translation_file.cpp msgid "Enable mod channels support." @@ -3566,24 +3551,21 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Enable random mod loading (mainly used for testing)." msgstr "" -"Active le chargement aléatoire des mods (principalement utilisé pour les " +"Activer le chargement aléatoire des mods (principalement utilisé pour les " "tests)." #: src/settings_translation_file.cpp msgid "Enable random user input (only used for testing)." msgstr "" -"Active l'entrée aléatoire du joueur (seulement utilisé pour les tests)." +"Activer l'entrée aléatoire du joueur (seulement utilisé pour les tests)." #: src/settings_translation_file.cpp -#, fuzzy msgid "Enable smooth lighting with simple ambient occlusion." -msgstr "" -"Activer le lissage de l'éclairage avec une occlusion ambiante simple.\n" -"Désactiver pour davantage de performances ou pour un visuel différent." +msgstr "Activer le lissage de l'éclairage avec une occlusion ambiante simple." #: src/settings_translation_file.cpp msgid "Enable split login/register" -msgstr "Active la séparation de connexion/s'inscrire" +msgstr "Activer la séparation de connexion/s'inscrire" #: src/settings_translation_file.cpp msgid "" @@ -3594,13 +3576,14 @@ msgid "" "expecting." msgstr "" "Activer pour empêcher les anciens clients de se connecter.\n" -"Les anciens clients sont compatibles dans le sens où ils ne s'interrompent " -"pas lors de la connexion aux serveurs récents,\n" +"Les anciens clients sont compatibles dans le sens où ils ne plantent pas " +"lors de la connexion aux serveurs récents,\n" "mais ils peuvent ne pas prendre en charge certaines fonctionnalités." #: src/settings_translation_file.cpp msgid "Enable updates available indicator on content tab" msgstr "" +"Activer l'indicateur de disponibilité des mises à jour dans l'onglet contenu" #: src/settings_translation_file.cpp msgid "" @@ -3619,7 +3602,7 @@ msgid "" "Enable view bobbing and amount of view bobbing.\n" "For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double." msgstr "" -"Active le balancement de la vue et la quantité de balancement de la vue.\n" +"Activer le balancement de la vue et la quantité de balancement de la vue.\n" "Par exemple : 0 pour aucun balancement de la vue, 1 pour normal, 2 pour " "double." @@ -3629,7 +3612,7 @@ msgid "" "Ignored if bind_address is set.\n" "Needs enable_ipv6 to be enabled." msgstr "" -"Active/désactive l'usage d'un serveur IPv6.\n" +"Activer/désactiver l'usage d'un serveur IPv6.\n" "Ignoré si « bind_address » est activé.\n" "A besoin de « enable_ipv6 » pour être activé." @@ -3651,20 +3634,20 @@ msgid "Enables animation of inventory items." msgstr "Active l'animation des objets de l'inventaire." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Enables caching of facedir rotated meshes.\n" "This is only effective with shaders disabled." -msgstr "Active la mise en cache des mailles orientés « facedir »." +msgstr "" +"Active la mise en cache des mailles orientés « facedir ».\n" +"Ceci n'a d'effet que si les nuanceurs sont désactivées." #: src/settings_translation_file.cpp msgid "Enables debug and error-checking in the OpenGL driver." msgstr "Active le débogage et la vérification des erreurs du pilote OpenGL." #: src/settings_translation_file.cpp -#, fuzzy msgid "Enables smooth scrolling." -msgstr "Activer le post-traitement" +msgstr "Active le défilement doux." #: src/settings_translation_file.cpp msgid "Enables the post processing pipeline." @@ -3677,6 +3660,9 @@ msgid "" "\"auto\" means that the touchscreen controls will be enabled and disabled\n" "automatically depending on the last used input method." msgstr "" +"Active les contrôles de l'écran tactile.\n" +"« automatique » signifie que les contrôles de l'écran tactile sont activées " +"et désactivées automatiquement selon la dernière méthode de saisie utilisée." #: src/settings_translation_file.cpp msgid "" @@ -3900,7 +3886,7 @@ msgid "" "be\n" "sized 16, 32, 48, etc., so a mod requesting a size of 25 will get 32." msgstr "" -"Pour les polices de style pixel qui ne s'adaptent pas bien, cela garantit " +"Pour les polices de style pixel qui ne s'adaptent pas bien, ceci garantit " "que les tailles de police utilisées avec cette police sont toujours " "divisibles par cette valeur, en pixels.\n" "Par exemple une police de style pixel de 16 pixels de haut doit avoir cette " @@ -3979,7 +3965,7 @@ msgstr "" "Distance maximale à laquelle les clients ont connaissance des objets, " "établie en blocs de carte (16 nœuds).\n" "\n" -"Définir cela plus grand que « active_block_range », ainsi le serveur " +"Définir ceci plus grand que « active_block_range », ainsi le serveur " "maintient les objets actifs jusqu’à cette distance dans la direction où un " "joueur regarde (cela peut éviter que des mobs disparaissent soudainement de " "la vue)." @@ -4263,6 +4249,9 @@ msgid "" "ContentDB to\n" "check for package updates when opening the mainmenu." msgstr "" +"Si activé et que des paquets ContentDB sont installés, Luanti peut contacter " +"ContentDB pour vérifier les mises à jour des paquets lors de l'ouverture du " +"menu principal." #: src/settings_translation_file.cpp msgid "" @@ -4317,7 +4306,7 @@ msgid "" msgstr "" "Si activé, le serveur effectue la détermination des blocs de carte " "invisibles selon la position des yeux du joueur.\n" -"Cela peut réduire le nombre de blocs envoyés au client de 50 à 80 %.\n" +"Ceci peut réduire le nombre de blocs envoyés au client de 50 à 80 %.\n" "Les clients ne reçoivent plus la plupart des blocs invisibles, de sorte que " "l'utilité du mode sans collisions est réduite." @@ -4402,13 +4391,12 @@ msgid "Instrument chat commands on registration." msgstr "Instrumenter les commandes de tchat à l'enregistrement." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Instrument global callback functions on registration.\n" "(anything you pass to a core.register_*() function)" msgstr "" "Instrumenter les fonctions de rappel global à l'enregistrement (tout ce que " -"vous passez à une fonction « minetest.register_*() »)." +"vous passez à une fonction « core.register_*() »)." #: src/settings_translation_file.cpp msgid "" @@ -4617,7 +4605,6 @@ msgid "Leaves style" msgstr "Apparence des feuilles" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Leaves style:\n" "- Fancy: all faces visible\n" @@ -4626,12 +4613,10 @@ msgid "" msgstr "" "Apparence des feuilles :\n" "– détaillée : toutes les faces sont visibles\n" -"– simple : seulement les faces externes, si les « special_tiles » définies " -"sont utilisées\n" +"– simple : seulement les faces externes\n" "– opaque : désactive la transparence" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Length of a server tick (the interval at which everything is generally " "updated),\n" @@ -4642,7 +4627,9 @@ msgid "" msgstr "" "Durée d'intervalle serveur (intervalle auquel tout est généralement mis à " "jour), établie en secondes.\n" -"Ne s'applique pas aux sessions hébergées à partir du menu client." +"Ne s'applique pas aux sessions hébergées à partir du menu client.\n" +"Il s'agit d'une limite inférieure, c.-à-d. que les étapes du serveur ne " +"peuvent pas être plus courtes que cela, mais elles sont souvent plus longues." #: src/settings_translation_file.cpp msgid "Length of liquid waves." @@ -4740,7 +4727,7 @@ msgstr "" "– l'obtention de média si le serveur utilise le paramètre « remote_media ».\n" "– le téléchargement de la liste des serveurs et l'annonce du serveur.\n" "– les téléchargements effectués par le menu (ex. : gestionnaire de mods).\n" -"A un effet seulement si Minetest est compilé avec cURL." +"A un effet seulement si Luanti est compilé avec cURL." #: src/settings_translation_file.cpp msgid "Liquid fluidity" @@ -4759,9 +4746,8 @@ msgid "Liquid queue purge time" msgstr "Délai de nettoyage d'une file de liquide" #: src/settings_translation_file.cpp -#, fuzzy msgid "Liquid reflections" -msgstr "Fluidité des liquides" +msgstr "Réflexions des liquides" #: src/settings_translation_file.cpp msgid "Liquid sinking" @@ -4857,11 +4843,11 @@ msgid "" "'altitude_dry': Reduces humidity with altitude." msgstr "" "Attributs spécifiques au générateur de terrain vallées.\n" -"« altitude_chill » : réduit la chaleur avec l’altitude.\n" -"« humid_rivers » : augmente l’humidité autour des rivières.\n" -"« vary_river_dept » : si activé, une humidité faible et une chaleur élevée " +"« altitude_chill » : réduit la chaleur avec l’altitude.\n" +"« humid_rivers » : augmente l’humidité autour des rivières.\n" +"« vary_river_dept » : si activé, une humidité faible et une chaleur élevée " "rendent les rivières moins profondes et parfois sèches.\n" -"« altitude_dry » : réduit l’humidité avec l’altitude." +"« altitude_dry » : réduit l’humidité avec l’altitude." #: src/settings_translation_file.cpp msgid "Map generation attributes specific to Mapgen v5." @@ -4891,10 +4877,10 @@ msgid "" "'caverns': Giant caves deep underground." msgstr "" "Attributs spécifiques au générateur de terrain v7.\n" -"« montagnes » : montagnes.\n" -"« crêtes » : rivières.\n" -"« terrains flottants » : masses de terrains flottants dans l'atmosphère.\n" -"« cavernes » : cavernes immenses loin sous la surface." +"« montagnes » : montagnes.\n" +"« crêtes » : rivières.\n" +"« terrains flottants » : masses de terrains flottants dans l'atmosphère.\n" +"« cavernes » : cavernes immenses loin sous la surface." #: src/settings_translation_file.cpp msgid "Map generation limit" @@ -5107,6 +5093,10 @@ msgid "" "You generally don't need to change this, however busy servers may benefit " "from a higher number." msgstr "" +"Nombre maximal de paquets envoyés par étape d'envoi dans le code réseau de " +"bas niveau.\n" +"Il n'est généralement pas nécessaire de modifier ce nombre, mais les " +"serveurs très sollicités peuvent bénéficier d'un nombre plus élevé." #: src/settings_translation_file.cpp msgid "Maximum number of players that can be connected simultaneously." @@ -5282,7 +5272,7 @@ msgid "" "For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double." msgstr "" "Facteur de balancement de chute.\n" -"Par exemple : 0 pour aucun balancement de la vue, 1 pour normal, 2 pour " +"Par exemple : 0 pour aucun balancement de chute, 1 pour normal, 2 pour " "double." #: src/settings_translation_file.cpp @@ -5345,7 +5335,7 @@ msgstr "Surbrillance des blocs" #: src/settings_translation_file.cpp msgid "Node specular" -msgstr "" +msgstr "Nœud spéculaire" #: src/settings_translation_file.cpp msgid "NodeTimer interval" @@ -5403,14 +5393,13 @@ msgid "Number of messages a player may send per 10 seconds." msgstr "Nombre de messages qu'un joueur peut envoyer en 10 secondes." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Number of threads to use for mesh generation.\n" "Value of 0 (default) will let Luanti autodetect the number of available " "threads." msgstr "" "Nombre de fils à utiliser pour la génération du maillage.\n" -"La valeur 0 (par défaut) permet à Minetest de détecter automatiquement le " +"La valeur 0 (par défaut) permet à Luanti de détecter automatiquement le " "nombre de fils disponibles." #: src/settings_translation_file.cpp @@ -5441,18 +5430,16 @@ msgid "OpenGL debug" msgstr "Débogage OpenGL" #: src/settings_translation_file.cpp -#, fuzzy msgid "Optimize GUI for touchscreens" -msgstr "Utiliser le réticule" +msgstr "Optimiser l'interface graphique pour les écrans tactiles" #: src/settings_translation_file.cpp msgid "Optional override for chat weblink color." msgstr "Remplacement optionnel pour la couleur du lien web du tchat." #: src/settings_translation_file.cpp -#, fuzzy msgid "Other Effects" -msgstr "Effets graphiques" +msgstr "Autres effets" #: src/settings_translation_file.cpp msgid "" @@ -5540,7 +5527,7 @@ msgstr "" "des boutons de la souris.\n" "Activer cette option lorsque vous creusez ou placez trop souvent par " "accident.\n" -"Sur écrans tactiles, cela a un effet seulement pour creuser." +"Sur écrans tactiles, ceci a un effet seulement pour creuser." #: src/settings_translation_file.cpp msgid "Prevent mods from doing insecure things like running shell commands." @@ -5572,7 +5559,6 @@ msgid "Prometheus listener address" msgstr "Adresse d'écoute pour Prometheus" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Prometheus listener address.\n" "If Luanti is compiled with ENABLE_PROMETHEUS option enabled,\n" @@ -5580,7 +5566,7 @@ msgid "" "Metrics can be fetched on http://127.0.0.1:30000/metrics" msgstr "" "Adresse d'écoute pour Prometheus.\n" -"Lorsque Minetest est compilé avec l'option « ENABLE_PROMETHEUS », cette " +"Lorsque Luanti est compilé avec l'option « ENABLE_PROMETHEUS », cette " "adresse est utilisée pour l'écoute de données pour Prometheus.\n" "Les métriques peuvent être récupérées sur http://127.0.0.1:30000/metrics." @@ -5609,6 +5595,8 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Radius to use when the block bounds HUD feature is set to near blocks." msgstr "" +"Rayon utilisé lorsque l'ATH des limites des blocs est défini sur les blocs " +"voisins." #: src/settings_translation_file.cpp msgid "Raises terrain to make valleys around the rivers." @@ -5670,13 +5658,13 @@ msgid "" msgstr "" "Limite l'accès de certaines fonctions côté client sur les serveurs.\n" "Combiner les « byteflags » ci dessous pour restreindre les fonctionnalités " -"client, ou mettre 0 pour laisser sans restriction :\n" +"client, ou définir à 0 pour laisser sans restriction :\n" "LOAD_CLIENT_MODS : 1 (désactive le chargement des mods client)\n" "CHAT_MESSAGES : 2 (désactive l'appel « send_chat_message » côté client)\n" "READ_ITEMDEFS : 4 (désactive l'appel « get_item_def » côté client)\n" "READ_NODEDEFS : 8 (désactive l'appel « get_node_def » côté client)\n" -"LOOKUP_NODES_LIMIT : 16 (limite l'appel « get_node » côté client à " -"« csm_restriction_noderange »)\n" +"LOOKUP_NODES_LIMIT : 16 (limite l'appel « get_node » côté client à « " +"csm_restriction_noderange »)\n" "READ_PLAYERINFO : 32 (désactive l'appel « get_player_names » côté client)" #: src/settings_translation_file.cpp @@ -5772,9 +5760,9 @@ msgid "" "edge pixels when images are scaled by non-integer sizes." msgstr "" "Met à l'échelle l'interface graphique par une valeur spécifiée par " -"l'utilisateur, à l'aide d'un filtre au plus proche voisin avec " -"anticrénelage.\n" -"Cela lisse certains bords grossiers, et mélange les pixels en réduisant " +"l'utilisateur, à l'aide d'un filtre au plus proche voisin avec anticrénelage." +"\n" +"Ceci lisse certains bords grossiers, et mélange les pixels en réduisant " "l'échelle.\n" "Au détriment d'un effet de flou sur des pixels en bordure quand les images " "sont mises à l'échelle par des valeurs fractionnelles." @@ -5933,11 +5921,12 @@ msgid "" "Send names of online players to the serverlist. If disabled only the player " "count is revealed." msgstr "" +"Envoyer les noms des joueurs en ligne à la liste des serveurs. Si désactivé, " +"seul le nombre de joueurs est affiché." #: src/settings_translation_file.cpp -#, fuzzy msgid "Send player names to the server list" -msgstr "Annoncer à cette liste de serveurs." +msgstr "Envoyer les noms des joueurs à la liste des serveurs" #: src/settings_translation_file.cpp msgid "Server" @@ -5965,6 +5954,9 @@ msgid "" "Flags are positive. Uncheck the flag to disable corresponding anticheat " "module." msgstr "" +"Configuration anti-triche du serveur.\n" +"Les options sont positives. Décocher l'option pour désactiver le module anti-" +"triche correspondant." #: src/settings_translation_file.cpp msgid "Server description" @@ -6014,7 +6006,7 @@ msgid "" "Value of 0.0 (default) means no exposure compensation.\n" "Range: from -1 to 1.0" msgstr "" -"Définit la compensation de l'exposition en unités EV.\n" +"Définir la compensation de l'exposition en unités EV.\n" "La valeur de 0,0 (par défaut) signifie qu'il n'y a pas de compensation " "d'exposition.\n" "Plage : de -1 à 1,0" @@ -6058,31 +6050,31 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Set to true to enable Shadow Mapping." -msgstr "Active le mappage des ombres." +msgstr "Activer le mappage des ombres." #: src/settings_translation_file.cpp msgid "" "Set to true to enable bloom effect.\n" "Bright colors will bleed over the neighboring objects." msgstr "" -"Active le flou lumineux.\n" +"Activer le flou lumineux.\n" "Les couleurs vives débordent sur les objets voisins." #: src/settings_translation_file.cpp msgid "Set to true to enable volumetric lighting effect (a.k.a. \"Godrays\")." -msgstr "Active l'éclairage volumétrique (parfois appelé « rayons de Dieu »)." +msgstr "Activer l'éclairage volumétrique (parfois appelé « rayons de Dieu »)." #: src/settings_translation_file.cpp msgid "Set to true to enable waving leaves." -msgstr "Active l'ondulation des feuilles." +msgstr "Activer l'ondulation des feuilles." #: src/settings_translation_file.cpp msgid "Set to true to enable waving liquids (like water)." -msgstr "Active l'ondulation des liquides (comme l'eau)." +msgstr "Activer l'ondulation des liquides (comme l'eau)." #: src/settings_translation_file.cpp msgid "Set to true to enable waving plants." -msgstr "Active l'ondulation des plantes." +msgstr "Activer l'ondulation des plantes." #: src/settings_translation_file.cpp msgid "" @@ -6091,7 +6083,7 @@ msgid "" "top-left - processed base image, top-right - final image\n" "bottom-left - raw base image, bottom-right - bloom texture." msgstr "" -"Restitue la partition de débogage du flou lumineux.\n" +"Restituer la partition de débogage du flou lumineux.\n" "En mode débogage, l'écran est divisé en 4 quadrants :\n" "en haut à gauche – image de base traitée, en haut à droite – image finale\n" "en bas à gauche – image de base brute, en bas à droite – texture de l'effet " @@ -6105,7 +6097,7 @@ msgid "" msgstr "" "Définit la qualité de la texture de l'ombre sur 32 bits.\n" "Si désactivé, une texture de 16 bits est utilisée.\n" -"Cela peut causer beaucoup plus d'artefacts sur l'ombre." +"Ceci peut causer beaucoup plus d'artefacts sur l'ombre." #: src/settings_translation_file.cpp msgid "Shader path" @@ -6120,6 +6112,8 @@ msgid "" "Shaders are a fundamental part of rendering and enable advanced visual " "effects." msgstr "" +"Les nuanceurs sont un élément fondamental du rendu et permettent des effets " +"visuels avancés." #: src/settings_translation_file.cpp msgid "Shadow filter quality" @@ -6192,7 +6186,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Simulate translucency when looking at foliage in the sunlight." -msgstr "" +msgstr "Simuler la translucidité en regardant le feuillage au soleil." #: src/settings_translation_file.cpp msgid "" @@ -6249,9 +6243,8 @@ msgid "Smooth lighting" msgstr "Lissage de l'éclairage" #: src/settings_translation_file.cpp -#, fuzzy msgid "Smooth scrolling" -msgstr "Lissage de l'éclairage" +msgstr "Défilement doux" #: src/settings_translation_file.cpp msgid "" @@ -6278,9 +6271,8 @@ msgid "Sneaking speed, in nodes per second." msgstr "Vitesse de déplacement lent, en nœuds par seconde." #: src/settings_translation_file.cpp -#, fuzzy msgid "Soft clouds" -msgstr "Nuages 3D" +msgstr "Nuages doux" #: src/settings_translation_file.cpp msgid "Soft shadow radius" @@ -6520,7 +6512,6 @@ msgstr "" "sauvegardés." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "The gesture for punching players/entities.\n" "This can be overridden by games and mods.\n" @@ -6539,7 +6530,7 @@ msgstr "" "Facile à utiliser et bien connu dans d'autres jeux.\n" "\n" "* appui long\n" -"Connu des contrôles classiques de Minetest mobile.\n" +"Connu des contrôles classiques de Luanti mobile.\n" "Le combat est plus ou moins impossible." #: src/settings_translation_file.cpp @@ -6571,7 +6562,7 @@ msgid "" "the dig button." msgstr "" "Durée minimale en secondes entre le minage de blocs lors du maintien du " -"bouton ceuser." +"bouton creuser." #: src/settings_translation_file.cpp msgid "The network interface that the server listens on." @@ -6604,17 +6595,15 @@ msgstr "" "Ceci doit être configuré avec « active_object_send_range_blocks »." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "The rendering back-end.\n" "Note: A restart is required after changing this!\n" "OpenGL is the default for desktop, and OGLES2 for Android." msgstr "" "Le moteur de rendu.\n" -"Remarque : un redémarrage est nécessaire après cette modification !\n" +"Remarque : un redémarrage est nécessaire après cette modification !\n" "OpenGL est la valeur par défaut pour les ordinateurs de bureau et OGLES2 " -"pour Android.\n" -"Les nuanceurs sont pris en charge par tout sauf OGLES1." +"pour Android." #: src/settings_translation_file.cpp msgid "" @@ -6735,7 +6724,7 @@ msgid "" msgstr "" "Pour réduire le décalage, le transfert des blocs est ralenti quand un joueur " "construit quelque chose.\n" -"Cela détermine la durée du ralentissement après placement ou destruction " +"Ceci détermine la durée du ralentissement après placement ou destruction " "d'un nœud." #: src/settings_translation_file.cpp @@ -6743,6 +6732,8 @@ msgid "" "Tolerance of movement cheat detector.\n" "Increase the value if players experience stuttery movement." msgstr "" +"Tolérance du détecteur de triche de mouvement.\n" +"Augmenter la valeur si les joueurs ont des mouvements saccadés." #: src/settings_translation_file.cpp msgid "Tooltip delay" @@ -6753,9 +6744,8 @@ msgid "Touchscreen" msgstr "Écran tactile" #: src/settings_translation_file.cpp -#, fuzzy msgid "Touchscreen controls" -msgstr "Sensibilité de l'écran tactile" +msgstr "Contrôles de l'écran tactile" #: src/settings_translation_file.cpp msgid "Touchscreen sensitivity" @@ -6770,9 +6760,8 @@ msgid "Tradeoffs for performance" msgstr "Compromis pour la performance" #: src/settings_translation_file.cpp -#, fuzzy msgid "Translucent foliage" -msgstr "Liquides translucides" +msgstr "Feuillage translucide" #: src/settings_translation_file.cpp msgid "Translucent liquids" @@ -6825,14 +6814,13 @@ msgstr "" "performance." #: src/settings_translation_file.cpp -#, fuzzy msgid "" "URL to JSON file which provides information about the newest Luanti " "release.\n" "If this is empty the engine will never check for updates." msgstr "" "URL du fichier JSON qui fournit des informations sur la nouvelle version de " -"Minetest.\n" +"Luanti.\n" "Si ce champ est vide, le moteur ne vérifie pas les mises à jour." #: src/settings_translation_file.cpp @@ -6855,7 +6843,7 @@ msgstr "" "Le sous-échantillonnage ressemble à l'utilisation d'une résolution d'écran " "inférieure.\n" "Il ne s'applique qu'au rendu 3D, gardant l'interface graphique intacte.\n" -"Cela doit donner un bonus de performance conséquent, au détriment de la " +"Ceci doit donner un bonus de performance conséquent, au détriment de la " "qualité d'image.\n" "Les valeurs plus élevées réduisent la qualité du détail des images." @@ -6936,7 +6924,7 @@ msgstr "" #: src/settings_translation_file.cpp msgid "Use smooth cloud shading." -msgstr "" +msgstr "Utiliser un ombrage doux pour les nuages." #: src/settings_translation_file.cpp msgid "" @@ -7145,12 +7133,16 @@ msgstr "Couleur du lien web" #: src/settings_translation_file.cpp msgid "When enabled, liquid reflections are simulated." msgstr "" +"Lorsque cette option est activée, les réflexions des liquides sont simulées." #: src/settings_translation_file.cpp msgid "" "When enabled, the GUI is optimized to be more usable on touchscreens.\n" "Whether this is enabled by default depends on your hardware form-factor." msgstr "" +"Lorsque cette option est activée, l'interface graphique est optimisée pour " +"les écrans tactiles.\n" +"L'activation par défaut dépend des caractéristiques matérielles." #: src/settings_translation_file.cpp msgid "" @@ -7229,7 +7221,7 @@ msgid "" "Whether to ask clients to reconnect after a (Lua) crash.\n" "Set this to true if your server is set up to restart automatically." msgstr "" -"S’il faut demander aux clients de se reconnecter après un crash (Lua).\n" +"S’il faut demander aux clients de se reconnecter après un plantage (Lua).\n" "Activer si le serveur est paramétré pour redémarrer automatiquement." #: src/settings_translation_file.cpp @@ -7268,13 +7260,12 @@ msgid "Window maximized" msgstr "Fenêtre maximisée" #: src/settings_translation_file.cpp -#, fuzzy msgid "" "Windows systems only: Start Luanti with the command line window in the " "background.\n" "Contains the same information as the file debug.txt (default name)." msgstr "" -"Systèmes Windows seulement : démarrer Minetest avec la fenêtre de ligne de " +"Systèmes Windows seulement : démarrer Luanti avec la fenêtre de ligne de " "commande en arrière-plan.\n" "Contient les mêmes informations que le fichier « debug.txt » (nom par " "défaut)." From 21c8c141aa8eb26a465923243123efa9b6332e2c Mon Sep 17 00:00:00 2001 From: chocomint Date: Sat, 9 Nov 2024 00:34:52 +0100 Subject: [PATCH 032/136] Added translation using Weblate (Spanish) --- android/app/src/main/res/values-es/strings.xml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 android/app/src/main/res/values-es/strings.xml diff --git a/android/app/src/main/res/values-es/strings.xml b/android/app/src/main/res/values-es/strings.xml new file mode 100644 index 000000000..a6b3daec9 --- /dev/null +++ b/android/app/src/main/res/values-es/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From 9a7471c5c0094d8b4d02b75820f2eedccba34ef1 Mon Sep 17 00:00:00 2001 From: chocomint Date: Fri, 8 Nov 2024 23:48:23 +0000 Subject: [PATCH 033/136] Translated using Weblate (Spanish) Currently translated at 100.0% (1383 of 1383 strings) --- android/app/src/main/res/values-es/strings.xml | 11 ++++++++++- po/es/luanti.po | 15 +++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/android/app/src/main/res/values-es/strings.xml b/android/app/src/main/res/values-es/strings.xml index a6b3daec9..c878f0304 100644 --- a/android/app/src/main/res/values-es/strings.xml +++ b/android/app/src/main/res/values-es/strings.xml @@ -1,2 +1,11 @@ - \ No newline at end of file + + No se encontró ningún navegador web + Cargando… + Notificaciones de Luanti + Menos de 1 minuto… + Hecho + Luanti + Cargando Luanti + Notificación General + \ No newline at end of file diff --git a/po/es/luanti.po b/po/es/luanti.po index 91b10e486..07fcbd4f0 100644 --- a/po/es/luanti.po +++ b/po/es/luanti.po @@ -3,8 +3,8 @@ msgstr "" "Project-Id-Version: Spanish (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-11-02 23:00+0000\n" -"Last-Translator: gallegonovato \n" +"PO-Revision-Date: 2024-11-08 23:53+0000\n" +"Last-Translator: chocomint \n" "Language-Team: Spanish \n" "Language: es\n" @@ -3270,15 +3270,14 @@ msgid "" "Luanti still enforces its own internal minimum, and enabling\n" "strict_protocol_version_checking will effectively override this." msgstr "" -"Define los clientes más antiguos permitidos para conectarse.\n" +"Define los clientes más antiguos permitidos a conectarse.\n" "Los clientes más antiguos son compatibles en el sentido de que no se " "bloquearán al conectarse\n" "a nuevos servidores, pero pueden no soportar todas las nuevas " "características que esperas.\n" -"Esto permite un control más detallado que la verificación estricta de la " -"versión del protocolo.\n" -"Luanti aún aplica su propio mínimo interno, y habilitar la verificación " -"estricta de la versión del protocolo anulará efectivamente esto." +"Esto permite un control más detallado del strict_protocol_version_checking.\n" +"Luanti aún aplica su propio mínimo interno, y habilitar\n" +"strict_protocol_version_checking anulará efectivamente esto." #: src/settings_translation_file.cpp msgid "Defines areas where trees have apples." @@ -6641,7 +6640,7 @@ msgid "" "in-game view frustum around." msgstr "" "La sensibilidad de los ejes del joystick para mover el\n" -"en el juego." +"frustum de vista en el juego." #: src/settings_translation_file.cpp msgid "" From 998d1a2b8c7807e7a497b6b836fe57d1421a1055 Mon Sep 17 00:00:00 2001 From: gallegonovato Date: Sat, 9 Nov 2024 01:40:59 +0000 Subject: [PATCH 034/136] Translated using Weblate (Spanish) Currently translated at 100.0% (1383 of 1383 strings) --- po/es/luanti.po | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/po/es/luanti.po b/po/es/luanti.po index 07fcbd4f0..52fe9aaaf 100644 --- a/po/es/luanti.po +++ b/po/es/luanti.po @@ -3,8 +3,8 @@ msgstr "" "Project-Id-Version: Spanish (Minetest)\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-10-28 19:57+0100\n" -"PO-Revision-Date: 2024-11-08 23:53+0000\n" -"Last-Translator: chocomint \n" +"PO-Revision-Date: 2024-11-10 00:00+0000\n" +"Last-Translator: gallegonovato \n" "Language-Team: Spanish \n" "Language: es\n" @@ -6639,8 +6639,8 @@ msgid "" "The sensitivity of the joystick axes for moving the\n" "in-game view frustum around." msgstr "" -"La sensibilidad de los ejes del joystick para mover el\n" -"frustum de vista en el juego." +"La sensibilidad de los ejes del joystick para mover la\n" +"vista del juego." #: src/settings_translation_file.cpp msgid "" From 3b2abbea70a1a1a4beb36931c6d48761257f6295 Mon Sep 17 00:00:00 2001 From: chocomint Date: Sat, 9 Nov 2024 00:54:10 +0100 Subject: [PATCH 035/136] Added translation using Weblate (Spanish (American)) --- android/app/src/main/res/values-es-rUS/strings.xml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 android/app/src/main/res/values-es-rUS/strings.xml diff --git a/android/app/src/main/res/values-es-rUS/strings.xml b/android/app/src/main/res/values-es-rUS/strings.xml new file mode 100644 index 000000000..a6b3daec9 --- /dev/null +++ b/android/app/src/main/res/values-es-rUS/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From fbab80fced1aa7d0c9b41a31d2e4deaef7469c17 Mon Sep 17 00:00:00 2001 From: chocomint Date: Fri, 8 Nov 2024 23:58:11 +0000 Subject: [PATCH 036/136] Translated using Weblate (Spanish (American)) Currently translated at 100.0% (8 of 8 strings) Translation: Minetest/Minetest Android Translate-URL: https://hosted.weblate.org/projects/minetest/minetest-android/es_US/ --- .../src/main/res/values-es-rUS/strings.xml | 11 +- po/es_US/luanti.po | 6465 +++++++++++++++++ 2 files changed, 6475 insertions(+), 1 deletion(-) create mode 100644 po/es_US/luanti.po diff --git a/android/app/src/main/res/values-es-rUS/strings.xml b/android/app/src/main/res/values-es-rUS/strings.xml index a6b3daec9..9be855811 100644 --- a/android/app/src/main/res/values-es-rUS/strings.xml +++ b/android/app/src/main/res/values-es-rUS/strings.xml @@ -1,2 +1,11 @@ - \ No newline at end of file + + Menos de 1 minuto… + Hecho + No se encontró ningún navegador web + Cargando… + Notificación General + Luanti + Notificaciones de Luanti + Cargando Luanti + \ No newline at end of file diff --git a/po/es_US/luanti.po b/po/es_US/luanti.po new file mode 100644 index 000000000..0d8500e7e --- /dev/null +++ b/po/es_US/luanti.po @@ -0,0 +1,6465 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the luanti package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: luanti\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-10-28 19:57+0100\n" +"PO-Revision-Date: 2024-11-10 17:11+0000\n" +"Last-Translator: chocomint \n" +"Language-Team: Spanish (American) \n" +"Language: es_US\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.8.2\n" + +#: builtin/client/chatcommands.lua +msgid "Issued command: " +msgstr "Comando emitido: " + +#: builtin/client/chatcommands.lua +msgid "Empty command." +msgstr "Comando vacío." + +#: builtin/client/chatcommands.lua +msgid "Invalid command: " +msgstr "Comando inválido: " + +#: builtin/client/chatcommands.lua +msgid "List online players" +msgstr "Lista de los jugadores conectados" + +#: builtin/client/chatcommands.lua +msgid "This command is disabled by server." +msgstr "Este comando esta deshabiitado por el servidor." + +#: builtin/client/chatcommands.lua +msgid "Online players: " +msgstr "Jugadores en línea: " + +#: builtin/client/chatcommands.lua +msgid "Exit to main menu" +msgstr "Salir al menu principal" + +#: builtin/client/chatcommands.lua +msgid "Clear the out chat queue" +msgstr "Limpiar la cola de chat" + +#: builtin/client/chatcommands.lua +msgid "The out chat queue is now empty." +msgstr "La cola de chat está ahora vacía." + +#: builtin/common/chatcommands.lua +msgid "Available commands: " +msgstr "Comandos disponibles: " + +#: builtin/common/chatcommands.lua +msgid "" +"Use '.help ' to get more information, or '.help all' to list everything." +msgstr "" +"Usa '.help ' para obtener más información, o '.help all' para enlistar " +"todo." + +#: builtin/common/chatcommands.lua +msgid "Available commands:" +msgstr "Comandos disponibles:" + +#: builtin/common/chatcommands.lua +msgid "Command not available: " +msgstr "Comando no disponible: " + +#: builtin/common/chatcommands.lua +msgid "[all | ] [-t]" +msgstr "[all | ] [-t]" + +#: builtin/common/chatcommands.lua +msgid "Get help for commands (-t: output in chat)" +msgstr "Obtén ayuda para comandos (-t: salida en el chat)" + +#: builtin/fstk/ui.lua +msgid "OK" +msgstr "OK" + +#: builtin/fstk/ui.lua +msgid "" +msgstr "" + +#: builtin/fstk/ui.lua +msgid "The server has requested a reconnect:" +msgstr "El servidor ha solicitado una reconexión:" + +#: builtin/fstk/ui.lua +msgid "Reconnect" +msgstr "Reconectar" + +#: builtin/fstk/ui.lua +msgid "Main menu" +msgstr "Menu principal" + +#: builtin/fstk/ui.lua +msgid "An error occurred in a Lua script:" +msgstr "Ocurrió un error en un script de Lua:" + +#: builtin/fstk/ui.lua +msgid "An error occurred:" +msgstr "Un error ha ocurrido:" + +#: builtin/mainmenu/common.lua +msgid "Server supports protocol versions between $1 and $2. " +msgstr "El servidor admite versiones de protocolo entre $1 y $2. " + +#: builtin/mainmenu/common.lua +msgid "Server enforces protocol version $1. " +msgstr "El servidor impone la versión del protocolo $1. " + +#: builtin/mainmenu/common.lua +msgid "We support protocol versions between version $1 and $2." +msgstr "" +"Apoyamos las versiones de protocolo entre la versión $1 y la versión $2." + +#: builtin/mainmenu/common.lua +msgid "We only support protocol version $1." +msgstr "Solo soportamos la versión de protocolo $1." + +#: builtin/mainmenu/common.lua +msgid "Protocol version mismatch. " +msgstr "Desajuste de versión del protocolo. " + +#: builtin/mainmenu/content/contentdb.lua +msgid "Failed to download \"$1\"" +msgstr "Error al descargar \"$1\"" + +#: builtin/mainmenu/content/contentdb.lua +msgid "" +"Failed to extract \"$1\" (insufficient disk space, unsupported file type or " +"broken archive)" +msgstr "" +"Error al extraer \"$1\" (espacio en disco insuficiente, tipo de archivo no " +"soportado o archivo dañado)" + +#: builtin/mainmenu/content/contentdb.lua +msgid "Error installing \"$1\": $2" +msgstr "Error al instalar \"$1\": $2" + +#: builtin/mainmenu/content/contentdb.lua +msgid "Failed to download $1" +msgstr "Fallo al descargar $1" + +#: builtin/mainmenu/content/dlg_contentdb.lua +msgid "ContentDB is not available when Luanti was compiled without cURL" +msgstr "ContentDB no está disponible cuando Luanti fue compilado sin cURL" + +#: builtin/mainmenu/content/dlg_contentdb.lua +msgid "The package $1 was not found." +msgstr "El paquete $1 no se encuentra." + +#: builtin/mainmenu/content/dlg_contentdb.lua +#: builtin/mainmenu/content/dlg_package.lua +#: builtin/mainmenu/settings/dlg_settings.lua +msgid "Back" +msgstr "Atrás" + +#: builtin/mainmenu/content/dlg_contentdb.lua +#: builtin/mainmenu/content/dlg_install.lua +#: builtin/mainmenu/content/dlg_package.lua builtin/mainmenu/serverlistmgr.lua +#: src/client/game.cpp +msgid "Loading..." +msgstr "Cargando..." + +#: builtin/mainmenu/content/dlg_contentdb.lua +#: builtin/mainmenu/content/dlg_package.lua +msgid "No packages could be retrieved" +msgstr "No se pueden recuperar paquetes" + +#: builtin/mainmenu/content/dlg_contentdb.lua +msgid "All" +msgstr "Todo" + +#: builtin/mainmenu/content/dlg_contentdb.lua +msgid "Games" +msgstr "Juegos" + +#: builtin/mainmenu/content/dlg_contentdb.lua +msgid "Mods" +msgstr "Mods" + +#: builtin/mainmenu/content/dlg_contentdb.lua +msgid "Texture Packs" +msgstr "Paquetes de texturas" + +#: builtin/mainmenu/content/dlg_contentdb.lua +msgid "" +"$1 downloading,\n" +"$2 queued" +msgstr "" +"$1 descargando,\n" +"$2 en cola" + +#: builtin/mainmenu/content/dlg_contentdb.lua +msgid "$1 downloading..." +msgstr "$1 descargando..." + +#: builtin/mainmenu/content/dlg_contentdb.lua +msgid "No updates" +msgstr "Sin actualizaciones" + +#: builtin/mainmenu/content/dlg_contentdb.lua +msgid "Update All [$1]" +msgstr "Actualizar Todo [$1]" + +#: builtin/mainmenu/content/dlg_contentdb.lua +#: builtin/mainmenu/settings/dlg_settings.lua +msgid "No results" +msgstr "Sin resultados" + +#: builtin/mainmenu/content/dlg_contentdb.lua +msgid "Downloading..." +msgstr "Descargando..." + +#: builtin/mainmenu/content/dlg_contentdb.lua +msgid "Queued" +msgstr "En cola" + +#: builtin/mainmenu/content/dlg_contentdb.lua +msgid "Featured" +msgstr "Destacado" + +#: builtin/mainmenu/content/dlg_install.lua +msgid "Already installed" +msgstr "Ya está instalado" + +#: builtin/mainmenu/content/dlg_install.lua +msgid "$1 by $2" +msgstr "$1 por $2" + +#: builtin/mainmenu/content/dlg_install.lua +msgid "Not found" +msgstr "No se encontró" + +#: builtin/mainmenu/content/dlg_install.lua +msgid "$1 and $2 dependencies will be installed." +msgstr "se instalarán $1 y $2 dependencias." + +#: builtin/mainmenu/content/dlg_install.lua +msgid "$1 will be installed, and $2 dependencies will be skipped." +msgstr "$1 será instalado, y las dependencias de $2 serán saltadas." + +#: builtin/mainmenu/content/dlg_install.lua +msgid "$1 required dependencies could not be found." +msgstr "Las dependencias requeridas de $1 no se pudieron encontrar." + +#: builtin/mainmenu/content/dlg_install.lua +msgid "Please check that the base game is correct." +msgstr "Por favor, compruebe que el juego base es correcto." + +#: builtin/mainmenu/content/dlg_install.lua +msgid "Install $1" +msgstr "Instalar $1" + +#: builtin/mainmenu/content/dlg_install.lua +msgid "Base Game:" +msgstr "Juego Base:" + +#: builtin/mainmenu/content/dlg_install.lua +#: builtin/mainmenu/dlg_config_world.lua builtin/mainmenu/tab_content.lua +msgid "Dependencies:" +msgstr "Dependencias:" + +#: builtin/mainmenu/content/dlg_install.lua +msgid "Install missing dependencies" +msgstr "Instalar las dependencias faltantes" + +#: builtin/mainmenu/content/dlg_install.lua +msgid "Install" +msgstr "Instalar" + +#: builtin/mainmenu/content/dlg_install.lua +#: builtin/mainmenu/content/dlg_overwrite.lua +#: builtin/mainmenu/dlg_config_world.lua builtin/mainmenu/dlg_create_world.lua +#: builtin/mainmenu/dlg_delete_content.lua +#: builtin/mainmenu/dlg_delete_world.lua builtin/mainmenu/dlg_register.lua +#: builtin/mainmenu/dlg_rename_modpack.lua +#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua +#: src/gui/guiKeyChangeMenu.cpp src/gui/guiOpenURL.cpp +#: src/gui/guiPasswordChange.cpp +msgid "Cancel" +msgstr "Cancelar" + +#: builtin/mainmenu/content/dlg_install.lua +msgid "Error getting dependencies for package $1" +msgstr "Error en obtener las dependencias para el paquete $1" + +#: builtin/mainmenu/content/dlg_install.lua +msgid "You need to install a game before you can install a mod" +msgstr "Necesitas instalar un juego antes de instalar un mod" + +#: builtin/mainmenu/content/dlg_overwrite.lua +msgid "\"$1\" already exists. Would you like to overwrite it?" +msgstr "\"$1\" ya existe. ¿Te gustaría sobreescribirlo?" + +#: builtin/mainmenu/content/dlg_overwrite.lua +msgid "Overwrite" +msgstr "Sobreescribir" + +#: builtin/mainmenu/content/dlg_package.lua +msgid "by $1 — $2 downloads — +$3 / $4 / -$5" +msgstr "por$1 — $2 descargas — +$3 / $4 / -$5" + +#: builtin/mainmenu/content/dlg_package.lua +msgid "ContentDB page" +msgstr "Página de ContentDB" + +#: builtin/mainmenu/content/dlg_package.lua +msgid "Install [$1]" +msgstr "Instalar [$1]" + +#: builtin/mainmenu/content/dlg_package.lua builtin/mainmenu/tab_content.lua +msgid "Update" +msgstr "Actualizar" + +#: builtin/mainmenu/content/dlg_package.lua builtin/mainmenu/tab_content.lua +msgid "Uninstall" +msgstr "Desinstalar" + +#: builtin/mainmenu/content/dlg_package.lua +msgid "Description" +msgstr "Descripción" + +#: builtin/mainmenu/content/dlg_package.lua +msgid "Information" +msgstr "Información" + +#: builtin/mainmenu/content/dlg_package.lua +msgid "Donate" +msgstr "Donar" + +#: builtin/mainmenu/content/dlg_package.lua +msgid "Website" +msgstr "Sitio web" + +#: builtin/mainmenu/content/dlg_package.lua +msgid "Source" +msgstr "Fuente" + +#: builtin/mainmenu/content/dlg_package.lua +msgid "Issue Tracker" +msgstr "Rastreador de problemas" + +#: builtin/mainmenu/content/dlg_package.lua +msgid "Translate" +msgstr "Traducir" + +#: builtin/mainmenu/content/dlg_package.lua +msgid "Forum Topic" +msgstr "Tema del Foro" + +#: builtin/mainmenu/content/pkgmgr.lua +msgid "$1 (Enabled)" +msgstr "$1 (Habilitado)" + +#: builtin/mainmenu/content/pkgmgr.lua +msgid "Unable to install a $1 as a texture pack" +msgstr "No se puede instalar un paquete de texturas de $1" + +#: builtin/mainmenu/content/pkgmgr.lua +msgid "Failed to install $1 to $2" +msgstr "Falló al instalar $1 a $2" + +#: builtin/mainmenu/content/pkgmgr.lua +msgid "Unable to find a valid mod, modpack, or game" +msgstr "Incapaz de encontrar un mod válido, modpack o juego" + +#: builtin/mainmenu/content/pkgmgr.lua +msgid "Unable to install a $1 as a $2" +msgstr "Incapaz de instalar un $1 como un $2" + +#: builtin/mainmenu/content/pkgmgr.lua +msgid "Install: Unable to find suitable folder name for $1" +msgstr "Instalar: Incapaz de encontrar el nombre de carpeta adecuado para $1" + +#: builtin/mainmenu/content/pkgmgr.lua +msgid "$1 mods" +msgstr "$1 mods" + +#: builtin/mainmenu/dlg_config_world.lua +msgid "World:" +msgstr "Mundo:" + +#: builtin/mainmenu/dlg_config_world.lua +msgid "No modpack description provided." +msgstr "Ninguna descripción del modpack proporcionada." + +#: builtin/mainmenu/dlg_config_world.lua +msgid "No game description provided." +msgstr "Ninguna descripción del juego proporcionada." + +#: builtin/mainmenu/dlg_config_world.lua +msgid "(Unsatisfied)" +msgstr "(Insatisfecho)" + +#: builtin/mainmenu/dlg_config_world.lua +msgid "(Enabled, has error)" +msgstr "(Habilitado, tiene error)" + +#: builtin/mainmenu/dlg_config_world.lua +msgid "Mod:" +msgstr "Mod:" + +#: builtin/mainmenu/dlg_config_world.lua +msgid "No (optional) dependencies" +msgstr "Sin dependencias (opcionales)" + +#: builtin/mainmenu/dlg_config_world.lua +msgid "No hard dependencies" +msgstr "Sin dependencias duras" + +#: builtin/mainmenu/dlg_config_world.lua builtin/mainmenu/tab_content.lua +msgid "Optional dependencies:" +msgstr "Dependencias opcionales:" + +#: builtin/mainmenu/dlg_config_world.lua +msgid "No optional dependencies" +msgstr "Sin dependencias opcionales" + +#: builtin/mainmenu/dlg_config_world.lua +#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua +#: src/gui/guiKeyChangeMenu.cpp +msgid "Save" +msgstr "Guardar" + +#: builtin/mainmenu/dlg_config_world.lua +msgid "Find More Mods" +msgstr "Encontrar Más Mods" + +#: builtin/mainmenu/dlg_config_world.lua +msgid "Disable modpack" +msgstr "Desactivar modpack" + +#: builtin/mainmenu/dlg_config_world.lua +msgid "Enable modpack" +msgstr "Activar modpack" + +#: builtin/mainmenu/dlg_config_world.lua +msgid "enabled" +msgstr "habilitado" + +#: builtin/mainmenu/dlg_config_world.lua +msgid "Disable all" +msgstr "Desactivar todo" + +#: builtin/mainmenu/dlg_config_world.lua +msgid "Enable all" +msgstr "Activar todo" + +#: builtin/mainmenu/dlg_config_world.lua +msgid "" +"Failed to enable mod \"$1\" as it contains disallowed characters. Only " +"characters [a-z0-9_] are allowed." +msgstr "" +"No se pudo habilitar el mod \"$1\" porque contiene caracteres no permitidos. " +"Sólo se permiten caracteres [a-z0-9_]." + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Caverns" +msgstr "Cavernas" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Very large caverns deep in the underground" +msgstr "Cavernas muy grandes en lo profundo del subsuelo" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Rivers" +msgstr "Ríos" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Sea level rivers" +msgstr "Nivel del mar de los ríos" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Mountains" +msgstr "Montañas" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Floatlands (experimental)" +msgstr "Tierras Flotantes (experimental)" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Floating landmasses in the sky" +msgstr "Masas de tierra flotantes en el cielo" + +#: builtin/mainmenu/dlg_create_world.lua src/settings_translation_file.cpp +msgid "Altitude chill" +msgstr "Altitud tranquila" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Reduces heat with altitude" +msgstr "Reduce el calor con la altitud" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Altitude dry" +msgstr "Altitud seca" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Reduces humidity with altitude" +msgstr "Reduce la humedad con la altitud" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Humid rivers" +msgstr "Ríos húmedos" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Increases humidity around rivers" +msgstr "Incrementa la humedad alrededor de los ríos" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Vary river depth" +msgstr "Varía la profundidad del río" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Low humidity and high heat causes shallow or dry rivers" +msgstr "La baja humedad y el alto calor provocan ríos poco profundos o secos" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Hills" +msgstr "Colinas" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Lakes" +msgstr "Lagos" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Additional terrain" +msgstr "Terreno Adicional" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Generate non-fractal terrain: Oceans and underground" +msgstr "Generar terreno no fractal: Océanos y subsuelo" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Trees and jungle grass" +msgstr "Árboles y hierba de la selva" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Flat terrain" +msgstr "Terreno plano" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Mud flow" +msgstr "Flujo de lodo" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Terrain surface erosion" +msgstr "Erosión de la superficie del terreno" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Desert temples" +msgstr "Templos del desierto" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "" +"Different dungeon variant generated in desert biomes (only if dungeons " +"enabled)" +msgstr "" +"Variante de mazmorra diferente generada en biomas desérticos (solo si las " +"mazmorras están habilitadas)" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Temperate, Desert, Jungle, Tundra, Taiga" +msgstr "Templado, Desierto, Selva, Tundra, Taiga" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Temperate, Desert, Jungle" +msgstr "Templado, Desierto, Selva" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Temperate, Desert" +msgstr "Templado, Desierto" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Caves" +msgstr "Cuevas" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Dungeons" +msgstr "Mazmorras" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Decorations" +msgstr "Decoraciones" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "" +"Structures appearing on the terrain (no effect on trees and jungle grass " +"created by v6)" +msgstr "" +"Estructuras que aparecen en el terreno (sin efecto en los árboles y la " +"hierba de la jungla creada por v6)" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Structures appearing on the terrain, typically trees and plants" +msgstr "Estructuras que aparecen en el terreno, típicamente árboles y plantas" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Network of tunnels and caves" +msgstr "Red de túneles y cuevas" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Biomes" +msgstr "Biomas" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Biome blending" +msgstr "Mezcla de biomas" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Smooth transition between biomes" +msgstr "Transición suave entre biomas" + +#: builtin/mainmenu/dlg_create_world.lua src/settings_translation_file.cpp +msgid "Mapgen flags" +msgstr "Banderas de Mapgen" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Mapgen-specific flags" +msgstr "Banderas específicas de Mapgen" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "World name" +msgstr "Nombre del mundo" + +#: builtin/mainmenu/dlg_create_world.lua +#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua +msgid "Seed" +msgstr "Semilla" + +#: builtin/mainmenu/dlg_create_world.lua src/settings_translation_file.cpp +msgid "Mapgen" +msgstr "Mapgen" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Development Test is meant for developers." +msgstr "La prueba de desarrollo está destinada a desarrolladores." + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Install another game" +msgstr "instalar otro juego" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "Create" +msgstr "Crear" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "No game selected" +msgstr "Ningún juego seleccionado" + +#: builtin/mainmenu/dlg_create_world.lua +msgid "A world named \"$1\" already exists" +msgstr "Ya existe un mundo llamado \"$1\"" + +#: builtin/mainmenu/dlg_delete_content.lua +msgid "Are you sure you want to delete \"$1\"?" +msgstr "¿Estás seguro de que quieres eliminar \"$ 1\"?" + +#: builtin/mainmenu/dlg_delete_content.lua +#: builtin/mainmenu/dlg_delete_world.lua builtin/mainmenu/tab_local.lua +msgid "Delete" +msgstr "Borrar" + +#: builtin/mainmenu/dlg_delete_content.lua +msgid "pkgmgr: failed to delete \"$1\"" +msgstr "pkgmgr: no se pudo eliminar \"$1\"" + +#: builtin/mainmenu/dlg_delete_content.lua +msgid "pkgmgr: invalid path \"$1\"" +msgstr "pkgmgr: ruta no válida \"$1\"" + +#: builtin/mainmenu/dlg_delete_world.lua +msgid "Delete World \"$1\"?" +msgstr "¿Eliminar el mundo \"$1\"?" + +#: builtin/mainmenu/dlg_register.lua +msgid "Joining $1" +msgstr "Unirse $1" + +#: builtin/mainmenu/dlg_register.lua builtin/mainmenu/tab_local.lua +#: builtin/mainmenu/tab_online.lua +msgid "Name" +msgstr "Nombre" + +#: builtin/mainmenu/dlg_register.lua builtin/mainmenu/tab_local.lua +#: builtin/mainmenu/tab_online.lua +msgid "Password" +msgstr "Contraseña" + +#: builtin/mainmenu/dlg_register.lua src/gui/guiPasswordChange.cpp +msgid "Confirm Password" +msgstr "Confirmar Contraseña" + +#: builtin/mainmenu/dlg_register.lua builtin/mainmenu/tab_online.lua +msgid "Register" +msgstr "Registrarse" + +#: builtin/mainmenu/dlg_register.lua +msgid "Missing name" +msgstr "Nombre faltante" + +#: builtin/mainmenu/dlg_register.lua +msgid "Passwords do not match" +msgstr "Las contraseñas no coinciden" + +#: builtin/mainmenu/dlg_reinstall_mtg.lua +msgid "Minetest Game is no longer installed by default" +msgstr "Minetest Game ya no está instalado por defecto" + +#: builtin/mainmenu/dlg_reinstall_mtg.lua +msgid "" +"For a long time, Luanti shipped with a default game called \"Minetest " +"Game\". Since version 5.8.0, Luanti ships without a default game." +msgstr "" +"Durante mucho tiempo, Luanti vino con un juego predeterminado llamado " +"\"Minetest Game\". Desde la versión 5.8.0, Luanti se envía sin un juego " +"predeterminado." + +#: builtin/mainmenu/dlg_reinstall_mtg.lua +msgid "" +"If you want to continue playing in your Minetest Game worlds, you need to " +"reinstall Minetest Game." +msgstr "" +"Si quieres seguir jugando en los mundos de Minetest Game, debes reinstalar " +"Minetest Game." + +#: builtin/mainmenu/dlg_reinstall_mtg.lua +msgid "Dismiss" +msgstr "Permitir" + +#: builtin/mainmenu/dlg_reinstall_mtg.lua +msgid "Reinstall Minetest Game" +msgstr "Reinstalar Minetest Game" + +#: builtin/mainmenu/dlg_rename_modpack.lua +msgid "Accept" +msgstr "Aceptar" + +#: builtin/mainmenu/dlg_rename_modpack.lua +msgid "" +"This modpack has an explicit name given in its modpack.conf which will " +"override any renaming here." +msgstr "" +"Este modpack tiene un nombre explícito en su modpack.conf que anulará " +"cualquier cambio de nombre aquí." + +#: builtin/mainmenu/dlg_rename_modpack.lua +msgid "Rename Modpack:" +msgstr "Renombrar Modpack:" + +#: builtin/mainmenu/dlg_version_info.lua +msgid "A new $1 version is available" +msgstr "Una nueva versión $1 está disponible" + +#: builtin/mainmenu/dlg_version_info.lua +msgid "" +"Installed version: $1\n" +"New version: $2\n" +"Visit $3 to find out how to get the newest version and stay up to date with " +"features and bugfixes." +msgstr "" +"Versión instalada: $1\n" +"Nueva versión: $2\n" +"Visita $3 para descubrir cómo obtener la versión más reciente y mantenerse " +"actualizado con funciones y correcciones de errores." + +#: builtin/mainmenu/dlg_version_info.lua +msgid "Visit website" +msgstr "Visitar página web" + +#: builtin/mainmenu/dlg_version_info.lua +msgid "Later" +msgstr "Después" + +#: builtin/mainmenu/dlg_version_info.lua +msgid "Never" +msgstr "Nunca" + +#: builtin/mainmenu/init.lua +msgid "Settings" +msgstr "Configuraciones" + +#: builtin/mainmenu/serverlistmgr.lua +msgid "Try reenabling public serverlist and check your internet connection." +msgstr "" +"Intente volver a habilitar la lista de servidores públicos y verifique su " +"conexión a Internet." + +#: builtin/mainmenu/serverlistmgr.lua +msgid "Public server list is disabled" +msgstr "La lista de servidores públicos está deshabilitada" + +#: builtin/mainmenu/settings/components.lua +msgid "Set" +msgstr "Establecer" + +#: builtin/mainmenu/settings/components.lua +msgid "Browse" +msgstr "Navegar" + +#: builtin/mainmenu/settings/components.lua +msgid "Select directory" +msgstr "Seleccionar directorio" + +#: builtin/mainmenu/settings/components.lua +msgid "Select file" +msgstr "Seleccionar archivo" + +#: builtin/mainmenu/settings/components.lua +msgid "Edit" +msgstr "Editar" + +#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua +#: src/settings_translation_file.cpp +msgid "Offset" +msgstr "Compensar" + +#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua +#: src/settings_translation_file.cpp +msgid "Scale" +msgstr "Escalar" + +#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua +msgid "X spread" +msgstr "Propagación en X" + +#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua +msgid "Y spread" +msgstr "Propagación en Y" + +#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua +msgid "2D Noise" +msgstr "Ruido 2D" + +#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua +msgid "Z spread" +msgstr "Propagación en Z" + +#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua +msgid "Octaves" +msgstr "Octavos" + +#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua +msgid "Persistence" +msgstr "Persistencia" + +#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua +msgid "Lacunarity" +msgstr "Lacunaridad" + +#. ~ "defaults" is a noise parameter flag. +#. It describes the default processing options +#. for noise settings in the settings menu. +#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua +msgid "defaults" +msgstr "Por predeterminado" + +#. ~ "eased" is a noise parameter flag. +#. It is used to make the map smoother and +#. can be enabled in noise settings in +#. the settings menu. +#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua +msgid "eased" +msgstr "aliviado" + +#. ~ "absvalue" is a noise parameter flag. +#. It is short for "absolute value". +#. It can be enabled in noise settings in +#. the settings menu. +#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua +msgid "absvalue" +msgstr "absvalor" + +#: builtin/mainmenu/settings/dlg_change_mapgen_flags.lua +msgid "(No description of setting given)" +msgstr "(No se proporciona descripción del entorno)" + +#: builtin/mainmenu/settings/dlg_settings.lua src/settings_translation_file.cpp +msgid "General" +msgstr "General" + +#: builtin/mainmenu/settings/dlg_settings.lua src/client/game.cpp +#: src/settings_translation_file.cpp +msgid "Controls" +msgstr "Controles" + +#: builtin/mainmenu/settings/dlg_settings.lua +msgid "Accessibility" +msgstr "Accesibilidad" + +#: builtin/mainmenu/settings/dlg_settings.lua src/gui/guiKeyChangeMenu.cpp +#: src/gui/touchcontrols.cpp src/settings_translation_file.cpp +msgid "Chat" +msgstr "Chat" + +#: builtin/mainmenu/settings/dlg_settings.lua +msgid "Movement" +msgstr "Movimiento" + +#: builtin/mainmenu/settings/dlg_settings.lua +msgid "(The game will need to enable automatic exposure as well)" +msgstr "(El juego también deberá habilitar la exposición automática)" + +#: builtin/mainmenu/settings/dlg_settings.lua +msgid "(The game will need to enable bloom as well)" +msgstr "(El juego también deberá habilitar el bloom)" + +#: builtin/mainmenu/settings/dlg_settings.lua +msgid "(The game will need to enable volumetric lighting as well)" +msgstr "(El juego también deberá habilitar la iluminación volumétrica)" + +#: builtin/mainmenu/settings/dlg_settings.lua +msgid "(Use system language)" +msgstr "(Utilice el idioma del sistema)" + +#: builtin/mainmenu/settings/dlg_settings.lua +msgid "Auto" +msgstr "Auto" + +#: builtin/mainmenu/settings/dlg_settings.lua +msgid "Enabled" +msgstr "Habilitado" + +#: builtin/mainmenu/settings/dlg_settings.lua +#: builtin/mainmenu/settings/shadows_component.lua +msgid "Disabled" +msgstr "Deshabilitado" + +#: builtin/mainmenu/settings/dlg_settings.lua +msgid "Show technical names" +msgstr "Mostrar nombres tecnicos" + +#: builtin/mainmenu/settings/dlg_settings.lua +msgid "Show advanced settings" +msgstr "Mostrar configuraciones avanzadas" + +#: builtin/mainmenu/settings/dlg_settings.lua builtin/mainmenu/tab_online.lua +msgid "Search" +msgstr "Buscar" + +#: builtin/mainmenu/settings/dlg_settings.lua builtin/mainmenu/tab_online.lua +msgid "Clear" +msgstr "Claro" + +#: builtin/mainmenu/settings/dlg_settings.lua +msgid "Reset setting to default ($1)" +msgstr "Restablecer la configuración predeterminada ($1)" + +#: builtin/mainmenu/settings/dlg_settings.lua +msgid "Reset setting to default" +msgstr "Restablecer la configuración a los valores predeterminados" + +#: builtin/mainmenu/settings/settingtypes.lua +msgid "Content: Games" +msgstr "Contenido: Juegos" + +#: builtin/mainmenu/settings/settingtypes.lua +msgid "Content: Mods" +msgstr "Contenido: Mods" + +#: builtin/mainmenu/settings/settingtypes.lua +msgid "Client Mods" +msgstr "Mods del Cliente" + +#: builtin/mainmenu/settings/shader_warning_component.lua +msgid "Shaders are disabled." +msgstr "Los Shaders estan desactivados." + +#: builtin/mainmenu/settings/shader_warning_component.lua +msgid "This is not a recommended configuration." +msgstr "Esta no es una configuración recomendada." + +#: builtin/mainmenu/settings/shader_warning_component.lua +msgid "Enable" +msgstr "Habilitar" + +#: builtin/mainmenu/settings/shadows_component.lua +msgid "Very Low" +msgstr "Muy Bajo" + +#: builtin/mainmenu/settings/shadows_component.lua +msgid "Low" +msgstr "Bajo" + +#: builtin/mainmenu/settings/shadows_component.lua +msgid "Medium" +msgstr "Medio" + +#: builtin/mainmenu/settings/shadows_component.lua +msgid "High" +msgstr "Alto" + +#: builtin/mainmenu/settings/shadows_component.lua +msgid "Very High" +msgstr "Muy Alto" + +#: builtin/mainmenu/settings/shadows_component.lua +msgid "Custom" +msgstr "Personalizado" + +#: builtin/mainmenu/settings/shadows_component.lua +#: src/settings_translation_file.cpp +msgid "Dynamic shadows" +msgstr "Sombras Dinámicas" + +#: builtin/mainmenu/settings/shadows_component.lua +msgid "(The game will need to enable shadows as well)" +msgstr "(El juego también deberá habilitar las sombras)" + +#: builtin/mainmenu/tab_about.lua +msgid "About" +msgstr "Acerca de" + +#: builtin/mainmenu/tab_about.lua +msgid "Core Developers" +msgstr "Desarrolladores principales" + +#: builtin/mainmenu/tab_about.lua +msgid "Core Team" +msgstr "Equipo principal" + +#: builtin/mainmenu/tab_about.lua +msgid "Active Contributors" +msgstr "Colaboradores activos" + +#: builtin/mainmenu/tab_about.lua +msgid "Previous Core Developers" +msgstr "Desarrolladores principales anteriores" + +#: builtin/mainmenu/tab_about.lua +msgid "Previous Contributors" +msgstr "Colaboradores anteriores" + +#: builtin/mainmenu/tab_about.lua +msgid "Active renderer:" +msgstr "Renderizado activo:" + +#: builtin/mainmenu/tab_about.lua +msgid "Irrlicht device:" +msgstr "Dispositivo Irrlicht:" + +#: builtin/mainmenu/tab_about.lua +msgid "Share debug log" +msgstr "Compartir registro de depuración" + +#: builtin/mainmenu/tab_about.lua +msgid "" +"Opens the directory that contains user-provided worlds, games, mods,\n" +"and texture packs in a file manager / explorer." +msgstr "" +"Abre el directorio que contiene mundos, juegos, mods, proporcionados por el " +"usuario.\n" +"y paquetes de texturas en un administrador/explorador de archivos." + +#: builtin/mainmenu/tab_about.lua +msgid "Open User Data Directory" +msgstr "Abrir directorio de datos de usuario" + +#: builtin/mainmenu/tab_content.lua +msgid "Browse online content" +msgstr "Explorar contenido en línea" + +#: builtin/mainmenu/tab_content.lua +msgid "Browse online content [$1]" +msgstr "Explorar contenido en linea [$1]" + +#: builtin/mainmenu/tab_content.lua +msgid "Installed Packages:" +msgstr "Paquetes Instalados:" + +#: builtin/mainmenu/tab_content.lua +msgid "Update available?" +msgstr "¿Actualización disponible?" + +#: builtin/mainmenu/tab_content.lua +msgid "No package description available" +msgstr "No hay descripción del paquete disponible" + +#: builtin/mainmenu/tab_content.lua +msgid "Rename" +msgstr "Renombrar" + +#: builtin/mainmenu/tab_content.lua +msgid "No dependencies." +msgstr "Sin dependencias." + +#: builtin/mainmenu/tab_content.lua +msgid "Disable Texture Pack" +msgstr "Deshabilitar Paquete de Textura" + +#: builtin/mainmenu/tab_content.lua +msgid "Use Texture Pack" +msgstr "Usar Paquete de Textura" + +#: builtin/mainmenu/tab_content.lua +msgid "Content" +msgstr "Contenido" + +#: builtin/mainmenu/tab_content.lua +msgid "Content [$1]" +msgstr "Contenido [$1]" + +#: builtin/mainmenu/tab_local.lua +msgid "Install games from ContentDB" +msgstr "Instalar juegos desde ContentDB" + +#: builtin/mainmenu/tab_local.lua +msgid "" +"Luanti is a game-creation platform that allows you to play many different " +"games." +msgstr "" +"Luanti es una plataforma de creación de juegos que te permite jugar muchos " +"diferentes juegos." + +#: builtin/mainmenu/tab_local.lua +msgid "Luanti doesn't come with a game by default." +msgstr "Luanti no viene con un juego por defecto." + +#: builtin/mainmenu/tab_local.lua +msgid "You need to install a game before you can create a world." +msgstr "Necesitas instalar un juego antes de poder crear un mundo." + +#: builtin/mainmenu/tab_local.lua +msgid "Install a game" +msgstr "Instalar un juego" + +#: builtin/mainmenu/tab_local.lua +msgid "Creative Mode" +msgstr "Modo Creativo" + +#: builtin/mainmenu/tab_local.lua +msgid "Enable Damage" +msgstr "Habilitar Daño" + +#: builtin/mainmenu/tab_local.lua +msgid "Host Server" +msgstr "Hostear Servidor" + +#: builtin/mainmenu/tab_local.lua +msgid "Select Mods" +msgstr "Seleccionar Mods" + +#: builtin/mainmenu/tab_local.lua +msgid "New" +msgstr "Nuevo" + +#: builtin/mainmenu/tab_local.lua +msgid "Select World:" +msgstr "Seleccionar Mundo:" + +#: builtin/mainmenu/tab_local.lua +msgid "Host Game" +msgstr "Hostear Juego" + +#: builtin/mainmenu/tab_local.lua +msgid "Announce Server" +msgstr "Anunciar Servidor" + +#: builtin/mainmenu/tab_local.lua +msgid "Bind Address" +msgstr "Dirección de Enlace" + +#: builtin/mainmenu/tab_local.lua builtin/mainmenu/tab_online.lua +msgid "Port" +msgstr "Puerto" + +#: builtin/mainmenu/tab_local.lua +msgid "Server Port" +msgstr "Puerto del Servidor" + +#: builtin/mainmenu/tab_local.lua +msgid "Play Game" +msgstr "Jugar" + +#: builtin/mainmenu/tab_local.lua +msgid "No world created or selected!" +msgstr "¡Ningún mundo creado o seleccionado!" + +#: builtin/mainmenu/tab_local.lua +msgid "Start Game" +msgstr "Iniciar Juego" + +#: builtin/mainmenu/tab_online.lua +msgid "Refresh" +msgstr "Refrescar" + +#: builtin/mainmenu/tab_online.lua +msgid "Address" +msgstr "Dirección" + +#: builtin/mainmenu/tab_online.lua +msgid "Server Description" +msgstr "Descripción del Servidor" + +#: builtin/mainmenu/tab_online.lua +msgid "Login" +msgstr "Acceder" + +#: builtin/mainmenu/tab_online.lua +msgid "Remove favorite" +msgstr "Remover favorito" + +#: builtin/mainmenu/tab_online.lua +msgid "Ping" +msgstr "Ping" + +#: builtin/mainmenu/tab_online.lua +msgid "Creative mode" +msgstr "Modo Creativo" + +#. ~ PvP = Player versus Player +#: builtin/mainmenu/tab_online.lua +msgid "Damage / PvP" +msgstr "Daño / PvP" + +#: builtin/mainmenu/tab_online.lua +msgid "Favorites" +msgstr "Favoritos" + +#: builtin/mainmenu/tab_online.lua +msgid "Public Servers" +msgstr "Servidores Públicos" + +#: builtin/mainmenu/tab_online.lua +msgid "Incompatible Servers" +msgstr "Servidores Incompatibles" + +#: builtin/mainmenu/tab_online.lua +msgid "Join Game" +msgstr "Unirse al Juego" + +#: src/client/client.cpp src/client/game.cpp +msgid "Connection timed out." +msgstr "Se agotó el tiempo de conexión." + +#: src/client/client.cpp +msgid "Connection aborted (protocol error?)." +msgstr "Conexión cancelada (¿error de protocolo?)." + +#: src/client/client.cpp +msgid "Loading textures..." +msgstr "Cargando Texturas…" + +#: src/client/client.cpp +msgid "Rebuilding shaders..." +msgstr "Reconstruyendo shaders…" + +#: src/client/client.cpp +msgid "Initializing nodes..." +msgstr "Inicializando nodos…" + +#: src/client/client.cpp +msgid "Initializing nodes" +msgstr "Inicializando nodos" + +#: src/client/client.cpp +msgid "Done!" +msgstr "¡Hecho!" + +#: src/client/clientlauncher.cpp +msgid "Main Menu" +msgstr "Menu Principal" + +#: src/client/clientlauncher.cpp +msgid "Provided password file failed to open: " +msgstr "El archivo de contraseña proporcionado no se pudo abrir: " + +#: src/client/clientlauncher.cpp +msgid "Please choose a name!" +msgstr "¡Por favor elige un nombre!" + +#: src/client/clientlauncher.cpp +msgid "Player name too long." +msgstr "Nombre de jugador muy largo." + +#: src/client/clientlauncher.cpp +msgid "No world selected and no address provided. Nothing to do." +msgstr "" +"No se seleccionó ningún mundo ni se proporcionó ninguna dirección. Nada que " +"hacer." + +#: src/client/clientlauncher.cpp +msgid "Provided world path doesn't exist: " +msgstr "La ruta de mundo proporcionado no existe: " + +#: src/client/clientlauncher.cpp +msgid "Could not find or load game: " +msgstr "No se pudo encontrar ni cargar el juego: " + +#: src/client/clientmedia.cpp src/client/game.cpp +msgid "Media..." +msgstr "Media…" + +#: src/client/game.cpp +msgid "Shutting down..." +msgstr "Cerrando..." + +#: src/client/game.cpp +msgid "Creating server..." +msgstr "Creando servidor..." + +#: src/client/game.cpp +#, c-format +msgid "Unable to listen on %s because IPv6 is disabled" +msgstr "No se puede escuchar en %s porque IPv6 está deshabilitado" + +#: src/client/game.cpp +msgid "Creating client..." +msgstr "Creando cliente..." + +#: src/client/game.cpp +msgid "Connection failed for unknown reason" +msgstr "La conexión falló por motivo desconocido" + +#: src/client/game.cpp +msgid "Singleplayer" +msgstr "Un Jugador" + +#: src/client/game.cpp +msgid "Multiplayer" +msgstr "Multijugador" + +#: src/client/game.cpp +msgid "Resolving address..." +msgstr "Resolviendo dirección..." + +#: src/client/game.cpp +#, c-format +msgid "Couldn't resolve address: %s" +msgstr "No se pudo resolver la dirección: %s" + +#: src/client/game.cpp +#, c-format +msgid "Unable to connect to %s because IPv6 is disabled" +msgstr "No se puede conectar a %s porque IPv6 está deshabilitado" + +#: src/client/game.cpp +#, c-format +msgid "Error creating client: %s" +msgstr "Error al crear cliente: %s" + +#: src/client/game.cpp +#, c-format +msgid "Access denied. Reason: %s" +msgstr "Acceso denegado. Razón: %s" + +#: src/client/game.cpp +msgid "Connecting to server..." +msgstr "Conectando al servidor..." + +#: src/client/game.cpp +msgid "Client disconnected" +msgstr "Cliente desconectado" + +#: src/client/game.cpp +msgid "Item definitions..." +msgstr "Definiciones de Objetos..." + +#: src/client/game.cpp +msgid "Node definitions..." +msgstr "Definiciones de nodos…" + +#: src/client/game.cpp +msgid "KiB/s" +msgstr "KiB/s" + +#: src/client/game.cpp +msgid "MiB/s" +msgstr "MiB/s" + +#: src/client/game.cpp +msgid "Client side scripting is disabled" +msgstr "Las secuencias de comandos del lado del cliente están deshabilitadas" + +#: src/client/game.cpp +msgid "Sound muted" +msgstr "Sonido muteado" + +#: src/client/game.cpp +msgid "Sound unmuted" +msgstr "Sonido desmuteado" + +#: src/client/game.cpp +msgid "Sound system is disabled" +msgstr "El sonido del sistema está deshabilitado" + +#: src/client/game.cpp +#, c-format +msgid "Volume changed to %d%%" +msgstr "Volumen cambiado a %d%%" + +#: src/client/game.cpp +msgid "Sound system is not supported on this build" +msgstr "El sistema de sonido no es compatible con esta compilación" + +#: src/client/game.cpp +msgid "Fly mode enabled" +msgstr "Modo vuelo habilitado" + +#: src/client/game.cpp +msgid "Fly mode enabled (note: no 'fly' privilege)" +msgstr "Modo de vuelo habilitado (nota: sin privilegio de \"volar\")" + +#: src/client/game.cpp +msgid "Fly mode disabled" +msgstr "Modo vuelo deshabilitado" + +#: src/client/game.cpp +msgid "Pitch move mode enabled" +msgstr "Modo inclinado habilitado" + +#: src/client/game.cpp +msgid "Pitch move mode disabled" +msgstr "Modo inclinado deshabilitado" + +#: src/client/game.cpp +msgid "Fast mode enabled" +msgstr "Modo rápido habilitado" + +#: src/client/game.cpp +msgid "Fast mode enabled (note: no 'fast' privilege)" +msgstr "Modo rápido habilitado (nota: sin privilegio \"fast\")" + +#: src/client/game.cpp +msgid "Fast mode disabled" +msgstr "Modo rápido deshabilitado" + +#: src/client/game.cpp +msgid "Noclip mode enabled" +msgstr "Modo Noclip habilitado" + +#: src/client/game.cpp +msgid "Noclip mode enabled (note: no 'noclip' privilege)" +msgstr "Modo Noclip habilitado (nota: sin privilegio 'noclip')" + +#: src/client/game.cpp +msgid "Noclip mode disabled" +msgstr "Modo Noclip deshabilitado" + +#: src/client/game.cpp +msgid "Cinematic mode enabled" +msgstr "Modo cinemático habilitado" + +#: src/client/game.cpp +msgid "Cinematic mode disabled" +msgstr "Modo cinemática deshabilitado" + +#: src/client/game.cpp +msgid "Can't show block bounds (disabled by game or mod)" +msgstr "" +"No se pueden mostrar los límites de los bloques (deshabilitado por el juego " +"o mod)" + +#: src/client/game.cpp +msgid "Block bounds hidden" +msgstr "Límites de bloque ocultos" + +#: src/client/game.cpp +msgid "Block bounds shown for current block" +msgstr "Se muestran los límites del bloque para el bloque actual" + +#: src/client/game.cpp +msgid "Block bounds shown for nearby blocks" +msgstr "Se muestran los límites de los bloques cercanos" + +#: src/client/game.cpp +msgid "Automatic forward enabled" +msgstr "Avanzado automático habilitado" + +#: src/client/game.cpp +msgid "Automatic forward disabled" +msgstr "Avanzado automático deshabilitado" + +#: src/client/game.cpp +msgid "Minimap currently disabled by game or mod" +msgstr "Minimapa actualmente deshabilitado por juego o mod" + +#: src/client/game.cpp +msgid "Fog enabled by game or mod" +msgstr "Niebla habilitada por juego o mod" + +#: src/client/game.cpp +msgid "Fog enabled" +msgstr "Niebla habilitada" + +#: src/client/game.cpp +msgid "Fog disabled" +msgstr "Niebla deshabilitado" + +#: src/client/game.cpp +msgid "Debug info shown" +msgstr "Información de depuración mostrado" + +#: src/client/game.cpp +msgid "Profiler graph shown" +msgstr "Gráfico del perfilador mostrado" + +#: src/client/game.cpp +msgid "Wireframe shown" +msgstr "Estructura alámbrica mostrado" + +#: src/client/game.cpp +msgid "Debug info, profiler graph, and wireframe hidden" +msgstr "" +"Información de depuración, gráfico de perfilado y estructura alámbrica oculto" + +#: src/client/game.cpp +msgid "Debug info and profiler graph hidden" +msgstr "Información de depuración y gráfico del perfilador ocultos" + +#: src/client/game.cpp +msgid "Camera update disabled" +msgstr "Actualización de cámara deshabilitado" + +#: src/client/game.cpp +msgid "Camera update enabled" +msgstr "Actualización de cámara habilitada" + +#: src/client/game.cpp +#, c-format +msgid "" +"Viewing range changed to %d (the maximum), but limited to %d by game or mod" +msgstr "" +"El rango de visión cambió a %d (el máximo), pero está limitado a %d por " +"juego o mod" + +#: src/client/game.cpp +#, c-format +msgid "Viewing range changed to %d (the maximum)" +msgstr "El rango de visión cambió a %d (el máximo)" + +#: src/client/game.cpp +#, c-format +msgid "Viewing range changed to %d, but limited to %d by game or mod" +msgstr "El rango de visión cambió a %d, pero está limitado a %d por juego o mod" + +#: src/client/game.cpp +#, c-format +msgid "Viewing range changed to %d" +msgstr "El rango de visión cambió a %d" + +#: src/client/game.cpp +#, c-format +msgid "Viewing changed to %d (the minimum), but limited to %d by game or mod" +msgstr "" +"La visualización cambió a %d (el mínimo), pero está limitada a %d por juego " +"o mod" + +#: src/client/game.cpp +#, c-format +msgid "Viewing changed to %d (the minimum)" +msgstr "La visualización cambió a %d (el mínimo)" + +#: src/client/game.cpp +msgid "Unlimited viewing range enabled, but forbidden by game or mod" +msgstr "" +"Rango de visualización ilimitado habilitado, pero prohibido por el juego o " +"mod" + +#: src/client/game.cpp +msgid "Unlimited viewing range enabled" +msgstr "Rango de visualización ilimitado habilitado" + +#: src/client/game.cpp +msgid "Unlimited viewing range disabled" +msgstr "Rango de visualización ilimitado deshabilitado" + +#: src/client/game.cpp +msgid "Zoom currently disabled by game or mod" +msgstr "Zoom actualmente deshabilitado por juego o mod" + +#: src/client/game.cpp +msgid "You died" +msgstr "Has muerto" + +#: src/client/game.cpp +msgid "Respawn" +msgstr "Reaparecer" + +#: src/client/game.cpp +msgid "" +"Controls:\n" +"No menu open:\n" +"- slide finger: look around\n" +"- tap: place/punch/use (default)\n" +"- long tap: dig/use (default)\n" +"Menu/inventory open:\n" +"- double tap (outside):\n" +" --> close\n" +"- touch stack, touch slot:\n" +" --> move stack\n" +"- touch&drag, tap 2nd finger\n" +" --> place single item to slot\n" +msgstr "" +"Controles:\n" +"No hay menú abierto:\n" +"- deslizar el dedo: mirar a su alrededor\n" +"- toque: colocar/perforar/usar (predeterminado)\n" +"- toque largo: excavar/usar (predeterminado)\n" +"Menú/inventario abierto:\n" +"- doble toque (afuera):\n" +" --> cerrar\n" +"- pila táctil, ranura táctil:\n" +" --> mover pila\n" +"- tocar y arrastrar, tocar el segundo dedo\n" +" -> colocar un solo elemento en un slot\n" + +#: src/client/game.cpp +msgid "Continue" +msgstr "" + +#: src/client/game.cpp +msgid "Change Password" +msgstr "" + +#: src/client/game.cpp +msgid "Game paused" +msgstr "" + +#: src/client/game.cpp +msgid "Sound Volume" +msgstr "" + +#: src/client/game.cpp +msgid "Exit to Menu" +msgstr "" + +#: src/client/game.cpp +msgid "Exit to OS" +msgstr "" + +#: src/client/game.cpp +msgid "Game info:" +msgstr "" + +#: src/client/game.cpp +msgid "- Mode: " +msgstr "" + +#: src/client/game.cpp +msgid "Hosting server" +msgstr "" + +#: src/client/game.cpp +msgid "Remote server" +msgstr "" + +#: src/client/game.cpp +msgid "On" +msgstr "" + +#: src/client/game.cpp +msgid "Off" +msgstr "" + +#. ~ PvP = Player versus Player +#: src/client/game.cpp +msgid "- PvP: " +msgstr "" + +#: src/client/game.cpp +msgid "- Public: " +msgstr "" + +#: src/client/game.cpp +msgid "- Server Name: " +msgstr "" + +#: src/client/game.cpp +#, c-format +msgid "The server is probably running a different version of %s." +msgstr "" + +#: src/client/game.cpp +msgid "A serialization error occurred:" +msgstr "" + +#: src/client/game.cpp src/client/shader.cpp src/server.cpp +msgid "" +"\n" +"Check debug.txt for details." +msgstr "" + +#: src/client/game.cpp +msgid "Connection error (timed out?)" +msgstr "" + +#: src/client/gameui.cpp +msgid "Chat shown" +msgstr "" + +#: src/client/gameui.cpp +msgid "Chat hidden" +msgstr "" + +#: src/client/gameui.cpp +msgid "Chat currently disabled by game or mod" +msgstr "" + +#: src/client/gameui.cpp +msgid "HUD shown" +msgstr "" + +#: src/client/gameui.cpp +msgid "HUD hidden" +msgstr "" + +#: src/client/gameui.cpp +#, c-format +msgid "Profiler shown (page %d of %d)" +msgstr "" + +#: src/client/gameui.cpp +msgid "Profiler hidden" +msgstr "" + +#: src/client/keycode.cpp +msgid "Left Button" +msgstr "" + +#: src/client/keycode.cpp +msgid "Right Button" +msgstr "" + +#. ~ Usually paired with the Pause key +#: src/client/keycode.cpp +msgid "Break Key" +msgstr "" + +#: src/client/keycode.cpp +msgid "Middle Button" +msgstr "" + +#: src/client/keycode.cpp +msgid "X Button 1" +msgstr "" + +#: src/client/keycode.cpp +msgid "X Button 2" +msgstr "" + +#: src/client/keycode.cpp +msgid "Backspace" +msgstr "" + +#: src/client/keycode.cpp +msgid "Tab" +msgstr "" + +#: src/client/keycode.cpp +msgid "Clear Key" +msgstr "" + +#: src/client/keycode.cpp +msgid "Return Key" +msgstr "" + +#: src/client/keycode.cpp +msgid "Shift Key" +msgstr "" + +#: src/client/keycode.cpp +msgid "Control Key" +msgstr "" + +#. ~ Key name, common on Windows keyboards +#: src/client/keycode.cpp +msgid "Menu Key" +msgstr "" + +#. ~ Usually paired with the Break key +#: src/client/keycode.cpp +msgid "Pause Key" +msgstr "" + +#: src/client/keycode.cpp +msgid "Caps Lock" +msgstr "" + +#: src/client/keycode.cpp +msgid "Space" +msgstr "" + +#: src/client/keycode.cpp +msgid "Page Up" +msgstr "" + +#: src/client/keycode.cpp +msgid "Page Down" +msgstr "" + +#: src/client/keycode.cpp +msgid "End" +msgstr "" + +#: src/client/keycode.cpp +msgid "Home" +msgstr "" + +#: src/client/keycode.cpp +msgid "Left Arrow" +msgstr "" + +#: src/client/keycode.cpp +msgid "Up Arrow" +msgstr "" + +#: src/client/keycode.cpp +msgid "Right Arrow" +msgstr "" + +#: src/client/keycode.cpp +msgid "Down Arrow" +msgstr "" + +#. ~ Key name +#: src/client/keycode.cpp +msgid "Select" +msgstr "" + +#. ~ "Print screen" key +#: src/client/keycode.cpp +msgid "Print" +msgstr "" + +#: src/client/keycode.cpp +msgid "Execute" +msgstr "" + +#: src/client/keycode.cpp +msgid "Snapshot" +msgstr "" + +#: src/client/keycode.cpp +msgid "Insert" +msgstr "" + +#: src/client/keycode.cpp +msgid "Delete Key" +msgstr "" + +#: src/client/keycode.cpp +msgid "Help" +msgstr "" + +#: src/client/keycode.cpp +msgid "Left Windows" +msgstr "" + +#: src/client/keycode.cpp +msgid "Right Windows" +msgstr "" + +#: src/client/keycode.cpp +msgid "Numpad 0" +msgstr "" + +#: src/client/keycode.cpp +msgid "Numpad 1" +msgstr "" + +#: src/client/keycode.cpp +msgid "Numpad 2" +msgstr "" + +#: src/client/keycode.cpp +msgid "Numpad 3" +msgstr "" + +#: src/client/keycode.cpp +msgid "Numpad 4" +msgstr "" + +#: src/client/keycode.cpp +msgid "Numpad 5" +msgstr "" + +#: src/client/keycode.cpp +msgid "Numpad 6" +msgstr "" + +#: src/client/keycode.cpp +msgid "Numpad 7" +msgstr "" + +#: src/client/keycode.cpp +msgid "Numpad 8" +msgstr "" + +#: src/client/keycode.cpp +msgid "Numpad 9" +msgstr "" + +#: src/client/keycode.cpp +msgid "Numpad *" +msgstr "" + +#: src/client/keycode.cpp +msgid "Numpad +" +msgstr "" + +#: src/client/keycode.cpp +msgid "Numpad ." +msgstr "" + +#: src/client/keycode.cpp +msgid "Numpad -" +msgstr "" + +#: src/client/keycode.cpp +msgid "Numpad /" +msgstr "" + +#: src/client/keycode.cpp +msgid "Num Lock" +msgstr "" + +#: src/client/keycode.cpp +msgid "Scroll Lock" +msgstr "" + +#: src/client/keycode.cpp +msgid "Left Shift" +msgstr "" + +#: src/client/keycode.cpp +msgid "Right Shift" +msgstr "" + +#: src/client/keycode.cpp +msgid "Left Control" +msgstr "" + +#: src/client/keycode.cpp +msgid "Right Control" +msgstr "" + +#: src/client/keycode.cpp +msgid "Left Menu" +msgstr "" + +#: src/client/keycode.cpp +msgid "Right Menu" +msgstr "" + +#: src/client/keycode.cpp +msgid "IME Escape" +msgstr "" + +#: src/client/keycode.cpp +msgid "IME Convert" +msgstr "" + +#: src/client/keycode.cpp +msgid "IME Nonconvert" +msgstr "" + +#: src/client/keycode.cpp +msgid "IME Accept" +msgstr "" + +#: src/client/keycode.cpp +msgid "IME Mode Change" +msgstr "" + +#: src/client/keycode.cpp +msgid "Apps" +msgstr "" + +#: src/client/keycode.cpp +msgid "Sleep" +msgstr "" + +#: src/client/keycode.cpp +msgid "Erase EOF" +msgstr "" + +#: src/client/keycode.cpp +msgid "Play" +msgstr "" + +#: src/client/keycode.cpp +msgid "Zoom Key" +msgstr "" + +#: src/client/keycode.cpp +msgid "OEM Clear" +msgstr "" + +#: src/client/minimap.cpp +msgid "Minimap hidden" +msgstr "" + +#: src/client/minimap.cpp +#, c-format +msgid "Minimap in surface mode, Zoom x%d" +msgstr "" + +#: src/client/minimap.cpp +#, c-format +msgid "Minimap in radar mode, Zoom x%d" +msgstr "" + +#: src/client/minimap.cpp +msgid "Minimap in texture mode" +msgstr "" + +#: src/client/shader.cpp +msgid "Shaders are enabled but GLSL is not supported by the driver." +msgstr "" + +#: src/client/shader.cpp +#, c-format +msgid "Failed to compile the \"%s\" shader." +msgstr "" + +#: src/content/mod_configuration.cpp +msgid "Some mods have unsatisfied dependencies:" +msgstr "" + +#. ~ Error when a mod is missing dependencies. Ex: "Mod Title is missing: mod1, mod2, mod3" +#: src/content/mod_configuration.cpp +#, c-format +msgid "%s is missing:" +msgstr "" + +#: src/content/mod_configuration.cpp +msgid "" +"Install and enable the required mods, or disable the mods causing errors." +msgstr "" + +#: src/content/mod_configuration.cpp +msgid "" +"Note: this may be caused by a dependency cycle, in which case try updating " +"the mods." +msgstr "" + +#: src/gui/guiChatConsole.cpp +msgid "Opening webpage" +msgstr "" + +#: src/gui/guiChatConsole.cpp +msgid "Failed to open webpage" +msgstr "" + +#: src/gui/guiFormSpecMenu.cpp +msgid "Proceed" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Keybindings." +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "\"Aux1\" = climb down" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Double tap \"jump\" to toggle fly" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp src/settings_translation_file.cpp +msgid "Automatic jumping" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Key already in use" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "press key" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Forward" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Backward" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Left" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Right" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp src/gui/touchcontrols.cpp +msgid "Aux1" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp src/gui/touchcontrols.cpp +msgid "Jump" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp src/gui/touchcontrols.cpp +msgid "Sneak" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp src/gui/touchcontrols.cpp +msgid "Drop" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp src/gui/touchcontrols.cpp +msgid "Inventory" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Prev. item" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Next item" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp src/gui/touchcontrols.cpp +msgid "Zoom" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp src/gui/touchcontrols.cpp +msgid "Change camera" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp src/gui/touchcontrols.cpp +msgid "Toggle minimap" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp src/gui/touchcontrols.cpp +msgid "Toggle fly" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Toggle pitchmove" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp src/gui/touchcontrols.cpp +msgid "Toggle fast" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp src/gui/touchcontrols.cpp +msgid "Toggle noclip" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Mute" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Dec. volume" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Inc. volume" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Autoforward" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Screenshot" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp src/gui/touchcontrols.cpp +msgid "Range select" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Dec. range" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Inc. range" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Console" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Command" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Local command" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Block bounds" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Toggle HUD" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp src/gui/touchcontrols.cpp +msgid "Toggle chat log" +msgstr "" + +#: src/gui/guiKeyChangeMenu.cpp +msgid "Toggle fog" +msgstr "" + +#: src/gui/guiOpenURL.cpp +msgid "Open URL?" +msgstr "" + +#: src/gui/guiOpenURL.cpp +msgid "Unable to open URL" +msgstr "" + +#: src/gui/guiOpenURL.cpp +msgid "Open" +msgstr "" + +#: src/gui/guiPasswordChange.cpp +msgid "Old Password" +msgstr "" + +#: src/gui/guiPasswordChange.cpp +msgid "New Password" +msgstr "" + +#: src/gui/guiPasswordChange.cpp +msgid "Change" +msgstr "" + +#: src/gui/guiPasswordChange.cpp +msgid "Passwords do not match!" +msgstr "" + +#: src/gui/guiVolumeChange.cpp +#, c-format +msgid "Sound Volume: %d%%" +msgstr "" + +#: src/gui/guiVolumeChange.cpp src/gui/touchcontrols.cpp +msgid "Exit" +msgstr "" + +#: src/gui/guiVolumeChange.cpp +msgid "Muted" +msgstr "" + +#: src/gui/touchcontrols.cpp +msgid "Overflow menu" +msgstr "" + +#: src/gui/touchcontrols.cpp +msgid "Toggle debug" +msgstr "" + +#: src/gui/touchcontrols.cpp +msgid "Joystick" +msgstr "" + +#: src/network/clientpackethandler.cpp +msgid "Invalid password" +msgstr "" + +#: src/network/clientpackethandler.cpp +msgid "" +"Your client sent something the server didn't expect. Try reconnecting or " +"updating your client." +msgstr "" + +#: src/network/clientpackethandler.cpp +msgid "The server is running in singleplayer mode. You cannot connect." +msgstr "" + +#: src/network/clientpackethandler.cpp +msgid "" +"Your client's version is not supported.\n" +"Please contact the server administrator." +msgstr "" + +#: src/network/clientpackethandler.cpp +msgid "Player name contains disallowed characters" +msgstr "" + +#: src/network/clientpackethandler.cpp +msgid "Player name not allowed" +msgstr "" + +#: src/network/clientpackethandler.cpp +msgid "Too many users" +msgstr "" + +#: src/network/clientpackethandler.cpp +msgid "Empty passwords are disallowed. Set a password and try again." +msgstr "" + +#: src/network/clientpackethandler.cpp +msgid "" +"Another client is connected with this name. If your client closed " +"unexpectedly, try again in a minute." +msgstr "" + +#: src/network/clientpackethandler.cpp +msgid "Internal server error" +msgstr "" + +#: src/network/clientpackethandler.cpp +msgid "Server shutting down" +msgstr "" + +#: src/network/clientpackethandler.cpp +msgid "" +"The server has experienced an internal error. You will now be disconnected." +msgstr "" + +#: src/network/clientpackethandler.cpp +msgid "" +"Name is not registered. To create an account on this server, click 'Register'" +msgstr "" + +#: src/network/clientpackethandler.cpp +msgid "Name is taken. Please choose another name" +msgstr "" + +#. ~ DO NOT TRANSLATE THIS LITERALLY! +#. This is a special string which needs to contain the translation's +#. language code (e.g. "de" for German). +#: src/network/clientpackethandler.cpp src/script/lua_api/l_client.cpp +#: src/script/lua_api/l_mainmenu.cpp +msgid "LANG_CODE" +msgstr "" + +#: src/network/clientpackethandler.cpp +msgid "Unknown disconnect reason." +msgstr "" + +#: src/server.cpp +#, c-format +msgid "%s while shutting down: " +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Camera smoothing" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Smooths rotation of camera, also called look or mouse smoothing. 0 to " +"disable." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Camera smoothing in cinematic mode" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Smooths rotation of camera when in cinematic mode, 0 to disable. Enter " +"cinematic mode by using the key set in Controls." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Build inside player" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"If enabled, you can place nodes at the position (feet + eye level) where you " +"stand.\n" +"This is helpful when working with nodeboxes in small areas." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Aux1 key for climbing/descending" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"If enabled, \"Aux1\" key instead of \"Sneak\" key is used for climbing down " +"and\n" +"descending." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Double tap jump for fly" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Double-tapping the jump key toggles fly mode." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Always fly fast" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"If disabled, \"Aux1\" key is used to fly fast if both fly and fast mode are\n" +"enabled." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Place repetition interval" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"The time in seconds it takes between repeated node placements when holding\n" +"the place button." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Minimum dig repetition interval" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"The minimum time in seconds it takes between digging nodes when holding\n" +"the dig button." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Automatically jump up single-node obstacles." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Safe digging and placing" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Prevent digging and placing from repeating when holding the respective " +"buttons.\n" +"Enable this when you dig or place too often by accident.\n" +"On touchscreens, this only affects digging." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Keyboard and Mouse" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Invert mouse" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Invert vertical mouse movement." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mouse sensitivity" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mouse sensitivity multiplier." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Hotbar: Enable mouse wheel for selection" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enable mouse wheel (scroll) for item selection in hotbar." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Hotbar: Invert mouse wheel direction" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Invert mouse wheel (scroll) direction for item selection in hotbar." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Touchscreen" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Touchscreen controls" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Enables the touchscreen controls, allowing you to play the game with a " +"touchscreen.\n" +"\"auto\" means that the touchscreen controls will be enabled and disabled\n" +"automatically depending on the last used input method." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Touchscreen sensitivity" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Touchscreen sensitivity multiplier." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Movement threshold" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"The length in pixels after which a touch interaction is considered movement." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Threshold for long taps" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"The delay in milliseconds after which a touch interaction is considered a " +"long tap." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Use crosshair for touch screen" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Use crosshair to select object instead of whole screen.\n" +"If enabled, a crosshair will be shown and will be used for selecting object." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Fixed virtual joystick" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Fixes the position of virtual joystick.\n" +"If disabled, virtual joystick will center to first-touch's position." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Virtual joystick triggers Aux1 button" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Use virtual joystick to trigger \"Aux1\" button.\n" +"If enabled, virtual joystick will also tap \"Aux1\" button when out of main " +"circle." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Punch gesture" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"The gesture for punching players/entities.\n" +"This can be overridden by games and mods.\n" +"\n" +"* short_tap\n" +"Easy to use and well-known from other games that shall not be named.\n" +"\n" +"* long_tap\n" +"Known from the classic Luanti mobile controls.\n" +"Combat is more or less impossible." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Graphics and Audio" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Graphics" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Screen" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Screen width" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Width component of the initial window size." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Screen height" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Height component of the initial window size." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Window maximized" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Whether the window is maximized." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Remember screen size" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Save window size automatically when modified.\n" +"If true, screen size is saved in screen_w and screen_h, and whether the " +"window\n" +"is maximized is stored in window_maximized.\n" +"(Autosaving window_maximized only works if compiled with SDL.)" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Full screen" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Fullscreen mode." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Pause on lost window focus" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Open the pause menu when the window's focus is lost. Does not pause if a " +"formspec is\n" +"open." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "FPS" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Maximum FPS" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"If FPS would go higher than this, limit it by sleeping\n" +"to not waste CPU power for no benefit." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "VSync" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Vertical screen synchronization. Your system may still force VSync on even " +"if this is disabled." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "FPS when unfocused or paused" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Maximum FPS when the window is not focused, or when the game is paused." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Viewing range" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "View distance in nodes." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Undersampling" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Undersampling is similar to using a lower screen resolution, but it applies\n" +"to the game world only, keeping the GUI intact.\n" +"It should give a significant performance boost at the cost of less detailed " +"image.\n" +"Higher values result in a less detailed image." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "3D" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "3D mode" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"3D support.\n" +"Currently supported:\n" +"- none: no 3d output.\n" +"- anaglyph: cyan/magenta color 3d.\n" +"- interlaced: odd/even line based polarization screen support.\n" +"- topbottom: split screen top/bottom.\n" +"- sidebyside: split screen side by side.\n" +"- crossview: Cross-eyed 3d\n" +"Note that the interlaced mode requires shaders to be enabled." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "3D mode parallax strength" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Strength of 3D mode parallax." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Bobbing" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Arm inertia" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Arm inertia, gives a more realistic movement of\n" +"the arm when the camera moves." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "View bobbing factor" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Enable view bobbing and amount of view bobbing.\n" +"For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Fall bobbing factor" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Multiplier for fall bobbing.\n" +"For example: 0 for no view bobbing; 1.0 for normal; 2.0 for double." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Camera" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Field of view" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Field of view in degrees." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Light curve gamma" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Alters the light curve by applying 'gamma correction' to it.\n" +"Higher values make middle and lower light levels brighter.\n" +"Value '1.0' leaves the light curve unaltered.\n" +"This only has significant effect on daylight and artificial\n" +"light, it has very little effect on natural night light." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Ambient occlusion gamma" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"The strength (darkness) of node ambient-occlusion shading.\n" +"Lower is darker, Higher is lighter. The valid range of values for this\n" +"setting is 0.25 to 4.0 inclusive. If the value is out of range it will be\n" +"set to the nearest valid value." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Screenshots" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Screenshot folder" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Path to save screenshots at. Can be an absolute or relative path.\n" +"The folder will be created if it doesn't already exist." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Screenshot format" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Format of screenshots." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Screenshot quality" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Screenshot quality. Only used for JPEG format.\n" +"1 means worst quality; 100 means best quality.\n" +"Use 0 for default quality." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Node and Entity Highlighting" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Node highlighting" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Method used to highlight selected object." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Show entity selection boxes" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Show entity selection boxes\n" +"A restart is required after changing this." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Selection box color" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Selection box border color (R,G,B)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Selection box width" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Width of the selection box lines around nodes." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Crosshair color" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Crosshair color (R,G,B).\n" +"Also controls the object crosshair color" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Crosshair alpha" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Crosshair alpha (opaqueness, between 0 and 255).\n" +"This also applies to the object crosshair." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Fog" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Whether to fog out the end of the visible area." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Colored fog" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Make fog and sky colors depend on daytime (dawn/sunset) and view direction." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Fog start" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Fraction of the visible distance at which fog starts to be rendered" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Clouds" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Clouds are a client-side effect." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "3D clouds" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Use 3D cloud look instead of flat." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Soft clouds" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Use smooth cloud shading." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Filtering and Antialiasing" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mipmapping" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Use mipmaps when scaling textures. May slightly increase performance,\n" +"especially when using a high-resolution texture pack.\n" +"Gamma-correct downscaling is not supported." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Bilinear filtering" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Use bilinear filtering when scaling textures." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Trilinear filtering" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Use trilinear filtering when scaling textures.\n" +"If both bilinear and trilinear filtering are enabled, trilinear filtering\n" +"is applied." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Anisotropic filtering" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Use anisotropic filtering when looking at textures from an angle." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Antialiasing method" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Select the antialiasing method to apply.\n" +"\n" +"* None - No antialiasing (default)\n" +"\n" +"* FSAA - Hardware-provided full-screen antialiasing\n" +"(incompatible with Post Processing and Undersampling)\n" +"A.K.A multi-sample antialiasing (MSAA)\n" +"Smoothens out block edges but does not affect the insides of textures.\n" +"A restart is required to change this option.\n" +"\n" +"* FXAA - Fast approximate antialiasing (requires shaders)\n" +"Applies a post-processing filter to detect and smoothen high-contrast " +"edges.\n" +"Provides balance between speed and image quality.\n" +"\n" +"* SSAA - Super-sampling antialiasing (requires shaders)\n" +"Renders higher-resolution image of the scene, then scales down to reduce\n" +"the aliasing effects. This is the slowest and the most accurate method." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Anti-aliasing scale" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Defines the size of the sampling grid for FSAA and SSAA antialiasing " +"methods.\n" +"Value of 2 means taking 2x2 = 4 samples." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Occlusion Culling" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Occlusion Culler" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Type of occlusion_culler\n" +"\n" +"\"loops\" is the legacy algorithm with nested loops and O(n³) complexity\n" +"\"bfs\" is the new algorithm based on breadth-first-search and side culling\n" +"\n" +"This setting should only be changed if you have performance problems." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enable Raytraced Culling" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Use raytraced occlusion culling in the new culler.\n" +"This flag enables use of raytraced occlusion culling test for\n" +"client mesh sizes smaller than 4x4x4 map blocks." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Effects" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Translucent liquids" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Allows liquids to be translucent." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Leaves style" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Leaves style:\n" +"- Fancy: all faces visible\n" +"- Simple: only outer faces\n" +"- Opaque: disable transparency" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Connect glass" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Connects glass if supported by node." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Smooth lighting" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enable smooth lighting with simple ambient occlusion." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Tradeoffs for performance" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Enables tradeoffs that reduce CPU load or increase rendering performance\n" +"at the expense of minor visual glitches that do not impact game playability." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Digging particles" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Adds particles when digging a node." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Waving Nodes" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Waving leaves" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Set to true to enable waving leaves." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Waving plants" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Set to true to enable waving plants." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Waving liquids" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Set to true to enable waving liquids (like water)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Waving liquids wave height" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"The maximum height of the surface of waving liquids.\n" +"4.0 = Wave height is two nodes.\n" +"0.0 = Wave doesn't move at all.\n" +"Default is 1.0 (1/2 node)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Waving liquids wavelength" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Length of liquid waves." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Waving liquids wave speed" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"How fast liquid waves will move. Higher = faster.\n" +"If negative, liquid waves will move backwards." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Set to true to enable Shadow Mapping." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Shadow strength gamma" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Set the shadow strength gamma.\n" +"Adjusts the intensity of in-game dynamic shadows.\n" +"Lower value means lighter shadows, higher value means darker shadows." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Shadow map max distance in nodes to render shadows" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Maximum distance to render shadows." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Shadow map texture size" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Texture size to render the shadow map on.\n" +"This must be a power of two.\n" +"Bigger numbers create better shadows but it is also more expensive." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Shadow map texture in 32 bits" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Sets shadow texture quality to 32 bits.\n" +"On false, 16 bits texture will be used.\n" +"This can cause much more artifacts in the shadow." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Poisson filtering" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Enable Poisson disk filtering.\n" +"On true uses Poisson disk to make \"soft shadows\". Otherwise uses PCF " +"filtering." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Shadow filter quality" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Define shadow filtering quality.\n" +"This simulates the soft shadows effect by applying a PCF or Poisson disk\n" +"but also uses more resources." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Colored shadows" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Enable colored shadows.\n" +"On true translucent nodes cast colored shadows. This is expensive." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Map shadows update frames" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Spread a complete update of shadow map over given number of frames.\n" +"Higher values might make shadows laggy, lower values\n" +"will consume more resources.\n" +"Minimum value: 1; maximum value: 16" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Soft shadow radius" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Set the soft shadow radius size.\n" +"Lower values mean sharper shadows, bigger values mean softer shadows.\n" +"Minimum value: 1.0; maximum value: 15.0" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Sky Body Orbit Tilt" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Set the default tilt of Sun/Moon orbit in degrees.\n" +"Games may change orbit tilt via API.\n" +"Value of 0 means no tilt / vertical orbit." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Post Processing" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enable Post Processing" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enables the post processing pipeline." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Filmic tone mapping" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Enables Hable's 'Uncharted 2' filmic tone mapping.\n" +"Simulates the tone curve of photographic film and how this approximates the\n" +"appearance of high dynamic range images. Mid-range contrast is slightly\n" +"enhanced, highlights and shadows are gradually compressed." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enable Automatic Exposure" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Enable automatic exposure correction\n" +"When enabled, the post-processing engine will\n" +"automatically adjust to the brightness of the scene,\n" +"simulating the behavior of human eye." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Exposure compensation" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Set the exposure compensation in EV units.\n" +"Value of 0.0 (default) means no exposure compensation.\n" +"Range: from -1 to 1.0" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enable Debanding" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Apply dithering to reduce color banding artifacts.\n" +"Dithering significantly increases the size of losslessly-compressed\n" +"screenshots and it works incorrectly if the display or operating system\n" +"performs additional dithering or if the color channels are not quantized\n" +"to 8 bits.\n" +"With OpenGL ES, dithering only works if the shader supports high\n" +"floating-point precision and it may have a higher performance impact." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enable Bloom" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Set to true to enable bloom effect.\n" +"Bright colors will bleed over the neighboring objects." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Volumetric lighting" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Set to true to enable volumetric lighting effect (a.k.a. \"Godrays\")." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Other Effects" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Translucent foliage" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Simulate translucency when looking at foliage in the sunlight." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Node specular" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Apply specular shading to nodes." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Liquid reflections" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "When enabled, liquid reflections are simulated." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Audio" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Volume" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Volume of all sounds.\n" +"Requires the sound system to be enabled." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Volume when unfocused" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Volume multiplier when the window is unfocused." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mute sound" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Whether to mute sounds. You can unmute sounds at any time, unless the\n" +"sound system is disabled (enable_sound=false).\n" +"In-game, you can toggle the mute state with the mute key or by using the\n" +"pause menu." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "User Interfaces" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Language" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Set the language. By default, the system language is used.\n" +"A restart is required after changing this." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "GUI" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Optimize GUI for touchscreens" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"When enabled, the GUI is optimized to be more usable on touchscreens.\n" +"Whether this is enabled by default depends on your hardware form-factor." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "GUI scaling" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Scale GUI by a user specified value.\n" +"Use a nearest-neighbor-anti-alias filter to scale the GUI.\n" +"This will smooth over some of the rough edges, and blend\n" +"pixels when scaling down, at the cost of blurring some\n" +"edge pixels when images are scaled by non-integer sizes." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Smooth scrolling" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enables smooth scrolling." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Inventory items animations" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enables animation of inventory items." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Formspec Full-Screen Background Opacity" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Formspec full-screen background opacity (between 0 and 255)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Formspec Full-Screen Background Color" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Formspec full-screen background color (R,G,B)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "GUI scaling filter" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"When gui_scaling_filter is true, all GUI images need to be\n" +"filtered in software, but some images are generated directly\n" +"to hardware (e.g. render-to-texture for nodes in inventory)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "GUI scaling filter txr2img" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"When gui_scaling_filter_txr2img is true, copy those images\n" +"from hardware to software for scaling. When false, fall back\n" +"to the old scaling method, for video drivers that don't\n" +"properly support downloading textures back from hardware." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Tooltip delay" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Delay showing tooltips, stated in milliseconds." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Append item name" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Append item name to tooltip." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Clouds in menu" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Use a cloud animation for the main menu background." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "HUD" +msgstr "HUD" + +#: src/settings_translation_file.cpp +msgid "HUD scaling" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Modifies the size of the HUD elements." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Show name tag backgrounds by default" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Whether name tag backgrounds should be shown by default.\n" +"Mods may still set a background." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Show debug info" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Whether to show the client debug info (has the same effect as hitting F5)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Block bounds HUD radius" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Radius to use when the block bounds HUD feature is set to near blocks." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Maximum hotbar width" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Maximum proportion of current window to be used for hotbar.\n" +"Useful if there's something to be displayed right or left of hotbar." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Recent Chat Messages" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Maximum number of recent chat messages to show" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Console height" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "In-game chat console height, between 0.1 (10%) and 1.0 (100%)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Console color" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "In-game chat console background color (R,G,B)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Console alpha" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "In-game chat console background alpha (opaqueness, between 0 and 255)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Chat weblinks" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Clickable weblinks (middle-click or Ctrl+left-click) enabled in chat console " +"output." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Weblink color" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Optional override for chat weblink color." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Chat font size" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Font size of the recent chat text and chat prompt in point (pt).\n" +"Value 0 will use the default font size." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Content Repository" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "ContentDB URL" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "The URL for the content repository" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enable updates available indicator on content tab" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"If enabled and you have ContentDB packages installed, Luanti may contact " +"ContentDB to\n" +"check for package updates when opening the mainmenu." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "ContentDB Flag Blacklist" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Comma-separated list of flags to hide in the content repository.\n" +"\"nonfree\" can be used to hide packages which do not qualify as 'free " +"software',\n" +"as defined by the Free Software Foundation.\n" +"You can also specify content ratings.\n" +"These flags are independent from Luanti versions,\n" +"so see a full list at https://content.minetest.net/help/content_flags/" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "ContentDB Max Concurrent Downloads" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Maximum number of concurrent downloads. Downloads exceeding this limit will " +"be queued.\n" +"This should be lower than curl_parallel_limit." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Client and Server" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Client" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Saving map received from server" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Save the map received by the client on disk." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Serverlist URL" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "URL to the server list displayed in the Multiplayer Tab." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enable split login/register" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"If enabled, account registration is separate from login in the UI.\n" +"If disabled, new accounts will be registered automatically when logging in." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Update information URL" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"URL to JSON file which provides information about the newest Luanti " +"release.\n" +"If this is empty the engine will never check for updates." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Server" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Admin name" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Name of the player.\n" +"When running a server, clients connecting with this name are admins.\n" +"When starting from the main menu, this is overridden." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Serverlist and MOTD" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Server name" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Name of the server, to be displayed when players join and in the serverlist." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Server description" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Description of server, to be displayed when players join and in the " +"serverlist." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Server address" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Domain name of server, to be displayed in the serverlist." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Server URL" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Homepage of server, to be displayed in the serverlist." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Announce server" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Automatically report to the serverlist." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Send player names to the server list" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Send names of online players to the serverlist. If disabled only the player " +"count is revealed." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Announce to this serverlist." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Message of the day" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Message of the day displayed to players connecting." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Maximum users" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Maximum number of players that can be connected simultaneously." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Static spawn point" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "If this is set, players will always (re)spawn at the given position." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Networking" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Server port" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Network port to listen (UDP).\n" +"This value will be overridden when starting from the main menu." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Bind address" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "The network interface that the server listens on." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Strict protocol checking" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Enable to disallow old clients from connecting.\n" +"Older clients are compatible in the sense that they will not crash when " +"connecting\n" +"to new servers, but they may not support all new features that you are " +"expecting." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Protocol version minimum" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Define the oldest clients allowed to connect.\n" +"Older clients are compatible in the sense that they will not crash when " +"connecting\n" +"to new servers, but they may not support all new features that you are " +"expecting.\n" +"This allows for more fine-grained control than " +"strict_protocol_version_checking.\n" +"Luanti still enforces its own internal minimum, and enabling\n" +"strict_protocol_version_checking will effectively override this." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Remote media" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Specifies URL from which client fetches media instead of using UDP.\n" +"$filename should be accessible from $remote_media$filename via cURL\n" +"(obviously, remote_media should end with a slash).\n" +"Files that are not present will be fetched the usual way." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "IPv6 server" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Enable/disable running an IPv6 server.\n" +"Ignored if bind_address is set.\n" +"Needs enable_ipv6 to be enabled." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Server Security" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Default password" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "New users need to input this password." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Disallow empty passwords" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"If enabled, players cannot join without a password or change theirs to an " +"empty password." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Default privileges" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"The privileges that new users automatically get.\n" +"See /privs in game for a full list on your server and mod configuration." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Basic privileges" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Privileges that players with basic_privs can grant" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Anticheat flags" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Server anticheat configuration.\n" +"Flags are positive. Uncheck the flag to disable corresponding anticheat " +"module." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Anticheat movement tolerance" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Tolerance of movement cheat detector.\n" +"Increase the value if players experience stuttery movement." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Rollback recording" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"If enabled, actions are recorded for rollback.\n" +"This option is only read when server starts." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Client-side Modding" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Client side modding restrictions" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Restricts the access of certain client-side functions on servers.\n" +"Combine the byteflags below to restrict client-side features, or set to 0\n" +"for no restrictions:\n" +"LOAD_CLIENT_MODS: 1 (disable loading client-provided mods)\n" +"CHAT_MESSAGES: 2 (disable send_chat_message call client-side)\n" +"READ_ITEMDEFS: 4 (disable get_item_def call client-side)\n" +"READ_NODEDEFS: 8 (disable get_node_def call client-side)\n" +"LOOKUP_NODES_LIMIT: 16 (limits get_node call client-side to\n" +"csm_restriction_noderange)\n" +"READ_PLAYERINFO: 32 (disable get_player_names call client-side)" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Client-side node lookup range restriction" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"If the CSM restriction for node range is enabled, get_node calls are " +"limited\n" +"to this distance from the player to the node." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Strip color codes" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Remove color codes from incoming chat messages\n" +"Use this to stop players from being able to use color in their messages" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Chat message max length" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Set the maximum length of a chat message (in characters) sent by clients." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Chat message count limit" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Number of messages a player may send per 10 seconds." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Chat message kick threshold" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Kick players who sent more than X messages per 10 seconds." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Server Gameplay" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Time speed" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Controls length of day/night cycle.\n" +"Examples:\n" +"72 = 20min, 360 = 4min, 1 = 24hour, 0 = day/night/whatever stays unchanged." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "World start time" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Time of day when a new world is started, in millihours (0-23999)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Item entity TTL" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Time in seconds for item entity (dropped items) to live.\n" +"Setting it to -1 disables the feature." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Default stack size" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Specifies the default stack size of nodes, items and tools.\n" +"Note that mods or games may explicitly set a stack for certain (or all) " +"items." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Physics" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Default acceleration" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Horizontal and vertical acceleration on ground or when climbing,\n" +"in nodes per second per second." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Acceleration in air" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Horizontal acceleration in air when jumping or falling,\n" +"in nodes per second per second." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Fast mode acceleration" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Horizontal and vertical acceleration in fast mode,\n" +"in nodes per second per second." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Walking speed" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Walking and flying speed, in nodes per second." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Sneaking speed" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Sneaking speed, in nodes per second." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Fast mode speed" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Walking, flying and climbing speed in fast mode, in nodes per second." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Climbing speed" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Vertical climbing speed, in nodes per second." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Jumping speed" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Initial vertical speed when jumping, in nodes per second." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Liquid fluidity" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"How much you are slowed down when moving inside a liquid.\n" +"Decrease this to increase liquid resistance to movement." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Liquid fluidity smoothing" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Maximum liquid resistance. Controls deceleration when entering liquid at\n" +"high speed." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Liquid sinking" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Controls sinking speed in liquid when idling. Negative values will cause\n" +"you to rise instead." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Gravity" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Acceleration of gravity, in nodes per second per second." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Fixed map seed" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"A chosen map seed for a new map, leave empty for random.\n" +"Will be overridden when creating a new world in the main menu." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapgen name" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Name of map generator to be used when creating a new world.\n" +"Creating a world in the main menu will override this.\n" +"Current mapgens in a highly unstable state:\n" +"- The optional floatlands of v7 (disabled by default)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Water level" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Water surface level of the world." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Max block generate distance" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"From how far blocks are generated for clients, stated in mapblocks (16 " +"nodes)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Map generation limit" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Limit of map generation, in nodes, in all 6 directions from (0, 0, 0).\n" +"Only mapchunks completely within the mapgen limit are generated.\n" +"Value is stored per-world." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Global map generation attributes.\n" +"In Mapgen v6 the 'decorations' flag controls all decorations except trees\n" +"and jungle grass, in all other mapgens this flag controls all decorations." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Biome API" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Heat noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Temperature variation for biomes." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Heat blend noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Small-scale temperature variation for blending biomes on borders." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Humidity noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Humidity variation for biomes." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Humidity blend noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Small-scale humidity variation for blending biomes on borders." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapgen V5" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapgen V5 specific flags" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Map generation attributes specific to Mapgen v5." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Cave width" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Controls width of tunnels, a smaller value creates wider tunnels.\n" +"Value >= 10.0 completely disables generation of tunnels and avoids the\n" +"intensive noise calculations." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Large cave depth" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Y of upper limit of large caves." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Small cave minimum number" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Minimum limit of random number of small caves per mapchunk." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Small cave maximum number" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Maximum limit of random number of small caves per mapchunk." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Large cave minimum number" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Minimum limit of random number of large caves per mapchunk." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Large cave maximum number" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Maximum limit of random number of large caves per mapchunk." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Large cave proportion flooded" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Proportion of large caves that contain liquid." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Cavern limit" +msgstr "Límite de la caverna" + +#: src/settings_translation_file.cpp +msgid "Y-level of cavern upper limit." +msgstr "Nivel Y del límite superior de la caverna." + +#: src/settings_translation_file.cpp +msgid "Cavern taper" +msgstr "Cono de caverna" + +#: src/settings_translation_file.cpp +msgid "Y-distance over which caverns expand to full size." +msgstr "" +"Distancia Y sobre la cual las cavernas se expanden hasta su tamaño completo." + +#: src/settings_translation_file.cpp +msgid "Cavern threshold" +msgstr "Umbral de la caverna" + +#: src/settings_translation_file.cpp +msgid "Defines full size of caverns, smaller values create larger caverns." +msgstr "" +"Define el tamaño completo de las cavernas, los valores más pequeños crean " +"cavernas más grandes." + +#: src/settings_translation_file.cpp +msgid "Dungeon minimum Y" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Lower Y limit of dungeons." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Dungeon maximum Y" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Upper Y limit of dungeons." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Noises" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Filler depth noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Variation of biome filler depth." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Factor noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Variation of terrain vertical scale.\n" +"When noise is < -0.55 terrain is near-flat." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Height noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Y-level of average terrain surface." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Cave1 noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "First of two 3D noises that together define tunnels." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Cave2 noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Second of two 3D noises that together define tunnels." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Cavern noise" +msgstr "Ruido de caverna" + +#: src/settings_translation_file.cpp +msgid "3D noise defining giant caverns." +msgstr "Ruido 3D que define cavernas gigantes." + +#: src/settings_translation_file.cpp +msgid "Ground noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "3D noise defining terrain." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Dungeon noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "3D noise that determines number of dungeons per mapchunk." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapgen V6" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapgen V6 specific flags" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Map generation attributes specific to Mapgen v6.\n" +"The 'snowbiomes' flag enables the new 5 biome system.\n" +"When the 'snowbiomes' flag is enabled jungles are automatically enabled and\n" +"the 'jungles' flag is ignored.\n" +"The 'temples' flag disables generation of desert temples. Normal dungeons " +"will appear instead." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Desert noise threshold" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Deserts occur when np_biome exceeds this value.\n" +"When the 'snowbiomes' flag is enabled, this is ignored." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Beach noise threshold" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Sandy beaches occur when np_beach exceeds this value." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Terrain base noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Y-level of lower terrain and seabed." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Terrain higher noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Y-level of higher terrain that creates cliffs." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Steepness noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Varies steepness of cliffs." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Height select noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Defines distribution of higher terrain." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mud noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Varies depth of biome surface nodes." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Beach noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Defines areas with sandy beaches." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Biome noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Cave noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Variation of number of caves." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Trees noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Defines tree areas and tree density." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Apple trees noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Defines areas where trees have apples." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapgen V7" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapgen V7 specific flags" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Map generation attributes specific to Mapgen v7.\n" +"'ridges': Rivers.\n" +"'floatlands': Floating land masses in the atmosphere.\n" +"'caverns': Giant caves deep underground." +msgstr "" +"Atributos de generación de mapas específicos de Mapgen v7.\n" +"'crestas': Ríos.\n" +"'floatlands': Masas de tierra flotantes en la atmósfera.\n" +"'Cavernas': Cuevas gigantes en las profundidades del subsuelo." + +#: src/settings_translation_file.cpp +msgid "Mountain zero level" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Y of mountain density gradient zero level. Used to shift mountains " +"vertically." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Floatland minimum Y" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Lower Y limit of floatlands." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Floatland maximum Y" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Upper Y limit of floatlands." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Floatland tapering distance" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Y-distance over which floatlands taper from full density to nothing.\n" +"Tapering starts at this distance from the Y limit.\n" +"For a solid floatland layer, this controls the height of hills/mountains.\n" +"Must be less than or equal to half the distance between the Y limits." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Floatland taper exponent" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Exponent of the floatland tapering. Alters the tapering behavior.\n" +"Value = 1.0 creates a uniform, linear tapering.\n" +"Values > 1.0 create a smooth tapering suitable for the default separated\n" +"floatlands.\n" +"Values < 1.0 (for example 0.25) create a more defined surface level with\n" +"flatter lowlands, suitable for a solid floatland layer." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Floatland density" +msgstr "" + +#: src/settings_translation_file.cpp +#, c-format +msgid "" +"Adjusts the density of the floatland layer.\n" +"Increase value to increase density. Can be positive or negative.\n" +"Value = 0.0: 50% of volume is floatland.\n" +"Value = 2.0 (can be higher depending on 'mgv7_np_floatland', always test\n" +"to be sure) creates a solid floatland layer." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Floatland water level" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Surface level of optional water placed on a solid floatland layer.\n" +"Water is disabled by default and will only be placed if this value is set\n" +"to above 'mgv7_floatland_ymax' - 'mgv7_floatland_taper' (the start of the\n" +"upper tapering).\n" +"***WARNING, POTENTIAL DANGER TO WORLDS AND SERVER PERFORMANCE***:\n" +"When enabling water placement, floatlands must be configured and tested\n" +"to be a solid layer by setting 'mgv7_floatland_density' to 2.0 (or other\n" +"required value depending on 'mgv7_np_floatland'), to avoid\n" +"server-intensive extreme water flow and to avoid vast flooding of the\n" +"world surface below." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Terrain alternative noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Terrain persistence noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Varies roughness of terrain.\n" +"Defines the 'persistence' value for terrain_base and terrain_alt noises." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Defines distribution of higher terrain and steepness of cliffs." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mountain height noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Variation of maximum mountain height (in nodes)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Ridge underwater noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Defines large-scale river channel structure." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mountain noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"3D noise defining mountain structure and height.\n" +"Also defines structure of floatland mountain terrain." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Ridge noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "3D noise defining structure of river canyon walls." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Floatland noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"3D noise defining structure of floatlands.\n" +"If altered from the default, the noise 'scale' (0.7 by default) may need\n" +"to be adjusted, as floatland tapering functions best when this noise has\n" +"a value range of approximately -2.0 to 2.0." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapgen Carpathian" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapgen Carpathian specific flags" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Map generation attributes specific to Mapgen Carpathian." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Base ground level" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Defines the base ground level." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "River channel width" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Defines the width of the river channel." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "River channel depth" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Defines the depth of the river channel." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "River valley width" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Defines the width of the river valley." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Hilliness1 noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "First of 4 2D noises that together define hill/mountain range height." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Hilliness2 noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Second of 4 2D noises that together define hill/mountain range height." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Hilliness3 noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Third of 4 2D noises that together define hill/mountain range height." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Hilliness4 noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Fourth of 4 2D noises that together define hill/mountain range height." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Rolling hills spread noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "2D noise that controls the size/occurrence of rolling hills." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Ridge mountain spread noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "2D noise that controls the size/occurrence of ridged mountain ranges." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Step mountain spread noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "2D noise that controls the size/occurrence of step mountain ranges." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Rolling hill size noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "2D noise that controls the shape/size of rolling hills." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Ridged mountain size noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "2D noise that controls the shape/size of ridged mountains." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Step mountain size noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "2D noise that controls the shape/size of step mountains." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "River noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "2D noise that locates the river valleys and channels." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mountain variation noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "3D noise for mountain overhangs, cliffs, etc. Usually small variations." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapgen Flat" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapgen Flat specific flags" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Map generation attributes specific to Mapgen Flat.\n" +"Occasional lakes and hills can be added to the flat world." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Ground level" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Y of flat ground." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Lake threshold" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Terrain noise threshold for lakes.\n" +"Controls proportion of world area covered by lakes.\n" +"Adjust towards 0.0 for a larger proportion." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Lake steepness" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Controls steepness/depth of lake depressions." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Hill threshold" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Terrain noise threshold for hills.\n" +"Controls proportion of world area covered by hills.\n" +"Adjust towards 0.0 for a larger proportion." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Hill steepness" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Controls steepness/height of hills." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Terrain noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Defines location and terrain of optional hills and lakes." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapgen Fractal" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapgen Fractal specific flags" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Map generation attributes specific to Mapgen Fractal.\n" +"'terrain' enables the generation of non-fractal terrain:\n" +"ocean, islands and underground." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Fractal type" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Selects one of 18 fractal types.\n" +"1 = 4D \"Roundy\" Mandelbrot set.\n" +"2 = 4D \"Roundy\" Julia set.\n" +"3 = 4D \"Squarry\" Mandelbrot set.\n" +"4 = 4D \"Squarry\" Julia set.\n" +"5 = 4D \"Mandy Cousin\" Mandelbrot set.\n" +"6 = 4D \"Mandy Cousin\" Julia set.\n" +"7 = 4D \"Variation\" Mandelbrot set.\n" +"8 = 4D \"Variation\" Julia set.\n" +"9 = 3D \"Mandelbrot/Mandelbar\" Mandelbrot set.\n" +"10 = 3D \"Mandelbrot/Mandelbar\" Julia set.\n" +"11 = 3D \"Christmas Tree\" Mandelbrot set.\n" +"12 = 3D \"Christmas Tree\" Julia set.\n" +"13 = 3D \"Mandelbulb\" Mandelbrot set.\n" +"14 = 3D \"Mandelbulb\" Julia set.\n" +"15 = 3D \"Cosine Mandelbulb\" Mandelbrot set.\n" +"16 = 3D \"Cosine Mandelbulb\" Julia set.\n" +"17 = 4D \"Mandelbulb\" Mandelbrot set.\n" +"18 = 4D \"Mandelbulb\" Julia set." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Iterations" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Iterations of the recursive function.\n" +"Increasing this increases the amount of fine detail, but also\n" +"increases processing load.\n" +"At iterations = 20 this mapgen has a similar load to mapgen V7." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"(X,Y,Z) scale of fractal in nodes.\n" +"Actual fractal size will be 2 to 3 times larger.\n" +"These numbers can be made very large, the fractal does\n" +"not have to fit inside the world.\n" +"Increase these to 'zoom' into the detail of the fractal.\n" +"Default is for a vertically-squashed shape suitable for\n" +"an island, set all 3 numbers equal for the raw shape." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"(X,Y,Z) offset of fractal from world center in units of 'scale'.\n" +"Can be used to move a desired point to (0, 0) to create a\n" +"suitable spawn point, or to allow 'zooming in' on a desired\n" +"point by increasing 'scale'.\n" +"The default is tuned for a suitable spawn point for Mandelbrot\n" +"sets with default parameters, it may need altering in other\n" +"situations.\n" +"Range roughly -2 to 2. Multiply by 'scale' for offset in nodes." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Slice w" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"W coordinate of the generated 3D slice of a 4D fractal.\n" +"Determines which 3D slice of the 4D shape is generated.\n" +"Alters the shape of the fractal.\n" +"Has no effect on 3D fractals.\n" +"Range roughly -2 to 2." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Julia x" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Julia set only.\n" +"X component of hypercomplex constant.\n" +"Alters the shape of the fractal.\n" +"Range roughly -2 to 2." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Julia y" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Julia set only.\n" +"Y component of hypercomplex constant.\n" +"Alters the shape of the fractal.\n" +"Range roughly -2 to 2." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Julia z" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Julia set only.\n" +"Z component of hypercomplex constant.\n" +"Alters the shape of the fractal.\n" +"Range roughly -2 to 2." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Julia w" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Julia set only.\n" +"W component of hypercomplex constant.\n" +"Alters the shape of the fractal.\n" +"Has no effect on 3D fractals.\n" +"Range roughly -2 to 2." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Seabed noise" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Y-level of seabed." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapgen Valleys" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapgen Valleys specific flags" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Map generation attributes specific to Mapgen Valleys.\n" +"'altitude_chill': Reduces heat with altitude.\n" +"'humid_rivers': Increases humidity around rivers.\n" +"'vary_river_depth': If enabled, low humidity and high heat causes rivers\n" +"to become shallower and occasionally dry.\n" +"'altitude_dry': Reduces humidity with altitude." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"The vertical distance over which heat drops by 20 if 'altitude_chill' is\n" +"enabled. Also, the vertical distance over which humidity drops by 10 if\n" +"'altitude_dry' is enabled." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Depth below which you'll find large caves." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Cavern upper limit" +msgstr "Límite superior de la caverna" + +#: src/settings_translation_file.cpp +msgid "Depth below which you'll find giant caverns." +msgstr "Profundidad debajo de la cual encontrarás cavernas gigantes." + +#: src/settings_translation_file.cpp +msgid "River depth" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "How deep to make rivers." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "River size" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "How wide to make rivers." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Cave noise #1" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Cave noise #2" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Filler depth" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Terrain height" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Base terrain height." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Valley depth" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Raises terrain to make valleys around the rivers." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Valley fill" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Slope and fill work together to modify the heights." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Valley profile" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Amplifies the valleys." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Valley slope" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Advanced" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Developer Options" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Client modding" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Enable Lua modding support on client.\n" +"This support is experimental and API can change." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Main menu script" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Replaces the default main menu with a custom one." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mod Security" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enable mod security" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Prevent mods from doing insecure things like running shell commands." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Trusted mods" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Comma-separated list of trusted mods that are allowed to access insecure\n" +"functions even when mod security is on (via request_insecure_environment())." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "HTTP mods" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Comma-separated list of mods that are allowed to access HTTP APIs, which\n" +"allow them to upload and download data to/from the internet." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Debugging" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Debug log level" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Level of logging to be written to debug.txt:\n" +"- (no logging)\n" +"- none (messages with no level)\n" +"- error\n" +"- warning\n" +"- action\n" +"- info\n" +"- verbose\n" +"- trace" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Debug log file size threshold" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"If the file size of debug.txt exceeds the number of megabytes specified in\n" +"this setting when it is opened, the file is moved to debug.txt.1,\n" +"deleting an older debug.txt.1 if it exists.\n" +"debug.txt is only moved if this setting is positive." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Chat log level" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Minimal level of logging to be written to chat." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Deprecated Lua API handling" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Handling for deprecated Lua API calls:\n" +"- none: Do not log deprecated calls\n" +"- log: mimic and log backtrace of deprecated call (default).\n" +"- error: abort on usage of deprecated call (suggested for mod developers)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Random input" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enable random user input (only used for testing)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Random mod load order" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enable random mod loading (mainly used for testing)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mod channels" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enable mod channels support." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mod Profiler" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Load the game profiler" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Load the game profiler to collect game profiling data.\n" +"Provides a /profiler command to access the compiled profile.\n" +"Useful for mod developers and server operators." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Default report format" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"The default format in which profiles are being saved,\n" +"when calling `/profiler save [format]` without format." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Report path" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"The file path relative to your world path in which profiles will be saved to." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Entity methods" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Instrument the methods of entities on registration." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Active Block Modifiers" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Instrument the action function of Active Block Modifiers on registration." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Loading Block Modifiers" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Instrument the action function of Loading Block Modifiers on registration." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Chat commands" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Instrument chat commands on registration." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Global callbacks" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Instrument global callback functions on registration.\n" +"(anything you pass to a core.register_*() function)" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Builtin" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Instrument builtin.\n" +"This is usually only needed by core/builtin contributors" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Profiler" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Have the profiler instrument itself:\n" +"* Instrument an empty function.\n" +"This estimates the overhead, that instrumentation is adding (+1 function " +"call).\n" +"* Instrument the sampler being used to update the statistics." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Engine Profiler" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Engine profiling data print interval" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Print the engine's profiling data in regular intervals (in seconds).\n" +"0 = disable. Useful for developers." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "IPv6" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Enable IPv6 support (for both client and server).\n" +"Required for IPv6 connections to work at all." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Ignore world errors" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"If enabled, invalid world data won't cause the server to shut down.\n" +"Only enable this if you know what you are doing." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Shaders" +msgstr "Shaders" + +#: src/settings_translation_file.cpp +msgid "" +"Shaders are a fundamental part of rendering and enable advanced visual " +"effects." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Shader path" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Path to shader directory. If no path is defined, default location will be " +"used." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Video driver" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"The rendering back-end.\n" +"Note: A restart is required after changing this!\n" +"OpenGL is the default for desktop, and OGLES2 for Android." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Transparency Sorting Distance" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Distance in nodes at which transparency depth sorting is enabled.\n" +"Use this to limit the performance impact of transparency depth sorting.\n" +"Set to 0 to disable it entirely." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Cloud radius" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Radius of cloud area stated in number of 64 node cloud squares.\n" +"Values larger than 26 will start to produce sharp cutoffs at cloud area " +"corners." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Desynchronize block animation" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Whether node texture animations should be desynchronized per mapblock." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mesh cache" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Enables caching of facedir rotated meshes.\n" +"This is only effective with shaders disabled." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapblock mesh generation delay" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Delay between mesh updates on the client in ms. Increasing this will slow\n" +"down the rate of mesh updates, thus reducing jitter on slower clients." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapblock mesh generation threads" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Number of threads to use for mesh generation.\n" +"Value of 0 (default) will let Luanti autodetect the number of available " +"threads." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Minimap scan height" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"True = 256\n" +"False = 128\n" +"Usable to make minimap smoother on slower machines." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "World-aligned textures mode" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Textures on a node may be aligned either to the node or to the world.\n" +"The former mode suits better things like machines, furniture, etc., while\n" +"the latter makes stairs and microblocks fit surroundings better.\n" +"However, as this possibility is new, thus may not be used by older servers,\n" +"this option allows enforcing it for certain node types. Note though that\n" +"that is considered EXPERIMENTAL and may not work properly." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Autoscaling mode" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"World-aligned textures may be scaled to span several nodes. However,\n" +"the server may not send the scale you want, especially if you use\n" +"a specially-designed texture pack; with this option, the client tries\n" +"to determine the scale automatically basing on the texture size.\n" +"See also texture_min_size.\n" +"Warning: This option is EXPERIMENTAL!" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Base texture size" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"When using bilinear/trilinear/anisotropic filters, low-resolution textures\n" +"can be blurred, so automatically upscale them with nearest-neighbor\n" +"interpolation to preserve crisp pixels. This sets the minimum texture size\n" +"for the upscaled textures; higher values look sharper, but require more\n" +"memory. Powers of 2 are recommended. This setting is ONLY applied if\n" +"bilinear/trilinear/anisotropic filtering is enabled.\n" +"This is also used as the base node texture size for world-aligned\n" +"texture autoscaling." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Client Mesh Chunksize" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Side length of a cube of map blocks that the client will consider together\n" +"when generating meshes.\n" +"Larger values increase the utilization of the GPU by reducing the number of\n" +"draw calls, benefiting especially high-end GPUs.\n" +"Systems with a low-end GPU (or no GPU) would benefit from smaller values." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "OpenGL debug" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enables debug and error-checking in the OpenGL driver." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enable Bloom Debug" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Set to true to render debugging breakdown of the bloom effect.\n" +"In debug mode, the screen is split into 4 quadrants:\n" +"top-left - processed base image, top-right - final image\n" +"bottom-left - raw base image, bottom-right - bloom texture." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Sound" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Sound Extensions Blacklist" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Comma-separated list of AL and ALC extensions that should not be used.\n" +"Useful for testing. See al_extensions.[h,cpp] for details." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Font" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Font bold by default" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Font italic by default" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Font shadow" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Shadow offset (in pixels) of the default font. If 0, then shadow will not be " +"drawn." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Font shadow alpha" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Opaqueness (alpha) of the shadow behind the default font, between 0 and 255." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Font size" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Font size of the default font where 1 unit = 1 pixel at 96 DPI" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Font size divisible by" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"For pixel-style fonts that do not scale well, this ensures that font sizes " +"used\n" +"with this font will always be divisible by this value, in pixels. For " +"instance,\n" +"a pixel font 16 pixels tall should have this set to 16, so it will only ever " +"be\n" +"sized 16, 32, 48, etc., so a mod requesting a size of 25 will get 32." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Regular font path" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Path to the default font. Must be a TrueType font.\n" +"The fallback font will be used if the font cannot be loaded." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Bold font path" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Italic font path" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Bold and italic font path" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Monospace font size" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Font size of the monospace font where 1 unit = 1 pixel at 96 DPI" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Monospace font size divisible by" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Monospace font path" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Path to the monospace font. Must be a TrueType font.\n" +"This font is used for e.g. the console and profiler screen." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Bold monospace font path" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Italic monospace font path" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Bold and italic monospace font path" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Fallback font path" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Path of the fallback font. Must be a TrueType font.\n" +"This font will be used for certain languages or if the default font is " +"unavailable." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Lighting" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Light curve low gradient" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Gradient of light curve at minimum light level.\n" +"Controls the contrast of the lowest light levels." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Light curve high gradient" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Gradient of light curve at maximum light level.\n" +"Controls the contrast of the highest light levels." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Light curve boost" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Strength of light curve boost.\n" +"The 3 'boost' parameters define a range of the light\n" +"curve that is boosted in brightness." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Light curve boost center" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Center of light curve boost range.\n" +"Where 0.0 is minimum light level, 1.0 is maximum light level." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Light curve boost spread" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Spread of light curve boost range.\n" +"Controls the width of the range to be boosted.\n" +"Standard deviation of the light curve boost Gaussian." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Prometheus listener address" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Prometheus listener address.\n" +"If Luanti is compiled with ENABLE_PROMETHEUS option enabled,\n" +"enable metrics listener for Prometheus on that address.\n" +"Metrics can be fetched on http://127.0.0.1:30000/metrics" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Maximum size of the outgoing chat queue" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Maximum size of the outgoing chat queue.\n" +"0 to disable queueing and -1 to make the queue size unlimited." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapblock unload timeout" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Timeout for client to remove unused map data from memory, in seconds." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapblock limit" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Maximum number of mapblocks for client to be kept in memory.\n" +"Set to -1 for unlimited amount." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Maximum simultaneous block sends per client" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Maximum number of blocks that are simultaneously sent per client.\n" +"The maximum total count is calculated dynamically:\n" +"max_total = ceil((#clients + max_users) * per_client / 4)" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Delay in sending blocks after building" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"To reduce lag, block transfers are slowed down when a player is building " +"something.\n" +"This determines how long they are slowed down after placing or removing a " +"node." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Max. packets per iteration" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Maximum number of packets sent per send step in the low-level networking " +"code.\n" +"You generally don't need to change this, however busy servers may benefit " +"from a higher number." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Map Compression Level for Network Transfer" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Compression level to use when sending mapblocks to the client.\n" +"-1 - use default compression level\n" +"0 - least compression, fastest\n" +"9 - best compression, slowest" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Chat message format" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Format of player chat messages. The following strings are valid " +"placeholders:\n" +"@name, @message, @timestamp (optional)" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Chat command time message threshold" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"If the execution of a chat command takes longer than this specified time in\n" +"seconds, add the time information to the chat command message" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Shutdown message" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "A message to be displayed to all clients when the server shuts down." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Crash message" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "A message to be displayed to all clients when the server crashes." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Ask to reconnect after crash" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Whether to ask clients to reconnect after a (Lua) crash.\n" +"Set this to true if your server is set up to restart automatically." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Server/Env Performance" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Dedicated server step" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Length of a server tick (the interval at which everything is generally " +"updated),\n" +"stated in seconds.\n" +"Does not apply to sessions hosted from the client menu.\n" +"This is a lower bound, i.e. server steps may not be shorter than this, but\n" +"they are often longer." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Unlimited player transfer distance" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Whether players are shown to clients without any range limit.\n" +"Deprecated, use the setting player_transfer_distance instead." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Player transfer distance" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Defines the maximal player transfer distance in blocks (0 = unlimited)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Active object send range" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"From how far clients know about objects, stated in mapblocks (16 nodes).\n" +"\n" +"Setting this larger than active_block_range will also cause the server\n" +"to maintain active objects up to this distance in the direction the\n" +"player is looking. (This can avoid mobs suddenly disappearing from view)" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Active block range" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"The radius of the volume of blocks around every player that is subject to " +"the\n" +"active block stuff, stated in mapblocks (16 nodes).\n" +"In active blocks objects are loaded and ABMs run.\n" +"This is also the minimum range in which active objects (mobs) are " +"maintained.\n" +"This should be configured together with active_object_send_range_blocks." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Max block send distance" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"From how far blocks are sent to clients, stated in mapblocks (16 nodes)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Maximum forceloaded blocks" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Default maximum number of forceloaded mapblocks.\n" +"Set this to -1 to disable the limit." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Time send interval" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Interval of sending time of day to clients, stated in seconds." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Map save interval" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Interval of saving important changes in the world, stated in seconds." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Unload unused server data" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"How long the server will wait before unloading unused mapblocks, stated in " +"seconds.\n" +"Higher value is smoother, but will use more RAM." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Maximum objects per block" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Maximum number of statically stored objects in a block." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Active block management interval" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Length of time between active block management cycles, stated in seconds." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "ABM interval" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Length of time between Active Block Modifier (ABM) execution cycles, stated " +"in seconds." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "ABM time budget" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"The time budget allowed for ABMs to execute on each step\n" +"(as a fraction of the ABM Interval)" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "NodeTimer interval" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Length of time between NodeTimer execution cycles, stated in seconds." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Liquid loop max" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Max liquids processed per step." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Liquid queue purge time" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"The time (in seconds) that the liquids queue may grow beyond processing\n" +"capacity until an attempt is made to decrease its size by dumping old queue\n" +"items. A value of 0 disables the functionality." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Liquid update tick" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Liquid update interval in seconds." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Block send optimize distance" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"At this distance the server will aggressively optimize which blocks are sent " +"to\n" +"clients.\n" +"Small values potentially improve performance a lot, at the expense of " +"visible\n" +"rendering glitches (some blocks might not be rendered correctly in caves).\n" +"Setting this to a value greater than max_block_send_distance disables this\n" +"optimization.\n" +"Stated in MapBlocks (16 nodes)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Server-side occlusion culling" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"If enabled, the server will perform map block occlusion culling based on\n" +"on the eye position of the player. This can reduce the number of blocks\n" +"sent to the client by 50-80%. Clients will no longer receive most\n" +"invisible blocks, so that the utility of noclip mode is reduced." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Block cull optimize distance" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"At this distance the server will perform a simpler and cheaper occlusion " +"check.\n" +"Smaller values potentially improve performance, at the expense of " +"temporarily visible\n" +"rendering glitches (missing blocks).\n" +"This is especially useful for very large viewing range (upwards of 500).\n" +"Stated in MapBlocks (16 nodes)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Chunk size" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Size of mapchunks generated by mapgen, stated in mapblocks (16 nodes).\n" +"WARNING: There is no benefit, and there are several dangers, in\n" +"increasing this value above 5.\n" +"Reducing this value increases cave and dungeon density.\n" +"Altering this value is for special usage, leaving it unchanged is\n" +"recommended." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Mapgen debug" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Dump the mapgen debug information." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Absolute limit of queued blocks to emerge" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Maximum number of blocks that can be queued for loading." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Per-player limit of queued blocks load from disk" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Maximum number of blocks to be queued that are to be loaded from file.\n" +"This limit is enforced per player." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Per-player limit of queued blocks to generate" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Maximum number of blocks to be queued that are to be generated.\n" +"This limit is enforced per player." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Number of emerge threads" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Number of emerge threads to use.\n" +"Value 0:\n" +"- Automatic selection. The number of emerge threads will be\n" +"- 'number of processors - 2', with a lower limit of 1.\n" +"Any other value:\n" +"- Specifies the number of emerge threads, with a lower limit of 1.\n" +"WARNING: Increasing the number of emerge threads increases engine mapgen\n" +"speed, but this may harm game performance by interfering with other\n" +"processes, especially in singleplayer and/or when running Lua code in\n" +"'on_generated'. For many users the optimum setting may be '1'." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "cURL" +msgstr "cURL" + +#: src/settings_translation_file.cpp +msgid "cURL interactive timeout" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Maximum time an interactive request (e.g. server list fetch) may take, " +"stated in milliseconds." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "cURL parallel limit" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Limits number of parallel HTTP requests. Affects:\n" +"- Media fetch if server uses remote_media setting.\n" +"- Serverlist download and server announcement.\n" +"- Downloads performed by main menu (e.g. mod manager).\n" +"Only has an effect if compiled with cURL." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "cURL file download timeout" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Maximum time a file download (e.g. a mod download) may take, stated in " +"milliseconds." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Miscellaneous" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Display Density Scaling Factor" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Adjust the detected display density, used for scaling UI elements." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enable console window" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Windows systems only: Start Luanti with the command line window in the " +"background.\n" +"Contains the same information as the file debug.txt (default name)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Max. clearobjects extra blocks" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Number of extra blocks that can be loaded by /clearobjects at once.\n" +"This is a trade-off between SQLite transaction overhead and\n" +"memory consumption (4096=100MB, as a rule of thumb)." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Map directory" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"World directory (everything in the world is stored here).\n" +"Not needed if starting from the main menu." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Synchronous SQLite" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "See https://www.sqlite.org/pragma.html#pragma_synchronous" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Map Compression Level for Disk Storage" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Compression level to use when saving mapblocks to disk.\n" +"-1 - use default compression level\n" +"0 - least compression, fastest\n" +"9 - best compression, slowest" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Connect to external media server" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"Enable usage of remote media server (if provided by server).\n" +"Remote servers offer a significantly faster way to download media (e.g. " +"textures)\n" +"when connecting to the server." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Serverlist file" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"File in client/serverlist/ that contains your favorite servers displayed in " +"the\n" +"Multiplayer Tab." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Gamepads" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enable joysticks" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Enable joysticks. Requires a restart to take effect" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Joystick ID" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "The identifier of the joystick to use" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Joystick type" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "The type of joystick" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Joystick button repetition interval" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"The time in seconds it takes between repeated events\n" +"when holding down a joystick button combination." +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Joystick dead zone" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "The dead zone of the joystick" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "Joystick frustum sensitivity" +msgstr "" + +#: src/settings_translation_file.cpp +msgid "" +"The sensitivity of the joystick axes for moving the\n" +"in-game view frustum around." +msgstr "" From ec7738934b5ce61157ba832c200c5adaa5ae50b4 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 10 Nov 2024 18:31:38 +0100 Subject: [PATCH 037/136] CI: fix workflows not running on translation update --- .github/workflows/android.yml | 2 ++ .github/workflows/linux.yml | 6 ++---- .github/workflows/macos.yml | 2 ++ .github/workflows/windows.yml | 2 ++ 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index ab68274b4..f404dc8a2 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -12,6 +12,7 @@ on: - 'irr/**.cpp' - '**/CMakeLists.txt' - 'cmake/Modules/**' + - 'po/**.po' - 'android/**' - '.github/workflows/android.yml' pull_request: @@ -24,6 +25,7 @@ on: - 'irr/**.cpp' - '**/CMakeLists.txt' - 'cmake/Modules/**' + - 'po/**.po' - 'android/**' - '.github/workflows/android.yml' diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 7b478693e..fe0c97324 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -12,9 +12,8 @@ on: - 'irr/**.cpp' - '**/CMakeLists.txt' - 'cmake/Modules/**' + - 'po/**.po' - 'util/ci/**' - - 'Dockerfile' - - '.dockerignore' - '.github/workflows/linux.yml' pull_request: paths: @@ -26,9 +25,8 @@ on: - 'irr/**.cpp' - '**/CMakeLists.txt' - 'cmake/Modules/**' + - 'po/**.po' - 'util/ci/**' - - 'Dockerfile' - - '.dockerignore' - '.github/workflows/linux.yml' env: diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 05315f06e..d5f3f4f0a 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -13,6 +13,7 @@ on: - 'irr/**.mm' # Objective-C(++) - '**/CMakeLists.txt' - 'cmake/Modules/**' + - 'po/**.po' - '.github/workflows/macos.yml' pull_request: paths: @@ -25,6 +26,7 @@ on: - 'irr/**.mm' # Objective-C(++) - '**/CMakeLists.txt' - 'cmake/Modules/**' + - 'po/**.po' - '.github/workflows/macos.yml' jobs: diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 30d682ad8..670ce12f8 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -12,6 +12,7 @@ on: - 'irr/**.cpp' - '**/CMakeLists.txt' - 'cmake/Modules/**' + - 'po/**.po' - 'util/buildbot/**' - 'misc/*.manifest' - '.github/workflows/windows.yml' @@ -25,6 +26,7 @@ on: - 'irr/**.cpp' - '**/CMakeLists.txt' - 'cmake/Modules/**' + - 'po/**.po' - 'util/buildbot/**' - 'misc/*.manifest' - '.github/workflows/windows.yml' From e55ba9c390c845c6c60bcdcbaf05b17ed541eb61 Mon Sep 17 00:00:00 2001 From: sfence Date: Sun, 10 Nov 2024 19:06:52 +0100 Subject: [PATCH 038/136] Support generation of working Xcode project for signature purposes on MacOS (#15303) --- .github/workflows/macos.yml | 43 +++++++++++- CMakeLists.txt | 6 +- doc/compiling/macos.md | 69 +++++++++++++++++-- irr/src/CMakeLists.txt | 38 +++++----- misc/{Info.plist => macos/Info.plist.in} | 8 ++- misc/macos/entitlements/debug.entitlements | 10 +++ .../entitlements/debug_map_jit.entitlements | 10 +++ misc/macos/entitlements/release.entitlements | 8 +++ .../entitlements/release_map_jit.entitlements | 8 +++ src/CMakeLists.txt | 49 +++++++++++++ util/ci/build_xcode.sh | 24 +++++++ util/xcode/capture_env.sh | 3 + util/xcode/install_resources.cmake | 63 +++++++++++++++++ 13 files changed, 309 insertions(+), 30 deletions(-) rename misc/{Info.plist => macos/Info.plist.in} (69%) create mode 100644 misc/macos/entitlements/debug.entitlements create mode 100644 misc/macos/entitlements/debug_map_jit.entitlements create mode 100644 misc/macos/entitlements/release.entitlements create mode 100644 misc/macos/entitlements/release_map_jit.entitlements create mode 100755 util/ci/build_xcode.sh create mode 100644 util/xcode/capture_env.sh create mode 100644 util/xcode/install_resources.cmake diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index d5f3f4f0a..c073fe106 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -30,7 +30,7 @@ on: - '.github/workflows/macos.yml' jobs: - build: + build-intel-macos: # use lowest possible macOS running on x86_64 supported by brew to support more users runs-on: macos-13 steps: @@ -70,3 +70,44 @@ jobs: with: name: luanti-macos path: ./build/macos/*.zip + build-arm-macos-xcode: + runs-on: macos-14 + steps: + - uses: actions/checkout@v4 + - name: Install deps + run: | + source ./util/ci/common.sh + install_macos_deps + # brew jsoncpp do not include libjsoncpp.a, and if installed header conflict caused build failure + brew uninstall jsoncpp + + - name: Build with Cmake + run: | + mkdir build + cd build + cmake .. \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=14 \ + -DCMAKE_FIND_FRAMEWORK=LAST \ + -DCMAKE_INSTALL_PREFIX=../build/macos/ \ + -DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE \ + -DENABLE_SYSTEM_JSONCPP=OFF + cmake --build . -j$(sysctl -n hw.logicalcpu) + make install + + - name: Build and Archive with Xcode + run: | + mkdir build_xcode + cd build_xcode + ../util/ci/build_xcode.sh + + - name: Tests + run: | + mkdir -p "${HOME}/Library/Application Support/minetest/games/" + ln -s "${PWD}/games/devtest" "${HOME}/Library/Application Support/minetest/games/" + ./build/macos/luanti.app/Contents/MacOS/luanti --run-unittests + ./build_xcode/luanti.xcarchive/Products/Applications/luanti.app/Contents/MacOS/luanti --run-unittests + + - name: Diff Resources + run: | + diff -rd ./build/macos/luanti.app/Contents/Resources ./build_xcode/build/Release/luanti.app/Contents/Resources || exit 1 + diff -rd ./build/macos/luanti.app/Contents/Resources ./build_xcode/luanti.xcarchive/Products/Applications/luanti.app/Contents/Resources || exit 1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 282fea4df..e496c0b7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -272,7 +272,11 @@ endif() if(APPLE) install(FILES "misc/luanti-icon.icns" DESTINATION "${SHAREDIR}") - install(FILES "misc/Info.plist" DESTINATION "${BUNDLE_PATH}/Contents") + install(FILES "${CMAKE_BINARY_DIR}/Info.plist" DESTINATION "${BUNDLE_PATH}/Contents") +endif() + +if(CMAKE_GENERATOR STREQUAL "Xcode") + set(client_RESOURCES "${CMAKE_SOURCE_DIR}/misc/luanti-icon.icns") endif() # Library pack diff --git a/doc/compiling/macos.md b/doc/compiling/macos.md index 6b9b4b6b8..09452004e 100644 --- a/doc/compiling/macos.md +++ b/doc/compiling/macos.md @@ -16,11 +16,13 @@ brew install cmake freetype gettext gmp hiredis jpeg-turbo jsoncpp leveldb libog Download source (this is the URL to the latest of source repository, which might not work at all times) using Git: ```bash -git clone --depth 1 https://github.com/minetest/minetest.git -cd minetest +git clone --depth 1 https://github.com/minetest/minetest.git luanti +cd luanti ``` -## Build +## Building for personal usage + +### Build ```bash mkdir build @@ -34,12 +36,65 @@ cmake .. \ make -j$(sysctl -n hw.logicalcpu) make install -# M1 Macs w/ MacOS >= BigSur -codesign --force --deep -s - macos/minetest.app +# Apple Silicon (M1/M2) Macs w/ MacOS >= BigSur signature for local run +codesign --force --deep -s - --entitlements ../misc/macos/entitlements/debug.entitlements macos/luanti.app ``` -## Run +If you are using LuaJIT with `MAP_JIT` support use `debug_map_jit.entitlements`. + +### Run ``` -open ./build/macos/minetest.app +open ./build/macos/luanti.app ``` + +## Building for distribution + +### Generate Xcode project + +```bash +mkdir build +cd build + +cmake .. \ + -DCMAKE_FIND_FRAMEWORK=LAST \ + -DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE \ + -DFREETYPE_LIBRARY=/path/to/lib/dir/libfreetype.a \ + -DGETTEXT_INCLUDE_DIR=/path/to/include/dir \ + -DGETTEXT_LIBRARY=/path/to/lib/dir/libintl.a \ + -DLUA_LIBRARY=/path/to/lib/dir/libluajit-5.1.a \ + -DOGG_LIBRARY=/path/to/lib/dir/libogg.a \ + -DVORBIS_LIBRARY=/path/to/lib/dir/libvorbis.a \ + -DVORBISFILE_LIBRARY=/path/to/lib/dir/libvorbisfile.a \ + -DZSTD_LIBRARY=/path/to/lib/dir/libzstd.a \ + -DGMP_LIBRARY=/path/to/lib/dir/libgmp.a \ + -DJSON_LIBRARY=/path/to/lib/dir/libjsoncpp.a \ + -DENABLE_LEVELDB=OFF \ + -DENABLE_POSTGRESQL=OFF \ + -DENABLE_REDIS=OFF \ + -DJPEG_LIBRARY=/path/to/lib/dir/libjpeg.a \ + -DPNG_LIBRARY=/path/to/lib/dir/libpng.a \ + -DCMAKE_EXE_LINKER_FLAGS=-lbz2\ + -GXcode +``` + +If you are using LuaJIT with `MAP_JIT` support add `-DXCODE_CODE_SIGN_ENTITLEMENTS=../misc/macos/entitlements/release_map_jit.entitlements`. + +*WARNING:* You have to regenerate Xcode project if you switch commit, branch or etc. + +### Build and Run + +* Open generated Xcode project +* Select scheme `luanti` +* Configure signing Team etc. +* Run Build command +* Open application from `build/build/Debug/` directory or run it from Xcode + +### Archive and Run + +* Open generated Xcode project +* Select scheme `luanti` +* Configure signing Team etc. +* Run Build command +* Open application archive in finder, go into it, copy application and test it. + diff --git a/irr/src/CMakeLists.txt b/irr/src/CMakeLists.txt index 41d6645e9..1d2996734 100644 --- a/irr/src/CMakeLists.txt +++ b/irr/src/CMakeLists.txt @@ -313,21 +313,6 @@ add_library(IRRMESHOBJ OBJECT target_link_libraries(IRRMESHOBJ PUBLIC tiniergltf::tiniergltf) -add_library(IRROBJ OBJECT - CBillboardSceneNode.cpp - CCameraSceneNode.cpp - CDummyTransformationSceneNode.cpp - CEmptySceneNode.cpp - CMeshManipulator.cpp - CSceneCollisionManager.cpp - CSceneManager.cpp - CMeshCache.cpp -) - -# Make sure IRROBJ gets the transitive include directories for -# tiniergltf from IRRMESHOBJ. -target_link_libraries(IRROBJ PRIVATE IRRMESHOBJ) - set(IRRDRVROBJ CNullDriver.cpp CGLXManager.cpp @@ -460,14 +445,29 @@ add_library(IRRGUIOBJ OBJECT # Library -add_library(IrrlichtMt STATIC) +# There have to be some sources in IrrlichtMt to workaround Cmake Xcode generator bug +add_library(IrrlichtMt STATIC + CBillboardSceneNode.cpp + CCameraSceneNode.cpp + CDummyTransformationSceneNode.cpp + CEmptySceneNode.cpp + CMeshManipulator.cpp + CSceneCollisionManager.cpp + CSceneManager.cpp + CMeshCache.cpp +) foreach(object_lib - IRRMESHOBJ IRROBJ IRRVIDEOOBJ + IRRMESHOBJ IRRVIDEOOBJ IRRIOOBJ IRROTHEROBJ IRRGUIOBJ) # Set include directories for object library compilation target_include_directories(${object_lib} PRIVATE ${link_includes}) - # Add objects from object library to main library - target_sources(IrrlichtMt PRIVATE $) + if(CMAKE_GENERATOR STREQUAL "Xcode") + # Workaround for Cmake Xcode project generator + target_link_libraries(IrrlichtMt PRIVATE ${object_lib}) + else() + # Add objects from object library to main library + target_sources(IrrlichtMt PRIVATE $) + endif() if(BUILD_WITH_TRACY) target_link_libraries(${object_lib} PRIVATE Tracy::TracyClient) diff --git a/misc/Info.plist b/misc/macos/Info.plist.in similarity index 69% rename from misc/Info.plist rename to misc/macos/Info.plist.in index 74ed6fe5c..3daf446b6 100644 --- a/misc/Info.plist +++ b/misc/macos/Info.plist.in @@ -9,11 +9,15 @@ CFBundleIconFile luanti-icon.icns CFBundleName - Luanti + @PROJECT_NAME_CAPITALIZED@ CFBundleDisplayName - Luanti + @PROJECT_NAME_CAPITALIZED@ CFBundleIdentifier org.luanti.luanti + CFBundleVersion + @VERSION_STRING@ + LSApplicationCategoryType + public.app-category.games NSHighResolutionCapable diff --git a/misc/macos/entitlements/debug.entitlements b/misc/macos/entitlements/debug.entitlements new file mode 100644 index 000000000..0b35f6b0f --- /dev/null +++ b/misc/macos/entitlements/debug.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.get-task-allow + + + diff --git a/misc/macos/entitlements/debug_map_jit.entitlements b/misc/macos/entitlements/debug_map_jit.entitlements new file mode 100644 index 000000000..39760e5a1 --- /dev/null +++ b/misc/macos/entitlements/debug_map_jit.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.cs.allow-jit + + com.apple.security.get-task-allow + + + diff --git a/misc/macos/entitlements/release.entitlements b/misc/macos/entitlements/release.entitlements new file mode 100644 index 000000000..a1c430a57 --- /dev/null +++ b/misc/macos/entitlements/release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.cs.allow-unsigned-executable-memory + + + diff --git a/misc/macos/entitlements/release_map_jit.entitlements b/misc/macos/entitlements/release_map_jit.entitlements new file mode 100644 index 000000000..d35e43ae5 --- /dev/null +++ b/misc/macos/entitlements/release_map_jit.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.cs.allow-jit + + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2275a2075..65e5ab6bc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -598,6 +598,14 @@ if(PRECOMPILE_HEADERS) target_precompile_headers(EngineCommon PRIVATE ${PRECOMPILED_HEADERS_LIST}) endif() +if(APPLE) + # Configure the Info.plist file + configure_file( + "${CMAKE_SOURCE_DIR}/misc/macos/Info.plist.in" + "${CMAKE_BINARY_DIR}/Info.plist" + ) +endif() + if(BUILD_CLIENT) # client target if(ANDROID) @@ -605,6 +613,47 @@ if(BUILD_CLIENT) else() add_executable(${PROJECT_NAME}) endif() + + + if(CMAKE_GENERATOR STREQUAL "Xcode") + # File with used entitlements + set(XCODE_CODE_SIGN_ENTITLEMENTS "${CMAKE_SOURCE_DIR}/misc/macos/entitlements/release.entitlements" CACHE FILEPATH "Path to entitlements file to be used with Xcode signing") + + set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/build") + set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/build") + + target_sources(${PROJECT_NAME} PUBLIC ${client_RESOURCES}) + + add_dependencies(${PROJECT_NAME} translations) + + set_target_properties(${PROJECT_NAME} PROPERTIES + MACOSX_BUNDLE TRUE + MACOSX_BUNDLE_INFO_PLIST "${CMAKE_BINARY_DIR}/Info.plist" + RESOURCE "${client_RESOURCES}" + XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "org.luanti.luanti" + XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME "YES" + XCODE_ATTRIBUTE_INSTALL_PATH "/Applications" + XCODE_ATTRIBUTE_SKIP_INSTALL "NO" + XCODE_ATTRIBUTE_DEBUG_INFORMATION_FORMAT "dwarf-with-dsym" + XCODE_ATTRIBUTE_GCC_GENERATE_DEBUGGING_SYMBOLS "YES" + XCODE_ATTRIBUTE_CONFIGURATION_BUILD_DIR "$(inherited)" + XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${XCODE_CODE_SIGN_ENTITLEMENTS}" + ) + + # Prinv env variables to file, for debugging purposes + #add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + # COMMAND ${CMAKE_COMMAND} -E env bash ${CMAKE_SOURCE_DIR}/util/xcode/capture_env.sh ${CMAKE_BINARY_DIR}/post_env.log + #) + + add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/util/xcode/install_resources.cmake + -DTARGET_DIR=$ + -DBINARY_DIR=${CMAKE_BINARY_DIR} + -DPROJECT_NAME=${PROJECT_NAME} + COMMENT "Checking INSTALL_ROOT and copying resources" + ) + endif() + list(SORT client_SRCS) target_sources(${PROJECT_NAME} PRIVATE $ diff --git a/util/ci/build_xcode.sh b/util/ci/build_xcode.sh new file mode 100755 index 000000000..b31d22789 --- /dev/null +++ b/util/ci/build_xcode.sh @@ -0,0 +1,24 @@ +#!/bin/bash -e + +cmake .. \ + -DCMAKE_FIND_FRAMEWORK=LAST \ + -DRUN_IN_PLACE=FALSE -DENABLE_GETTEXT=TRUE \ + -DFREETYPE_LIBRARY=/opt/homebrew/lib/libfreetype.a \ + -DGETTEXT_INCLUDE_DIR=/path/to/include/dir \ + -DGETTEXT_LIBRARY=/opt/homebrew/lib/libintl.a \ + -DLUA_LIBRARY=/opt/homebrew/lib/libluajit-5.1.a \ + -DOGG_LIBRARY=/opt/homebrew/lib/libogg.a \ + -DVORBIS_LIBRARY=/opt/homebrew/lib/libvorbis.a \ + -DVORBISFILE_LIBRARY=/opt/homebrew/lib/libvorbisfile.a \ + -DZSTD_LIBRARY=/opt/homebrew/lib/libzstd.a \ + -DGMP_LIBRARY=/opt/homebrew/lib/libgmp.a \ + -DENABLE_SYSTEM_JSONCPP=OFF \ + -DENABLE_LEVELDB=OFF \ + -DENABLE_POSTGRESQL=OFF \ + -DENABLE_REDIS=OFF \ + -DJPEG_LIBRARY=/opt/homebrew/lib/libjpeg.a \ + -DPNG_LIBRARY=/opt/homebrew/lib/libpng.a \ + -DCMAKE_EXE_LINKER_FLAGS=-lbz2\ + -GXcode +xcodebuild -project luanti.xcodeproj -scheme luanti -configuration Release build +xcodebuild -project luanti.xcodeproj -scheme luanti -archivePath ./luanti.xcarchive archive diff --git a/util/xcode/capture_env.sh b/util/xcode/capture_env.sh new file mode 100644 index 000000000..a447e5bbc --- /dev/null +++ b/util/xcode/capture_env.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +env > $1 diff --git a/util/xcode/install_resources.cmake b/util/xcode/install_resources.cmake new file mode 100644 index 000000000..01fb663f0 --- /dev/null +++ b/util/xcode/install_resources.cmake @@ -0,0 +1,63 @@ + +# This is only one working solution I found to be working for normal and Archive builds under Xcode 15.4 +# I expect higger sensitivity to Xcode version. + +if(DEFINED ENV{INSTALL_ROOT} AND EXISTS "$ENV{INSTALL_ROOT}") + set(RESOURCES_DIR "$ENV{INSTALL_ROOT}/Applications/$ENV{PRODUCT_NAME}.app/Contents/Resources") +else() + set(RESOURCES_DIR "$ENV{TARGET_BUILD_DIR}/$ENV{UNLOCALIZED_RESOURCES_FOLDER_PATH}") +endif() + +# Write debug information to a file +#file(WRITE "$ENV{PROJECT_FILE_PATH}/../debug_output.txt" "INSTALL_ROOT: $ENV{INSTALL_ROOT}\n") +#file(APPEND "$ENV{PROJECT_FILE_PATH}/../debug_output.txt" "RESOURCES_DIR: ${RESOURCES_DIR}\n") +#file(APPEND "$ENV{PROJECT_FILE_PATH}/../debug_output.txt" "TARGET_BUILD_DIR: $ENV{TARGET_BUILD_DIR}\n") +#file(APPEND "$ENV{PROJECT_FILE_PATH}/../debug_output.txt" "BUILT_PRODUCTS_DIR: $ENV{BUILT_PRODUCTS_DIR}\n") +#file(APPEND "$ENV{PROJECT_FILE_PATH}/../debug_output.txt" "SOURCE_ROOT: $ENV{SOURCE_ROOT}\n") +#file(APPEND "$ENV{PROJECT_FILE_PATH}/../debug_output.txt" "PRODUCT_NAME: $ENV{PRODUCT_NAME}\n") + +execute_process( + COMMAND ${CMAKE_COMMAND} -E copy_directory + "$ENV{SOURCE_ROOT}/builtin" + "${RESOURCES_DIR}/builtin" +) +execute_process( + COMMAND ${CMAKE_COMMAND} -E copy_directory + "$ENV{SOURCE_ROOT}/client/shaders" + "${RESOURCES_DIR}/client/shaders" +) +execute_process( + COMMAND ${CMAKE_COMMAND} -E copy_directory + "$ENV{SOURCE_ROOT}/fonts" + "${RESOURCES_DIR}/fonts" +) +execute_process( + COMMAND ${CMAKE_COMMAND} -E copy_directory + "$ENV{PROJECT_FILE_PATH}/../locale" + "${RESOURCES_DIR}/locale" +) +execute_process( + COMMAND ${CMAKE_COMMAND} -E make_directory + "${RESOURCES_DIR}/$ENV{PRODUCT_NAME}" +) +set(RESOURCE_LUANTI_FILES + "$ENV{SOURCE_ROOT}/README.md" + "$ENV{SOURCE_ROOT}/doc/client_lua_api.md" + "$ENV{SOURCE_ROOT}/doc/lua_api.md" + "$ENV{SOURCE_ROOT}/doc/menu_lua_api.md" + "$ENV{SOURCE_ROOT}/minetest.conf.example" + "$ENV{SOURCE_ROOT}/doc/texture_packs.md" + "$ENV{SOURCE_ROOT}/doc/world_format.md" +) +foreach (file ${RESOURCE_LUANTI_FILES}) + execute_process( + COMMAND ${CMAKE_COMMAND} -E copy + "${file}" + "${RESOURCES_DIR}/$ENV{PRODUCT_NAME}/" + ) +endforeach() +execute_process( + COMMAND ${CMAKE_COMMAND} -E copy_directory + "$ENV{SOURCE_ROOT}/textures/base/pack" + "${RESOURCES_DIR}/textures/base/pack" +) From a983b72713ef4ca66394a374ddd9ec9acbc50e53 Mon Sep 17 00:00:00 2001 From: ROllerozxa Date: Sun, 10 Nov 2024 19:08:08 +0100 Subject: [PATCH 039/136] Add Fastlane metadata for F-Droid (#15411) Co-authored-by: grorp --- .../metadata/android/en-US/full_description.txt | 7 +++++++ fastlane/metadata/android/en-US/images/icon.png | Bin 0 -> 8652 bytes .../metadata/android/en-US/short_description.txt | 1 + fastlane/metadata/android/en-US/title.txt | 1 + 4 files changed, 9 insertions(+) create mode 100644 fastlane/metadata/android/en-US/full_description.txt create mode 100644 fastlane/metadata/android/en-US/images/icon.png create mode 100644 fastlane/metadata/android/en-US/short_description.txt create mode 100644 fastlane/metadata/android/en-US/title.txt diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt new file mode 100644 index 000000000..c08797ff6 --- /dev/null +++ b/fastlane/metadata/android/en-US/full_description.txt @@ -0,0 +1,7 @@ +Luanti is a voxel-based game platform with multiplayer capabilities. + +The objective of the available games varies, from sandbox games where you can explore, dig and build in a very large voxel world, to arcade-style games. + +There is a wide range of built-in map generators for procedurally generated terrain, and voxel-based lighting that adapts to the environment and light sources. + +All games and mods are written in Lua with a scripting API that is easy to use and makes it easy for modders to get started. diff --git a/fastlane/metadata/android/en-US/images/icon.png b/fastlane/metadata/android/en-US/images/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..47f6fc2c489157d9e5e4199388b09668a21e856f GIT binary patch literal 8652 zcmV;-Av4~IP)I~6001FtNklGIPVOxROTBkXsS+*gP)r1cT_yb%e_&8@; zJ|i$&>oFpAAmI?opSzD-AF+jDXE!>6+;hf16!uNz}gbo6;wJdYa5Vj@aiU?m5pn;;?5*hTuoIrcI)xz!Ls5g;1|#MAwNhdX3+7Azbo#B6vtR zOHhc?&GCUr8j;hVu&dgKgTQ>d_e3GWmNRklwxJ>K^Pza zT69K!ixmKoZcCU*_zwYu>jZ!2WNUMcp*0IYlGNUkh)yEhAwUPe6J8f3TfZnUTk8^l zr@H+!@;Ga6mn5spMDjxo>B=H&gv_*sIF%=a9|$uD_5!oDd;ut8toun4t#(xJa1bEL zutLnL4j6K&E2`e>hWull;Wy4k_e8i)$Py=6nR^f|Q2-th?d_xqR+EXq?`ud+u|miU zTNIt{!id*K<@Ihz-`xqWrR}vv@Q`qU;O3lU^>oJvEkywC5mpwmcqwVMA`PN9@(h(I` z8Nu~N@tH1A&9Q?xh36LjLl`GYZf7HS+N=c#K(kXpfJ>ScBA0bQ*#+k3pA2+b`i0SW6Iq zM@4&N?(c+3=I4!%As4$MdSwT=r1MULUkIxR4uaNfrY-;)K0*0qcHB2Q3Qu)G@N`>< z`0>GagevFcc2B6e311*Tge2i&CCL*9pzWL zB4~;&PXttd*lWPL_H=3qbB<;K=%est7X(e?y8>yV6+(h-c0T@wl+dbr?ENRge!^b` zrfg;ba435e46fh@gVGcm_=dMfjE61am9{$`vzAiAy98+AN5X7ECqub03!sSvz|z6( z{B%%E7(Ub)mtIRls#g~xpA&%o8ftbucTt8v^~~^q5M>BAW&t#+0JwsX_eg$0C@H@m z-dr7vua1=BtHY&y0qC!v1>uSo(d;&qYH3^e%@9ITz!Sj^1E?_zz%T(cyd>2vKGW5kU1w zSgRI5ZA~F*N_)(m;Es=9&t=4adAJ0}7DuBb>`#n%4N_IlA}gT{GUF}Y&xp1NObZh} z!`nc^YgxOMB!Dc_7Jx|)g*I3Kb+?64Rz3(9HmBliBA$TD8&WYbeK3#s5t+TPdyNx{ zGukl$RO9!|IE(!$v6h3l6SM^iz|_aWCHcYz3m~tS!H}5T=WuX&G-$W8U4L^|E|yn$ zAknQu4e{B*opEfN3_sip#c$t)$$VsxO5kh7{oBxUEbGB#!nB>I}5<$>R zYbwuneq!QF&UJ-)fgNu&%q`U(>t+Yy_JKl1{JjH3*gai^Oy6!b#3#AiVdH{9`1>cp zjCgJQ`gJ%yyX1{I6MAa|0C8&&04IdzzZ&K-f_&}4jufRoc@-~VgFU3#oS%0|ZjY&B z*d?oYlFhl;2_bH}}_EoN4|fX^@a5z##2_3-nTVYv9F62pr-wk`oQ=jBjY zp%6)1I-ug}6E%NWw=i>GC%BjM{d`{OOE|M3311&6W8}ZPIRn#k#T4D!)sSD2@ z+=y5;Be=f!_w5k4=d^2m0?@f0zMJr{k*g=A_yEFn{ z94cnSfA)GF){gR~Bi_D-_zeG!IJnUT|GmTfyutY8D>XdxtXi)C6miyrX&mdQD1}s> zE`*UE5CQ)wRw#J8bAuZ<@_g;%-WtoN`{35T0!I872aBf`( zQOQ5{$B&WX-5r@Yvnmn8<6h#Wb(2f~gip@-aDKjt1mKZo`DsR!r9@!L<{4q#mZoou zY3%wN?FIE6Ys1nhO)({Atu0(~g)s0TQ7o;C-)P5nZDTibWGOcAi?Go&a!?Z89cT9| z@xKRQ9EnXR0RJ>gQ0DL})eqK?5KL>*$m`K9n|NzK8oR!(O}uMKd!+5^SZgj`e7ZB@ zh+LKjKjtxUVnPCuUvjofBTx0{w{qzuLs6jvgY2|!B-pJc>XhNp%LoBnAi?vd8^H03g#j{6^K{5G`gRSi-Lex~AJ; z%VsD1>$a-N1h9+*pn2bSp9W#ussYGJ;<<&NNeGKGB86QWg?R7qc8_k;x{;qhuYJo# zQDBXfZ5=6^Hf&*s((C8*1)vLk0kBx2c~Ee?GXf^^=lo)eyWr%JCl3t&_azA+w|)Xx zyz*rd4FCPNuli!al)k!d;aiFiO4GuP_>gV7P5T`A`OUmrHWV>OEq}6GHkH@Aqx^gi z%ulVq0Ok}3QGTIEGYon1yMh^eI>BuSKR&1!_Z&XF=w09VfW7Xg2WotKGZgMQ^%KCf z1ux;7Pr~rSeKmg3`aM6>DRSkwD@K=f<_Uq?&hKT!Soo)fwSDs8(kM?mODg7!rsMwK z+P7(gr`fXV*^`u8%P)6F$tedEywMx;Qw$J5t`G%>dZFYU2UO6{;M_s;O#Q~MvxhW` ziw`6eA1qq>SA6wxU|qyhxj39$hZ=X^3&p$d1j9AEegYUX<1e^=Is~__s_@-sVN5{U zg8Tli3P*Q{P?YhkZrgbe#RvTbPhx(m_AiLJUC;br>P~|jE$sCbSG%M1ED?XS7jpLW zLC%go1_@wxju6@Oo}9gXQ1E6il$|3XTy0h%u(UL69)B_@Ag2Q!e5fY^c6|T$t{M+M z2*rozLvZ;-FwP$fgfhE+y@1ivU&MvCf^g~WV7z}egb9d*!~~@+gl|3y#QG(FL3W~r zwp;iyJwjMu_zB=)+s7l?nh8JyWwABVNCfpgiYu>m#}GR13*YL6+6Ur|VA$D*{mi_B zy-|F!C(181ZG4dTW@q?~jR43`hvN%6^4~iX!Y5x}01S!>O9U@uCk zmB;Ddc>>TE0pZ%I5Zt~Vitq2SxPX^t7N!|V09z&ovhLU?dvY;a z`EJZNlaD4}txLQpou^`NtKM?Zl zXSMqxY_3wAqg4ve6k^Vz!FuFhrg-4Sxe(lcKNSDD!*c@+_ulnGUW(AD0$})>aB)i- zDu+2jtT_Uc+QYTL9?JP*lL4%q&h66dvEf9ZG-xfHhR@sC?{^y_2<|N1-xyVniUkZ)`OaQO0Y zDUPg;L43jUOaP+z4sed4I(l(8B(Cbk2&pfM*7wAek+xWn)CThjlg8SiU?cZ4npyzt z;>ThAiyz5FFW~4JcJYI)!KZtQv1n8h`b$IM;H+Z!vor)N7YF0-pN8=QGa`x+cALcn zAw*;_?=;x9S&78T9*p>aLOZNjDaP5O0X(07jeP#6*^)Q!CjBCvc#ca*K}VKDK`1?)453t(MA zdU6;qz4OoP%3`2<2aCW4Lf-Lr^$M#YzNaXZzzM-4Fa(Epg|Om{mJk?m-%?gU z!5b0E3l16K8`jHk;-H^i)c?^16-E8b*Xu?7AD#2W)R7K6(kGPkM^2(~T|k}qV0R8? zOmKxHi9`@@N2ftYND{k1J>3BrTNzQtgYknvR@IDJ&YugAr`lriG;iG8n+G-!dZY|* zF3(0xcmyL^1Lx2pq)pqy;HWC#eJ>+37*|iKh$x-9z&$l1^rQ13j9^_KugUvwP~Lx! z^8SCbyr1vqzxp5mYZmn9<^AQE-Ed@CIPQ~J^OJ3wN&sAZaBfpFipmE-lxV};f{5IL zGOH_M7WYKf_J)#f{4|g{f9$DY@_fFZA3e$iSGQ+yanGiF49Sc^FA+!Xi(V;+9la6d zYc8R3-8F_G^mWY0b$G!oq2_hH={=Lj2jlL$q5APbb!CtWJdAM7aZjluOCf8i{87-S z!hzSED9vkILwp{kp|8#G!R>wd)nYAeY5{O~aJU5fmq#Kzr#F}o;_OKX zW?{k@DO{3lSbQL&_&}Q61rf6ykh$%##Iu4@{-NFtZU&Y9jr#kG?I2Fm>hGs@z{**E zxV1mOCc8PfBnx4xaGo!Bi5P;+S#J=jR~fN}pyJi5NS?eC0|Rq7F%b$2L-4`5P~I-* zzUJ!t8>qgYqvhvIGdkhm;!rlV{6}kk^|c)MdOKpUixeV>=*?yo0D-CW)P_W4m;Qwp zAGqapMclGl-2(af=U6G3O3GAPW`4dwH-2O}+7mwQF=d<_B+ly3S4IV$JlZwUAab~4 z+cyIV!}cT zt2!vH4WI2P#L`g_kjP~q@)?|6#71!e#sIr)v1_Rs!C4N>EokBc->U9NUe}xR^N-TH zw>UrFkRHCfP7lAZ{AHZkn5?<+L;kZ6lgr}KSIiOrCwVl&D_5Xw<#|S)F;TSiH2iXA zpqH3)FN57fuyX^855Ri-L$rJR7ML^C5$|qI`{Q*zSc2Vi6AkQSD9#qWfMeXB;`FVD;cRat46P@=Q4y=e`K`M(;_7!8*gcJ-^aQ>M{ zVdNApJ;lgsOk~YD1Zi|7-_>{qB0O{eG7~Hr`6KiD;xt!$(ghRosnr?Cj`QY`?h_aY zM~SS-1wciT5`%gc4qG?{dhRrc**u+Kf8#Yd=Le{LIqKv5#&puPy^u6peYCi8Eg`NN?4a`MWEQ|IT zxkR$b2!O#+!gf3Rx-KL~coIpeTxwGf+@T15-Mm0}q<5@o*o+z}W?6*hHJ3N%qausn zu<7raObwe2T*Jo1kiY0SJW|H-TFIWiYV4kup>dm3_$k7Qv5}A}xb=2Xx|)yx3Y&K3yg^N4i z&wHj#1T}0-llW>-%Be~D*oiePHx^g76!1#tg-O2r;!Z#SDu-2Qc7E#+fChoSuGlpv zft57tCZ229sB3B1WXwDO+Fd3~d~E_4Qy535*&na3)YT37MfsREW3ql>Gtpdq$(2*9z9@4fvP0nlP`oiuqg)D_D? z4I7gs+9(1@YDEHYC+r&R$VA}S00H!tgri`|Ns}emEPy{ilvsjMA~8xtE?D8@{G7iQuC zSLbK{XRgvGLrg*(#!Vb!(5@dfW&~8>YMpFL@|{>Bs&tpV+)nT$7VBzfLBuB$?hv5C zgtWo9@M;Q_%K8aFqI5-&Di|I<-f)yONC2z|bZDu55l9wOh0>LOGX>(=sib~1+#!qN zm3fzqO~$Q#yhfOw0BD-WAmS%Z9*@M7BsfXs+Qk1Vb`h<0l?-qY7{lU}Hnv3kWWs+n zB1mwxuOpx5rd0fc0uUV+h1mFLhOme*$lcuy7XTk@ZhzgBR5&Wx?qWez!Qzw6p4uf% z+QCjGMtpUdw=z2h*SIooodT#BT3#RGSyeEvFb`5!-da8sNyO)r(t(NqS>I;_#x^3p zA7LBew>V`7kkbCJ(c|gsgUILzM!GIy;-cA!AeJli-n)BlqCvwW8%PAEAb{NY$DoKG zL7#;??!!YPaP*aIuFTtT0Wd#bIkW=a0RcLGUi?5I9h~VWd)`9On3kaI@C*sSGfruL zsWt)7?q<83h<+@hVOzYH;V&)JPKIA5i>cr;h%_;!aZ44=1z^06}d-<ViAG?`d5Y-UhN2J2|;yAp&oy(StA%MwKCm=N=4bC#2 zpMNNmI34woy*NAP(G4erD zQsq030+Bj`z{etnUKFF1%lTPYEL?;#y9F;dyXMqrBOB5|^CmWY!{2zPbUz>u&IgHD5} zmhrg`<&=^H0D?v*(sbt_Y)Qs>Xw{V%4x60%Q z2o7XE-#7x`E=wL?nS=PqNM4X84liZnV$_O#>=kah70iZBH1B;u63U(iMkkF?iNF6w zG4{?1L%dIaZ9o5;kL;xlQHm~o1g*)WE`u%UG{_|(e5oY_Ht(iVtLhYhOd+rLydZ)1 zBrk<0e_+%*V>0dT6SX#NQYP=hz<_M6*Q?lbfoR;^n8dSz&vUC2F)Z#ctg5P#_l1*- z1fJ3Xm%ryhE$_ImuZbm29Z3jth}fTadB2wzs|RR_fCZ1*ugQ$@#_84R2Blh` zP^)#W&d7LQSrpV2uV_ZeSitC-IEr`Nt3twA&*7`X#=RE*(e`XCD3SC2`e>x0`!^(l z!g!^fQ1G-EH7i~s)gRD}4}1drScQ-Tz|u!QN+X@QMhCkJJ)tO=U5z$i;n^^0X+{i@ z%pWH8%bh_1V>s7cl!s#V#1v|Mml%_H_Q$5TPYFhvcb6LC2|p8-$Gh5g6FiM3b#Z)# z(#BwN3paTAu3UjYRgfk=U_Av7A0J)`)ZbfK&$xg;#Bz997OT-S!a1i@B6!b8Gof{VaxkKBS|Tgr9IDed_?FA{chM_70$uaoFf?G|Vjp|;DD_3k9D zpPC9MR~8?zdxR7?a<0Wlcz;VKX63u^j(frvgtT~torS<`x^BU_JGq5rMDQ{834jANoC>jbK?e6!6C>fyz5+Hzm*UY$oA{pya|reVvprS_PUIHe(k?4I zNoDX241lYrr>+1@26U5|O-vPs_0>J@j}Qh3%w|wEu?^J^qDTmz=@dy!QUKRBrDIB# z6C+&T%8v9_~| zM3hLCvk$aM7!m&x&aO`69-eGu+}xdudYy z2}MMFTY=e3)8geeZHT1U>Kq&zj7u4ai|bNoS3kaKvvX=N()mrBUkED*-34ZA8J3{1 zvmwI968^0rGSRgImXy2V;~hD*Hf>HVueE9O4nZO?Tgx;euPfuy#kO?rZxt);+hE!!wtc!tPyBb?Wc56Z%y$Ex9;wKZ+#5;_XZ*1C)? zxmpsj8HD=;@WF&}lrTtOw$^P#vOQr2;RgZ;w+OLGavO8g=4mn_{Y64qyt!#(HnW+{ eY-W49?Ee9F4{>4p_0Vkq0000 Date: Sun, 10 Nov 2024 19:17:53 +0100 Subject: [PATCH 040/136] Bump version to 5.10.0 --- CMakeLists.txt | 2 +- misc/net.minetest.minetest.metainfo.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e496c0b7c..a23828426 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,7 +16,7 @@ set(VERSION_PATCH 0) set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string") # Change to false for releases -set(DEVELOPMENT_BUILD TRUE) +set(DEVELOPMENT_BUILD FALSE) set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") if(VERSION_EXTRA) diff --git a/misc/net.minetest.minetest.metainfo.xml b/misc/net.minetest.minetest.metainfo.xml index 92f8a80ef..ca61fe80c 100644 --- a/misc/net.minetest.minetest.metainfo.xml +++ b/misc/net.minetest.minetest.metainfo.xml @@ -149,6 +149,6 @@ celeron55@gmail.com - + From 8503d8de5ec536f3d6a0cbc7eca24bcc36b21ef3 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 10 Nov 2024 19:17:56 +0100 Subject: [PATCH 041/136] Continue with 5.11.0-dev --- CMakeLists.txt | 4 ++-- android/build.gradle | 2 +- doc/client_lua_api.md | 2 +- doc/menu_lua_api.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a23828426..de97d49bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,12 +11,12 @@ set(CLANG_MINIMUM_VERSION "7.0.1") # You should not need to edit these manually, use util/bump_version.sh set(VERSION_MAJOR 5) -set(VERSION_MINOR 10) +set(VERSION_MINOR 11) set(VERSION_PATCH 0) set(VERSION_EXTRA "" CACHE STRING "Stuff to append to version string") # Change to false for releases -set(DEVELOPMENT_BUILD FALSE) +set(DEVELOPMENT_BUILD TRUE) set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") if(VERSION_EXTRA) diff --git a/android/build.gradle b/android/build.gradle index 40266815e..a6b9c512d 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. project.ext.set("versionMajor", 5) // Version Major -project.ext.set("versionMinor", 10) // Version Minor +project.ext.set("versionMinor", 11) // Version Minor project.ext.set("versionPatch", 0) // Version Patch // ^ keep in sync with cmake diff --git a/doc/client_lua_api.md b/doc/client_lua_api.md index 715f6aa03..fe65dd92e 100644 --- a/doc/client_lua_api.md +++ b/doc/client_lua_api.md @@ -1,4 +1,4 @@ -Luanti Lua Client Modding API Reference 5.10.0 +Luanti Lua Client Modding API Reference 5.11.0 ============================================== **WARNING**: if you're looking for the `minetest` namespace (e.g. `minetest.something`), diff --git a/doc/menu_lua_api.md b/doc/menu_lua_api.md index f69c5917f..ae4afd998 100644 --- a/doc/menu_lua_api.md +++ b/doc/menu_lua_api.md @@ -1,4 +1,4 @@ -Luanti Lua Mainmenu API Reference 5.10.0 +Luanti Lua Mainmenu API Reference 5.11.0 ======================================== Introduction From a5e3fca40c8feb74c91cafca1aef1423e5375bb6 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 10 Nov 2024 20:22:02 +0100 Subject: [PATCH 042/136] Revert "Disable SDL2 for 5.10.0 (#15284)" This reverts commit 6d7a5197407460515b68e1ca18052c124b2fe15b. --- .github/workflows/windows.yml | 2 +- doc/compiling/linux.md | 12 ++++++------ doc/compiling/windows.md | 3 +-- irr/README.md | 2 +- irr/src/CMakeLists.txt | 2 +- util/buildbot/buildwin32.sh | 1 + util/buildbot/buildwin64.sh | 1 + util/buildbot/common.sh | 3 +++ util/ci/common.sh | 2 +- 9 files changed, 16 insertions(+), 12 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 670ce12f8..d82b9785d 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -73,7 +73,7 @@ jobs: env: VCPKG_VERSION: 01f602195983451bc83e72f4214af2cbc495aa94 # 2024.05.24 - vcpkg_packages: zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp opengl-registry + vcpkg_packages: zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp sdl2 strategy: fail-fast: false matrix: diff --git a/doc/compiling/linux.md b/doc/compiling/linux.md index 3b31250e8..573c6908e 100644 --- a/doc/compiling/linux.md +++ b/doc/compiling/linux.md @@ -21,27 +21,27 @@ For Debian/Ubuntu users: - sudo apt install g++ make libc6-dev cmake libpng-dev libjpeg-dev libxi-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev libzstd-dev libluajit-5.1-dev gettext + sudo apt install g++ make libc6-dev cmake libpng-dev libjpeg-dev libgl1-mesa-dev libsqlite3-dev libogg-dev libvorbis-dev libopenal-dev libcurl4-gnutls-dev libfreetype6-dev zlib1g-dev libgmp-dev libjsoncpp-dev libzstd-dev libluajit-5.1-dev gettext libsdl2-dev For Fedora users: - sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl-devel openal-soft-devel libpng-devel libjpeg-devel libvorbis-devel libXi-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel libzstd-devel gettext + sudo dnf install make automake gcc gcc-c++ kernel-devel cmake libcurl-devel openal-soft-devel libpng-devel libjpeg-devel libvorbis-devel libogg-devel freetype-devel mesa-libGL-devel zlib-devel jsoncpp-devel gmp-devel sqlite-devel luajit-devel leveldb-devel ncurses-devel spatialindex-devel libzstd-devel gettext SDL2-devel For openSUSE users: - sudo zypper install gcc gcc-c++ cmake libjpeg8-devel libpng16-devel openal-soft-devel libcurl-devel sqlite3-devel luajit-devel libzstd-devel Mesa-libGL-devel libXi-devel libvorbis-devel freetype2-devel + sudo zypper install gcc gcc-c++ cmake libjpeg8-devel libpng16-devel openal-soft-devel libcurl-devel sqlite3-devel luajit-devel libzstd-devel Mesa-libGL-devel libvorbis-devel freetype2-devel SDL2-devel For Arch users: - sudo pacman -S --needed base-devel libcurl-gnutls cmake libxi libpng sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses zstd gettext + sudo pacman -S --needed base-devel libcurl-gnutls cmake libpng sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses zstd gettext sdl2 For Alpine users: - sudo apk add build-base cmake libpng-dev jpeg-dev libxi-dev mesa-dev sqlite-dev libogg-dev libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev gmp-dev jsoncpp-dev luajit-dev zstd-dev gettext + sudo apk add build-base cmake libpng-dev jpeg-dev mesa-dev sqlite-dev libogg-dev libvorbis-dev openal-soft-dev curl-dev freetype-dev zlib-dev gmp-dev jsoncpp-dev luajit-dev zstd-dev gettext sdl2-dev For Void users: - sudo xbps-install cmake libpng-devel jpeg-devel libXi-devel mesa sqlite-devel libogg-devel libvorbis-devel libopenal-devel libcurl-devel freetype-devel zlib-devel gmp-devel jsoncpp-devel LuaJIT-devel zstd libzstd-devel gettext + sudo xbps-install cmake libpng-devel jpeg-devel mesa sqlite-devel libogg-devel libvorbis-devel libopenal-devel libcurl-devel freetype-devel zlib-devel gmp-devel jsoncpp-devel LuaJIT-devel zstd libzstd-devel gettext SDL2-devel ## Download diff --git a/doc/compiling/windows.md b/doc/compiling/windows.md index b36db4d9a..a4d9699f6 100644 --- a/doc/compiling/windows.md +++ b/doc/compiling/windows.md @@ -13,9 +13,8 @@ It is highly recommended to use vcpkg as package manager. After you successfully built vcpkg you can easily install the required libraries: - ```powershell -vcpkg install zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp gettext[tools] opengl-registry --triplet x64-windows +vcpkg install zlib zstd curl[winssl] openal-soft libvorbis libogg libjpeg-turbo sqlite3 freetype luajit gmp jsoncpp gettext[tools] sdl2 --triplet x64-windows ``` - `curl` is optional, but required to read the serverlist, `curl[winssl]` is required to use the content store. diff --git a/irr/README.md b/irr/README.md index 25fff00e5..50e7338a5 100644 --- a/irr/README.md +++ b/irr/README.md @@ -21,7 +21,7 @@ Aside from standard search options (`ZLIB_INCLUDE_DIR`, `ZLIB_LIBRARY`, ...) the * `ENABLE_OPENGL` - Enable OpenGL driver * `ENABLE_OPENGL3` (default: `OFF`) - Enable OpenGL 3+ driver * `ENABLE_GLES2` - Enable OpenGL ES 2+ driver -* `USE_SDL2` (default: ON for Android, OFF for other platforms) - Use SDL2 instead of older native device code +* `USE_SDL2` (default: platform-dependent, usually `ON`) - Use SDL2 instead of older native device code However, IrrlichtMt cannot be built or installed separately. diff --git a/irr/src/CMakeLists.txt b/irr/src/CMakeLists.txt index 1d2996734..3b578d699 100644 --- a/irr/src/CMakeLists.txt +++ b/irr/src/CMakeLists.txt @@ -1,6 +1,6 @@ # When enabling SDL2 by default on macOS, don't forget to change # "NSHighResolutionCapable" to true in "Info.plist". -if(ANDROID) +if(NOT APPLE) set(DEFAULT_SDL2 ON) endif() diff --git a/util/buildbot/buildwin32.sh b/util/buildbot/buildwin32.sh index b070a4343..34767f707 100755 --- a/util/buildbot/buildwin32.sh +++ b/util/buildbot/buildwin32.sh @@ -42,6 +42,7 @@ download "$libhost/llvm/libleveldb-$leveldb_version-win32.zip" download "$libhost/llvm/openal-soft-$openal_version-win32.zip" download "$libhost/llvm/libjpeg-$libjpeg_version-win32.zip" download "$libhost/llvm/libpng-$libpng_version-win32.zip" +download "$libhost/llvm/sdl2-$sdl2_version-win32.zip" # Set source dir, downloading Minetest as needed get_sources diff --git a/util/buildbot/buildwin64.sh b/util/buildbot/buildwin64.sh index 541045a02..c63a18901 100755 --- a/util/buildbot/buildwin64.sh +++ b/util/buildbot/buildwin64.sh @@ -42,6 +42,7 @@ download "$libhost/llvm/libleveldb-$leveldb_version-win64.zip" download "$libhost/llvm/openal-soft-$openal_version-win64.zip" download "$libhost/llvm/libjpeg-$libjpeg_version-win64.zip" download "$libhost/llvm/libpng-$libpng_version-win64.zip" +download "$libhost/llvm/sdl2-$sdl2_version-win64.zip" # Set source dir, downloading Minetest as needed get_sources diff --git a/util/buildbot/common.sh b/util/buildbot/common.sh index 32434abdd..ff3aef2e9 100644 --- a/util/buildbot/common.sh +++ b/util/buildbot/common.sh @@ -88,6 +88,9 @@ add_cmake_libs () { -DJPEG_INCLUDE_DIR=$libdir/libjpeg/include -DJPEG_DLL="$(_dlls $libdir/libjpeg/bin/libjpeg*)" + -DCMAKE_PREFIX_PATH=$libdir/sdl2/lib/cmake + -DSDL2_DLL="$(_dlls $libdir/sdl2/bin/*)" + -DZLIB_INCLUDE_DIR=$libdir/zlib/include -DZLIB_LIBRARY=$libdir/zlib/lib/libz.dll.a -DZLIB_DLL=$libdir/zlib/bin/zlib1.dll diff --git a/util/ci/common.sh b/util/ci/common.sh index bd0220db5..201b182f2 100644 --- a/util/ci/common.sh +++ b/util/ci/common.sh @@ -4,7 +4,7 @@ install_linux_deps() { local pkgs=( cmake gettext postgresql - libpng-dev libjpeg-dev libgl1-mesa-dev libxi-dev libfreetype-dev + libpng-dev libjpeg-dev libgl1-mesa-dev libsdl2-dev libfreetype-dev libsqlite3-dev libhiredis-dev libogg-dev libgmp-dev libvorbis-dev libopenal-dev libpq-dev libleveldb-dev libcurl4-openssl-dev libzstd-dev ) From af61de77773b8cbb37fbd888c77421cf63173dd2 Mon Sep 17 00:00:00 2001 From: grorp Date: Tue, 12 Nov 2024 10:52:20 +0100 Subject: [PATCH 043/136] Minor rendering code fixes (#15399) * Fix line numbers in shader errors * Fix uninitialized variables in shadow code --- src/client/shader.cpp | 9 ++++----- src/client/shadows/dynamicshadowsrender.cpp | 5 +++-- src/client/shadows/dynamicshadowsrender.h | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/client/shader.cpp b/src/client/shader.cpp index a227eb37a..778e17d2d 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -730,19 +730,18 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, shaders_header << "#define VOLUMETRIC_LIGHT 1\n"; } - shaders_header << "#line 0\n"; // reset the line counter for meaningful diagnostics - std::string common_header = shaders_header.str(); + const char *final_header = "#line 0\n"; // reset the line counter for meaningful diagnostics std::string vertex_shader = m_sourcecache.getOrLoad(name, "opengl_vertex.glsl"); std::string fragment_shader = m_sourcecache.getOrLoad(name, "opengl_fragment.glsl"); std::string geometry_shader = m_sourcecache.getOrLoad(name, "opengl_geometry.glsl"); - vertex_shader = common_header + vertex_header + vertex_shader; - fragment_shader = common_header + fragment_header + fragment_shader; + vertex_shader = common_header + vertex_header + final_header + vertex_shader; + fragment_shader = common_header + fragment_header + final_header + fragment_shader; const char *geometry_shader_ptr = nullptr; // optional if (!geometry_shader.empty()) { - geometry_shader = common_header + geometry_header + geometry_shader; + geometry_shader = common_header + geometry_header + final_header + geometry_shader; geometry_shader_ptr = geometry_shader.c_str(); } diff --git a/src/client/shadows/dynamicshadowsrender.cpp b/src/client/shadows/dynamicshadowsrender.cpp index 909e2761e..466903cbc 100644 --- a/src/client/shadows/dynamicshadowsrender.cpp +++ b/src/client/shadows/dynamicshadowsrender.cpp @@ -21,8 +21,9 @@ ShadowRenderer::ShadowRenderer(IrrlichtDevice *device, Client *client) : m_smgr(device->getSceneManager()), m_driver(device->getVideoDriver()), - m_client(client), m_current_frame(0), - m_perspective_bias_xy(0.8), m_perspective_bias_z(0.5) + m_client(client), m_shadow_strength(0.0f), m_shadow_tint(255, 0, 0, 0), + m_time_day(0.0f), m_force_update_shadow_map(false), m_current_frame(0), + m_perspective_bias_xy(0.8f), m_perspective_bias_z(0.5f) { (void) m_client; diff --git a/src/client/shadows/dynamicshadowsrender.h b/src/client/shadows/dynamicshadowsrender.h index 5395c90b3..a12ba01e4 100644 --- a/src/client/shadows/dynamicshadowsrender.h +++ b/src/client/shadows/dynamicshadowsrender.h @@ -118,11 +118,11 @@ private: std::vector m_shadow_node_array; float m_shadow_strength; - video::SColor m_shadow_tint{ 255, 0, 0, 0 }; + video::SColor m_shadow_tint; float m_shadow_strength_gamma; float m_shadow_map_max_distance; float m_shadow_map_texture_size; - float m_time_day{0.0f}; + float m_time_day; int m_shadow_samples; bool m_shadow_map_texture_32bit; bool m_shadows_enabled; @@ -130,7 +130,7 @@ private: bool m_shadow_map_colored; bool m_force_update_shadow_map; u8 m_map_shadow_update_frames; /* Use this number of frames to update map shaodw */ - u8 m_current_frame{0}; /* Current frame */ + u8 m_current_frame; /* Current frame */ f32 m_perspective_bias_xy; f32 m_perspective_bias_z; From 1c92d6243fd42291d25798982c1dd1f1bd1013bb Mon Sep 17 00:00:00 2001 From: wrrrzr <161970349+wrrrzr@users.noreply.github.com> Date: Tue, 12 Nov 2024 12:52:37 +0300 Subject: [PATCH 044/136] MainMenuManager: fix FIXME (#15414) --- src/client/game.cpp | 3 +-- src/gui/mainmenumanager.h | 8 +++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/client/game.cpp b/src/client/game.cpp index 27b58334f..f9f175d1b 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1219,8 +1219,7 @@ void Game::shutdown() /* cleanup menus */ while (g_menumgr.menuCount() > 0) { - g_menumgr.m_stack.front()->setVisible(false); - g_menumgr.deletingMenu(g_menumgr.m_stack.front()); + g_menumgr.deleteFront(); } m_game_ui->deleteFormspec(); diff --git a/src/gui/mainmenumanager.h b/src/gui/mainmenumanager.h index a37db2a32..d5f43796d 100644 --- a/src/gui/mainmenumanager.h +++ b/src/gui/mainmenumanager.h @@ -70,6 +70,12 @@ public: return m_stack.size(); } + void deleteFront() + { + m_stack.front()->setVisible(false); + deletingMenu(m_stack.front()); + } + bool pausesGame() { for (gui::IGUIElement *i : m_stack) { @@ -80,7 +86,7 @@ public: return false; } - // FIXME: why isn't this private? +private: std::list m_stack; }; From f916f5de78c970b55257f38e5d66a6ae34be695f Mon Sep 17 00:00:00 2001 From: sfan5 Date: Tue, 5 Nov 2024 19:14:44 +0100 Subject: [PATCH 045/136] Add basic unit tests for collisionMoveSimple --- src/collision.cpp | 6 +- src/collision.h | 8 ++- src/dummymap.h | 14 ++++ src/unittest/test_collision.cpp | 113 ++++++++++++++++++++++++++++++++ 4 files changed, 139 insertions(+), 2 deletions(-) diff --git a/src/collision.cpp b/src/collision.cpp index dcb318b0f..9fd872eb8 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -21,6 +21,8 @@ #warning "-ffast-math is known to cause bugs in collision code, do not use!" #endif +bool g_collision_problems_encountered = false; + namespace { struct NearbyCollisionInfo { @@ -342,6 +344,7 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, warningstream << "collisionMoveSimple: maximum step interval exceeded," " lost movement details!"<= 100) { - warningstream << "collisionMoveSimple: Loop count exceeded, aborting to avoid infiniite loop" << std::endl; + warningstream << "collisionMoveSimple: Loop count exceeded, aborting to avoid infinite loop" << std::endl; + g_collision_problems_encountered = true; break; } diff --git a/src/collision.h b/src/collision.h index 20dd42201..fa88c469d 100644 --- a/src/collision.h +++ b/src/collision.h @@ -37,6 +37,8 @@ struct CollisionInfo v3f new_pos; v3f old_speed; v3f new_speed; + + // FIXME: this is equivalent to `axis`, why does it exist? int plane = -1; }; @@ -44,12 +46,16 @@ struct collisionMoveResult { collisionMoveResult() = default; - bool touching_ground = false; bool collides = false; + bool touching_ground = false; bool standing_on_object = false; std::vector collisions; }; +/// Status if any problems were ever encountered during collision detection. +/// @warning For unit test use only. +extern bool g_collision_problems_encountered; + /// @brief Moves using a single iteration; speed should not exceed pos_max_d/dtime /// @param self (optional) ActiveObject to ignore in the collision detection. collisionMoveResult collisionMoveSimple(Environment *env,IGameDef *gamedef, diff --git a/src/dummymap.h b/src/dummymap.h index ab36f211b..2da371884 100644 --- a/src/dummymap.h +++ b/src/dummymap.h @@ -24,5 +24,19 @@ public: ~DummyMap() = default; + void fill(v3s16 bpmin, v3s16 bpmax, MapNode n) + { + for (s16 z = bpmin.Z; z <= bpmax.Z; z++) + for (s16 y = bpmin.Y; y <= bpmax.Y; y++) + for (s16 x = bpmin.X; x <= bpmax.X; x++) { + MapBlock *block = getBlockNoCreateNoEx({x, y, z}); + if (block) { + for (size_t i = 0; i < MapBlock::nodecount; i++) + block->getData()[i] = n; + block->expireIsAirCache(); + } + } + } + bool maySaveBlocks() override { return false; } }; diff --git a/src/unittest/test_collision.cpp b/src/unittest/test_collision.cpp index ce2e3933c..0c9ba0798 100644 --- a/src/unittest/test_collision.cpp +++ b/src/unittest/test_collision.cpp @@ -3,6 +3,9 @@ // Copyright (C) 2013 celeron55, Perttu Ahola #include "test.h" +#include "dummymap.h" +#include "environment.h" +#include "irrlicht_changes/printing.h" #include "collision.h" @@ -14,6 +17,7 @@ public: void runTests(IGameDef *gamedef); void testAxisAlignedCollision(); + void testCollisionMoveSimple(IGameDef *gamedef); }; static TestCollision g_test_instance; @@ -21,8 +25,42 @@ static TestCollision g_test_instance; void TestCollision::runTests(IGameDef *gamedef) { TEST(testAxisAlignedCollision); + TEST(testCollisionMoveSimple, gamedef); } +namespace { + class TestEnvironment : public Environment { + DummyMap map; + public: + TestEnvironment(IGameDef *gamedef) + : Environment(gamedef), map(gamedef, {-1, -1, -1}, {1, 1, 1}) + { + map.fill({-1, -1, -1}, {1, 1, 1}, MapNode(CONTENT_AIR)); + } + + void step(f32 dtime) override {} + + Map &getMap() override { return map; } + + void getSelectedActiveObjects(const core::line3d &shootline_on_map, + std::vector &objects, + const std::optional &pointabilities) override {} + }; +} + +#define UASSERTEQ_F(actual, expected) do { \ + f32 a = (actual); \ + f32 e = (expected); \ + UTEST(fabsf(a - e) <= 0.0001f, "actual: %.f expected: %.f", a, e) \ + } while (0) + +#define UASSERTEQ_V3F(actual, expected) do { \ + v3f va = (actual); \ + v3f ve = (expected); \ + UASSERTEQ_F(va.X, ve.X); UASSERTEQ_F(va.Y, ve.Y); UASSERTEQ_F(va.Z, ve.Z); \ + } while (0) + + //////////////////////////////////////////////////////////////////////////////// void TestCollision::testAxisAlignedCollision() @@ -163,3 +201,78 @@ void TestCollision::testAxisAlignedCollision() } } } + +#define fpos(x,y,z) (BS * v3f(x, y, z)) + +void TestCollision::testCollisionMoveSimple(IGameDef *gamedef) +{ + auto env = std::make_unique(gamedef); + g_collision_problems_encountered = false; + + for (s16 x = 0; x < MAP_BLOCKSIZE; x++) + for (s16 z = 0; z < MAP_BLOCKSIZE; z++) + env->getMap().setNode({x, 0, z}, MapNode(t_CONTENT_STONE)); + + const f32 pos_max_d = 0.25f * BS; // ? + v3f pos, speed, accel; + const aabb3f box(fpos(-0.1f, 0, -0.1f), fpos(0.1f, 1.4f, 0.1f)); + collisionMoveResult res; + + /* simple movement with accel */ + pos = fpos(4, 1, 4); + speed = fpos(0, 0, 0); + accel = fpos(0, 1, 0); + res = collisionMoveSimple(env.get(), gamedef, pos_max_d, box, 0.0f, 1.0f, + &pos, &speed, accel); + + UASSERT(!res.touching_ground || !res.collides || !res.standing_on_object); + UASSERT(res.collisions.empty()); + // FIXME: it's easy to tell that this should be y=1.5f, but our code does it wrong. + // It's unclear if/how this will be fixed. + UASSERTEQ_V3F(pos, fpos(4, 2, 4)); + UASSERTEQ_V3F(speed, fpos(0, 1, 0)); + + /* standing on ground */ + pos = fpos(0, 0.5f, 0); + speed = fpos(0, 0, 0); + accel = fpos(0, -9.81f, 0); + res = collisionMoveSimple(env.get(), gamedef, pos_max_d, box, 0.0f, 0.04f, + &pos, &speed, accel); + + UASSERT(res.collides); + UASSERT(res.touching_ground); + UASSERT(!res.standing_on_object); + UASSERTEQ_V3F(pos, fpos(0, 0.5f, 0)); + UASSERTEQ_V3F(speed, fpos(0, 0, 0)); + UASSERT(res.collisions.size() == 1); + { + auto &ci = res.collisions.front(); + UASSERTEQ(int, ci.type, COLLISION_NODE); + UASSERTEQ(int, ci.axis, COLLISION_AXIS_Y); + UASSERTEQ(v3s16, ci.node_p, v3s16(0, 0, 0)); + } + + /* not moving never collides */ + pos = fpos(0, -100, 0); + speed = fpos(0, 0, 0); + accel = fpos(0, 0, 0); + res = collisionMoveSimple(env.get(), gamedef, pos_max_d, box, 0.0f, 1/60.0f, + &pos, &speed, accel); + UASSERT(!res.collides); + + /* collision in ignore */ + pos = fpos(0, -100, 0); + speed = fpos(5, 0, 0); + accel = fpos(0, 0, 0); + res = collisionMoveSimple(env.get(), gamedef, pos_max_d, box, 0.0f, 1/60.0f, + &pos, &speed, accel); + UASSERTEQ_V3F(speed, fpos(0, 0, 0)); + UASSERT(!res.collides); // FIXME this is actually inconsistent + UASSERT(res.collisions.empty()); + + // TODO things to test: + // standing_on_object, multiple collisions, bouncy, stepheight + + // No warnings should have been raised during our test. + UASSERT(!g_collision_problems_encountered); +} From 9a44d835d6380e8e8a8f2b5070899dc8770aa1db Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 8 Nov 2024 15:03:48 +0100 Subject: [PATCH 046/136] Remove redundant CollisionInfo::plane --- src/client/localplayer.cpp | 2 +- src/collision.cpp | 1 - src/collision.h | 7 ++----- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/client/localplayer.cpp b/src/client/localplayer.cpp index 2ea4c5495..4286e48ff 100644 --- a/src/client/localplayer.cpp +++ b/src/client/localplayer.cpp @@ -1196,7 +1196,7 @@ void LocalPlayer::handleAutojump(f32 dtime, Environment *env, bool horizontal_collision = false; for (const auto &colinfo : result.collisions) { - if (colinfo.type == COLLISION_NODE && colinfo.plane != 1) { + if (colinfo.type == COLLISION_NODE && colinfo.axis != COLLISION_AXIS_Y) { horizontal_collision = true; break; // one is enough } diff --git a/src/collision.cpp b/src/collision.cpp index 9fd872eb8..e352b0827 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -509,7 +509,6 @@ collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, info.object = nearest_info.obj; info.new_pos = *pos_f; info.old_speed = *speed_f; - info.plane = nearest_collided; // Set the speed component that caused the collision to zero if (step_up) { diff --git a/src/collision.h b/src/collision.h index fa88c469d..67b4735f4 100644 --- a/src/collision.h +++ b/src/collision.h @@ -12,13 +12,13 @@ class IGameDef; class Environment; class ActiveObject; -enum CollisionType +enum CollisionType : u8 { COLLISION_NODE, COLLISION_OBJECT, }; -enum CollisionAxis +enum CollisionAxis : s8 { COLLISION_AXIS_NONE = -1, COLLISION_AXIS_X, @@ -37,9 +37,6 @@ struct CollisionInfo v3f new_pos; v3f old_speed; v3f new_speed; - - // FIXME: this is equivalent to `axis`, why does it exist? - int plane = -1; }; struct collisionMoveResult From c00129360ee0bb0d001f16c286191611311cdfeb Mon Sep 17 00:00:00 2001 From: sfan5 Date: Mon, 11 Nov 2024 19:46:02 +0100 Subject: [PATCH 047/136] Remove unused pos_max_d --- src/client/clientenvironment.cpp | 6 ++--- src/client/content_cao.cpp | 3 +-- src/client/localplayer.cpp | 43 ++++++++------------------------ src/client/localplayer.h | 13 +++++----- src/client/particles.cpp | 2 +- src/collision.cpp | 2 +- src/collision.h | 5 ++-- src/player.h | 7 ------ src/server/luaentity_sao.cpp | 3 +-- src/serverenvironment.cpp | 15 ----------- src/unittest/test_collision.cpp | 9 +++---- 11 files changed, 29 insertions(+), 79 deletions(-) diff --git a/src/client/clientenvironment.cpp b/src/client/clientenvironment.cpp index b6ae67588..bda9fc870 100644 --- a/src/client/clientenvironment.cpp +++ b/src/client/clientenvironment.cpp @@ -96,7 +96,6 @@ void ClientEnvironment::step(float dtime) /* Maximum position increment */ - //f32 position_max_increment = 0.05*BS; f32 position_max_increment = 0.1*BS; // Maximum time increment (for collision detection etc) @@ -176,12 +175,11 @@ void ClientEnvironment::step(float dtime) } /* - Move the lplayer. + Move the local player. This also does collision detection. */ - lplayer->move(dtime_part, this, position_max_increment, - &player_collisions); + lplayer->move(dtime_part, this, &player_collisions); } bool player_immortal = false; diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 16ceda4ec..6c7976ea7 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -1143,11 +1143,10 @@ void GenericCAO::step(float dtime, ClientEnvironment *env) box.MinEdge *= BS; box.MaxEdge *= BS; collisionMoveResult moveresult; - f32 pos_max_d = BS*0.125; // Distance per iteration v3f p_pos = m_position; v3f p_velocity = m_velocity; moveresult = collisionMoveSimple(env,env->getGameDef(), - pos_max_d, box, m_prop.stepheight, dtime, + box, m_prop.stepheight, dtime, &p_pos, &p_velocity, m_acceleration, this, m_prop.collideWithObjects); // Apply results diff --git a/src/client/localplayer.cpp b/src/client/localplayer.cpp index 4286e48ff..53a9db810 100644 --- a/src/client/localplayer.cpp +++ b/src/client/localplayer.cpp @@ -209,7 +209,7 @@ bool LocalPlayer::updateSneakNode(Map *map, const v3f &position, return true; } -void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d, +void LocalPlayer::move(f32 dtime, Environment *env, std::vector *collision_info) { // Node at feet position, update each ClientEnvironment::step() @@ -218,7 +218,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d, // Temporary option for old move code if (!physics_override.new_move) { - old_move(dtime, env, pos_max_d, collision_info); + old_move(dtime, env, collision_info); return; } @@ -320,17 +320,6 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d, nodemgr->get(node2.getContent()).climbable) && !free_move; } - /* - Collision uncertainty radius - Make it a bit larger than the maximum distance of movement - */ - //f32 d = pos_max_d * 1.1; - // A fairly large value in here makes moving smoother - f32 d = 0.15f * BS; - - // This should always apply, otherwise there are glitches - sanity_check(d > pos_max_d); - // Player object property step height is multiplied by BS in // /src/script/common/c_content.cpp and /src/content_sao.cpp float player_stepheight = (m_cao == nullptr) ? 0.0f : @@ -341,7 +330,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d, const v3f initial_speed = m_speed; collisionMoveResult result = collisionMoveSimple(env, m_client, - pos_max_d, m_collisionbox, player_stepheight, dtime, + m_collisionbox, player_stepheight, dtime, &position, &m_speed, accel_f, m_cao); bool could_sneak = control.sneak && !free_move && !in_liquid && @@ -528,12 +517,12 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d, m_can_jump = m_can_jump && jumpspeed != 0.0f; // Autojump - handleAutojump(dtime, env, result, initial_position, initial_speed, pos_max_d); + handleAutojump(dtime, env, result, initial_position, initial_speed); } -void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d) +void LocalPlayer::move(f32 dtime, Environment *env) { - move(dtime, env, pos_max_d, NULL); + move(dtime, env, nullptr); } void LocalPlayer::applyControl(float dtime, Environment *env) @@ -827,7 +816,7 @@ void LocalPlayer::accelerate(const v3f &target_speed, const f32 max_increase_H, } // Temporary option for old move code -void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d, +void LocalPlayer::old_move(f32 dtime, Environment *env, std::vector *collision_info) { Map *map = &env->getMap(); @@ -924,15 +913,6 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d, is_climbing = (nodemgr->get(node.getContent()).climbable || nodemgr->get(node2.getContent()).climbable) && !free_move; - /* - Collision uncertainty radius - Make it a bit larger than the maximum distance of movement - */ - //f32 d = pos_max_d * 1.1; - // A fairly large value in here makes moving smoother - f32 d = 0.15f * BS; - // This should always apply, otherwise there are glitches - sanity_check(d > pos_max_d); // Maximum distance over border for sneaking f32 sneak_max = BS * 0.4f; @@ -971,7 +951,7 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d, const v3f initial_speed = m_speed; collisionMoveResult result = collisionMoveSimple(env, m_client, - pos_max_d, m_collisionbox, player_stepheight, dtime, + m_collisionbox, player_stepheight, dtime, &position, &m_speed, accel_f, m_cao); // Position was slightly changed; update standing node pos @@ -1155,7 +1135,7 @@ void LocalPlayer::old_move(f32 dtime, Environment *env, f32 pos_max_d, } // Autojump - handleAutojump(dtime, env, result, initial_position, initial_speed, pos_max_d); + handleAutojump(dtime, env, result, initial_position, initial_speed); } float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH) @@ -1178,8 +1158,7 @@ float LocalPlayer::getSlipFactor(Environment *env, const v3f &speedH) } void LocalPlayer::handleAutojump(f32 dtime, Environment *env, - const collisionMoveResult &result, const v3f &initial_position, - const v3f &initial_speed, f32 pos_max_d) + const collisionMoveResult &result, v3f initial_position, v3f initial_speed) { PlayerSettings &player_settings = getPlayerSettings(); if (!player_settings.autojump) @@ -1235,7 +1214,7 @@ void LocalPlayer::handleAutojump(f32 dtime, Environment *env, v3f jump_speed = initial_speed; // try at peak of jump, zero step height - collisionMoveResult jump_result = collisionMoveSimple(env, m_client, pos_max_d, + collisionMoveResult jump_result = collisionMoveSimple(env, m_client, m_collisionbox, 0.0f, dtime, &jump_pos, &jump_speed, v3f(0.0f), m_cao); // see if we can get a little bit farther horizontally if we had diff --git a/src/client/localplayer.h b/src/client/localplayer.h index db99d3679..93b768ceb 100644 --- a/src/client/localplayer.h +++ b/src/client/localplayer.h @@ -16,6 +16,7 @@ class GenericCAO; class ClientActiveObject; class ClientEnvironment; class IGameDef; +struct CollisionInfo; struct collisionMoveResult; enum class LocalPlayerAnimation @@ -68,11 +69,8 @@ public: f32 gravity = 0; // total downwards acceleration - void move(f32 dtime, Environment *env, f32 pos_max_d); - void move(f32 dtime, Environment *env, f32 pos_max_d, - std::vector *collision_info); - // Temporary option for old move code - void old_move(f32 dtime, Environment *env, f32 pos_max_d, + void move(f32 dtime, Environment *env); + void move(f32 dtime, Environment *env, std::vector *collision_info); void applyControl(float dtime, Environment *env); @@ -174,10 +172,11 @@ private: const f32 max_increase_V, const bool use_pitch); bool updateSneakNode(Map *map, const v3f &position, const v3f &sneak_max); float getSlipFactor(Environment *env, const v3f &speedH); + void old_move(f32 dtime, Environment *env, + std::vector *collision_info); void handleAutojump(f32 dtime, Environment *env, const collisionMoveResult &result, - const v3f &position_before_move, const v3f &speed_before_move, - f32 pos_max_d); + v3f position_before_move, v3f speed_before_move); v3f m_position; v3s16 m_standing_node; diff --git a/src/client/particles.cpp b/src/client/particles.cpp index 114abba08..6ba7fa701 100644 --- a/src/client/particles.cpp +++ b/src/client/particles.cpp @@ -89,7 +89,7 @@ void Particle::step(float dtime, ClientEnvironment *env) aabb3f box(v3f(-m_p.size / 2.0f), v3f(m_p.size / 2.0f)); v3f p_pos = m_pos * BS; v3f p_velocity = m_velocity * BS; - collisionMoveResult r = collisionMoveSimple(env, env->getGameDef(), BS * 0.5f, + collisionMoveResult r = collisionMoveSimple(env, env->getGameDef(), box, 0.0f, dtime, &p_pos, &p_velocity, m_acceleration * BS, nullptr, m_p.object_collision); diff --git a/src/collision.cpp b/src/collision.cpp index e352b0827..4ee9d5ed8 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -323,7 +323,7 @@ static void add_object_boxes(Environment *env, #define PROFILER_NAME(text) (dynamic_cast(env) ? ("Server: " text) : ("Client: " text)) collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, - f32 pos_max_d, const aabb3f &box_0, + const aabb3f &box_0, f32 stepheight, f32 dtime, v3f *pos_f, v3f *speed_f, v3f accel_f, ActiveObject *self, diff --git a/src/collision.h b/src/collision.h index 67b4735f4..5306cdd8a 100644 --- a/src/collision.h +++ b/src/collision.h @@ -53,10 +53,9 @@ struct collisionMoveResult /// @warning For unit test use only. extern bool g_collision_problems_encountered; -/// @brief Moves using a single iteration; speed should not exceed pos_max_d/dtime /// @param self (optional) ActiveObject to ignore in the collision detection. -collisionMoveResult collisionMoveSimple(Environment *env,IGameDef *gamedef, - f32 pos_max_d, const aabb3f &box_0, +collisionMoveResult collisionMoveSimple(Environment *env, IGameDef *gamedef, + const aabb3f &box_0, f32 stepheight, f32 dtime, v3f *pos_f, v3f *speed_f, v3f accel_f, ActiveObject *self=NULL, diff --git a/src/player.h b/src/player.h index 0af737d32..25c80039c 100644 --- a/src/player.h +++ b/src/player.h @@ -127,7 +127,6 @@ struct PlayerPhysicsOverride }; class Map; -struct CollisionInfo; struct HudElement; class Environment; @@ -140,12 +139,6 @@ public: DISABLE_CLASS_COPY(Player); - virtual void move(f32 dtime, Environment *env, f32 pos_max_d) - {} - virtual void move(f32 dtime, Environment *env, f32 pos_max_d, - std::vector *collision_info) - {} - // in BS-space inline void setSpeed(v3f speed) { diff --git a/src/server/luaentity_sao.cpp b/src/server/luaentity_sao.cpp index 27408565d..5de0167d6 100644 --- a/src/server/luaentity_sao.cpp +++ b/src/server/luaentity_sao.cpp @@ -155,12 +155,11 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) aabb3f box = m_prop.collisionbox; box.MinEdge *= BS; box.MaxEdge *= BS; - f32 pos_max_d = BS*0.25; // Distance per iteration v3f p_pos = m_base_position; v3f p_velocity = m_velocity; v3f p_acceleration = m_acceleration; moveresult = collisionMoveSimple(m_env, m_env->getGameDef(), - pos_max_d, box, m_prop.stepheight, dtime, + box, m_prop.stepheight, dtime, &p_pos, &p_velocity, p_acceleration, this, m_prop.collideWithObjects); moveresult_p = &moveresult; diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index b333a30ec..d60e41ad9 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -1404,21 +1404,6 @@ void ServerEnvironment::step(float dtime) m_game_time_fraction_counter -= (float)inc_i; } - /* - Handle players - */ - { - ScopeProfiler sp(g_profiler, "ServerEnv: move players", SPT_AVG); - for (RemotePlayer *player : m_players) { - // Ignore disconnected players - if (player->getPeerId() == PEER_ID_INEXISTENT) - continue; - - // Move - player->move(dtime, this, 100 * BS); - } - } - /* Manage active block list */ diff --git a/src/unittest/test_collision.cpp b/src/unittest/test_collision.cpp index 0c9ba0798..40cd52798 100644 --- a/src/unittest/test_collision.cpp +++ b/src/unittest/test_collision.cpp @@ -213,7 +213,6 @@ void TestCollision::testCollisionMoveSimple(IGameDef *gamedef) for (s16 z = 0; z < MAP_BLOCKSIZE; z++) env->getMap().setNode({x, 0, z}, MapNode(t_CONTENT_STONE)); - const f32 pos_max_d = 0.25f * BS; // ? v3f pos, speed, accel; const aabb3f box(fpos(-0.1f, 0, -0.1f), fpos(0.1f, 1.4f, 0.1f)); collisionMoveResult res; @@ -222,7 +221,7 @@ void TestCollision::testCollisionMoveSimple(IGameDef *gamedef) pos = fpos(4, 1, 4); speed = fpos(0, 0, 0); accel = fpos(0, 1, 0); - res = collisionMoveSimple(env.get(), gamedef, pos_max_d, box, 0.0f, 1.0f, + res = collisionMoveSimple(env.get(), gamedef, box, 0.0f, 1.0f, &pos, &speed, accel); UASSERT(!res.touching_ground || !res.collides || !res.standing_on_object); @@ -236,7 +235,7 @@ void TestCollision::testCollisionMoveSimple(IGameDef *gamedef) pos = fpos(0, 0.5f, 0); speed = fpos(0, 0, 0); accel = fpos(0, -9.81f, 0); - res = collisionMoveSimple(env.get(), gamedef, pos_max_d, box, 0.0f, 0.04f, + res = collisionMoveSimple(env.get(), gamedef, box, 0.0f, 0.04f, &pos, &speed, accel); UASSERT(res.collides); @@ -256,7 +255,7 @@ void TestCollision::testCollisionMoveSimple(IGameDef *gamedef) pos = fpos(0, -100, 0); speed = fpos(0, 0, 0); accel = fpos(0, 0, 0); - res = collisionMoveSimple(env.get(), gamedef, pos_max_d, box, 0.0f, 1/60.0f, + res = collisionMoveSimple(env.get(), gamedef, box, 0.0f, 1/60.0f, &pos, &speed, accel); UASSERT(!res.collides); @@ -264,7 +263,7 @@ void TestCollision::testCollisionMoveSimple(IGameDef *gamedef) pos = fpos(0, -100, 0); speed = fpos(5, 0, 0); accel = fpos(0, 0, 0); - res = collisionMoveSimple(env.get(), gamedef, pos_max_d, box, 0.0f, 1/60.0f, + res = collisionMoveSimple(env.get(), gamedef, box, 0.0f, 1/60.0f, &pos, &speed, accel); UASSERTEQ_V3F(speed, fpos(0, 0, 0)); UASSERT(!res.collides); // FIXME this is actually inconsistent From 44b261d136fb0cbad5a971b0cb5a7d4803995b0b Mon Sep 17 00:00:00 2001 From: cx384 Date: Tue, 12 Nov 2024 10:53:04 +0100 Subject: [PATCH 048/136] Luacheck: add VoxelManip to globals --- .luacheckrc | 1 + games/devtest/.luacheckrc | 1 + 2 files changed, 2 insertions(+) diff --git a/.luacheckrc b/.luacheckrc index afc136c7c..3a4667b4a 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -15,6 +15,7 @@ read_globals = { "fgettext", "fgettext_ne", "vector", "VoxelArea", + "VoxelManip", "profiler", "Settings", "PerlinNoise", "PerlinNoiseMap", diff --git a/games/devtest/.luacheckrc b/games/devtest/.luacheckrc index 261cacf56..c5a7119a4 100644 --- a/games/devtest/.luacheckrc +++ b/games/devtest/.luacheckrc @@ -23,6 +23,7 @@ read_globals = { "fgettext", "fgettext_ne", "vector", "VoxelArea", + "VoxelManip", "profiler", "Settings", "check", From 4c44942a39f61f7a87a4f4ddecbad8cec441057f Mon Sep 17 00:00:00 2001 From: Erich Schubert Date: Tue, 12 Nov 2024 10:53:17 +0100 Subject: [PATCH 049/136] Add weights to biomes (#15142) --- builtin/game/features.lua | 1 + doc/lua_api.md | 6 ++++++ src/mapgen/mg_biome.cpp | 6 +++++- src/mapgen/mg_biome.h | 1 + src/script/lua_api/l_mapgen.cpp | 1 + 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/builtin/game/features.lua b/builtin/game/features.lua index 88ec282c3..8d7753839 100644 --- a/builtin/game/features.lua +++ b/builtin/game/features.lua @@ -43,6 +43,7 @@ core.features = { hotbar_hud_element = true, bulk_lbms = true, abm_without_neighbors = true, + biome_weights = true, } function core.has_feature(arg) diff --git a/doc/lua_api.md b/doc/lua_api.md index e27964fc5..ba3a0e630 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -5657,6 +5657,8 @@ Utilities bulk_lbms = true, -- ABM supports field without_neighbors (5.10.0) abm_without_neighbors = true, + -- biomes have a weight parameter (5.11.0) + biome_weights = true, } ``` @@ -10709,6 +10711,10 @@ performance and computing power the practical limit is much lower. -- distribution of the biomes. -- Heat and humidity have average values of 50, vary mostly between -- 0 and 100 but can exceed these values. + + weight = 1.0, + -- Relative weight of the biome in the Voronoi diagram. + -- A value of 0 (or less) is ignored and equivalent to 1.0. } ``` diff --git a/src/mapgen/mg_biome.cpp b/src/mapgen/mg_biome.cpp index 40e6aeda9..a1c4f5810 100644 --- a/src/mapgen/mg_biome.cpp +++ b/src/mapgen/mg_biome.cpp @@ -39,6 +39,7 @@ BiomeManager::BiomeManager(Server *server) : b->heat_point = 0.0; b->humidity_point = 0.0; b->vertical_blend = 0; + b->weight = 1.0f; b->m_nodenames.emplace_back("mapgen_stone"); b->m_nodenames.emplace_back("mapgen_stone"); @@ -256,7 +257,9 @@ Biome *BiomeGenOriginal::calcBiomeFromNoise(float heat, float humidity, v3s16 po float d_heat = heat - b->heat_point; float d_humidity = humidity - b->humidity_point; - float dist = (d_heat * d_heat) + (d_humidity * d_humidity); + float dist = ((d_heat * d_heat) + (d_humidity * d_humidity)); + if (b->weight > 0.f) + dist /= b->weight; if (pos.Y <= b->max_pos.Y) { // Within y limits of biome b if (dist < dist_min) { @@ -321,6 +324,7 @@ ObjDef *Biome::clone() const obj->heat_point = heat_point; obj->humidity_point = humidity_point; obj->vertical_blend = vertical_blend; + obj->weight = weight; return obj; } diff --git a/src/mapgen/mg_biome.h b/src/mapgen/mg_biome.h index c23dab2aa..3e9de89d9 100644 --- a/src/mapgen/mg_biome.h +++ b/src/mapgen/mg_biome.h @@ -54,6 +54,7 @@ public: float heat_point; float humidity_point; s16 vertical_blend; + float weight; virtual void resolveNodeNames(); }; diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index 0e9c15a1b..c8b412c73 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -374,6 +374,7 @@ Biome *read_biome_def(lua_State *L, int index, const NodeDefManager *ndef) b->heat_point = getfloatfield_default(L, index, "heat_point", 0.f); b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.f); b->vertical_blend = getintfield_default(L, index, "vertical_blend", 0); + b->weight = getfloatfield_default(L, index, "weight", 1.f); b->flags = 0; // reserved b->min_pos = getv3s16field_default( From 1fd4e0b82dd4e15aef0025eccdcb3bc984f70d9d Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 3 Nov 2024 14:24:35 +0100 Subject: [PATCH 050/136] Refactor ScriptApiSecurity for cleaner separation of concerns --- src/script/common/c_internal.cpp | 10 +- src/script/common/c_internal.h | 1 + src/script/cpp_api/s_async.h | 8 +- src/script/cpp_api/s_base.cpp | 33 +----- src/script/cpp_api/s_base.h | 20 ++-- src/script/cpp_api/s_security.cpp | 183 +++++++++++++++++++----------- src/script/cpp_api/s_security.h | 68 +++++++++-- src/script/lua_api/l_util.cpp | 13 +-- src/script/scripting_client.h | 12 ++ src/script/scripting_emerge.h | 7 ++ src/script/scripting_server.h | 9 ++ 11 files changed, 229 insertions(+), 135 deletions(-) diff --git a/src/script/common/c_internal.cpp b/src/script/common/c_internal.cpp index ae6b5cc23..eb74bfa8e 100644 --- a/src/script/common/c_internal.cpp +++ b/src/script/common/c_internal.cpp @@ -3,6 +3,7 @@ // Copyright (C) 2013 celeron55, Perttu Ahola #include "common/c_internal.h" +#include "cpp_api/s_security.h" #include "util/numeric.h" #include "debug.h" #include "log.h" @@ -184,12 +185,9 @@ void log_deprecated(lua_State *L, std::string_view message, int stack_depth, boo void call_string_dump(lua_State *L, int idx) { - // Retrieve string.dump from insecure env to avoid it being tampered with - lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP); - if (!lua_isnil(L, -1)) - lua_getfield(L, -1, "string"); - else - lua_getglobal(L, "string"); + // Retrieve string.dump from untampered env + ScriptApiSecurity::getGlobalsBackup(L); + lua_getfield(L, -1, "string"); lua_getfield(L, -1, "dump"); lua_remove(L, -2); // remove _G lua_remove(L, -2); // remove 'string' table diff --git a/src/script/common/c_internal.h b/src/script/common/c_internal.h index e0b30044b..ce948801b 100644 --- a/src/script/common/c_internal.h +++ b/src/script/common/c_internal.h @@ -39,6 +39,7 @@ enum { #endif CUSTOM_RIDX_SCRIPTAPI, + /// @warning don't use directly, `ScriptApiSecurity` has wrappers CUSTOM_RIDX_GLOBALS_BACKUP, CUSTOM_RIDX_CURRENT_MOD_NAME, CUSTOM_RIDX_ERROR_HANDLER, diff --git a/src/script/cpp_api/s_async.h b/src/script/cpp_api/s_async.h index 3dc339821..8a081b2fc 100644 --- a/src/script/cpp_api/s_async.h +++ b/src/script/cpp_api/s_async.h @@ -50,11 +50,17 @@ class AsyncWorkerThread : public Thread, public: virtual ~AsyncWorkerThread(); - void *run(); + void *run() override; protected: AsyncWorkerThread(AsyncEngine* jobDispatcher, const std::string &name); + bool checkPathInternal(const std::string &abs_path, bool write_required, + bool *write_allowed) override { + return ScriptApiSecurity::checkPathWithGamedef(getStack(), + abs_path, write_required, write_allowed); + }; + private: AsyncEngine *jobDispatcher = nullptr; bool isErrored = false; diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp index d04419302..9cf886efd 100644 --- a/src/script/cpp_api/s_base.cpp +++ b/src/script/cpp_api/s_base.cpp @@ -225,37 +225,6 @@ std::string ScriptApiBase::getCurrentModNameInsecure(lua_State *L) return ret; } -std::string ScriptApiBase::getCurrentModName(lua_State *L) -{ - auto script = ModApiBase::getScriptApiBase(L); - if (script->getType() == ScriptingType::Async || - script->getType() == ScriptingType::Emerge) - { - // As a precaution never return a "secure" mod name in the async and - // emerge environment, because these currently do not track mod origins - // in a spoof-safe way (see l_register_async_dofile and l_register_mapgen_script). - return ""; - } - - // We have to make sure that this function is being called directly by - // a mod, otherwise a malicious mod could override a function and - // steal its return value. (e.g. request_insecure_environment) - lua_Debug info; - - // Make sure there's only one item below this function on the stack... - if (lua_getstack(L, 2, &info)) - return ""; - FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed"); - FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed"); - - // ...and that that item is the main file scope. - if (strcmp(info.what, "main") != 0) - return ""; - - // at this point we can trust this value: - return getCurrentModNameInsecure(L); -} - void ScriptApiBase::loadMod(const std::string &script_path, const std::string &mod_name) { @@ -273,7 +242,7 @@ void ScriptApiBase::loadScript(const std::string &script_path) int error_handler = PUSH_ERROR_HANDLER(L); bool ok; - if (m_secure) { + if (ScriptApiSecurity::isSecure(L)) { ok = ScriptApiSecurity::safeLoadFile(L, script_path.c_str()); } else { ok = !luaL_loadfile(L, script_path.c_str()); diff --git a/src/script/cpp_api/s_base.h b/src/script/cpp_api/s_base.h index b08a887f0..34ac22595 100644 --- a/src/script/cpp_api/s_base.h +++ b/src/script/cpp_api/s_base.h @@ -101,17 +101,15 @@ public: void setOriginDirect(const char *origin); void setOriginFromTableRaw(int index, const char *fxn); - // Returns the currently running mod, only during init time. - // The reason this is "insecure" is that mods can mess with each others code, - // so the boundary of who is responsible is fuzzy. - // Note: checking this against BUILTIN_MOD_NAME is always safe (not spoofable). - // returns "" on error + /** + * Returns the currently running mod, only during init time. + * The reason this is insecure is that mods can mess with each others code, + * so the boundary of who is responsible is fuzzy. + * @note Checking this against BUILTIN_MOD_NAME is always safe (not spoofable). + * @note See ScriptApiSecurity::getCurrentModName() for the secure equivalent. + * @return mod name or "" on error + */ static std::string getCurrentModNameInsecure(lua_State *L); - // Returns the currently running mod, only during init time. - // This checks the Lua stack to only permit direct calls in the file - // scope. That way it is assured that it's really the mod it claims to be. - // returns "" on error - static std::string getCurrentModName(lua_State *L); #if !CHECK_CLIENT_BUILD() inline void clientOpenLibs(lua_State *L) { assert(false); } @@ -171,7 +169,7 @@ protected: std::recursive_mutex m_luastackmutex; std::string m_last_run_mod; - bool m_secure = false; + #ifdef SCRIPTAPI_LOCK_DEBUG int m_lock_recursion_count{}; std::thread::id m_owning_thread; diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index b23e94cd2..ef882a1f6 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -260,6 +260,8 @@ void ScriptApiSecurity::initializeSecurity() lua_pop(L, 1); // Pop empty string } +#if CHECK_CLIENT_BUILD() + void ScriptApiSecurity::initializeSecurityClient() { static const char *whitelist[] = { @@ -375,6 +377,8 @@ void ScriptApiSecurity::initializeSecurityClient() setLuaEnv(L, thread); } +#endif + int ScriptApiSecurity::getThread(lua_State *L) { #if LUA_VERSION_NUM <= 501 @@ -408,19 +412,24 @@ void ScriptApiSecurity::setLuaEnv(lua_State *L, int thread) bool ScriptApiSecurity::isSecure(lua_State *L) { -#if CHECK_CLIENT_BUILD() - auto script = ModApiBase::getScriptApiBase(L); - // CSM keeps no globals backup but is always secure - if (script->getType() == ScriptingType::Client) - return true; -#endif - lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP); - bool secure = !lua_isnil(L, -1); - lua_pop(L, 1); - return secure; + auto *script = ModApiBase::getScriptApiBase(L); + if (auto *sec = dynamic_cast(script)) + return sec->m_secure; + return false; } -bool ScriptApiSecurity::safeLoadString(lua_State *L, const std::string &code, const char *chunk_name) +void ScriptApiSecurity::getGlobalsBackup(lua_State *L) +{ + if (!ScriptApiSecurity::isSecure(L)) { + lua_getglobal(L, "_G"); + return; + } + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP); + // We cannot fulfill the callers wish securely if they don't exist. + FATAL_ERROR_IF(lua_isnil(L, -1), "Globals backup requested, but it is not available. Cannot proceed securely."); +} + +bool ScriptApiSecurity::safeLoadString(lua_State *L, std::string_view code, const char *chunk_name) { if (code.size() > 0 && code[0] == LUA_SIGNATURE[0]) { lua_pushliteral(L, "Bytecode prohibited when mod security is enabled."); @@ -441,7 +450,7 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char fp = stdin; chunk_name = const_cast("=stdin"); } else { - fp = fopen(path, "rb"); + fp = std::fopen(path, "rb"); if (!fp) { lua_pushfstring(L, "%s: %s", path, strerror(errno)); return false; @@ -500,7 +509,35 @@ bool ScriptApiSecurity::safeLoadFile(lua_State *L, const char *path, const char } -bool checkModNameWhitelisted(const std::string &mod_name, const std::string &setting) +std::string ScriptApiSecurity::getCurrentModName(lua_State *L) +{ + auto *script = ModApiBase::getScriptApiBase(L); + + auto *sec = dynamic_cast(script); + if (sec && !sec->modNamesAreTrusted()) + return ""; + + // We have to make sure that this function is being called directly by + // a mod, otherwise a malicious mod could override a function and + // steal its return value. (e.g. request_insecure_environment) + lua_Debug info; + + // Make sure there's only one item below this function on the stack... + if (lua_getstack(L, 2, &info)) + return ""; + FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed"); + FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed"); + + // ...and that that item is the main file scope. + if (strcmp(info.what, "main") != 0) + return ""; + + // at this point we can trust this value: + return getCurrentModNameInsecure(L); +} + + +static bool checkModNameWhitelisted(const std::string &mod_name, const std::string &setting) { assert(str_starts_with(setting, "secure.")); @@ -517,7 +554,7 @@ bool checkModNameWhitelisted(const std::string &mod_name, const std::string &set bool ScriptApiSecurity::checkWhitelisted(lua_State *L, const std::string &setting) { - std::string mod_name = ScriptApiBase::getCurrentModName(L); + std::string mod_name = getCurrentModName(L); return checkModNameWhitelisted(mod_name, setting); } @@ -528,16 +565,8 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path, if (write_allowed) *write_allowed = false; - std::string str; // Transient - std::string abs_path = fs::AbsolutePath(path); - if (!abs_path.empty()) { - // Don't allow accessing the settings file - str = fs::AbsolutePath(g_settings_path); - if (str == abs_path) return false; - } - // If we couldn't find the absolute path (path doesn't exist) then // try removing the last components until it works (to allow // non-existent files/folders for mkdir). @@ -560,61 +589,84 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path, } if (abs_path.empty()) return false; - // Add the removed parts back so that you can't, eg, create a + // Add the removed parts back so that you can e.g. create a // directory in worldmods if worldmods doesn't exist. if (!removed.empty()) abs_path += DIR_DELIM + removed; - // Get gamedef from registry - ScriptApiBase *script = ModApiBase::getScriptApiBase(L); - const IGameDef *gamedef = script->getGameDef(); + tracestream << "ScriptApiSecurity: path \"" << path << "\" resolved to \"" + << abs_path << "\"" << std::endl; + + // Ask the environment-specific implementation + auto *sec = ModApiBase::getScriptApi(L); + return sec->checkPathInternal(abs_path, write_required, write_allowed); +} + + +bool ScriptApiSecurity::checkPathWithGamedef(lua_State *L, + const std::string &abs_path, bool write_required, bool *write_allowed) +{ + const auto &set_write_allowed = [&] (bool v) { + if (write_allowed) + *write_allowed = v; + }; + std::string str; // Transient + + auto *gamedef = ModApiBase::getGameDef(L); if (!gamedef) return false; + if (!abs_path.empty()) { + // Don't allow accessing the settings file + str = fs::AbsolutePath(g_settings_path); + if (str == abs_path) + return false; + } + // Get mod name std::string mod_name = ScriptApiBase::getCurrentModNameInsecure(L); if (!mod_name.empty()) { // Builtin can access anything if (mod_name == BUILTIN_MOD_NAME) { - if (write_allowed) *write_allowed = true; + set_write_allowed(true); return true; } + } - // Allow paths in mod path - // Don't bother if write access isn't important, since it will be handled later - if (write_required || write_allowed != NULL) { - const ModSpec *mod = gamedef->getModSpec(mod_name); - if (mod) { - str = fs::AbsolutePath(mod->path); - if (!str.empty() && fs::PathStartsWith(abs_path, str)) { - // `mod_name` cannot be trusted here, so we catch the scenarios where this becomes a problem: - bool is_trusted = checkModNameWhitelisted(mod_name, "secure.trusted_mods") || - checkModNameWhitelisted(mod_name, "secure.http_mods"); - std::string filename = lowercase(fs::GetFilenameFromPath(abs_path.c_str())); - // By writing to any of these a malicious mod could turn itself into - // an existing trusted mod by renaming or becoming a modpack. - bool is_dangerous_file = filename == "mod.conf" || - filename == "modpack.conf" || - filename == "modpack.txt"; - if (write_required) { - if (is_trusted) { - throw LuaError( - "Unable to write to a trusted or http mod's directory. " - "For data storage consider minetest.get_mod_data_path() or minetest.get_worldpath() instead."); - } else if (is_dangerous_file) { - throw LuaError( - "Unable to write to special file for security reasons"); - } else { - const char *message = - "Writing to mod directories is deprecated, as any changes " - "will be overwritten when updating content. " - "For data storage consider minetest.get_mod_data_path() or minetest.get_worldpath() instead."; - log_deprecated(L, message, 1); - } + // Allow paths in mod path + // Don't bother if write access isn't important, since it will be handled later + if (write_required || write_allowed) { + const ModSpec *mod = gamedef->getModSpec(mod_name); + if (mod) { + str = fs::AbsolutePath(mod->path); + if (!str.empty() && fs::PathStartsWith(abs_path, str)) { + // `mod_name` cannot be trusted here, so we catch the scenarios where this becomes a problem: + bool is_trusted = checkModNameWhitelisted(mod_name, "secure.trusted_mods") || + checkModNameWhitelisted(mod_name, "secure.http_mods"); + std::string filename = lowercase(fs::GetFilenameFromPath(abs_path.c_str())); + // By writing to any of these a malicious mod could turn itself into + // an existing trusted mod by renaming or becoming a modpack. + bool is_dangerous_file = filename == "mod.conf" || + filename == "modpack.conf" || + filename == "modpack.txt"; + if (write_required) { + if (is_trusted) { + throw LuaError( + "Unable to write to a trusted or http mod's directory. " + "For data storage consider minetest.get_mod_data_path() or minetest.get_worldpath() instead."); + } else if (is_dangerous_file) { + throw LuaError( + "Unable to write to special file for security reasons"); + } else { + const char *message = + "Writing to mod directories is deprecated, as any changes " + "will be overwritten when updating content. " + "For data storage consider minetest.get_mod_data_path() or minetest.get_worldpath() instead."; + log_deprecated(L, message, 1); } - if (write_allowed) *write_allowed = !is_trusted && !is_dangerous_file; - return true; } + set_write_allowed(!is_trusted && !is_dangerous_file); + return true; } } } @@ -624,9 +676,8 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path, const SubgameSpec *game_spec = gamedef->getGameSpec(); if (game_spec && !game_spec->path.empty()) { str = fs::AbsolutePath(game_spec->path); - if (!str.empty() && fs::PathStartsWith(abs_path, str)) { + if (!str.empty() && fs::PathStartsWith(abs_path, str)) return true; - } } } @@ -635,16 +686,15 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path, const std::vector &mods = gamedef->getMods(); for (const ModSpec &mod : mods) { str = fs::AbsolutePath(mod.path); - if (!str.empty() && fs::PathStartsWith(abs_path, str)) { + if (!str.empty() && fs::PathStartsWith(abs_path, str)) return true; - } } } // Allow read/write access to all mod common dirs str = fs::AbsolutePath(gamedef->getModDataPath()); if (!str.empty() && fs::PathStartsWith(abs_path, str)) { - if (write_allowed) *write_allowed = true; + set_write_allowed(true); return true; } @@ -662,12 +712,11 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path, } // Allow all other paths in world path if (fs::PathStartsWith(abs_path, str)) { - if (write_allowed) *write_allowed = true; + set_write_allowed(true); return true; } } - // Default to disallowing return false; } diff --git a/src/script/cpp_api/s_security.h b/src/script/cpp_api/s_security.h index 91d5dce54..1241b0b06 100644 --- a/src/script/cpp_api/s_security.h +++ b/src/script/cpp_api/s_security.h @@ -12,10 +12,12 @@ throw LuaError(std::string("Mod security: Blocked attempted ") + \ (write_required ? "write to " : "read from ") + path); \ } + #define CHECK_SECURE_PATH(L, path, write_required) \ if (ScriptApiSecurity::isSecure(L)) { \ - CHECK_SECURE_PATH_INTERNAL(L, path, write_required, NULL); \ + CHECK_SECURE_PATH_INTERNAL(L, path, write_required, nullptr); \ } + #define CHECK_SECURE_PATH_POSSIBLE_WRITE(L, path, ptr) \ if (ScriptApiSecurity::isSecure(L)) { \ CHECK_SECURE_PATH_INTERNAL(L, path, false, ptr); \ @@ -27,19 +29,65 @@ class ScriptApiSecurity : virtual public ScriptApiBase public: // Sets up security on the ScriptApi's Lua state void initializeSecurity(); +#if CHECK_CLIENT_BUILD() void initializeSecurityClient(); +#else + inline void initializeSecurityClient() { assert(0); } +#endif + // Checks if the Lua state has been secured static bool isSecure(lua_State *L); - // Loads a string as Lua code safely (doesn't allow bytecode). - static bool safeLoadString(lua_State *L, const std::string &code, const char *chunk_name); - // Loads a file as Lua code safely (doesn't allow bytecode). - static bool safeLoadFile(lua_State *L, const char *path, const char *display_name = NULL); - // Check if mod is whitelisted in the given setting - // This additionally checks that the mod's main file scope is executing. + // Leaves the untampered globals (table) on top of the stack + static void getGlobalsBackup(lua_State *L); + + /// Loads a string as Lua code safely (doesn't allow bytecode). + static bool safeLoadString(lua_State *L, std::string_view code, const char *chunk_name); + /// Loads a file as Lua code safely (doesn't allow bytecode). + /// @warning path is not validated in any way + static bool safeLoadFile(lua_State *L, const char *path, const char *display_name = nullptr); + + /** + * Returns the currently running mod, only during init time. + * This checks the Lua stack to only permit direct calls in the file + * scope. That way it is assured that it's really the mod it claims to be. + * @return mod name or "" on error + */ + static std::string getCurrentModName(lua_State *L); + /// Check if mod is whitelisted in the given setting. + /// This additionally does main scope checks (see above method). + /// @note check is performed even in non-secured Lua state static bool checkWhitelisted(lua_State *L, const std::string &setting); - // Checks if mods are allowed to read (and optionally write) to the path + + /// Checks if mods are allowed to read (and optionally write) to the path + /// @note invalid to call in non-secured Lua state static bool checkPath(lua_State *L, const char *path, bool write_required, - bool *write_allowed=NULL); + bool *write_allowed = nullptr); + +protected: + // To be implemented by descendants: + + /** + * Specify if the mod names during init time(!) can be trusted. + * It needs to be assured that no tampering happens before any call to `loadMod()`. + * @note disabling this implies that mod whitelisting never works + * @return boolean value + */ + virtual bool modNamesAreTrusted() { return false; } + + /** + * Should check if the given path may be accessed. + * If `write_required` is true test for write access, if false test for read access. + * @param abs_path absolute file/directory path, may not exist + * @param write_required was write access requested? + * @param write_allowed output parameter (nullable): set to true if writing is allowed + * @return true if access is allowed + */ + virtual bool checkPathInternal(const std::string &abs_path, bool write_required, + bool *write_allowed) = 0; + + // Ready-made implementation of `checkPathInternal` suitable for server-related uses + static bool checkPathWithGamedef(lua_State *L, const std::string &abs_path, + bool write_required, bool *write_allowed); private: int getThread(lua_State *L); @@ -48,6 +96,8 @@ private: // creates an empty Lua environment void createEmptyEnv(lua_State *L); + bool m_secure = false; + // Syntax: "sl_" '_' // (sl stands for Secure Lua) diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index e464cb3a2..cfea974b3 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -494,18 +494,13 @@ int ModApiUtil::l_request_insecure_environment(lua_State *L) { NO_MAP_LOCK_REQUIRED; - // Just return _G if security is disabled - if (!ScriptApiSecurity::isSecure(L)) { - lua_getglobal(L, "_G"); - return 1; - } - - if (!ScriptApiSecurity::checkWhitelisted(L, "secure.trusted_mods")) { - return 0; + if (ScriptApiSecurity::isSecure(L)) { + if (!ScriptApiSecurity::checkWhitelisted(L, "secure.trusted_mods")) + return 0; } // Push insecure environment - lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP); + ScriptApiSecurity::getGlobalsBackup(L); return 1; } diff --git a/src/script/scripting_client.h b/src/script/scripting_client.h index cfe4133c7..872ad295a 100644 --- a/src/script/scripting_client.h +++ b/src/script/scripting_client.h @@ -5,6 +5,8 @@ #pragma once +#include + #include "cpp_api/s_base.h" #include "cpp_api/s_client.h" #include "cpp_api/s_modchannels.h" @@ -27,6 +29,16 @@ public: void on_camera_ready(Camera *camera); void on_minimap_ready(Minimap *minimap); +protected: + // from ScriptApiSecurity: + bool checkPathInternal(const std::string &abs_path, bool write_required, + bool *write_allowed) override { + warningstream << "IO API called in client scripting" << std::endl; + assert(0); + return false; + } + bool modNamesAreTrusted() override { return true; } + private: virtual void InitializeModApi(lua_State *L, int top); }; diff --git a/src/script/scripting_emerge.h b/src/script/scripting_emerge.h index 8f3c7c348..8e645fd9d 100644 --- a/src/script/scripting_emerge.h +++ b/src/script/scripting_emerge.h @@ -17,6 +17,13 @@ class EmergeScripting: public: EmergeScripting(EmergeThread *parent); +protected: + bool checkPathInternal(const std::string &abs_path, bool write_required, + bool *write_allowed) override { + return ScriptApiSecurity::checkPathWithGamedef(getStack(), + abs_path, write_required, write_allowed); + }; + private: void InitializeModApi(lua_State *L, int top); }; diff --git a/src/script/scripting_server.h b/src/script/scripting_server.h index 54093e84a..6c0583553 100644 --- a/src/script/scripting_server.h +++ b/src/script/scripting_server.h @@ -50,6 +50,15 @@ public: u32 queueAsync(std::string &&serialized_func, PackedValue *param, const std::string &mod_origin); +protected: + // from ScriptApiSecurity: + bool checkPathInternal(const std::string &abs_path, bool write_required, + bool *write_allowed) override { + return ScriptApiSecurity::checkPathWithGamedef(getStack(), + abs_path, write_required, write_allowed); + } + bool modNamesAreTrusted() override { return true; } + private: void InitializeModApi(lua_State *L, int top); From ea4ae55e24d2c27524490cb8e0d3c34aa46e3da3 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 3 Nov 2024 16:53:01 +0100 Subject: [PATCH 051/136] Implement script sandboxing for main menu --- builtin/mainmenu/async_event.lua | 7 +- builtin/mainmenu/content/contentdb.lua | 36 +++---- builtin/mainmenu/init.lua | 1 + src/script/cpp_api/s_async.cpp | 25 ++++- src/script/cpp_api/s_async.h | 5 +- src/script/cpp_api/s_security.cpp | 1 + src/script/lua_api/l_mainmenu.cpp | 129 +++++++++---------------- src/script/lua_api/l_mainmenu.h | 8 -- src/script/scripting_mainmenu.cpp | 43 ++++++++- src/script/scripting_mainmenu.h | 17 +++- 10 files changed, 146 insertions(+), 126 deletions(-) diff --git a/builtin/mainmenu/async_event.lua b/builtin/mainmenu/async_event.lua index 04bfb78d6..2358ee70e 100644 --- a/builtin/mainmenu/async_event.lua +++ b/builtin/mainmenu/async_event.lua @@ -11,11 +11,6 @@ end core.async_event_handler = handle_job function core.handle_async(func, parameter, callback) - -- Serialize function - local serialized_func = string.dump(func) - - assert(serialized_func ~= nil) - -- Serialize parameters local serialized_param = core.serialize(parameter) @@ -23,7 +18,7 @@ function core.handle_async(func, parameter, callback) return false end - local jobid = core.do_async_callback(serialized_func, serialized_param) + local jobid = core.do_async_callback(func, serialized_param) core.async_jobs[jobid] = callback diff --git a/builtin/mainmenu/content/contentdb.lua b/builtin/mainmenu/content/contentdb.lua index c352a260b..963400a12 100644 --- a/builtin/mainmenu/content/contentdb.lua +++ b/builtin/mainmenu/content/contentdb.lua @@ -392,7 +392,7 @@ function contentdb.resolve_dependencies(package, game, callback) end -local function fetch_pkgs(params) +local function fetch_pkgs() local version = core.get_version() local base_url = core.settings:get("contentdb_url") local url = base_url .. @@ -429,41 +429,43 @@ local function fetch_pkgs(params) if not packages or #packages == 0 then return end - local aliases = {} + return packages +end + + +function contentdb.set_packages_from_api(packages) + contentdb.package_by_id = {} + contentdb.aliases = {} for _, package in pairs(packages) do - package.id = params.calculate_package_id(package.type, package.author, package.name) + package.id = contentdb.calculate_package_id(package.type, package.author, package.name) package.url_part = core.urlencode(package.author) .. "/" .. core.urlencode(package.name) + contentdb.package_by_id[package.id] = package + if package.aliases then for _, alias in ipairs(package.aliases) do -- We currently don't support name changing local suffix = "/" .. package.name if alias:sub(-#suffix) == suffix then - aliases[alias:lower()] = package.id + contentdb.aliases[alias:lower()] = package.id end end end end - return { packages = packages, aliases = aliases } + contentdb.load_ok = true + contentdb.load_error = false + contentdb.packages = packages + contentdb.packages_full = packages + contentdb.packages_full_unordered = packages end - function contentdb.fetch_pkgs(callback) contentdb.loading = true - core.handle_async(fetch_pkgs, { calculate_package_id = contentdb.calculate_package_id }, function(result) + core.handle_async(fetch_pkgs, nil, function(result) if result then - contentdb.load_ok = true - contentdb.load_error = false - contentdb.packages = result.packages - contentdb.packages_full = result.packages - contentdb.packages_full_unordered = result.packages - contentdb.aliases = result.aliases - - for _, package in ipairs(result.packages) do - contentdb.package_by_id[package.id] = package - end + contentdb.set_packages_from_api(result) else contentdb.load_error = true end diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua index fc237e158..41519b2ee 100644 --- a/builtin/mainmenu/init.lua +++ b/builtin/mainmenu/init.lua @@ -133,4 +133,5 @@ local function init_globals() check_new_version() end +assert(os.execute == nil) init_globals() diff --git a/src/script/cpp_api/s_async.cpp b/src/script/cpp_api/s_async.cpp index f55082308..4cb46f6bb 100644 --- a/src/script/cpp_api/s_async.cpp +++ b/src/script/cpp_api/s_async.cpp @@ -14,10 +14,14 @@ extern "C" { #include "server.h" #include "s_async.h" #include "log.h" +#include "config.h" #include "filesys.h" #include "porting.h" #include "common/c_internal.h" #include "common/c_packer.h" +#if CHECK_CLIENT_BUILD() +#include "script/scripting_mainmenu.h" +#endif #include "lua_api/l_base.h" /******************************************************************************/ @@ -256,7 +260,6 @@ bool AsyncEngine::prepareEnvironment(lua_State* L, int top) return true; } -/******************************************************************************/ AsyncWorkerThread::AsyncWorkerThread(AsyncEngine* jobDispatcher, const std::string &name) : ScriptApiBase(ScriptingType::Async), @@ -270,6 +273,8 @@ AsyncWorkerThread::AsyncWorkerThread(AsyncEngine* jobDispatcher, if (g_settings->getBool("secure.enable_security")) initializeSecurity(); + } else { + initializeSecurity(); } // Prepare job lua environment @@ -287,13 +292,27 @@ AsyncWorkerThread::AsyncWorkerThread(AsyncEngine* jobDispatcher, lua_pop(L, 1); } -/******************************************************************************/ AsyncWorkerThread::~AsyncWorkerThread() { sanity_check(!isRunning()); } -/******************************************************************************/ +bool AsyncWorkerThread::checkPathInternal(const std::string &abs_path, + bool write_required, bool *write_allowed) +{ + auto *L = getStack(); + // dispatch to the right implementation. this should be refactored some day... + if (jobDispatcher->server) { + return ScriptApiSecurity::checkPathWithGamedef(L, abs_path, write_required, write_allowed); + } else { +#if CHECK_CLIENT_BUILD() + return MainMenuScripting::checkPathAccess(abs_path, write_required, write_allowed); +#else + FATAL_ERROR("should never get here"); +#endif + } +} + void* AsyncWorkerThread::run() { if (isErrored) diff --git a/src/script/cpp_api/s_async.h b/src/script/cpp_api/s_async.h index 8a081b2fc..d2a6913ef 100644 --- a/src/script/cpp_api/s_async.h +++ b/src/script/cpp_api/s_async.h @@ -56,10 +56,7 @@ protected: AsyncWorkerThread(AsyncEngine* jobDispatcher, const std::string &name); bool checkPathInternal(const std::string &abs_path, bool write_required, - bool *write_allowed) override { - return ScriptApiSecurity::checkPathWithGamedef(getStack(), - abs_path, write_required, write_allowed); - }; + bool *write_allowed) override; private: AsyncEngine *jobDispatcher = nullptr; diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index ef882a1f6..40a95ca1a 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -66,6 +66,7 @@ void ScriptApiSecurity::initializeSecurity() "core", "collectgarbage", "DIR_DELIM", + "PLATFORM", "error", "getfenv", "getmetatable", diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index 69f63d964..e8c969268 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -343,6 +343,8 @@ int ModApiMainMenu::l_get_content_info(lua_State *L) { std::string path = luaL_checkstring(L, 1); + CHECK_SECURE_PATH(L, path.c_str(), false) + ContentSpec spec; spec.path = path; parseContentInfo(spec); @@ -410,6 +412,8 @@ int ModApiMainMenu::l_check_mod_configuration(lua_State *L) { std::string worldpath = luaL_checkstring(L, 1); + CHECK_SECURE_PATH(L, worldpath.c_str(), false) + ModConfiguration modmgr; // Add all game mods @@ -732,15 +736,13 @@ int ModApiMainMenu::l_get_temp_path(lua_State *L) } /******************************************************************************/ -int ModApiMainMenu::l_create_dir(lua_State *L) { +int ModApiMainMenu::l_create_dir(lua_State *L) +{ const char *path = luaL_checkstring(L, 1); - if (ModApiMainMenu::mayModifyPath(path)) { - lua_pushboolean(L, fs::CreateAllDirs(path)); - return 1; - } + CHECK_SECURE_PATH(L, path, true) - lua_pushboolean(L, false); + lua_pushboolean(L, fs::CreateAllDirs(path)); return 1; } @@ -749,14 +751,9 @@ int ModApiMainMenu::l_delete_dir(lua_State *L) { const char *path = luaL_checkstring(L, 1); - std::string absolute_path = fs::RemoveRelativePathComponents(path); + CHECK_SECURE_PATH(L, path, true) - if (ModApiMainMenu::mayModifyPath(absolute_path)) { - lua_pushboolean(L, fs::RecursiveDelete(absolute_path)); - return 1; - } - - lua_pushboolean(L, false); + lua_pushboolean(L, fs::RecursiveDelete(path)); return 1; } @@ -766,24 +763,16 @@ int ModApiMainMenu::l_copy_dir(lua_State *L) const char *source = luaL_checkstring(L, 1); const char *destination = luaL_checkstring(L, 2); - bool keep_source = true; - if (!lua_isnoneornil(L, 3)) - keep_source = readParam(L, 3); + bool keep_source = readParam(L, 3, true); - std::string abs_destination = fs::RemoveRelativePathComponents(destination); - std::string abs_source = fs::RemoveRelativePathComponents(source); - - if (!ModApiMainMenu::mayModifyPath(abs_destination) || - (!keep_source && !ModApiMainMenu::mayModifyPath(abs_source))) { - lua_pushboolean(L, false); - return 1; - } + CHECK_SECURE_PATH(L, source, !keep_source) + CHECK_SECURE_PATH(L, destination, true) bool retval; if (keep_source) - retval = fs::CopyDir(abs_source, abs_destination); + retval = fs::CopyDir(source, destination); else - retval = fs::MoveDir(abs_source, abs_destination); + retval = fs::MoveDir(source, destination); lua_pushboolean(L, retval); return 1; } @@ -793,6 +782,8 @@ int ModApiMainMenu::l_is_dir(lua_State *L) { const char *path = luaL_checkstring(L, 1); + CHECK_SECURE_PATH(L, path, false) + lua_pushboolean(L, fs::IsDir(path)); return 1; } @@ -803,16 +794,12 @@ int ModApiMainMenu::l_extract_zip(lua_State *L) const char *zipfile = luaL_checkstring(L, 1); const char *destination = luaL_checkstring(L, 2); - std::string absolute_destination = fs::RemoveRelativePathComponents(destination); + CHECK_SECURE_PATH(L, zipfile, false) + CHECK_SECURE_PATH(L, destination, true) - if (ModApiMainMenu::mayModifyPath(absolute_destination)) { - auto fs = RenderingEngine::get_raw_device()->getFileSystem(); - bool ok = fs::extractZipFile(fs, zipfile, destination); - lua_pushboolean(L, ok); - return 1; - } - - lua_pushboolean(L,false); + auto fs = RenderingEngine::get_raw_device()->getFileSystem(); + bool ok = fs::extractZipFile(fs, zipfile, destination); + lua_pushboolean(L, ok); return 1; } @@ -826,40 +813,13 @@ int ModApiMainMenu::l_get_mainmenu_path(lua_State *L) return 1; } -/******************************************************************************/ -bool ModApiMainMenu::mayModifyPath(std::string path) -{ - path = fs::RemoveRelativePathComponents(path); - - if (fs::PathStartsWith(path, fs::TempPath())) - return true; - - std::string path_user = fs::RemoveRelativePathComponents(porting::path_user); - - if (fs::PathStartsWith(path, path_user + DIR_DELIM "client")) - return true; - if (fs::PathStartsWith(path, path_user + DIR_DELIM "games")) - return true; - if (fs::PathStartsWith(path, path_user + DIR_DELIM "mods")) - return true; - if (fs::PathStartsWith(path, path_user + DIR_DELIM "textures")) - return true; - if (fs::PathStartsWith(path, path_user + DIR_DELIM "worlds")) - return true; - - if (fs::PathStartsWith(path, fs::RemoveRelativePathComponents(porting::path_cache))) - return true; - - return false; -} - - /******************************************************************************/ int ModApiMainMenu::l_may_modify_path(lua_State *L) { const char *target = luaL_checkstring(L, 1); - std::string absolute_destination = fs::RemoveRelativePathComponents(target); - lua_pushboolean(L, ModApiMainMenu::mayModifyPath(absolute_destination)); + bool write_allowed = false; + bool ok = ScriptApiSecurity::checkPath(L, target, false, &write_allowed); + lua_pushboolean(L, ok && write_allowed); return 1; } @@ -892,19 +852,9 @@ int ModApiMainMenu::l_download_file(lua_State *L) const char *url = luaL_checkstring(L, 1); const char *target = luaL_checkstring(L, 2); - //check path - std::string absolute_destination = fs::RemoveRelativePathComponents(target); + CHECK_SECURE_PATH(L, target, true) - if (ModApiMainMenu::mayModifyPath(absolute_destination)) { - if (GUIEngine::downloadFile(url,absolute_destination)) { - lua_pushboolean(L,true); - return 1; - } - } else { - errorstream << "DOWNLOAD denied: " << absolute_destination - << " isn't an allowed path" << std::endl; - } - lua_pushboolean(L,false); + lua_pushboolean(L, GUIEngine::downloadFile(url, target)); return 1; } @@ -1068,16 +1018,22 @@ int ModApiMainMenu::l_open_url_dialog(lua_State *L) /******************************************************************************/ int ModApiMainMenu::l_open_dir(lua_State *L) { - std::string path = luaL_checkstring(L, 1); - lua_pushboolean(L, porting::open_directory(path)); + const char *target = luaL_checkstring(L, 1); + + CHECK_SECURE_PATH(L, target, false) + + lua_pushboolean(L, porting::open_directory(target)); return 1; } /******************************************************************************/ int ModApiMainMenu::l_share_file(lua_State *L) { + const char *path = luaL_checkstring(L, 1); + + CHECK_SECURE_PATH(L, path, false) + #ifdef __ANDROID__ - std::string path = luaL_checkstring(L, 1); porting::shareFileAndroid(path); lua_pushboolean(L, true); #else @@ -1091,19 +1047,20 @@ int ModApiMainMenu::l_do_async_callback(lua_State *L) { MainMenuScripting *script = getScriptApi(L); - size_t func_length, param_length; - const char* serialized_func_raw = luaL_checklstring(L, 1, &func_length); - const char* serialized_param_raw = luaL_checklstring(L, 2, ¶m_length); + luaL_checktype(L, 1, LUA_TFUNCTION); + call_string_dump(L, 1); + size_t func_length; + const char *serialized_func_raw = lua_tolstring(L, -1, &func_length); - sanity_check(serialized_func_raw != NULL); - sanity_check(serialized_param_raw != NULL); + size_t param_length; + const char* serialized_param_raw = luaL_checklstring(L, 2, ¶m_length); u32 jobId = script->queueAsync( std::string(serialized_func_raw, func_length), std::string(serialized_param_raw, param_length)); + lua_settop(L, 0); lua_pushinteger(L, jobId); - return 1; } diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h index 25ea551bc..d0f72b6c4 100644 --- a/src/script/lua_api/l_mainmenu.h +++ b/src/script/lua_api/l_mainmenu.h @@ -37,14 +37,6 @@ private: */ static int getBoolData(lua_State *L, const std::string &name ,bool& valid); - /** - * Checks if a path may be modified. Paths in the temp directory or the user - * games, mods, textures, or worlds directories may be modified. - * @param path path to check - * @return true if the path may be modified - */ - static bool mayModifyPath(std::string path); - //api calls static int l_start(lua_State *L); diff --git a/src/script/scripting_mainmenu.cpp b/src/script/scripting_mainmenu.cpp index 17e2ebb1e..d5434c325 100644 --- a/src/script/scripting_mainmenu.cpp +++ b/src/script/scripting_mainmenu.cpp @@ -12,11 +12,14 @@ #include "lua_api/l_util.h" #include "lua_api/l_settings.h" #include "log.h" +#include "filesys.h" +#include "porting.h" extern "C" { #include "lualib.h" } -#define MAINMENU_NUM_ASYNC_THREADS 4 + +#define MAINMENU_NUM_ASYNC_THREADS 2 MainMenuScripting::MainMenuScripting(GUIEngine* guiengine): @@ -26,6 +29,8 @@ MainMenuScripting::MainMenuScripting(GUIEngine* guiengine): SCRIPTAPI_PRECHECKHEADER + initializeSecurity(); + lua_getglobal(L, "core"); int top = lua_gettop(L); @@ -69,6 +74,42 @@ void MainMenuScripting::registerLuaClasses(lua_State *L, int top) MainMenuSoundHandle::Register(L); } +bool MainMenuScripting::mayModifyPath(const std::string &path) +{ + if (fs::PathStartsWith(path, fs::TempPath())) + return true; + + std::string path_user = fs::RemoveRelativePathComponents(porting::path_user); + + if (fs::PathStartsWith(path, path_user + DIR_DELIM "client")) + return true; + if (fs::PathStartsWith(path, path_user + DIR_DELIM "games")) + return true; + if (fs::PathStartsWith(path, path_user + DIR_DELIM "mods")) + return true; + if (fs::PathStartsWith(path, path_user + DIR_DELIM "textures")) + return true; + if (fs::PathStartsWith(path, path_user + DIR_DELIM "worlds")) + return true; + + if (fs::PathStartsWith(path, fs::RemoveRelativePathComponents(porting::path_cache))) + return true; + + return false; +} + +bool MainMenuScripting::checkPathAccess(const std::string &abs_path, bool write_required, + bool *write_allowed) +{ + if (mayModifyPath(abs_path)) { + if (write_allowed) + *write_allowed = true; + return true; + } + // TODO?: global read access sounds too broad + return !write_required; +} + void MainMenuScripting::beforeClose() { SCRIPTAPI_PRECHECKHEADER diff --git a/src/script/scripting_mainmenu.h b/src/script/scripting_mainmenu.h index 8b7c0cfe8..f56c67727 100644 --- a/src/script/scripting_mainmenu.h +++ b/src/script/scripting_mainmenu.h @@ -6,6 +6,7 @@ #include "cpp_api/s_base.h" #include "cpp_api/s_mainmenu.h" +#include "cpp_api/s_security.h" #include "cpp_api/s_async.h" /*****************************************************************************/ @@ -14,7 +15,8 @@ class MainMenuScripting : virtual public ScriptApiBase, - public ScriptApiMainMenu + public ScriptApiMainMenu, + public ScriptApiSecurity { public: MainMenuScripting(GUIEngine* guiengine); @@ -29,6 +31,19 @@ public: u32 queueAsync(std::string &&serialized_func, std::string &&serialized_param); + // Is the main menu allowed writeable access to this path? + static bool mayModifyPath(const std::string &path); + + // (public implementation so it can be used from AsyncEngine) + static bool checkPathAccess(const std::string &abs_path, bool write_required, + bool *write_allowed); + +protected: + bool checkPathInternal(const std::string &abs_path, bool write_required, + bool *write_allowed) override { + return checkPathAccess(abs_path, write_required, write_allowed); + } + private: void initializeModApi(lua_State *L, int top); static void registerLuaClasses(lua_State *L, int top); From 11e04ec1136f9cd37817a2e129770fe463f2aea1 Mon Sep 17 00:00:00 2001 From: grorp Date: Wed, 13 Nov 2024 14:23:13 +0100 Subject: [PATCH 052/136] Replace forgotten SEvent memset --- irr/src/CIrrDeviceSDL.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/irr/src/CIrrDeviceSDL.cpp b/irr/src/CIrrDeviceSDL.cpp index 60cf54d04..408027761 100644 --- a/irr/src/CIrrDeviceSDL.cpp +++ b/irr/src/CIrrDeviceSDL.cpp @@ -713,7 +713,7 @@ bool CIrrDeviceSDL::run() while (!Close && wrap_PollEvent(&SDL_event)) { // os::Printer::log("event: ", core::stringc((int)SDL_event.type).c_str(), ELL_INFORMATION); // just for debugging - memset(&irrevent, 0, sizeof(irrevent)); + irrevent = {}; switch (SDL_event.type) { case SDL_MOUSEMOTION: { From 0fde9ab7e84490914a7e22fe674f1de237c3a674 Mon Sep 17 00:00:00 2001 From: veprogames <75524847+veprogames@users.noreply.github.com> Date: Wed, 13 Nov 2024 14:23:39 +0100 Subject: [PATCH 053/136] Change minetest.net to luanti.org in 'Further documentation' --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9eecbfc19..b21153d54 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Table of Contents Further documentation ---------------------- -- Website: https://www.minetest.net/ +- Website: https://www.luanti.org/ - Wiki: https://wiki.minetest.net/ - Forum: https://forum.luanti.org/ - GitHub: https://github.com/minetest/minetest/ From 794aea8e92b9f06d3118f65223729b92b505568a Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 13 Nov 2024 14:24:01 +0100 Subject: [PATCH 054/136] Drop fixed pipeline support code (#15421) OpenGL 2.0 is now mandatory. --- builtin/mainmenu/settings/dlg_settings.lua | 12 +-- .../settings/shader_warning_component.lua | 26 ------- builtin/settingtypes.txt | 76 +++++++------------ doc/android.md | 26 ++----- doc/developing/os-compatibility.md | 9 +-- irr/src/COpenGLExtensionHandler.cpp | 6 +- src/client/clouds.cpp | 22 ++---- src/client/clouds.h | 2 +- src/client/content_cao.cpp | 42 ++-------- src/client/content_cao.h | 2 - src/client/content_mapblock.cpp | 20 ++--- src/client/content_mapblock.h | 3 - src/client/hud.cpp | 14 +--- src/client/mapblock_mesh.cpp | 59 ++------------ src/client/mapblock_mesh.h | 13 +--- src/client/mesh_generator_thread.cpp | 3 +- src/client/mesh_generator_thread.h | 2 - src/client/minimap.cpp | 3 +- src/client/minimap.h | 1 - src/client/render/plain.cpp | 6 +- src/client/shader.cpp | 25 ++---- src/client/shadows/dynamicshadowsrender.cpp | 24 ++---- src/client/sky.cpp | 15 +--- src/client/sky.h | 1 - src/client/tile.h | 1 - src/client/wieldmesh.cpp | 31 +++----- src/client/wieldmesh.h | 3 +- src/defaultsettings.cpp | 2 - src/environment.cpp | 3 +- src/environment.h | 1 - src/gui/guiScene.cpp | 5 -- src/nodedef.cpp | 61 +++------------ src/nodedef.h | 3 +- src/unittest/test_content_mapblock.cpp | 4 +- util/test_multiplayer.sh | 2 +- 35 files changed, 117 insertions(+), 411 deletions(-) delete mode 100644 builtin/mainmenu/settings/shader_warning_component.lua diff --git a/builtin/mainmenu/settings/dlg_settings.lua b/builtin/mainmenu/settings/dlg_settings.lua index 57e5a1300..dbd77a4db 100644 --- a/builtin/mainmenu/settings/dlg_settings.lua +++ b/builtin/mainmenu/settings/dlg_settings.lua @@ -19,8 +19,6 @@ local component_funcs = dofile(core.get_mainmenu_path() .. DIR_DELIM .. "settings" .. DIR_DELIM .. "components.lua") -local shader_warning_component = dofile(core.get_mainmenu_path() .. DIR_DELIM .. - "settings" .. DIR_DELIM .. "shader_warning_component.lua") local shadows_component = dofile(core.get_mainmenu_path() .. DIR_DELIM .. "settings" .. DIR_DELIM .. "shadows_component.lua") @@ -154,12 +152,7 @@ local function load() table.insert(page_by_id.controls_keyboard_and_mouse.content, 1, change_keys) do - local content = page_by_id.graphics_and_audio_graphics.content - table.insert(content, 1, shader_warning_component) - - content = page_by_id.graphics_and_audio_effects.content - table.insert(content, 1, shader_warning_component) - + local content = page_by_id.graphics_and_audio_effects.content local idx = table.indexof(content, "enable_dynamic_shadows") table.insert(content, idx, shadows_component) @@ -348,7 +341,6 @@ local function check_requirements(name, requires) end local video_driver = core.get_active_driver() - local shaders_support = video_driver == "opengl" or video_driver == "opengl3" or video_driver == "ogles2" local touch_support = core.irrlicht_device_supports_touch() local touch_controls = core.settings:get("touch_controls") local special = { @@ -359,8 +351,6 @@ local function check_requirements(name, requires) -- be used, so we show settings for both. touchscreen = touch_support and (touch_controls == "auto" or core.is_yes(touch_controls)), keyboard_mouse = not touch_support or (touch_controls == "auto" or not core.is_yes(touch_controls)), - shaders_support = shaders_support, - shaders = core.settings:get_bool("enable_shaders") and shaders_support, opengl = video_driver == "opengl", gles = video_driver:sub(1, 5) == "ogles", } diff --git a/builtin/mainmenu/settings/shader_warning_component.lua b/builtin/mainmenu/settings/shader_warning_component.lua deleted file mode 100644 index b227bcee3..000000000 --- a/builtin/mainmenu/settings/shader_warning_component.lua +++ /dev/null @@ -1,26 +0,0 @@ --- Luanti --- SPDX-License-Identifier: LGPL-2.1-or-later - -return { - query_text = "Shaders", - requires = { - shaders_support = true, - shaders = false, - }, - full_width = true, - get_formspec = function(self, avail_w) - local fs = { - "box[0,0;", avail_w, ",1.2;", mt_color_orange, "]", - "label[0.2,0.4;", fgettext("Shaders are disabled."), "]", - "label[0.2,0.8;", fgettext("This is not a recommended configuration."), "]", - "button[", avail_w - 2.2, ",0.2;2,0.8;fix_shader_warning;", fgettext("Enable"), "]", - } - return table.concat(fs, ""), 1.2 - end, - on_submit = function(self, fields) - if fields.fix_shader_warning then - core.settings:remove("enable_shaders") -- default value is true - return true - end - end, -} diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 728eaf425..71d976ec7 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -61,7 +61,7 @@ # # # This is a comment # # -# # Requires: shaders, enable_dynamic_shadows, !enable_waving_leaves +# # Requires: enable_dynamic_shadows, !enable_waving_leaves # name (Readable name) type type_args # # A requirement can be the name of a boolean setting or an engine-defined value. @@ -69,8 +69,6 @@ # # * The value of a boolean setting, such as enable_dynamic_shadows # * An engine-defined value: -# * shaders_support (a video driver that supports shaders, may not be enabled) -# * shaders (both enable_shaders and shaders_support) # * desktop / android # * touchscreen / keyboard_mouse # * opengl / gles @@ -277,7 +275,6 @@ undersampling (Undersampling) int 1 1 8 # - topbottom: split screen top/bottom. # - sidebyside: split screen side by side. # - crossview: Cross-eyed 3d -# Note that the interlaced mode requires shaders to be enabled. 3d_mode (3D mode) enum none none,anaglyph,interlaced,topbottom,sidebyside,crossview # Strength of 3D mode parallax. @@ -416,11 +413,11 @@ anisotropic_filter (Anisotropic filtering) bool false # Smoothens out block edges but does not affect the insides of textures. # A restart is required to change this option. # -# * FXAA - Fast approximate antialiasing (requires shaders) +# * FXAA - Fast approximate antialiasing # Applies a post-processing filter to detect and smoothen high-contrast edges. # Provides balance between speed and image quality. # -# * SSAA - Super-sampling antialiasing (requires shaders) +# * SSAA - Super-sampling antialiasing # Renders higher-resolution image of the scene, then scales down to reduce # the aliasing effects. This is the slowest and the most accurate method. antialiasing (Antialiasing method) enum none none,fsaa,fxaa,ssaa @@ -473,18 +470,12 @@ enable_particles (Digging particles) bool true [**Waving Nodes] # Set to true to enable waving leaves. -# -# Requires: shaders enable_waving_leaves (Waving leaves) bool false # Set to true to enable waving plants. -# -# Requires: shaders enable_waving_plants (Waving plants) bool false # Set to true to enable waving liquids (like water). -# -# Requires: shaders enable_waving_water (Waving liquids) bool false # The maximum height of the surface of waving liquids. @@ -492,70 +483,70 @@ enable_waving_water (Waving liquids) bool false # 0.0 = Wave doesn't move at all. # Default is 1.0 (1/2 node). # -# Requires: shaders, enable_waving_water +# Requires: enable_waving_water water_wave_height (Waving liquids wave height) float 1.0 0.0 4.0 # Length of liquid waves. # -# Requires: shaders, enable_waving_water +# Requires: enable_waving_water water_wave_length (Waving liquids wavelength) float 20.0 0.1 # How fast liquid waves will move. Higher = faster. # If negative, liquid waves will move backwards. # -# Requires: shaders, enable_waving_water +# Requires: enable_waving_water water_wave_speed (Waving liquids wave speed) float 5.0 [**Dynamic shadows] # Set to true to enable Shadow Mapping. # -# Requires: shaders, opengl +# Requires: opengl enable_dynamic_shadows (Dynamic shadows) bool false # Set the shadow strength gamma. # Adjusts the intensity of in-game dynamic shadows. # Lower value means lighter shadows, higher value means darker shadows. # -# Requires: shaders, enable_dynamic_shadows, opengl +# Requires: enable_dynamic_shadows, opengl shadow_strength_gamma (Shadow strength gamma) float 1.0 0.1 10.0 # Maximum distance to render shadows. # -# Requires: shaders, enable_dynamic_shadows, opengl +# Requires: enable_dynamic_shadows, opengl shadow_map_max_distance (Shadow map max distance in nodes to render shadows) float 140.0 10.0 1000.0 # Texture size to render the shadow map on. # This must be a power of two. # Bigger numbers create better shadows but it is also more expensive. # -# Requires: shaders, enable_dynamic_shadows, opengl +# Requires: enable_dynamic_shadows, opengl shadow_map_texture_size (Shadow map texture size) int 2048 128 8192 # Sets shadow texture quality to 32 bits. # On false, 16 bits texture will be used. # This can cause much more artifacts in the shadow. # -# Requires: shaders, enable_dynamic_shadows, opengl +# Requires: enable_dynamic_shadows, opengl shadow_map_texture_32bit (Shadow map texture in 32 bits) bool true # Enable Poisson disk filtering. # On true uses Poisson disk to make "soft shadows". Otherwise uses PCF filtering. # -# Requires: shaders, enable_dynamic_shadows, opengl +# Requires: enable_dynamic_shadows, opengl shadow_poisson_filter (Poisson filtering) bool true # Define shadow filtering quality. # This simulates the soft shadows effect by applying a PCF or Poisson disk # but also uses more resources. # -# Requires: shaders, enable_dynamic_shadows, opengl +# Requires: enable_dynamic_shadows, opengl shadow_filters (Shadow filter quality) enum 1 0,1,2 # Enable colored shadows. # On true translucent nodes cast colored shadows. This is expensive. # -# Requires: shaders, enable_dynamic_shadows, opengl +# Requires: enable_dynamic_shadows, opengl shadow_map_color (Colored shadows) bool false # Spread a complete update of shadow map over given number of frames. @@ -563,28 +554,26 @@ shadow_map_color (Colored shadows) bool false # will consume more resources. # Minimum value: 1; maximum value: 16 # -# Requires: shaders, enable_dynamic_shadows, opengl +# Requires: enable_dynamic_shadows, opengl shadow_update_frames (Map shadows update frames) int 8 1 16 # Set the soft shadow radius size. # Lower values mean sharper shadows, bigger values mean softer shadows. # Minimum value: 1.0; maximum value: 15.0 # -# Requires: shaders, enable_dynamic_shadows, opengl +# Requires: enable_dynamic_shadows, opengl shadow_soft_radius (Soft shadow radius) float 5.0 1.0 15.0 # Set the default tilt of Sun/Moon orbit in degrees. # Games may change orbit tilt via API. # Value of 0 means no tilt / vertical orbit. # -# Requires: shaders, enable_dynamic_shadows, opengl +# Requires: enable_dynamic_shadows, opengl shadow_sky_body_orbit_tilt (Sky Body Orbit Tilt) float 0.0 -60.0 60.0 [**Post Processing] # Enables the post processing pipeline. -# -# Requires: shaders enable_post_processing (Enable Post Processing) bool true # Enables Hable's 'Uncharted 2' filmic tone mapping. @@ -592,7 +581,7 @@ enable_post_processing (Enable Post Processing) bool true # appearance of high dynamic range images. Mid-range contrast is slightly # enhanced, highlights and shadows are gradually compressed. # -# Requires: shaders, enable_post_processing +# Requires: enable_post_processing tone_mapping (Filmic tone mapping) bool false # Enable automatic exposure correction @@ -600,14 +589,14 @@ tone_mapping (Filmic tone mapping) bool false # automatically adjust to the brightness of the scene, # simulating the behavior of human eye. # -# Requires: shaders, enable_post_processing +# Requires: enable_post_processing enable_auto_exposure (Enable Automatic Exposure) bool false # Set the exposure compensation in EV units. # Value of 0.0 (default) means no exposure compensation. # Range: from -1 to 1.0 # -# Requires: shaders, enable_post_processing, enable_auto_exposure +# Requires: enable_post_processing, enable_auto_exposure exposure_compensation (Exposure compensation) float 0.0 -1.0 1.0 # Apply dithering to reduce color banding artifacts. @@ -618,35 +607,35 @@ exposure_compensation (Exposure compensation) float 0.0 -1.0 1.0 # With OpenGL ES, dithering only works if the shader supports high # floating-point precision and it may have a higher performance impact. # -# Requires: shaders, enable_post_processing +# Requires: enable_post_processing debanding (Enable Debanding) bool true # Set to true to enable bloom effect. # Bright colors will bleed over the neighboring objects. # -# Requires: shaders, enable_post_processing +# Requires: enable_post_processing enable_bloom (Enable Bloom) bool false # Set to true to enable volumetric lighting effect (a.k.a. "Godrays"). # -# Requires: shaders, enable_post_processing, enable_bloom +# Requires: enable_post_processing, enable_bloom enable_volumetric_lighting (Volumetric lighting) bool false [**Other Effects] # Simulate translucency when looking at foliage in the sunlight. # -# Requires: shaders, enable_dynamic_shadows +# Requires: enable_dynamic_shadows enable_translucent_foliage (Translucent foliage) bool false # Apply specular shading to nodes. # -# Requires: shaders, enable_dynamic_shadows +# Requires: enable_dynamic_shadows enable_node_specular (Node specular) bool false # When enabled, liquid reflections are simulated. # -# Requires: shaders, enable_waving_water, enable_dynamic_shadows +# Requires: enable_waving_water, enable_dynamic_shadows enable_water_reflections (Liquid reflections) bool false [*Audio] @@ -1837,14 +1826,7 @@ ignore_world_load_errors (Ignore world errors) bool false [**Graphics] -# Shaders are a fundamental part of rendering and enable advanced visual effects. -# -# Requires: shaders_support -enable_shaders (Shaders) bool true - # Path to shader directory. If no path is defined, default location will be used. -# -# Requires: shaders shader_path (Shader path) path # The rendering back-end. @@ -1864,10 +1846,6 @@ cloud_radius (Cloud radius) int 12 1 62 # Whether node texture animations should be desynchronized per mapblock. desynchronize_mapblock_texture_animation (Desynchronize block animation) bool false -# Enables caching of facedir rotated meshes. -# This is only effective with shaders disabled. -enable_mesh_cache (Mesh cache) bool false - # Delay between mesh updates on the client in ms. Increasing this will slow # down the rate of mesh updates, thus reducing jitter on slower clients. mesh_generation_interval (Mapblock mesh generation delay) int 0 0 50 @@ -1922,7 +1900,7 @@ opengl_debug (OpenGL debug) bool false # top-left - processed base image, top-right - final image # bottom-left - raw base image, bottom-right - bloom texture. # -# Requires: shaders, enable_post_processing, enable_bloom +# Requires: enable_post_processing, enable_bloom enable_bloom_debug (Enable Bloom Debug) bool false [**Sound] diff --git a/doc/android.md b/doc/android.md index 19d7e569b..65cc0440c 100644 --- a/doc/android.md +++ b/doc/android.md @@ -3,8 +3,6 @@ All Luanti builds, including the Android variant, are based on the same code. However, additional Java code is used for proper Android integration. ## Controls -Compared to Luanti binaries for PC, the Android port has limited functionality -due to limited capabilities of common devices. What can be done is described below: While you're playing the game normally (that is, no menu or inventory is shown), the following controls are available: @@ -58,35 +56,25 @@ Mobile device generally have less RAM than PC, this setting limit how many mapbl this setting limit max FPS (Frame per second). Default value is 60, which lowest Android device screen refresh rate commonly found, but if you're using an device have lower refresh rate, change this ## Requirements -The minimal and recommended system requirements for Luanti are listed below. +The recommended system requirements for Luanti are listed below. ### CPU Supported architectures: -1. ARM v7 -2. ARM v8 +1. ARMv7 +2. AArch64 3. x86 4. x86_64 -CPU architectures similar to ARM or x86 might run Luanti but are not tested. - -### Minimum -1. Graphics API: OpenGL ES 1.0 - * Shaders might not work correctly or work at all on OpenGL ES 1.0. -2. Android version: Android 4.1 (API Level 16) -3. Free RAM: 500 MB -4. Free storage: 100 MB - * More storage is highly recommended - ### Recommended 1. Graphics API: OpenGL ES 2.0 -2. Android version: Android 4.4 (API Level 19) or newer -3. Empty RAM: 850 MB -4. Free storage: 480 MB +2. Android version: Android 5 (API Level 21) or newer +3. Free RAM: 1 GB +4. Free storage: 500 MB ## Rendering Unlike on PC, Android devices use OpenGL ES which less powerful than OpenGL, thus some shader settings cannot be used on OpenGL ES. -Changing the graphic driver setting to OpenGL will result in undesirable behavior. +Changing the graphic driver setting to OpenGL will not work. ## Building Requirements In order to build, your PC has to be set up to build Luanti in the usual diff --git a/doc/developing/os-compatibility.md b/doc/developing/os-compatibility.md index 29b271e6f..794328e7b 100644 --- a/doc/developing/os-compatibility.md +++ b/doc/developing/os-compatibility.md @@ -45,13 +45,8 @@ There's usually no reason to raise this unless the NDK drops older versions. **Compilers**: gcc, clang and MSVC (exceptions exist) -**OpenGL** is an entirely different beast, there is no formal consensus on changing the requirements -and neither do we have an exact set of requirements. - -We still support OpenGL 1.4 without shaders (fixed-pipeline), which could be considered very unreasonable in 2024. -OpenGL ES 2.0 is supported for the sake of mobile platforms. - -It has been [proposed](https://irc.minetest.net/minetest-dev/2022-08-18) moving to OpenGL 2.x or 3.0 with shaders required. +We require **OpenGL** 2.0 or ES 2.0, so shaders can be relied on. +Graphics code should generally work on both. Newer features can be used as long as a fallback exists. General **system requirements** are not bounded either. Being able to play Luanti on a recent low-end phone is a reasonable target. diff --git a/irr/src/COpenGLExtensionHandler.cpp b/irr/src/COpenGLExtensionHandler.cpp index 6127d6e46..a20932c8f 100644 --- a/irr/src/COpenGLExtensionHandler.cpp +++ b/irr/src/COpenGLExtensionHandler.cpp @@ -130,10 +130,10 @@ void COpenGLExtensionHandler::initExtensions(video::IContextManager *cmgr, bool { const f32 ogl_ver = core::fast_atof(reinterpret_cast(glGetString(GL_VERSION))); Version = static_cast(core::floor32(ogl_ver) * 100 + core::round32(core::fract(ogl_ver) * 10.0f)); - if (Version >= 102) - os::Printer::log("OpenGL driver version is 1.2 or better.", ELL_INFORMATION); + if (Version >= 200) + os::Printer::log("OpenGL driver version is 2.0 or newer.", ELL_INFORMATION); else - os::Printer::log("OpenGL driver version is not 1.2 or better.", ELL_WARNING); + os::Printer::log("OpenGL driver version is older than 2.0.", ELL_WARNING); { const char *t = reinterpret_cast(glGetString(GL_EXTENSIONS)); diff --git a/src/client/clouds.cpp b/src/client/clouds.cpp index 37f044f22..82a85d7b0 100644 --- a/src/client/clouds.cpp +++ b/src/client/clouds.cpp @@ -33,16 +33,13 @@ Clouds::Clouds(scene::ISceneManager* mgr, IShaderSource *ssrc, m_seed(seed) { assert(ssrc); - m_enable_shaders = g_settings->getBool("enable_shaders"); m_material.BackfaceCulling = true; m_material.FogEnable = true; m_material.AntiAliasing = video::EAAM_SIMPLE; - if (m_enable_shaders) { + { auto sid = ssrc->getShader("cloud_shader", TILE_MATERIAL_ALPHA); m_material.MaterialType = ssrc->getShaderInfo(sid).material; - } else { - m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; } m_params = SkyboxDefaults::getCloudDefaults(); @@ -119,15 +116,11 @@ void Clouds::updateMesh() // Colors with primitive shading - video::SColorf c_top_f(m_color); - video::SColorf c_side_1_f(m_color); - video::SColorf c_side_2_f(m_color); - video::SColorf c_bottom_f(m_color); - if (m_enable_shaders) { - // shader mixes the base color, set via ColorParam - c_top_f = c_side_1_f = c_side_2_f = c_bottom_f = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f); - } - video::SColorf shadow = m_params.color_shadow; + video::SColorf c_top_f(1, 1, 1, 1); + video::SColorf c_side_1_f(1, 1, 1, 1); + video::SColorf c_side_2_f(1, 1, 1, 1); + video::SColorf c_bottom_f(1, 1, 1, 1); + const video::SColorf shadow = m_params.color_shadow; c_side_1_f.r *= shadow.r * 0.25f + 0.75f; c_side_1_f.g *= shadow.g * 0.25f + 0.75f; @@ -385,8 +378,7 @@ void Clouds::render() } m_material.BackfaceCulling = is3D(); - if (m_enable_shaders) - m_material.ColorParam = m_color.toSColor(); + m_material.ColorParam = m_color.toSColor(); driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); driver->setMaterial(m_material); diff --git a/src/client/clouds.h b/src/client/clouds.h index 06a4f090b..950327aa2 100644 --- a/src/client/clouds.h +++ b/src/client/clouds.h @@ -169,7 +169,7 @@ private: v3s16 m_camera_offset; bool m_camera_inside_cloud = false; - bool m_enable_shaders, m_enable_3d; + bool m_enable_3d; video::SColorf m_color = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f); CloudParams m_params; }; diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 6c7976ea7..b73b3602c 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -349,8 +349,6 @@ bool GenericCAO::collideWithObjects() const void GenericCAO::initialize(const std::string &data) { processInitData(data); - - m_enable_shaders = g_settings->getBool("enable_shaders"); } void GenericCAO::processInitData(const std::string &data) @@ -603,7 +601,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) m_material_type_param = 0.5f; // May cut off alpha < 128 depending on m_material_type - if (m_enable_shaders) { + { IShaderSource *shader_source = m_client->getShaderSource(); MaterialType material_type; @@ -616,13 +614,6 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) u32 shader_id = shader_source->getShader("object_shader", material_type, NDT_NORMAL); m_material_type = shader_source->getShaderInfo(shader_id).material; - } else { - if (m_prop.use_texture_alpha) { - m_material_type = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - m_material_type_param = 1.0f / 256.f; // minimal alpha for texture rendering - } else { - m_material_type = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; - } } auto grabMatrixNode = [this] { @@ -688,9 +679,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) // Set material setMaterial(buf->getMaterial()); - if (m_enable_shaders) { - buf->getMaterial().ColorParam = c; - } + buf->getMaterial().ColorParam = c; // Add to mesh mesh->addMeshBuffer(buf); @@ -714,9 +703,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) // Set material setMaterial(buf->getMaterial()); - if (m_enable_shaders) { - buf->getMaterial().ColorParam = c; - } + buf->getMaterial().ColorParam = c; // Add to mesh mesh->addMeshBuffer(buf); @@ -741,8 +728,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) }); } else if (m_prop.visual == "mesh") { grabMatrixNode(); - // can't cache mesh if shaders disabled, since we modify vertices - scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, m_enable_shaders); + scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true); if (mesh) { if (!checkMeshNormals(mesh)) { infostream << "GenericCAO: recalculating normals for mesh " @@ -795,7 +781,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) /* Set VBO hint */ // wieldmesh sets its own hint, no need to handle it - if (m_enable_shaders && (m_meshnode || m_animated_meshnode)) { + if (m_meshnode || m_animated_meshnode) { // sprite uses vertex animation if (m_meshnode && m_prop.visual != "upright_sprite") m_meshnode->getMesh()->setHardwareMappingHint(scene::EHM_STATIC); @@ -893,10 +879,7 @@ void GenericCAO::updateLight(u32 day_night_ratio) // Encode light into color, adding a small boost // based on the entity glow. - if (m_enable_shaders) - light = encode_light(light_at_pos, m_prop.glow); - else - final_color_blend(&light, light_at_pos, day_night_ratio); + light = encode_light(light_at_pos, m_prop.glow); if (light != m_last_light) { m_last_light = light; @@ -912,22 +895,11 @@ void GenericCAO::setNodeLight(const video::SColor &light_color) return; } - if (m_enable_shaders) { + { auto *node = getSceneNode(); if (!node) return; setColorParam(node, light_color); - } else { - // TODO refactor vertex colors to be separate from the other vertex attributes - // instead of mutating meshes / buffers for everyone via setMeshColor. - // (Note: There are a couple more places here where setMeshColor is used.) - if (m_meshnode) { - setMeshColor(m_meshnode->getMesh(), light_color); - } else if (m_animated_meshnode) { - setMeshColor(m_animated_meshnode->getMesh(), light_color); - } else if (m_spritenode) { - m_spritenode->setColor(light_color); - } } } diff --git a/src/client/content_cao.h b/src/client/content_cao.h index 714a7f241..1115b6819 100644 --- a/src/client/content_cao.h +++ b/src/client/content_cao.h @@ -116,8 +116,6 @@ private: // Material video::E_MATERIAL_TYPE m_material_type; f32 m_material_type_param; - // Settings - bool m_enable_shaders = false; bool visualExpiryRequired(const ObjectProperties &newprops) const; diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index 0c1113d0c..2d294953a 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -67,8 +67,6 @@ MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector nodedef(data->nodedef), meshmanip(mm), blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE), - enable_mesh_cache(g_settings->getBool("enable_mesh_cache") && - !data->m_smooth_lighting), // Mesh cache is not supported with smooth lighting smooth_liquids(g_settings->getBool("enable_water_reflections")) { } @@ -1657,31 +1655,27 @@ void MapblockMeshGenerator::drawMeshNode() } else if (cur_node.f->param_type_2 == CPT2_WALLMOUNTED || cur_node.f->param_type_2 == CPT2_COLORED_WALLMOUNTED) { // Convert wallmounted to 6dfacedir. - // When cache enabled, it is already converted. facedir = cur_node.n.getWallMounted(nodedef); - if (!enable_mesh_cache) - facedir = wallmounted_to_facedir[facedir]; + facedir = wallmounted_to_facedir[facedir]; } else if (cur_node.f->param_type_2 == CPT2_DEGROTATE || cur_node.f->param_type_2 == CPT2_COLORED_DEGROTATE) { degrotate = cur_node.n.getDegRotate(nodedef); } - if (!data->m_smooth_lighting && cur_node.f->mesh_ptr[facedir] && !degrotate) { - // use cached meshes - private_mesh = false; - mesh = cur_node.f->mesh_ptr[facedir]; - } else if (cur_node.f->mesh_ptr[0]) { - // no cache, clone and rotate mesh + if (cur_node.f->mesh_ptr) { + // clone and rotate mesh private_mesh = true; - mesh = cloneMesh(cur_node.f->mesh_ptr[0]); + mesh = cloneMesh(cur_node.f->mesh_ptr); if (facedir) rotateMeshBy6dFacedir(mesh, facedir); else if (degrotate) rotateMeshXZby(mesh, 1.5f * degrotate); recalculateBoundingBox(mesh); meshmanip->recalculateNormals(mesh, true, false); - } else + } else { + warningstream << "drawMeshNode(): missing mesh" << std::endl; return; + } int mesh_buffer_count = mesh->getMeshBufferCount(); for (int j = 0; j < mesh_buffer_count; j++) { diff --git a/src/client/content_mapblock.h b/src/client/content_mapblock.h index 88b0e8a79..0473a9b75 100644 --- a/src/client/content_mapblock.h +++ b/src/client/content_mapblock.h @@ -60,9 +60,6 @@ private: const v3s16 blockpos_nodes; -// options - const bool enable_mesh_cache; - // current node struct { v3s16 p; diff --git a/src/client/hud.cpp b/src/client/hud.cpp index 2da9efa5e..6929d4c9e 100644 --- a/src/client/hud.cpp +++ b/src/client/hud.cpp @@ -84,15 +84,11 @@ Hud::Hud(Client *client, LocalPlayer *player, } // Initialize m_selection_material - - - if (g_settings->getBool("enable_shaders")) { - IShaderSource *shdrsrc = client->getShaderSource(); + IShaderSource *shdrsrc = client->getShaderSource(); + { auto shader_id = shdrsrc->getShader( m_mode == HIGHLIGHT_HALO ? "selection_shader" : "default_shader", TILE_MATERIAL_ALPHA); m_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material; - } else { - m_selection_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; } if (m_mode == HIGHLIGHT_BOX) { @@ -106,12 +102,9 @@ Hud::Hud(Client *client, LocalPlayer *player, } // Initialize m_block_bounds_material - if (g_settings->getBool("enable_shaders")) { - IShaderSource *shdrsrc = client->getShaderSource(); + { auto shader_id = shdrsrc->getShader("default_shader", TILE_MATERIAL_ALPHA); m_block_bounds_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material; - } else { - m_block_bounds_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; } m_block_bounds_material.Thickness = rangelim(g_settings->getS16("selectionbox_width"), 1, 5); @@ -1171,6 +1164,7 @@ void drawItemStack( auto &p = imesh->buffer_colors[j]; p.applyOverride(c); + // TODO: could be moved to a shader if (p.needColorize(c)) { buf->setDirty(scene::EBT_VERTEX); if (imesh->needs_shading) diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index 0922b9500..c212bd148 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -25,10 +25,9 @@ MeshMakeData */ -MeshMakeData::MeshMakeData(const NodeDefManager *ndef, u16 side_length, bool use_shaders): +MeshMakeData::MeshMakeData(const NodeDefManager *ndef, u16 side_length): side_length(side_length), - nodedef(ndef), - m_use_shaders(use_shaders) + nodedef(ndef) {} void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos) @@ -267,7 +266,8 @@ u16 getSmoothLightTransparent(const v3s16 &p, const v3s16 &corner, MeshMakeData return getSmoothLightCombined(p, dirs, data); } -void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio){ +void get_sunlight_color(video::SColorf *sunlight, u32 daynight_ratio) +{ f32 rg = daynight_ratio / 1000.0f - 0.04f; f32 b = (0.98f * daynight_ratio) / 1000.0f + 0.078f; sunlight->r = rg; @@ -594,14 +594,12 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs m_shdrsrc(client->getShaderSource()), m_bounding_sphere_center((data->side_length * 0.5f - 0.5f) * BS), m_animation_force_timer(0), // force initial animation - m_last_crack(-1), - m_last_daynight_ratio((u32) -1) + m_last_crack(-1) { ZoneScoped; for (auto &m : m_mesh) m = make_irr(); - m_enable_shaders = data->m_use_shaders; auto mesh_grid = client->getMeshGrid(); v3s16 bp = data->m_blockpos; @@ -695,30 +693,6 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs p.layer.texture = (*p.layer.frames)[0].texture; } - if (!m_enable_shaders) { - // Extract colors for day-night animation - // Dummy sunlight to handle non-sunlit areas - video::SColorf sunlight; - get_sunlight_color(&sunlight, 0); - - std::map colors; - const u32 vertex_count = p.vertices.size(); - for (u32 j = 0; j < vertex_count; j++) { - video::SColor *vc = &p.vertices[j].Color; - video::SColor copy = *vc; - if (vc->getAlpha() == 0) // No sunlight - no need to animate - final_color_blend(vc, copy, sunlight); // Finalize color - else // Record color to animate - colors[j] = copy; - - // The sunlight ratio has been stored, - // delete alpha (for the final rendering). - vc->setAlpha(255); - } - if (!colors.empty()) - m_daynight_diffs[{layer, i}] = std::move(colors); - } - // Create material video::SMaterial material; material.BackfaceCulling = true; @@ -729,12 +703,10 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs tex.MagFilter = video::ETMAGF_NEAREST; }); - if (m_enable_shaders) { + { material.MaterialType = m_shdrsrc->getShaderInfo( p.layer.shader_id).material; p.layer.applyMaterialOptionsWithShaders(material); - } else { - p.layer.applyMaterialOptions(material); } scene::SMeshBuffer *buf = new scene::SMeshBuffer(); @@ -771,7 +743,6 @@ MapBlockMesh::MapBlockMesh(Client *client, MeshMakeData *data, v3s16 camera_offs // Check if animation is required for this mesh m_has_animation = !m_crack_materials.empty() || - !m_daynight_diffs.empty() || !m_animation_info.empty(); } @@ -844,24 +815,6 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, buf->getMaterial().setTexture(0, frame.texture); } - // Day-night transition - if (!m_enable_shaders && (daynight_ratio != m_last_daynight_ratio)) { - video::SColorf day_color; - get_sunlight_color(&day_color, daynight_ratio); - - for (auto &daynight_diff : m_daynight_diffs) { - auto *mesh = m_mesh[daynight_diff.first.first].get(); - mesh->setDirty(scene::EBT_VERTEX); // force reload to VBO - scene::IMeshBuffer *buf = mesh-> - getMeshBuffer(daynight_diff.first.second); - video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices(); - for (const auto &j : daynight_diff.second) - final_color_blend(&(vertices[j.first].Color), j.second, - day_color); - } - m_last_daynight_ratio = daynight_ratio; - } - return true; } diff --git a/src/client/mapblock_mesh.h b/src/client/mapblock_mesh.h index 9bdebec7c..5a8daf50c 100644 --- a/src/client/mapblock_mesh.h +++ b/src/client/mapblock_mesh.h @@ -35,9 +35,8 @@ struct MeshMakeData u16 side_length; const NodeDefManager *nodedef; - bool m_use_shaders; - MeshMakeData(const NodeDefManager *ndef, u16 side_length, bool use_shaders); + MeshMakeData(const NodeDefManager *ndef, u16 side_length); /* Copy block data manually (to allow optimizations by the caller) @@ -235,8 +234,6 @@ private: f32 m_bounding_radius; v3f m_bounding_sphere_center; - bool m_enable_shaders; - // Must animate() be called before rendering? bool m_has_animation; int m_animation_force_timer; @@ -252,14 +249,6 @@ private: // Keys are pairs of (mesh index, buffer index in the mesh) std::map, AnimationInfo> m_animation_info; - // Animation info: day/night transitions - // Last daynight_ratio value passed to animate() - u32 m_last_daynight_ratio; - // For each mesh and mesh buffer, stores pre-baked colors - // of sunlit vertices - // Keys are pairs of (mesh index, buffer index in the mesh) - std::map, std::map > m_daynight_diffs; - // list of all semitransparent triangles in the mapblock std::vector m_transparent_triangles; // Binary Space Partitioning tree for the block diff --git a/src/client/mesh_generator_thread.cpp b/src/client/mesh_generator_thread.cpp index ec868980c..3d80f8e67 100644 --- a/src/client/mesh_generator_thread.cpp +++ b/src/client/mesh_generator_thread.cpp @@ -39,7 +39,6 @@ QueuedMeshUpdate::~QueuedMeshUpdate() MeshUpdateQueue::MeshUpdateQueue(Client *client): m_client(client) { - m_cache_enable_shaders = g_settings->getBool("enable_shaders"); m_cache_smooth_lighting = g_settings->getBool("smooth_lighting"); } @@ -177,7 +176,7 @@ 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, m_cache_enable_shaders); + MeshMakeData *data = new MeshMakeData(m_client->ndef(), MAP_BLOCKSIZE * mesh_grid.cell_size); q->data = data; data->fillBlockDataBegin(q->p); diff --git a/src/client/mesh_generator_thread.h b/src/client/mesh_generator_thread.h index d6e2863bf..fb9b5ae9e 100644 --- a/src/client/mesh_generator_thread.h +++ b/src/client/mesh_generator_thread.h @@ -70,11 +70,9 @@ private: std::mutex m_mutex; // TODO: Add callback to update these when g_settings changes - bool m_cache_enable_shaders; bool m_cache_smooth_lighting; void fillDataFromMapBlocks(QueuedMeshUpdate *q); - void cleanupCache(); }; struct MeshUpdateResult diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp index 3bc208808..f28f6a39a 100644 --- a/src/client/minimap.cpp +++ b/src/client/minimap.cpp @@ -173,7 +173,6 @@ Minimap::Minimap(Client *client) m_current_mode_index = 0; // Initialize static settings - m_enable_shaders = g_settings->getBool("enable_shaders"); m_surface_mode_scan_height = g_settings->getBool("minimap_double_scan_height") ? 256 : 128; @@ -599,7 +598,7 @@ void Minimap::drawMinimap(core::rect rect) material.TextureLayers[0].Texture = minimap_texture; material.TextureLayers[1].Texture = data->heightmap_texture; - if (m_enable_shaders && data->mode.type == MINIMAP_TYPE_SURFACE) { + if (data->mode.type == MINIMAP_TYPE_SURFACE) { auto sid = m_shdrsrc->getShader("minimap_shader", TILE_MATERIAL_ALPHA); material.MaterialType = m_shdrsrc->getShaderInfo(sid).material; } else { diff --git a/src/client/minimap.h b/src/client/minimap.h index 5bc69894f..15112d565 100644 --- a/src/client/minimap.h +++ b/src/client/minimap.h @@ -152,7 +152,6 @@ private: const NodeDefManager *m_ndef; std::unique_ptr m_minimap_update_thread; irr_ptr m_meshbuffer; - bool m_enable_shaders; std::vector m_modes; size_t m_current_mode_index; u16 m_surface_mode_scan_height; diff --git a/src/client/render/plain.cpp b/src/client/render/plain.cpp index c08ae78b2..2215ad777 100644 --- a/src/client/render/plain.cpp +++ b/src/client/render/plain.cpp @@ -87,7 +87,7 @@ void UpscaleStep::run(PipelineContext &context) std::unique_ptr create3DStage(Client *client, v2f scale) { RenderStep *step = new Draw3D(); - if (g_settings->getBool("enable_shaders") && g_settings->getBool("enable_post_processing")) { + if (g_settings->getBool("enable_post_processing")) { RenderPipeline *pipeline = new RenderPipeline(); pipeline->addStep(pipeline->own(std::unique_ptr(step))); @@ -111,8 +111,8 @@ RenderStep* addUpscaling(RenderPipeline *pipeline, RenderStep *previousStep, v2f if (downscale_factor.X == 1.0f && downscale_factor.Y == 1.0f) return previousStep; - // When shaders are enabled, post-processing pipeline takes care of rescaling - if (g_settings->getBool("enable_shaders") && g_settings->getBool("enable_post_processing")) + // post-processing pipeline takes care of rescaling + if (g_settings->getBool("enable_post_processing")) return previousStep; diff --git a/src/client/shader.cpp b/src/client/shader.cpp index 778e17d2d..8d2d5744a 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -307,9 +307,6 @@ public: private: - // Are shaders even enabled? - bool m_enabled; - // The id of the thread that is allowed to use irrlicht directly std::thread::id m_main_thread; @@ -348,12 +345,6 @@ ShaderSource::ShaderSource() // Add a dummy ShaderInfo as the first index, named "" m_shaderinfo_cache.emplace_back(); - m_enabled = g_settings->getBool("enable_shaders"); - if (!m_enabled) { - warningstream << "You are running " PROJECT_NAME_C " with shaders disabled, " - "this is not a recommended configuration." << std::endl; - } - // Add main global constant setter addShaderConstantSetterFactory(new MainShaderConstantSetterFactory()); } @@ -362,11 +353,9 @@ ShaderSource::~ShaderSource() { MutexAutoLock lock(m_shaderinfo_cache_mutex); - if (!m_enabled) - return; - // Delete materials auto *gpu = RenderingEngine::get_video_driver()->getGPUProgrammingServices(); + assert(gpu); for (ShaderInfo &i : m_shaderinfo_cache) { if (!i.name.empty()) gpu->deleteShaderMaterial(i.material); @@ -495,11 +484,9 @@ void ShaderSource::rebuildShaders() { MutexAutoLock lock(m_shaderinfo_cache_mutex); - if (!m_enabled) - return; - // Delete materials auto *gpu = RenderingEngine::get_video_driver()->getGPUProgrammingServices(); + assert(gpu); for (ShaderInfo &i : m_shaderinfo_cache) { if (!i.name.empty()) { gpu->deleteShaderMaterial(i.material); @@ -546,14 +533,14 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, } shaderinfo.material = shaderinfo.base_material; - if (!m_enabled) + video::IVideoDriver *driver = RenderingEngine::get_video_driver(); + // The null driver doesn't support shaders (duh), but we can pretend it does. + if (driver->getDriverType() == video::EDT_NULL) return shaderinfo; - video::IVideoDriver *driver = RenderingEngine::get_video_driver(); auto *gpu = driver->getGPUProgrammingServices(); if (!driver->queryFeature(video::EVDF_ARB_GLSL) || !gpu) { - throw ShaderException(gettext("Shaders are enabled but GLSL is not " - "supported by the driver.")); + throw ShaderException(gettext("GLSL is not supported by the driver")); } // Create shaders header diff --git a/src/client/shadows/dynamicshadowsrender.cpp b/src/client/shadows/dynamicshadowsrender.cpp index 466903cbc..2bf3adeb3 100644 --- a/src/client/shadows/dynamicshadowsrender.cpp +++ b/src/client/shadows/dynamicshadowsrender.cpp @@ -107,25 +107,13 @@ void ShadowRenderer::disable() void ShadowRenderer::preInit(IWritableShaderSource *shsrc) { - if (g_settings->getBool("enable_shaders") && - g_settings->getBool("enable_dynamic_shadows")) { + if (g_settings->getBool("enable_dynamic_shadows")) { shsrc->addShaderConstantSetterFactory(new ShadowConstantSetterFactory()); } } void ShadowRenderer::initialize() { - auto *gpu = m_driver->getGPUProgrammingServices(); - - // we need glsl - if (!m_shadows_supported || !gpu || !m_driver->queryFeature(video::EVDF_ARB_GLSL)) { - m_shadows_supported = false; - - warningstream << "Shadows: GLSL Shader not supported on this system." - << std::endl; - return; - } - createShaders(); @@ -533,7 +521,7 @@ void ShadowRenderer::mixShadowsQuad() void ShadowRenderer::createShaders() { - video::IGPUProgrammingServices *gpu = m_driver->getGPUProgrammingServices(); + auto *gpu = m_driver->getGPUProgrammingServices(); if (depth_shader == -1) { std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass1_vertex.glsl"); @@ -706,14 +694,12 @@ std::string ShadowRenderer::readShaderFile(const std::string &path) ShadowRenderer *createShadowRenderer(IrrlichtDevice *device, Client *client) { // disable if unsupported - if (g_settings->getBool("enable_dynamic_shadows") && ( - device->getVideoDriver()->getDriverType() != video::EDT_OPENGL || - !g_settings->getBool("enable_shaders"))) { + if (g_settings->getBool("enable_dynamic_shadows") && + device->getVideoDriver()->getDriverType() != video::EDT_OPENGL) { g_settings->setBool("enable_dynamic_shadows", false); } - if (g_settings->getBool("enable_shaders") && - g_settings->getBool("enable_dynamic_shadows")) { + if (g_settings->getBool("enable_dynamic_shadows")) { ShadowRenderer *shadow_renderer = new ShadowRenderer(device, client); shadow_renderer->initialize(); return shadow_renderer; diff --git a/src/client/sky.cpp b/src/client/sky.cpp index cd02b5554..cfce57ef3 100644 --- a/src/client/sky.cpp +++ b/src/client/sky.cpp @@ -53,8 +53,6 @@ Sky::Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShade m_box.MaxEdge.set(0, 0, 0); m_box.MinEdge.set(0, 0, 0); - m_enable_shaders = g_settings->getBool("enable_shaders"); - m_sky_params = SkyboxDefaults::getSkyDefaults(); m_sun_params = SkyboxDefaults::getSunDefaults(); m_moon_params = SkyboxDefaults::getMoonDefaults(); @@ -63,9 +61,8 @@ Sky::Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShade // Create materials m_materials[0] = baseMaterial(); - m_materials[0].MaterialType = m_enable_shaders ? - ssrc->getShaderInfo(ssrc->getShader("stars_shader", TILE_MATERIAL_ALPHA)).material : - video::EMT_TRANSPARENT_ALPHA_CHANNEL; + m_materials[0].MaterialType = + ssrc->getShaderInfo(ssrc->getShader("stars_shader", TILE_MATERIAL_ALPHA)).material; m_materials[1] = baseMaterial(); m_materials[1].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; @@ -668,10 +665,7 @@ void Sky::draw_stars(video::IVideoDriver * driver, float wicked_time_of_day) color.a *= alpha; if (color.a <= 0.0f) // Stars are only drawn when not fully transparent return; - if (m_enable_shaders) - m_materials[0].ColorParam = color.toSColor(); - else - setMeshBufferColor(m_stars.get(), color.toSColor()); + m_materials[0].ColorParam = color.toSColor(); auto sky_rotation = core::matrix4().setRotationAxisRadians(2.0f * M_PI * (wicked_time_of_day - 0.25f), v3f(0.0f, 0.0f, 1.0f)); auto world_matrix = driver->getTransform(video::ETS_WORLD); @@ -841,8 +835,7 @@ void Sky::updateStars() indices.push_back(i * 4 + 3); indices.push_back(i * 4 + 0); } - if (m_enable_shaders) - m_stars->setHardwareMappingHint(scene::EHM_STATIC); + m_stars->setHardwareMappingHint(scene::EHM_STATIC); } void Sky::setSkyColors(const SkyColor &sky_color) diff --git a/src/client/sky.h b/src/client/sky.h index 8986a505c..73f377ae2 100644 --- a/src/client/sky.h +++ b/src/client/sky.h @@ -173,7 +173,6 @@ private: bool m_clouds_enabled = true; // Initialised to true, reset only by set_sky API bool m_directional_colored_fog; bool m_in_clouds = true; // Prevent duplicating bools to remember old values - bool m_enable_shaders = false; video::SColorf m_bgcolor_bright_f = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f); video::SColorf m_skycolor_bright_f = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f); diff --git a/src/client/tile.h b/src/client/tile.h index ceee54243..df02d2244 100644 --- a/src/client/tile.h +++ b/src/client/tile.h @@ -78,7 +78,6 @@ struct TileLayer return !(*this == other); } - // Sets everything else except the texture in the material void applyMaterialOptions(video::SMaterial &material) const; void applyMaterialOptionsWithShaders(video::SMaterial &material) const; diff --git a/src/client/wieldmesh.cpp b/src/client/wieldmesh.cpp index 28fe362a7..5e645e9be 100644 --- a/src/client/wieldmesh.cpp +++ b/src/client/wieldmesh.cpp @@ -184,7 +184,6 @@ WieldMeshSceneNode::WieldMeshSceneNode(scene::ISceneManager *mgr, s32 id): scene::ISceneNode(mgr->getRootSceneNode(), mgr, id), m_material_type(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF) { - m_enable_shaders = g_settings->getBool("enable_shaders"); m_anisotropic_filter = g_settings->getBool("anisotropic_filter"); m_bilinear_filter = g_settings->getBool("bilinear_filter"); m_trilinear_filter = g_settings->getBool("trilinear_filter"); @@ -233,7 +232,7 @@ void WieldMeshSceneNode::setCube(const ContentFeatures &f, scene::IMesh *cubemesh = g_extrusion_mesh_cache->createCube(); scene::SMesh *copy = cloneMesh(cubemesh); cubemesh->drop(); - postProcessNodeMesh(copy, f, false, true, &m_material_type, &m_colors, true); + postProcessNodeMesh(copy, f, false, &m_material_type, &m_colors, true); changeToMesh(copy); copy->drop(); m_meshnode->setScale(wield_scale * WIELD_SCALE_FACTOR); @@ -297,7 +296,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename, static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n, std::vector *colors, const ContentFeatures &f) { - MeshMakeData mesh_make_data(client->ndef(), 1, false); + 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, @@ -354,10 +353,8 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che scene::SMesh *mesh = nullptr; - if (m_enable_shaders) { - u32 shader_id = shdrsrc->getShader("object_shader", TILE_MATERIAL_BASIC, NDT_NORMAL); - m_material_type = shdrsrc->getShaderInfo(shader_id).material; - } + u32 shader_id = shdrsrc->getShader("object_shader", TILE_MATERIAL_BASIC, NDT_NORMAL); + m_material_type = shdrsrc->getShaderInfo(shader_id).material; // Color-related m_colors.clear(); @@ -500,10 +497,7 @@ void WieldMeshSceneNode::setColor(video::SColor c) if (m_colors[j].needColorize(buffercolor)) { buf->setDirty(scene::EBT_VERTEX); - if (m_enable_shaders) - setMeshBufferColor(buf, buffercolor); - else - colorizeMeshBuffer(buf, &buffercolor); + setMeshBufferColor(buf, buffercolor); } } } @@ -513,13 +507,11 @@ void WieldMeshSceneNode::setNodeLightColor(video::SColor color) if (!m_meshnode) return; - if (m_enable_shaders) { + { for (u32 i = 0; i < m_meshnode->getMaterialCount(); ++i) { video::SMaterial &material = m_meshnode->getMaterial(i); material.ColorParam = color; } - } else { - setColor(color); } } @@ -538,12 +530,7 @@ void WieldMeshSceneNode::changeToMesh(scene::IMesh *mesh) dummymesh->drop(); // m_meshnode grabbed it } else { m_meshnode->setMesh(mesh); - // without shaders recolored often for lighting - // otherwise only once - if (m_enable_shaders) - mesh->setHardwareMappingHint(scene::EHM_STATIC); - else - mesh->setHardwareMappingHint(scene::EHM_DYNAMIC); + mesh->setHardwareMappingHint(scene::EHM_STATIC); } m_meshnode->setVisible(true); @@ -596,7 +583,7 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result) } else scaleMesh(mesh, v3f(1.2, 1.2, 1.2)); // add overlays - postProcessNodeMesh(mesh, f, false, false, nullptr, + postProcessNodeMesh(mesh, f, false, nullptr, &result->buffer_colors, true); if (f.drawtype == NDT_ALLFACES) scaleMesh(mesh, v3f(f.visual_scale)); @@ -704,7 +691,7 @@ scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, } void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f, - bool use_shaders, bool set_material, const video::E_MATERIAL_TYPE *mattype, + bool set_material, const video::E_MATERIAL_TYPE *mattype, std::vector *colors, bool apply_scale) { const u32 mc = mesh->getMeshBufferCount(); diff --git a/src/client/wieldmesh.h b/src/client/wieldmesh.h index 8291cce14..5a5a6957a 100644 --- a/src/client/wieldmesh.h +++ b/src/client/wieldmesh.h @@ -117,7 +117,6 @@ private: scene::IMeshSceneNode *m_meshnode = nullptr; video::E_MATERIAL_TYPE m_material_type; - bool m_enable_shaders; bool m_anisotropic_filter; bool m_bilinear_filter; bool m_trilinear_filter; @@ -152,6 +151,6 @@ scene::SMesh *getExtrudedMesh(ITextureSource *tsrc, const std::string &imagename * 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 use_shaders, +void postProcessNodeMesh(scene::SMesh *mesh, const ContentFeatures &f, bool set_material, const video::E_MATERIAL_TYPE *mattype, std::vector *colors, bool apply_scale = false); diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 7758c96bf..2142615e2 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -102,7 +102,6 @@ void set_default_settings() settings->setDefault("sound_volume_unfocused", "0.3"); settings->setDefault("mute_sound", "false"); settings->setDefault("sound_extensions_blacklist", ""); - settings->setDefault("enable_mesh_cache", "false"); settings->setDefault("mesh_generation_interval", "0"); settings->setDefault("mesh_generation_threads", "0"); settings->setDefault("free_move", "false"); @@ -299,7 +298,6 @@ void set_default_settings() settings->setDefault("enable_local_map_saving", "false"); settings->setDefault("show_entity_selectionbox", "false"); settings->setDefault("ambient_occlusion_gamma", "1.8"); - settings->setDefault("enable_shaders", "true"); settings->setDefault("enable_particles", "true"); settings->setDefault("arm_inertia", "true"); settings->setDefault("show_nametag_backgrounds", "true"); diff --git a/src/environment.cpp b/src/environment.cpp index 533959723..fe582afd4 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -17,7 +17,6 @@ Environment::Environment(IGameDef *gamedef): m_day_count(0), m_gamedef(gamedef) { - m_cache_enable_shaders = g_settings->getBool("enable_shaders"); m_cache_active_block_mgmt_interval = g_settings->getFloat("active_block_mgmt_interval"); m_cache_abm_interval = g_settings->getFloat("abm_interval"); m_cache_nodetimer_interval = g_settings->getFloat("nodetimer_interval"); @@ -32,7 +31,7 @@ u32 Environment::getDayNightRatio() MutexAutoLock lock(m_time_lock); if (m_enable_day_night_ratio_override) return m_day_night_ratio_override; - return time_to_daynight_ratio(m_time_of_day_f * 24000, m_cache_enable_shaders); + return time_to_daynight_ratio(m_time_of_day_f * 24000, true); } void Environment::setTimeOfDaySpeed(float speed) diff --git a/src/environment.h b/src/environment.h index 925154d84..b668e69c2 100644 --- a/src/environment.h +++ b/src/environment.h @@ -131,7 +131,6 @@ protected: * (as opposed to the this local caching). This can be addressed in * a later release. */ - bool m_cache_enable_shaders; float m_cache_active_block_mgmt_interval; float m_cache_abm_interval; float m_cache_nodetimer_interval; diff --git a/src/gui/guiScene.cpp b/src/gui/guiScene.cpp index f30c4f3d1..88865b384 100644 --- a/src/gui/guiScene.cpp +++ b/src/gui/guiScene.cpp @@ -98,11 +98,6 @@ void GUIScene::draw() if (m_inf_rot) rotateCamera(v3f(0.f, -0.03f * (float)dtime_ms, 0.f)); - // HACK restore mesh vertex colors to full brightness: - // They may have been mutated in entity rendering code before. - if (!g_settings->getBool("enable_shaders")) - setMeshColor(m_mesh->getMesh(), irr::video::SColor(0xFFFFFFFF)); - m_smgr->drawAll(); if (m_initial_rotation && m_mesh) { diff --git a/src/nodedef.cpp b/src/nodedef.cpp index c956bbdfd..2301b179f 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -270,18 +270,12 @@ void TextureSettings::readSettings() { connected_glass = g_settings->getBool("connected_glass"); translucent_liquids = g_settings->getBool("translucent_liquids"); - bool smooth_lighting = g_settings->getBool("smooth_lighting"); - enable_mesh_cache = g_settings->getBool("enable_mesh_cache"); enable_minimap = g_settings->getBool("enable_minimap"); node_texture_size = std::max(g_settings->getU16("texture_min_size"), 1); std::string leaves_style_str = g_settings->get("leaves_style"); std::string world_aligned_mode_str = g_settings->get("world_aligned_mode"); std::string autoscale_mode_str = g_settings->get("autoscale_mode"); - // Mesh cache is not supported in combination with smooth lighting - if (smooth_lighting) - enable_mesh_cache = false; - if (leaves_style_str == "fancy") { leaves_style = LEAVES_FANCY; } else if (leaves_style_str == "simple") { @@ -357,8 +351,7 @@ void ContentFeatures::reset() drawtype = NDT_NORMAL; mesh.clear(); #if CHECK_CLIENT_BUILD() - for (auto &i : mesh_ptr) - i = NULL; + mesh_ptr = nullptr; minimap_color = video::SColor(0, 0, 0, 0); #endif visual_scale = 1.0; @@ -952,48 +945,14 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc if (drawtype == NDT_MESH && !mesh.empty()) { // Meshnode drawtype // Read the mesh and apply scale - mesh_ptr[0] = client->getMesh(mesh); - if (mesh_ptr[0]){ - v3f scale = v3f(1.0, 1.0, 1.0) * BS * visual_scale; - scaleMesh(mesh_ptr[0], scale); - recalculateBoundingBox(mesh_ptr[0]); - meshmanip->recalculateNormals(mesh_ptr[0], true, false); + mesh_ptr = client->getMesh(mesh); + if (mesh_ptr) { + v3f scale = v3f(BS) * visual_scale; + scaleMesh(mesh_ptr, scale); + recalculateBoundingBox(mesh_ptr); + meshmanip->recalculateNormals(mesh_ptr, true, false); } } - - //Cache 6dfacedir and wallmounted rotated clones of meshes - if (tsettings.enable_mesh_cache && mesh_ptr[0] && - (param_type_2 == CPT2_FACEDIR - || param_type_2 == CPT2_COLORED_FACEDIR)) { - for (u16 j = 1; j < 24; j++) { - mesh_ptr[j] = cloneMesh(mesh_ptr[0]); - rotateMeshBy6dFacedir(mesh_ptr[j], j); - recalculateBoundingBox(mesh_ptr[j]); - meshmanip->recalculateNormals(mesh_ptr[j], true, false); - } - } else if (tsettings.enable_mesh_cache && mesh_ptr[0] && - (param_type_2 == CPT2_4DIR - || param_type_2 == CPT2_COLORED_4DIR)) { - for (u16 j = 1; j < 4; j++) { - mesh_ptr[j] = cloneMesh(mesh_ptr[0]); - rotateMeshBy6dFacedir(mesh_ptr[j], j); - recalculateBoundingBox(mesh_ptr[j]); - meshmanip->recalculateNormals(mesh_ptr[j], true, false); - } - } else if (tsettings.enable_mesh_cache && mesh_ptr[0] - && (param_type_2 == CPT2_WALLMOUNTED || - param_type_2 == CPT2_COLORED_WALLMOUNTED)) { - static const u8 wm_to_6d[6] = { 20, 0, 16 + 1, 12 + 3, 8, 4 + 2 }; - for (u16 j = 1; j < 6; j++) { - mesh_ptr[j] = cloneMesh(mesh_ptr[0]); - rotateMeshBy6dFacedir(mesh_ptr[j], wm_to_6d[j]); - recalculateBoundingBox(mesh_ptr[j]); - meshmanip->recalculateNormals(mesh_ptr[j], true, false); - } - rotateMeshBy6dFacedir(mesh_ptr[0], wm_to_6d[0]); - recalculateBoundingBox(mesh_ptr[0]); - meshmanip->recalculateNormals(mesh_ptr[0], true, false); - } } #endif @@ -1014,10 +973,8 @@ NodeDefManager::~NodeDefManager() { #if CHECK_CLIENT_BUILD() for (ContentFeatures &f : m_content_features) { - for (auto &j : f.mesh_ptr) { - if (j) - j->drop(); - } + if (f.mesh_ptr) + f.mesh_ptr->drop(); } #endif } diff --git a/src/nodedef.h b/src/nodedef.h index bc0058101..c3f88ce83 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -171,7 +171,6 @@ public: int node_texture_size; bool translucent_liquids; bool connected_glass; - bool enable_mesh_cache; bool enable_minimap; TextureSettings() = default; @@ -337,7 +336,7 @@ struct ContentFeatures enum NodeDrawType drawtype; std::string mesh; #if CHECK_CLIENT_BUILD() - scene::IMesh *mesh_ptr[24]; + scene::IMesh *mesh_ptr; // mesh in case of mesh node video::SColor minimap_color; #endif float visual_scale; // Misc. scale parameter diff --git a/src/unittest/test_content_mapblock.cpp b/src/unittest/test_content_mapblock.cpp index acc6213a4..6e0026cba 100644 --- a/src/unittest/test_content_mapblock.cpp +++ b/src/unittest/test_content_mapblock.cpp @@ -36,9 +36,9 @@ public: node_mgr()->resolveCrossrefs(); } - MeshMakeData makeSingleNodeMMD(bool smooth_lighting = true, bool for_shaders = true) + MeshMakeData makeSingleNodeMMD(bool smooth_lighting = true) { - MeshMakeData data{ndef(), 1, for_shaders}; + MeshMakeData data{ndef(), 1}; data.setSmoothLighting(smooth_lighting); data.m_blockpos = {0, 0, 0}; for (s16 x = -1; x <= 1; x++) diff --git a/util/test_multiplayer.sh b/util/test_multiplayer.sh index 5c0e6bfaa..ade24b648 100755 --- a/util/test_multiplayer.sh +++ b/util/test_multiplayer.sh @@ -29,7 +29,7 @@ mkdir -p "$worldpath/worldmods" printf '%s\n' >"$testspath/client1.conf" \ video_driver=null name=client1 viewing_range=10 \ - enable_{sound,minimap,shaders}=false + enable_{sound,minimap,post_processing}=false printf '%s\n' >"$testspath/server.conf" \ max_block_send_distance=1 active_block_range=1 \ From 0c3117f9b32624955846314ebf87f757d124184f Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 13 Nov 2024 18:39:10 +0100 Subject: [PATCH 055/136] Fix mainmenu settings crash caused by last commit closes #15432 --- builtin/mainmenu/settings/dlg_settings.lua | 2 +- builtin/mainmenu/settings/shadows_component.lua | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/builtin/mainmenu/settings/dlg_settings.lua b/builtin/mainmenu/settings/dlg_settings.lua index dbd77a4db..f03596815 100644 --- a/builtin/mainmenu/settings/dlg_settings.lua +++ b/builtin/mainmenu/settings/dlg_settings.lua @@ -359,7 +359,7 @@ local function check_requirements(name, requires) if special[req_key] == nil then local required_setting = get_setting_info(req_key) if required_setting == nil then - core.log("warning", "Unknown setting " .. req_key .. " required by " .. name) + core.log("warning", "Unknown setting " .. req_key .. " required by " .. (name or "???")) end local actual_value = core.settings:get_bool(req_key, required_setting and core.is_yes(required_setting.default)) diff --git a/builtin/mainmenu/settings/shadows_component.lua b/builtin/mainmenu/settings/shadows_component.lua index 2ca03b71b..2d68f9d3d 100644 --- a/builtin/mainmenu/settings/shadows_component.lua +++ b/builtin/mainmenu/settings/shadows_component.lua @@ -82,7 +82,6 @@ end return { query_text = "Shadows", requires = { - shaders = true, opengl = true, }, get_formspec = function(self, avail_w) From d4378a74d3c593c9dd4dfbba30120049e8128102 Mon Sep 17 00:00:00 2001 From: cx384 Date: Fri, 15 Nov 2024 11:37:17 +0100 Subject: [PATCH 056/136] Fix register_ore ore_type error handling --- src/mapgen/mg_ore.h | 3 +-- src/script/lua_api/l_mapgen.cpp | 33 +++++++++++++++++---------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/mapgen/mg_ore.h b/src/mapgen/mg_ore.h index 435933046..eed13ebfc 100644 --- a/src/mapgen/mg_ore.h +++ b/src/mapgen/mg_ore.h @@ -172,9 +172,8 @@ public: return new OreVein; case ORE_STRATUM: return new OreStratum; - default: - return nullptr; } + return nullptr; } void clear(); diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index c8b412c73..89323b2f6 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -1323,20 +1323,20 @@ int ModApiMapgen::l_register_ore(lua_State *L) BiomeManager *bmgr = emerge->getWritableBiomeManager(); OreManager *oremgr = emerge->getWritableOreManager(); - enum OreType oretype = (OreType)getenumfield(L, index, - "ore_type", es_OreType, ORE_SCATTER); - Ore *ore = oremgr->create(oretype); - if (!ore) { - errorstream << "register_ore: ore_type " << oretype << " not implemented\n"; - return 0; + int oretype_int; + std::string oretype_string = getstringfield_default(L, index, "ore_type", "nil"); + if (!string_to_enum(es_OreType, oretype_int, oretype_string)) { + throw LuaError("register_ore: unknown oretype \"" + oretype_string + "\""); } + enum OreType oretype = (OreType) oretype_int; + std::unique_ptr ore(oremgr->create(oretype)); ore->name = getstringfield_default(L, index, "name", ""); ore->ore_param2 = (u8)getintfield_default(L, index, "ore_param2", 0); ore->clust_scarcity = getintfield_default(L, index, "clust_scarcity", 1); ore->clust_num_ores = getintfield_default(L, index, "clust_num_ores", 1); ore->clust_size = getintfield_default(L, index, "clust_size", 0); - ore->noise = NULL; + ore->noise = nullptr; ore->flags = 0; //// Get noise_threshold @@ -1368,12 +1368,11 @@ int ModApiMapgen::l_register_ore(lua_State *L) if (ore->clust_scarcity <= 0 || ore->clust_num_ores <= 0) { errorstream << "register_ore: clust_scarcity and clust_num_ores" "must be greater than 0" << std::endl; - delete ore; return 0; } //// Get flags - getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, NULL); + getflagsfield(L, index, "flags", flagdesc_ore, &ore->flags, nullptr); //// Get biomes associated with this decoration (if any) lua_getfield(L, index, "biomes"); @@ -1394,7 +1393,7 @@ int ModApiMapgen::l_register_ore(lua_State *L) //// Get type-specific parameters switch (oretype) { case ORE_SHEET: { - OreSheet *oresheet = (OreSheet *)ore; + OreSheet *oresheet = (OreSheet *)ore.get(); oresheet->column_height_min = getintfield_default(L, index, "column_height_min", 1); @@ -1406,7 +1405,7 @@ int ModApiMapgen::l_register_ore(lua_State *L) break; } case ORE_PUFF: { - OrePuff *orepuff = (OrePuff *)ore; + OrePuff *orepuff = (OrePuff *)ore.get(); lua_getfield(L, index, "np_puff_top"); read_noiseparams(L, -1, &orepuff->np_puff_top); @@ -1419,7 +1418,7 @@ int ModApiMapgen::l_register_ore(lua_State *L) break; } case ORE_VEIN: { - OreVein *orevein = (OreVein *)ore; + OreVein *orevein = (OreVein *)ore.get(); orevein->random_factor = getfloatfield_default(L, index, "random_factor", 1.f); @@ -1427,7 +1426,7 @@ int ModApiMapgen::l_register_ore(lua_State *L) break; } case ORE_STRATUM: { - OreStratum *orestratum = (OreStratum *)ore; + OreStratum *orestratum = (OreStratum *)ore.get(); lua_getfield(L, index, "np_stratum_thickness"); if (read_noiseparams(L, -1, &orestratum->np_stratum_thickness)) @@ -1443,9 +1442,8 @@ int ModApiMapgen::l_register_ore(lua_State *L) break; } - ObjDefHandle handle = oremgr->add(ore); + ObjDefHandle handle = oremgr->add(ore.get()); if (handle == OBJDEF_INVALID_HANDLE) { - delete ore; return 0; } @@ -1454,7 +1452,10 @@ int ModApiMapgen::l_register_ore(lua_State *L) size_t nnames = getstringlistfield(L, index, "wherein", &ore->m_nodenames); ore->m_nnlistsizes.push_back(nnames); - ndef->pendNodeResolve(ore); + ndef->pendNodeResolve(ore.get()); + + // We passed ownership of the ore object to oremgr earlier. + ore.release(); lua_pushinteger(L, handle); return 1; From a9fe83126a3f5c7240359272495eaf3eecd9a272 Mon Sep 17 00:00:00 2001 From: grorp Date: Fri, 15 Nov 2024 11:38:56 +0100 Subject: [PATCH 057/136] Get rid of depth buffer workaround in the render pipeline code (#15407) I originally wanted to get of the legacy IVideoDriver::setRenderTarget altogether, but that ended up being too much work. The remaining usage is in "dynamicshadowsrender.cpp". Here's a comment I wrote about the workaround: ---------------------------------------- Use legacy call when there's single texture without depth texture This means Irrlicht creates a depth texture for us and binds it to the FBO This is currently necessary for a working depth buffer in the following cases: - post-processing disabled, undersampling enabled (addUpscaling specifies no depth texture) - post-processing disabled, 3d_mode = sidebyside / topbottom / crossview (populateSideBySidePipeline specifies no depth texture) - post-processing disabled, 3d_mode = interlaced (probably, can't test since it's broken) (populateInterlacedPipeline specifies no depth texture) With post-processing disabled, the world is rendered to the TextureBufferOutput created in the functions listed above, so a depth buffer is needed (-> this workaround is needed). With post-processing enabled, only a fullscreen rectangle is rendered to this TextureBufferOutput, so a depth buffer isn't actually needed. But: These pipeline steps shouldn't rely on what ends up being rendered to the TextureBufferOutput they provide, since that may change. This workaround was added in 1e9640395468beb53f70303ef6b7aa72e395b7b4 / https://irc.minetest.net/minetest-dev/2022-10-04#i_6021940 This workaround should be replaced by explicitly configuring depth textures where needed. ---------------------------------------- --- builtin/settingtypes.txt | 2 ++ src/client/render/interlaced.cpp | 7 +++++++ src/client/render/pipeline.cpp | 9 +-------- src/client/render/plain.cpp | 32 ++++++++++++++++++++++++++----- src/client/render/plain.h | 5 ++++- src/client/render/secondstage.cpp | 12 ++---------- src/client/render/sidebyside.cpp | 14 +++++++++++--- 7 files changed, 54 insertions(+), 27 deletions(-) diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 71d976ec7..f8f1dec05 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -263,6 +263,8 @@ viewing_range (Viewing range) int 190 20 4000 # to the game world only, keeping the GUI intact. # It should give a significant performance boost at the cost of less detailed image. # Higher values result in a less detailed image. +# Note: Undersampling is currently not supported if the "3d_mode" setting is set +# to a non-default value. undersampling (Undersampling) int 1 1 8 [**3D] diff --git a/src/client/render/interlaced.cpp b/src/client/render/interlaced.cpp index ae085877f..7399d9242 100644 --- a/src/client/render/interlaced.cpp +++ b/src/client/render/interlaced.cpp @@ -35,6 +35,13 @@ void InitInterlacedMaskStep::run(PipelineContext &context) void populateInterlacedPipeline(RenderPipeline *pipeline, Client *client) { + // FIXME: "3d_mode = interlaced" is currently broken. Two options: + // 1. Remove it + // 2. Fix it + // If you fix it, make sure to test it with "enable_post_processing = false". + // You'll probably have to add a depth texture to make that combination work. + // Also, this code should probably use selectColorFormat/selectDepthFormat. + static const u8 TEXTURE_LEFT = 0; static const u8 TEXTURE_RIGHT = 1; static const u8 TEXTURE_MASK = 2; diff --git a/src/client/render/pipeline.cpp b/src/client/render/pipeline.cpp index 5558d05b0..a37fd32fd 100644 --- a/src/client/render/pipeline.cpp +++ b/src/client/render/pipeline.cpp @@ -177,13 +177,6 @@ void TextureBufferOutput::activate(PipelineContext &context) size = texture->getSize(); } - // Use legacy call when there's single texture without depth texture - // This binds default depth buffer to the FBO - if (textures.size() == 1 && depth_stencil == NO_DEPTH_TEXTURE) { - driver->setRenderTarget(textures[0], m_clear, m_clear, context.clear_color); - return; - } - video::ITexture *depth_texture = nullptr; if (depth_stencil != NO_DEPTH_TEXTURE) depth_texture = buffer->getTexture(depth_stencil); @@ -211,7 +204,7 @@ video::ITexture *DynamicSource::getTexture(u8 index) void ScreenTarget::activate(PipelineContext &context) { auto driver = context.device->getVideoDriver(); - driver->setRenderTarget(nullptr, m_clear, m_clear, context.clear_color); + driver->setRenderTargetEx(nullptr, m_clear ? video::ECBF_ALL : video::ECBF_NONE, context.clear_color); driver->OnResize(size); RenderTarget::activate(context); } diff --git a/src/client/render/plain.cpp b/src/client/render/plain.cpp index 2215ad777..22b167518 100644 --- a/src/client/render/plain.cpp +++ b/src/client/render/plain.cpp @@ -104,9 +104,10 @@ static v2f getDownscaleFactor() return v2f(1.0f / undersampling); } -RenderStep* addUpscaling(RenderPipeline *pipeline, RenderStep *previousStep, v2f downscale_factor) +RenderStep* addUpscaling(RenderPipeline *pipeline, RenderStep *previousStep, v2f downscale_factor, Client *client) { - const int TEXTURE_UPSCALE = 0; + const int TEXTURE_LOWRES_COLOR = 0; + const int TEXTURE_LOWRES_DEPTH = 1; if (downscale_factor.X == 1.0f && downscale_factor.Y == 1.0f) return previousStep; @@ -115,13 +116,18 @@ RenderStep* addUpscaling(RenderPipeline *pipeline, RenderStep *previousStep, v2f if (g_settings->getBool("enable_post_processing")) return previousStep; + auto driver = client->getSceneManager()->getVideoDriver(); + video::ECOLOR_FORMAT color_format = selectColorFormat(driver); + video::ECOLOR_FORMAT depth_format = selectDepthFormat(driver); // Initialize buffer TextureBuffer *buffer = pipeline->createOwned(); - buffer->setTexture(TEXTURE_UPSCALE, downscale_factor, "upscale", video::ECF_A8R8G8B8); + buffer->setTexture(TEXTURE_LOWRES_COLOR, downscale_factor, "lowres_color", color_format); + buffer->setTexture(TEXTURE_LOWRES_DEPTH, downscale_factor, "lowres_depth", depth_format); // Attach previous step to the buffer - TextureBufferOutput *buffer_output = pipeline->createOwned(buffer, TEXTURE_UPSCALE); + TextureBufferOutput *buffer_output = pipeline->createOwned( + buffer, std::vector {TEXTURE_LOWRES_COLOR}, TEXTURE_LOWRES_DEPTH); previousStep->setRenderTarget(buffer_output); // Add upscaling step @@ -140,9 +146,25 @@ void populatePlainPipeline(RenderPipeline *pipeline, Client *client) pipeline->addStep(); pipeline->addStep(); - step3D = addUpscaling(pipeline, step3D, downscale_factor); + step3D = addUpscaling(pipeline, step3D, downscale_factor, client); step3D->setRenderTarget(pipeline->createOwned()); pipeline->addStep(); } + +video::ECOLOR_FORMAT selectColorFormat(video::IVideoDriver *driver) +{ + if (driver->queryTextureFormat(video::ECF_A16B16G16R16F)) + return video::ECF_A16B16G16R16F; + return video::ECF_A8R8G8B8; +} + +video::ECOLOR_FORMAT selectDepthFormat(video::IVideoDriver *driver) +{ + if (driver->queryTextureFormat(video::ECF_D32)) + return video::ECF_D32; + if (driver->queryTextureFormat(video::ECF_D24S8)) + return video::ECF_D24S8; + return video::ECF_D16; // fallback depth format +} diff --git a/src/client/render/plain.h b/src/client/render/plain.h index 889dd0f01..b0ce29608 100644 --- a/src/client/render/plain.h +++ b/src/client/render/plain.h @@ -82,6 +82,9 @@ private: }; std::unique_ptr create3DStage(Client *client, v2f scale); -RenderStep* addUpscaling(RenderPipeline *pipeline, RenderStep *previousStep, v2f downscale_factor); +RenderStep* addUpscaling(RenderPipeline *pipeline, RenderStep *previousStep, v2f downscale_factor, Client *client); void populatePlainPipeline(RenderPipeline *pipeline, Client *client); + +video::ECOLOR_FORMAT selectColorFormat(video::IVideoDriver *driver); +video::ECOLOR_FORMAT selectDepthFormat(video::IVideoDriver *driver); diff --git a/src/client/render/secondstage.cpp b/src/client/render/secondstage.cpp index b5156cd41..212074535 100644 --- a/src/client/render/secondstage.cpp +++ b/src/client/render/secondstage.cpp @@ -87,16 +87,8 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep auto driver = client->getSceneManager()->getVideoDriver(); // configure texture formats - video::ECOLOR_FORMAT color_format = video::ECF_A8R8G8B8; - if (driver->queryTextureFormat(video::ECF_A16B16G16R16F)) - color_format = video::ECF_A16B16G16R16F; - - video::ECOLOR_FORMAT depth_format = video::ECF_D16; // fallback depth format - if (driver->queryTextureFormat(video::ECF_D32)) - depth_format = video::ECF_D32; - else if (driver->queryTextureFormat(video::ECF_D24S8)) - depth_format = video::ECF_D24S8; - + video::ECOLOR_FORMAT color_format = selectColorFormat(driver); + video::ECOLOR_FORMAT depth_format = selectDepthFormat(driver); // init post-processing buffer static const u8 TEXTURE_COLOR = 0; diff --git a/src/client/render/sidebyside.cpp b/src/client/render/sidebyside.cpp index 02a7e7a86..57d5b474e 100644 --- a/src/client/render/sidebyside.cpp +++ b/src/client/render/sidebyside.cpp @@ -4,6 +4,7 @@ // Copyright (C) 2017 numzero, Lobachevskiy Vitaliy #include "sidebyside.h" +#include "client/client.h" #include "client/hud.h" #include "client/camera.h" @@ -35,6 +36,11 @@ void populateSideBySidePipeline(RenderPipeline *pipeline, Client *client, bool h { static const u8 TEXTURE_LEFT = 0; static const u8 TEXTURE_RIGHT = 1; + static const u8 TEXTURE_DEPTH = 2; + + auto driver = client->getSceneManager()->getVideoDriver(); + video::ECOLOR_FORMAT color_format = selectColorFormat(driver); + video::ECOLOR_FORMAT depth_format = selectDepthFormat(driver); v2f offset; if (horizontal) { @@ -47,15 +53,17 @@ void populateSideBySidePipeline(RenderPipeline *pipeline, Client *client, bool h } TextureBuffer *buffer = pipeline->createOwned(); - buffer->setTexture(TEXTURE_LEFT, virtual_size_scale, "3d_render_left", video::ECF_A8R8G8B8); - buffer->setTexture(TEXTURE_RIGHT, virtual_size_scale, "3d_render_right", video::ECF_A8R8G8B8); + buffer->setTexture(TEXTURE_LEFT, virtual_size_scale, "3d_render_left", color_format); + buffer->setTexture(TEXTURE_RIGHT, virtual_size_scale, "3d_render_right", color_format); + buffer->setTexture(TEXTURE_DEPTH, virtual_size_scale, "3d_depthmap_sidebyside", depth_format); auto step3D = pipeline->own(create3DStage(client, virtual_size_scale)); // eyes for (bool right : { false, true }) { pipeline->addStep(flipped ? !right : right); - auto output = pipeline->createOwned(buffer, right ? TEXTURE_RIGHT : TEXTURE_LEFT); + auto output = pipeline->createOwned( + buffer, std::vector {right ? TEXTURE_RIGHT : TEXTURE_LEFT}, TEXTURE_DEPTH); pipeline->addStep(step3D, output); pipeline->addStep(step3D); pipeline->addStep(); From 58dd42166df90425521a09102dc06ef1e9b783d1 Mon Sep 17 00:00:00 2001 From: sfence Date: Fri, 15 Nov 2024 11:39:08 +0100 Subject: [PATCH 058/136] Add some info to compiling README --- doc/compiling/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/doc/compiling/README.md b/doc/compiling/README.md index 70a78946f..55357adf6 100644 --- a/doc/compiling/README.md +++ b/doc/compiling/README.md @@ -61,7 +61,14 @@ Library specific options: GETTEXT_INCLUDE_DIR - Only when building with gettext; directory that contains libintl.h GETTEXT_LIBRARY - Optional/platform-dependent with gettext; path to libintl.so/libintl.dll.a GETTEXT_MSGFMT - Only when building with gettext; path to msgfmt/msgfmt.exe + GMP_INCLUDE_DIR - Directory that contains gmp.h + GMP_LIBRARY - Path to libgmp.a/libgmp.so/libgmp.lib ICONV_LIBRARY - Optional/platform-dependent; path to libiconv.so/libiconv.dylib + JPEG_DLL - Only on Windows; path to libjpeg.dll + JPEG_INCLUDE_DIR - Directory that contains jpeg.h + JPEG_LIBRARY - Path to libjpeg.a/libjpeg.so/libjpeg.lib + JSON_INCLUDE_DIR - Directory that contains json/allocator.h + JSON_LIBRARY - Path to libjson.a/libjson.so/libjson.lib LEVELDB_INCLUDE_DIR - Only when building with LevelDB; directory that contains db.h LEVELDB_LIBRARY - Only when building with LevelDB; path to libleveldb.a/libleveldb.so/libleveldb.dll.a LEVELDB_DLL - Only when building with LevelDB on Windows; path to libleveldb.dll @@ -79,6 +86,12 @@ Library specific options: OPENAL_DLL - Only if building with sound on Windows; path to OpenAL32.dll OPENAL_INCLUDE_DIR - Only if building with sound; directory where al.h is located OPENAL_LIBRARY - Only if building with sound; path to libopenal.a/libopenal.so/OpenAL32.lib + PNG_DLL - Only on Windows; path to libpng.dll + PNG_INCLUDE_DIR - Directory that contains png.h + PNG_LIBRARY - Path to libpng.a/libpng.so/libpng.lib + PROMETHEUS_PULL_LIBRARY - Only if building with prometheus; path to prometheus-cpp-pull + PROMETHEUS_CORE_LIBRARY - Only if building with prometheus; path to prometheus-cpp-core + PROMETHEUS_CPP_INCLUDE_DIR - Only if building with prometheus; directory where prometheus/counter.h is located SQLITE3_INCLUDE_DIR - Directory that contains sqlite3.h SQLITE3_LIBRARY - Path to libsqlite3.a/libsqlite3.so/sqlite3.lib VORBISFILE_LIBRARY - Only if building with sound; path to libvorbisfile.a/libvorbisfile.so/libvorbisfile.dll.a From 87ac32edeafafea662b62dc0a96fda9b663737b4 Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Sat, 2 Nov 2024 15:52:29 +0100 Subject: [PATCH 059/136] Dynamic shadows: whitelist the 'opengl3' driver --- builtin/mainmenu/settings/dlg_settings.lua | 2 +- src/client/shadows/dynamicshadowsrender.cpp | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/builtin/mainmenu/settings/dlg_settings.lua b/builtin/mainmenu/settings/dlg_settings.lua index f03596815..ef28398b1 100644 --- a/builtin/mainmenu/settings/dlg_settings.lua +++ b/builtin/mainmenu/settings/dlg_settings.lua @@ -351,7 +351,7 @@ local function check_requirements(name, requires) -- be used, so we show settings for both. touchscreen = touch_support and (touch_controls == "auto" or core.is_yes(touch_controls)), keyboard_mouse = not touch_support or (touch_controls == "auto" or not core.is_yes(touch_controls)), - opengl = video_driver == "opengl", + opengl = (video_driver == "opengl" or video_driver == "opengl3"), gles = video_driver:sub(1, 5) == "ogles", } diff --git a/src/client/shadows/dynamicshadowsrender.cpp b/src/client/shadows/dynamicshadowsrender.cpp index 2bf3adeb3..039ab1a98 100644 --- a/src/client/shadows/dynamicshadowsrender.cpp +++ b/src/client/shadows/dynamicshadowsrender.cpp @@ -694,9 +694,13 @@ std::string ShadowRenderer::readShaderFile(const std::string &path) ShadowRenderer *createShadowRenderer(IrrlichtDevice *device, Client *client) { // disable if unsupported - if (g_settings->getBool("enable_dynamic_shadows") && - device->getVideoDriver()->getDriverType() != video::EDT_OPENGL) { - g_settings->setBool("enable_dynamic_shadows", false); + if (g_settings->getBool("enable_dynamic_shadows")) { + // See also checks in builtin/mainmenu/settings/dlg_settings.lua + const video::E_DRIVER_TYPE type = device->getVideoDriver()->getDriverType(); + if (type != video::EDT_OPENGL && type != video::EDT_OPENGL3) { + warningstream << "Shadows: disabled dynamic shadows due to being unsupported" << std::endl; + g_settings->setBool("enable_dynamic_shadows", false); + } } if (g_settings->getBool("enable_dynamic_shadows")) { From 4838eb2f7de8477ef5be7e064d072954ff78e36c Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Sat, 2 Nov 2024 15:51:44 +0100 Subject: [PATCH 060/136] Non-SDL: Add opengl3 support --- irr/src/CIrrDeviceLinux.cpp | 58 ++++++++++++++----------------------- irr/src/CIrrDeviceOSX.mm | 9 +----- irr/src/CIrrDeviceSDL.cpp | 47 ------------------------------ irr/src/CIrrDeviceStub.cpp | 36 +++++++++++++++++++++++ irr/src/CIrrDeviceStub.h | 10 ++++++- irr/src/CIrrDeviceWin32.cpp | 36 +++++++++-------------- irr/src/CMakeLists.txt | 18 ++++++++---- irr/src/COpenGLDriver.cpp | 18 ++---------- irr/src/OpenGL/Driver.cpp | 4 +-- irr/src/OpenGL3/Driver.cpp | 10 +++++-- 10 files changed, 107 insertions(+), 139 deletions(-) diff --git a/irr/src/CIrrDeviceLinux.cpp b/irr/src/CIrrDeviceLinux.cpp index f20be36f7..e88902936 100644 --- a/irr/src/CIrrDeviceLinux.cpp +++ b/irr/src/CIrrDeviceLinux.cpp @@ -38,7 +38,7 @@ #include "CEGLManager.h" #endif -#if defined(_IRR_COMPILE_WITH_OPENGL_) +#if defined(_IRR_COMPILE_WITH_GLX_MANAGER_) #include "CGLXManager.h" #endif @@ -69,24 +69,6 @@ #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ -namespace irr -{ -namespace video -{ -#ifdef _IRR_COMPILE_WITH_OPENGL_ -IVideoDriver *createOpenGLDriver(const irr::SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager); -#endif - -#ifdef _IRR_COMPILE_WITH_OGLES2_ -IVideoDriver *createOGLES2Driver(const irr::SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager); -#endif - -#ifdef _IRR_COMPILE_WITH_WEBGL1_ -IVideoDriver *createWebGL1Driver(const irr::SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager); -#endif -} -} // end namespace irr - namespace { Atom X_ATOM_CLIPBOARD; @@ -397,10 +379,11 @@ bool CIrrDeviceLinux::createWindow() if (WMCheck != None) HasNetWM = true; -#if defined(_IRR_COMPILE_WITH_OPENGL_) +#if defined(_IRR_COMPILE_WITH_GLX_MANAGER_) // don't use the XVisual with OpenGL, because it ignores all requested // properties of the CreationParams - if (CreationParams.DriverType == video::EDT_OPENGL) { + if (CreationParams.DriverType == video::EDT_OPENGL + || CreationParams.DriverType == video::EDT_OPENGL3) { video::SExposedVideoData data; data.OpenGLLinux.X11Display = XDisplay; ContextManager = new video::CGLXManager(CreationParams, data, Screennr); @@ -539,51 +522,54 @@ void CIrrDeviceLinux::createDriver() switch (CreationParams.DriverType) { #ifdef _IRR_COMPILE_WITH_X11_ case video::EDT_OPENGL: -#ifdef _IRR_COMPILE_WITH_OPENGL_ { +#ifdef _IRR_COMPILE_WITH_OPENGL_ video::SExposedVideoData data; data.OpenGLLinux.X11Window = XWindow; data.OpenGLLinux.X11Display = XDisplay; ContextManager->initialize(CreationParams, data); - +#endif VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager); } -#else - os::Printer::log("No OpenGL support compiled in.", ELL_ERROR); + break; + case video::EDT_OPENGL3: + { +#ifdef ENABLE_OPENGL3 + video::SExposedVideoData data; + data.OpenGLLinux.X11Window = XWindow; + data.OpenGLLinux.X11Display = XDisplay; + + ContextManager->initialize(CreationParams, data); #endif + VideoDriver = video::createOpenGL3Driver(CreationParams, FileSystem, ContextManager); + } break; case video::EDT_OGLES2: -#ifdef _IRR_COMPILE_WITH_OGLES2_ { +#ifdef _IRR_COMPILE_WITH_OGLES2_ video::SExposedVideoData data; data.OpenGLLinux.X11Window = XWindow; data.OpenGLLinux.X11Display = XDisplay; ContextManager = new video::CEGLManager(); ContextManager->initialize(CreationParams, data); - +#endif VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager); } -#else - os::Printer::log("No OpenGL-ES2 support compiled in.", ELL_ERROR); -#endif break; case video::EDT_WEBGL1: -#ifdef _IRR_COMPILE_WITH_WEBGL1_ { +#ifdef _IRR_COMPILE_WITH_WEBGL1_ video::SExposedVideoData data; data.OpenGLLinux.X11Window = XWindow; data.OpenGLLinux.X11Display = XDisplay; ContextManager = new video::CEGLManager(); ContextManager->initialize(CreationParams, data); - +#endif VideoDriver = video::createWebGL1Driver(CreationParams, FileSystem, ContextManager); } -#else - os::Printer::log("No WebGL1 support compiled in.", ELL_ERROR); -#endif break; case video::EDT_NULL: VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); @@ -591,7 +577,7 @@ void CIrrDeviceLinux::createDriver() default: os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR); break; -#else +#else // no X11 case video::EDT_NULL: VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); break; diff --git a/irr/src/CIrrDeviceOSX.mm b/irr/src/CIrrDeviceOSX.mm index 43c1c81b6..4b46e5e29 100644 --- a/irr/src/CIrrDeviceOSX.mm +++ b/irr/src/CIrrDeviceOSX.mm @@ -433,14 +433,6 @@ long GetDictionaryLong(CFDictionaryRef theDict, const void *key) return value; } -namespace irr -{ -namespace video -{ -IVideoDriver *createOpenGLDriver(const SIrrlichtCreationParameters ¶m, io::IFileSystem *io, IContextManager *contextManager); -} -} // end namespace irr - static bool firstLaunch = true; @implementation CIrrDelegateOSX { @@ -721,6 +713,7 @@ void CIrrDeviceMacOSX::createDriver() #endif break; + case video::EDT_OPENGL3: case video::EDT_OGLES2: os::Printer::log("This driver is not available on OSX.", ELL_ERROR); break; diff --git a/irr/src/CIrrDeviceSDL.cpp b/irr/src/CIrrDeviceSDL.cpp index 408027761..543bea63e 100644 --- a/irr/src/CIrrDeviceSDL.cpp +++ b/irr/src/CIrrDeviceSDL.cpp @@ -29,53 +29,6 @@ static int SDLDeviceInstances = 0; -namespace irr -{ -namespace video -{ -#ifdef _IRR_COMPILE_WITH_OPENGL_ -IVideoDriver *createOpenGLDriver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager); -#else -static IVideoDriver *createOpenGLDriver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager) -{ - os::Printer::log("No OpenGL support compiled in.", ELL_ERROR); - return nullptr; -} -#endif - -#ifdef ENABLE_OPENGL3 -IVideoDriver *createOpenGL3Driver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager); -#else -static IVideoDriver *createOpenGL3Driver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager) -{ - os::Printer::log("No OpenGL 3 support compiled in.", ELL_ERROR); - return nullptr; -} -#endif - -#ifdef _IRR_COMPILE_WITH_OGLES2_ -IVideoDriver *createOGLES2Driver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager); -#else -static IVideoDriver *createOGLES2Driver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager) -{ - os::Printer::log("No OpenGL ES 2 support compiled in.", ELL_ERROR); - return nullptr; -} -#endif - -#ifdef _IRR_COMPILE_WITH_WEBGL1_ -IVideoDriver *createWebGL1Driver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager); -#else -static IVideoDriver *createWebGL1Driver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager) -{ - os::Printer::log("No WebGL 1 support compiled in.", ELL_ERROR); - return nullptr; -} -#endif -} // end namespace video - -} // end namespace irr - namespace irr { #ifdef _IRR_EMSCRIPTEN_PLATFORM_ diff --git a/irr/src/CIrrDeviceStub.cpp b/irr/src/CIrrDeviceStub.cpp index fd8e458c8..2bd0fb1d0 100644 --- a/irr/src/CIrrDeviceStub.cpp +++ b/irr/src/CIrrDeviceStub.cpp @@ -17,6 +17,42 @@ namespace irr { +namespace video +{ +#ifndef _IRR_COMPILE_WITH_OPENGL_ +IVideoDriver *createOpenGLDriver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager) +{ + os::Printer::log("No OpenGL support compiled in.", ELL_ERROR); + return nullptr; +} +#endif + +#ifndef ENABLE_OPENGL3 +IVideoDriver *createOpenGL3Driver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager) +{ + os::Printer::log("No OpenGL 3 support compiled in.", ELL_ERROR); + return nullptr; +} +#endif + +#ifndef _IRR_COMPILE_WITH_OGLES2_ +IVideoDriver *createOGLES2Driver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager) +{ + os::Printer::log("No OpenGL ES 2 support compiled in.", ELL_ERROR); + return nullptr; +} +#endif + +#ifndef _IRR_COMPILE_WITH_WEBGL1_ +IVideoDriver *createWebGL1Driver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager) +{ + os::Printer::log("No WebGL 1 support compiled in.", ELL_ERROR); + return nullptr; +} +#endif +} + + //! constructor CIrrDeviceStub::CIrrDeviceStub(const SIrrlichtCreationParameters ¶ms) : IrrlichtDevice(), VideoDriver(0), GUIEnvironment(0), SceneManager(0), diff --git a/irr/src/CIrrDeviceStub.h b/irr/src/CIrrDeviceStub.h index 9a1966f01..c46fd64fc 100644 --- a/irr/src/CIrrDeviceStub.h +++ b/irr/src/CIrrDeviceStub.h @@ -33,7 +33,15 @@ IFileSystem *createFileSystem(); namespace video { -IVideoDriver *createNullDriver(io::IFileSystem *io, const core::dimension2d &screenSize); + IVideoDriver *createNullDriver(io::IFileSystem *io, const core::dimension2d &screenSize); + + IVideoDriver *createOpenGLDriver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager); + + IVideoDriver *createOpenGL3Driver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager); + + IVideoDriver *createOGLES2Driver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager); + + IVideoDriver *createWebGL1Driver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager); } //! Stub for an Irrlicht Device implementation diff --git a/irr/src/CIrrDeviceWin32.cpp b/irr/src/CIrrDeviceWin32.cpp index 366be8013..417694517 100644 --- a/irr/src/CIrrDeviceWin32.cpp +++ b/irr/src/CIrrDeviceWin32.cpp @@ -34,24 +34,10 @@ #include "CEGLManager.h" #endif -#if defined(_IRR_COMPILE_WITH_OPENGL_) +#if defined(_IRR_COMPILE_WITH_WGL_MANAGER_) #include "CWGLManager.h" #endif -namespace irr -{ -namespace video -{ -#ifdef _IRR_COMPILE_WITH_OPENGL_ -IVideoDriver *createOpenGLDriver(const irr::SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager); -#endif - -#ifdef _IRR_COMPILE_WITH_OGLES2_ -IVideoDriver *createOGLES2Driver(const irr::SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager); -#endif -} -} // end namespace irr - namespace irr { struct SJoystickWin32Control @@ -880,14 +866,23 @@ void CIrrDeviceWin32::createDriver() ContextManager = new video::CWGLManager(); ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd)); - +#endif VideoDriver = video::createOpenGLDriver(CreationParams, FileSystem, ContextManager); if (!VideoDriver) os::Printer::log("Could not create OpenGL driver.", ELL_ERROR); -#else - os::Printer::log("OpenGL driver was not compiled in.", ELL_ERROR); + break; + case video::EDT_OPENGL3: +#ifdef ENABLE_OPENGL3 + switchToFullScreen(); + + ContextManager = new video::CWGLManager(); + ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd)); #endif + VideoDriver = video::createOpenGL3Driver(CreationParams, FileSystem, ContextManager); + + if (!VideoDriver) + os::Printer::log("Could not create OpenGL 3 driver.", ELL_ERROR); break; case video::EDT_OGLES2: #ifdef _IRR_COMPILE_WITH_OGLES2_ @@ -895,14 +890,11 @@ void CIrrDeviceWin32::createDriver() ContextManager = new video::CEGLManager(); ContextManager->initialize(CreationParams, video::SExposedVideoData(HWnd)); - +#endif VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager); if (!VideoDriver) os::Printer::log("Could not create OpenGL-ES2 driver.", ELL_ERROR); -#else - os::Printer::log("OpenGL-ES2 driver was not compiled in.", ELL_ERROR); -#endif break; case video::EDT_WEBGL1: os::Printer::log("WebGL1 driver not supported on Win32 device.", ELL_ERROR); diff --git a/irr/src/CMakeLists.txt b/irr/src/CMakeLists.txt index 3b578d699..b95c3ef73 100644 --- a/irr/src/CMakeLists.txt +++ b/irr/src/CMakeLists.txt @@ -123,10 +123,10 @@ if(USE_SDL2) if(NOT ANDROID) set(DEFAULT_OPENGL3 TRUE) endif() - option(ENABLE_OPENGL3 "Enable OpenGL 3+" ${DEFAULT_OPENGL3}) else() - set(ENABLE_OPENGL3 FALSE) + set(DEFAULT_OPENGL3 FALSE) endif() +option(ENABLE_OPENGL3 "Enable OpenGL 3+" ${DEFAULT_OPENGL3}) if(ANDROID OR EMSCRIPTEN) set(ENABLE_OPENGL FALSE) @@ -152,9 +152,11 @@ else() endif() endif() -if(ENABLE_OPENGL) - add_definitions(-D_IRR_COMPILE_WITH_OPENGL_) - set(OPENGL_DIRECT_LINK TRUE) # driver relies on this +if(ENABLE_OPENGL OR (ENABLE_OPENGL3 AND NOT USE_SDL2)) + if(ENABLE_OPENGL) + add_definitions(-D_IRR_COMPILE_WITH_OPENGL_) + set(OPENGL_DIRECT_LINK TRUE) # driver relies on this + endif() if(DEVICE STREQUAL "WINDOWS") add_definitions(-D_IRR_COMPILE_WITH_WGL_MANAGER_) elseif(DEVICE STREQUAL "X11") @@ -165,7 +167,11 @@ if(ENABLE_OPENGL) endif() if(ENABLE_OPENGL3) - if (NOT USE_SDL2) + if(DEVICE STREQUAL "WINDOWS") + # supported + elseif(DEVICE STREQUAL "X11") + # supported + elseif (NOT USE_SDL2) message(FATAL_ERROR "OpenGL 3 driver requires SDL2") endif() endif() diff --git a/irr/src/COpenGLDriver.cpp b/irr/src/COpenGLDriver.cpp index ee63fc845..2cbf6d8e6 100644 --- a/irr/src/COpenGLDriver.cpp +++ b/irr/src/COpenGLDriver.cpp @@ -3239,19 +3239,9 @@ COpenGLCacheHandler *COpenGLDriver::getCacheHandler() const return CacheHandler; } -} // end namespace -} // end namespace - -#endif // _IRR_COMPILE_WITH_OPENGL_ - -namespace irr -{ -namespace video -{ IVideoDriver *createOpenGLDriver(const SIrrlichtCreationParameters ¶ms, io::IFileSystem *io, IContextManager *contextManager) { -#ifdef _IRR_COMPILE_WITH_OPENGL_ COpenGLDriver *ogl = new COpenGLDriver(params, io, contextManager); if (!ogl->initDriver()) { @@ -3260,10 +3250,8 @@ IVideoDriver *createOpenGLDriver(const SIrrlichtCreationParameters ¶ms, io:: } return ogl; -#else - return 0; -#endif } -} // end namespace -} // end namespace +} // end namespace video +} // end namespace irr +#endif // opengl diff --git a/irr/src/OpenGL/Driver.cpp b/irr/src/OpenGL/Driver.cpp index fe9a24758..4f3ac627a 100644 --- a/irr/src/OpenGL/Driver.cpp +++ b/irr/src/OpenGL/Driver.cpp @@ -226,8 +226,8 @@ void COpenGL3DriverBase::initVersion() printVersion(); // print renderer information - VendorName = GL.GetString(GL_VENDOR); - os::Printer::log("Vendor", VendorName.c_str(), ELL_INFORMATION); + VendorName = GL.GetString(GL_RENDERER); + os::Printer::log("Renderer", VendorName.c_str(), ELL_INFORMATION); Version = getVersionFromOpenGL(); } diff --git a/irr/src/OpenGL3/Driver.cpp b/irr/src/OpenGL3/Driver.cpp index fd018b91d..53cb8c7ed 100644 --- a/irr/src/OpenGL3/Driver.cpp +++ b/irr/src/OpenGL3/Driver.cpp @@ -34,8 +34,14 @@ OpenGLVersion COpenGL3Driver::getVersionFromOpenGL() const void COpenGL3Driver::initFeatures() { - assert(Version.Spec == OpenGLSpec::Compat); - assert(isVersionAtLeast(3, 2)); + if (Version.Spec != OpenGLSpec::Compat) { + os::Printer::log("OpenGL 3 driver requires Compatibility Mode", ELL_ERROR); + throw std::exception(); + } + if (!isVersionAtLeast(3, 2)) { + os::Printer::log("OpenGL 3 driver requires OpenGL >= 3.2 ", ELL_ERROR); + throw std::exception(); + } initExtensions(); TextureFormats[ECF_A1R5G5B5] = {GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV}; // WARNING: may not be renderable From 8f03b705841e4fbdb11f6c09facdc0a9a6f5abda Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Sun, 3 Nov 2024 08:20:51 +0100 Subject: [PATCH 061/136] IrrlichtMt: Document Driver/Device compatibility --- irr/README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/irr/README.md b/irr/README.md index 50e7338a5..449903cfe 100644 --- a/irr/README.md +++ b/irr/README.md @@ -36,6 +36,27 @@ We aim to support these platforms: This doesn't mean other platforms don't work or won't be supported, if you find something that doesn't work contributions are welcome. +Compatibility matrix +-------------------- + +Driver (rows) vs Device (columns) + +| | SDL [1] | Linux [2] | OSX [3] | Win32 [4] | +|---------------------------|----------|----------------|------------------|-----------------| +| OpenGL 1.2 (to 2.1) | Works | Works (GLX) | Works (NSOpenGL) | Works (WGL) | +| OpenGL 3.2+ | Works | Testing (GLX) | Not implemented | Testing (WGL) | +| OpenGL ES 2.x | Works | Untested (EGL) | Not implemented | Untested (EGL) | +| WebGL 1 | Untested | Untested (EGL) | Not implemented | Not implemented | +| Null (no graphics output) | Works | Works | Works | Works | + +Notes: + +* [1] `CIrrDeviceSDL`: supports Android, Linux, macOS, Windows +* [2] `CIrrDeviceLinux`: supports Linux +* [3] `CIrrDeviceOSX`: supports macOS +* [4] `CIrrDeviceWin32`: supports Windows + + License ------- From 46f0baff090855d08e512c2913a5f1b9636f5019 Mon Sep 17 00:00:00 2001 From: Erich Schubert Date: Fri, 15 Nov 2024 12:19:41 +0100 Subject: [PATCH 062/136] Improve documentation of liquid_surface (#15012) --- doc/lua_api.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index ba3a0e630..d3310e027 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -10788,10 +10788,9 @@ See [Decoration types]. Used by `core.register_decoration`. flags = "liquid_surface, force_placement, all_floors, all_ceilings", -- Flags for all decoration types. - -- "liquid_surface": Instead of placement on the highest solid surface - -- in a mapchunk column, placement is on the highest liquid surface. - -- Placement is disabled if solid nodes are found above the liquid - -- surface. + -- "liquid_surface": Find the highest liquid (not solid) surface under + -- open air. Search stops and fails on the first solid node. + -- Cannot be used with "all_floors" or "all_ceilings" below. -- "force_placement": Nodes other than "air" and "ignore" are replaced -- by the decoration. -- "all_floors", "all_ceilings": Instead of placement on the highest From 11837d4623bf0eab0b706ed2cc81bf0bcfb79da8 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 15 Nov 2024 12:21:30 +0100 Subject: [PATCH 063/136] Remove BMP image support (#15434) Co-authored-by: Lars Mueller --- doc/lua_api.md | 6 +- irr/include/irrlicht.h | 113 ---------- irr/src/CColorConverter.cpp | 87 -------- irr/src/CColorConverter.h | 8 - irr/src/CImageLoaderBMP.cpp | 402 ------------------------------------ irr/src/CImageLoaderBMP.h | 81 -------- irr/src/CMakeLists.txt | 1 - irr/src/CNullDriver.cpp | 4 - src/client/client.cpp | 2 +- src/client/texturepaths.cpp | 6 +- src/server.cpp | 9 +- 11 files changed, 6 insertions(+), 713 deletions(-) delete mode 100644 irr/src/CImageLoaderBMP.cpp delete mode 100644 irr/src/CImageLoaderBMP.h diff --git a/doc/lua_api.md b/doc/lua_api.md index d3310e027..48ef798c4 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -276,7 +276,7 @@ the clients (see [Translations]). Accepted characters for names are: Accepted formats are: - images: .png, .jpg, .tga, (deprecated:) .bmp + images: .png, .jpg, .tga sounds: .ogg vorbis models: .x, .b3d, .obj, (since version 5.10:) .gltf, .glb @@ -486,9 +486,7 @@ stripping out the file extension: * e.g. `foomod_foothing.png` * e.g. `foomod_foothing` -Supported texture formats are PNG (`.png`), JPEG (`.jpg`), Bitmap (`.bmp`) -and Targa (`.tga`). -Since better alternatives exist, the latter two may be removed in the future. +Supported texture formats are PNG (`.png`), JPEG (`.jpg`) and Targa (`.tga`). Texture modifiers ----------------- diff --git a/irr/include/irrlicht.h b/irr/include/irrlicht.h index 14a190e53..8bac30e3d 100644 --- a/irr/include/irrlicht.h +++ b/irr/include/irrlicht.h @@ -36,119 +36,6 @@ #include "SIrrCreationParameters.h" #include "IrrCompileConfig.h" // for IRRLICHT_API and IRRCALLCONV -/*! \mainpage Irrlicht Engine 1.9 API documentation - * - *
- * - * \section intro Introduction - * - * Welcome to the Irrlicht Engine API documentation. - * Here you'll find any information you'll need to develop applications with - * the Irrlicht Engine. If you are looking for a tutorial on how to start, you'll - * find some on the homepage of the Irrlicht Engine at - * irrlicht.sourceforge.net - * or inside the SDK in the examples directory. - * - * The Irrlicht Engine is intended to be an easy-to-use 3d engine, so - * this documentation is an important part of it. If you have any questions or - * suggestions, just send a email to the author of the engine, Nikolaus Gebhardt - * (niko (at) irrlicht3d.org). - * - * - * \section links Links - * - * Namespaces: A very good place to start reading - * the documentation.
- * Class list: List of all classes with descriptions.
- * Class members: Good place to find forgotten features.
- * - * \section irrexample Short example - * - * A simple application, starting up the engine, loading a Quake 2 animated - * model file and the corresponding texture, animating and displaying it - * in front of a blue background and placing a user controlable 3d camera - * would look like the following code. I think this example shows the usage - * of the engine quite well: - * - * \code - * #include - * // include a bunch of other stuff... - * - * using namespace irr; - * - * int main() - * { - * // start up the engine - * IrrlichtDevice *device = createDevice(video::EDT_OPENGL, - * core::dimension2d(640,480)); - * - * video::IVideoDriver* driver = device->getVideoDriver(); - * scene::ISceneManager* scenemgr = device->getSceneManager(); - * - * device->setWindowCaption(L"Hello World!"); - * - * // load and show quake2 .md2 model - * scene::ISceneNode* node = scenemgr->addAnimatedMeshSceneNode( - * scenemgr->getMesh("quake2model.md2")); - * - * // if everything worked, add a texture and disable lighting - * if (node) - * { - * node->setMaterialTexture(0, driver->getTexture("texture.bmp")); - * node->setMaterialFlag(video::EMF_LIGHTING, false); - * } - * - * // add a first person shooter style user controlled camera - * scenemgr->addCameraSceneNodeFPS(); - * - * // draw everything - * while(device->run() && driver) - * { - * driver->beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, video::SColor(255,0,0,255)); - * scenemgr->drawAll(); - * driver->endScene(); - * } - * - * // delete device - * device->drop(); - * return 0; - * } - * \endcode - * - * Irrlicht can load a lot of file formats automatically, see irr::scene::ISceneManager::getMesh() - * for a detailed list. So if you would like to replace the simple blue screen background by - * a cool Quake 3 Map, optimized by an octree, just insert this code - * somewhere before the while loop: - * - * \code - * // add .pk3 archive to the file system - * device->getFileSystem()->addZipFileArchive("quake3map.pk3"); - * - * // load .bsp file and show it using an octree - * scenemgr->addOctreeSceneNode( - * scenemgr->getMesh("quake3map.bsp")); - * \endcode - * - * As you can see, the engine uses namespaces. Everything in the engine is - * placed into the namespace 'irr', but there are also 5 sub namespaces. - * You can find a list of all namespaces with descriptions at the - * namespaces page. - * This is also a good place to start reading the documentation. If you - * don't want to write the namespace names all the time, just use all namespaces like - * this: - * \code - * using namespace core; - * using namespace scene; - * using namespace video; - * using namespace io; - * using namespace gui; - * \endcode - * - * There is a lot more the engine can do, but I hope this gave a short - * overview over the basic features of the engine. For more examples, please take - * a look into the examples directory of the SDK. - */ - //! Everything in the Irrlicht Engine can be found in this namespace. namespace irr { diff --git a/irr/src/CColorConverter.cpp b/irr/src/CColorConverter.cpp index 96b22c544..7749ececf 100644 --- a/irr/src/CColorConverter.cpp +++ b/irr/src/CColorConverter.cpp @@ -12,93 +12,6 @@ namespace irr namespace video { -//! converts a monochrome bitmap to A1R5G5B5 data -void CColorConverter::convert1BitTo16Bit(const u8 *in, s16 *out, s32 width, s32 height, s32 linepad, bool flip) -{ - if (!in || !out) - return; - - if (flip) - out += width * height; - - for (s32 y = 0; y < height; ++y) { - s32 shift = 7; - if (flip) - out -= width; - - for (s32 x = 0; x < width; ++x) { - out[x] = *in >> shift & 0x01 ? (s16)0xffff : (s16)0x8000; - - if ((--shift) < 0) { // 8 pixel done - shift = 7; - ++in; - } - } - - if (shift != 7) // width did not fill last byte - ++in; - - if (!flip) - out += width; - in += linepad; - } -} - -//! converts a 4 bit palettized image to A1R5G5B5 -void CColorConverter::convert4BitTo16Bit(const u8 *in, s16 *out, s32 width, s32 height, const s32 *palette, s32 linepad, bool flip) -{ - if (!in || !out || !palette) - return; - - if (flip) - out += width * height; - - for (s32 y = 0; y < height; ++y) { - s32 shift = 4; - if (flip) - out -= width; - - for (s32 x = 0; x < width; ++x) { - out[x] = X8R8G8B8toA1R5G5B5(palette[(u8)((*in >> shift) & 0xf)]); - - if (shift == 0) { - shift = 4; - ++in; - } else - shift = 0; - } - - if (shift == 0) // odd width - ++in; - - if (!flip) - out += width; - in += linepad; - } -} - -//! converts a 8 bit palettized image into A1R5G5B5 -void CColorConverter::convert8BitTo16Bit(const u8 *in, s16 *out, s32 width, s32 height, const s32 *palette, s32 linepad, bool flip) -{ - if (!in || !out || !palette) - return; - - if (flip) - out += width * height; - - for (s32 y = 0; y < height; ++y) { - if (flip) - out -= width; // one line back - for (s32 x = 0; x < width; ++x) { - out[x] = X8R8G8B8toA1R5G5B5(palette[(u8)(*in)]); - ++in; - } - if (!flip) - out += width; - in += linepad; - } -} - //! converts a 8 bit palettized or non palettized image (A8) into R8G8B8 void CColorConverter::convert8BitTo24Bit(const u8 *in, u8 *out, s32 width, s32 height, const u8 *palette, s32 linepad, bool flip) { diff --git a/irr/src/CColorConverter.h b/irr/src/CColorConverter.h index 7f1628297..af7b13726 100644 --- a/irr/src/CColorConverter.h +++ b/irr/src/CColorConverter.h @@ -15,14 +15,6 @@ namespace video class CColorConverter { public: - //! converts a monochrome bitmap to A1R5G5B5 - static void convert1BitTo16Bit(const u8 *in, s16 *out, s32 width, s32 height, s32 linepad = 0, bool flip = false); - - //! converts a 4 bit palettized image to A1R5G5B5 - static void convert4BitTo16Bit(const u8 *in, s16 *out, s32 width, s32 height, const s32 *palette, s32 linepad = 0, bool flip = false); - - //! converts a 8 bit palettized image to A1R5G5B5 - static void convert8BitTo16Bit(const u8 *in, s16 *out, s32 width, s32 height, const s32 *palette, s32 linepad = 0, bool flip = false); //! converts a 8 bit palettized or non palettized image (A8) into R8G8B8 static void convert8BitTo24Bit(const u8 *in, u8 *out, s32 width, s32 height, const u8 *palette, s32 linepad = 0, bool flip = false); diff --git a/irr/src/CImageLoaderBMP.cpp b/irr/src/CImageLoaderBMP.cpp deleted file mode 100644 index 40989882e..000000000 --- a/irr/src/CImageLoaderBMP.cpp +++ /dev/null @@ -1,402 +0,0 @@ -// Copyright (C) 2002-2012 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#include "CImageLoaderBMP.h" - -#include "IReadFile.h" -#include "SColor.h" -#include "CColorConverter.h" -#include "CImage.h" -#include "coreutil.h" -#include "os.h" - -namespace irr -{ -namespace video -{ - -//! constructor -CImageLoaderBMP::CImageLoaderBMP() -{ -#ifdef _DEBUG - setDebugName("CImageLoaderBMP"); -#endif -} - -//! returns true if the file maybe is able to be loaded by this class -//! based on the file extension (e.g. ".tga") -bool CImageLoaderBMP::isALoadableFileExtension(const io::path &filename) const -{ - return core::hasFileExtension(filename, "bmp"); -} - -//! returns true if the file maybe is able to be loaded by this class -bool CImageLoaderBMP::isALoadableFileFormat(io::IReadFile *file) const -{ - u16 headerID; - file->read(&headerID, sizeof(u16)); -#ifdef __BIG_ENDIAN__ - headerID = os::Byteswap::byteswap(headerID); -#endif - return headerID == 0x4d42; -} - -// UB-safe overflow check -static inline bool overflowCheck(const void *base, size_t offset, const void *end) -{ - auto baseI = reinterpret_cast(base), - endI = reinterpret_cast(end); - return baseI > endI || offset >= (endI - baseI); -} -// check whether &p[0] to &p[_off - 1] can be accessed -#define CHECKP(_off) \ - if ((_off) < 0 || overflowCheck(p, _off, pEnd)) \ - goto exit -// same for d -#define CHECKD(_off) \ - if ((_off) < 0 || overflowCheck(d, _off, destEnd)) \ - goto exit - -void CImageLoaderBMP::decompress8BitRLE(u8 *&bmpData, s32 size, s32 width, s32 height, s32 pitch) const -{ - u8 *p = bmpData; - const u8 *pEnd = bmpData + size; - u8 *newBmp = new u8[(width + pitch) * height]; - u8 *d = newBmp; - const u8 *destEnd = newBmp + (width + pitch) * height; - s32 line = 0; - - while (p < pEnd && d < destEnd) { - if (*p == 0) { - ++p; - CHECKP(1); - - switch (*p) { - case 0: // end of line - ++p; - ++line; - d = newBmp + (line * (width + pitch)); - break; - case 1: // end of bmp - goto exit; - case 2: - ++p; - CHECKP(2); - d += (u8)*p; - ++p; // delta - d += ((u8)*p) * (width + pitch); - ++p; - break; - default: { - // absolute mode - s32 count = (u8)*p; - ++p; - s32 readAdditional = ((2 - (count % 2)) % 2); - - CHECKP(count); - CHECKD(count); - for (s32 i = 0; i < count; ++i) { - *d = *p; - ++p; - ++d; - } - - CHECKP(readAdditional); - for (s32 i = 0; i < readAdditional; ++i) - ++p; - } - } - } else { - s32 count = (u8)*p; - ++p; - CHECKP(1); - u8 color = *p; - ++p; - CHECKD(count); - for (s32 i = 0; i < count; ++i) { - *d = color; - ++d; - } - } - } - -exit: - delete[] bmpData; - bmpData = newBmp; -} - -// how many bytes will be touched given the current state of decompress4BitRLE -static inline u32 shiftedCount(s32 count, s32 shift) -{ - _IRR_DEBUG_BREAK_IF(count < 0) - u32 ret = count / 2; - if (shift == 0 || count % 2 == 1) - ++ret; - return ret; -} - -void CImageLoaderBMP::decompress4BitRLE(u8 *&bmpData, s32 size, s32 width, s32 height, s32 pitch) const -{ - const s32 lineWidth = (width + 1) / 2 + pitch; - u8 *p = bmpData; - const u8 *pEnd = bmpData + size; - u8 *newBmp = new u8[lineWidth * height]; - u8 *d = newBmp; - const u8 *destEnd = newBmp + lineWidth * height; - s32 line = 0; - s32 shift = 4; - - while (p < pEnd && d < destEnd) { - if (*p == 0) { - ++p; - CHECKP(1); - - switch (*p) { - case 0: // end of line - ++p; - ++line; - d = newBmp + (line * lineWidth); - shift = 4; - break; - case 1: // end of bmp - goto exit; - case 2: { - ++p; - CHECKP(2); - s32 x = (u8)*p; - ++p; - s32 y = (u8)*p; - ++p; - d += x / 2 + y * lineWidth; - shift = x % 2 == 0 ? 4 : 0; - } break; - default: { - // absolute mode - s32 count = (u8)*p; - ++p; - s32 readAdditional = ((2 - ((count) % 2)) % 2); - s32 readShift = 4; - - CHECKP(shiftedCount(count, readShift)); - CHECKD(shiftedCount(count, shift)); - for (s32 i = 0; i < count; ++i) { - s32 color = (((u8)*p) >> readShift) & 0x0f; - readShift -= 4; - if (readShift < 0) { - ++*p; // <- bug? - readShift = 4; - } - - u8 mask = 0x0f << shift; - *d = (*d & (~mask)) | ((color << shift) & mask); - - shift -= 4; - if (shift < 0) { - shift = 4; - ++d; - } - } - - CHECKP(readAdditional); - for (s32 i = 0; i < readAdditional; ++i) - ++p; - } - } - } else { - s32 count = (u8)*p; - ++p; - CHECKP(1); - s32 color1 = (u8)*p; - color1 = color1 & 0x0f; - s32 color2 = (u8)*p; - color2 = (color2 >> 4) & 0x0f; - ++p; - - CHECKD(shiftedCount(count, shift)); - for (s32 i = 0; i < count; ++i) { - u8 mask = 0x0f << shift; - u8 toSet = (shift == 0 ? color1 : color2) << shift; - *d = (*d & (~mask)) | (toSet & mask); - - shift -= 4; - if (shift < 0) { - shift = 4; - ++d; - } - } - } - } - -exit: - delete[] bmpData; - bmpData = newBmp; -} - -#undef CHECKOFF -#undef CHECKP -#undef CHECKD - -//! creates a surface from the file -IImage *CImageLoaderBMP::loadImage(io::IReadFile *file) const -{ - SBMPHeader header; - - file->read(&header, sizeof(header)); - -#ifdef __BIG_ENDIAN__ - header.Id = os::Byteswap::byteswap(header.Id); - header.FileSize = os::Byteswap::byteswap(header.FileSize); - header.BitmapDataOffset = os::Byteswap::byteswap(header.BitmapDataOffset); - header.BitmapHeaderSize = os::Byteswap::byteswap(header.BitmapHeaderSize); - header.Width = os::Byteswap::byteswap(header.Width); - header.Height = os::Byteswap::byteswap(header.Height); - header.Planes = os::Byteswap::byteswap(header.Planes); - header.BPP = os::Byteswap::byteswap(header.BPP); - header.Compression = os::Byteswap::byteswap(header.Compression); - header.BitmapDataSize = os::Byteswap::byteswap(header.BitmapDataSize); - header.PixelPerMeterX = os::Byteswap::byteswap(header.PixelPerMeterX); - header.PixelPerMeterY = os::Byteswap::byteswap(header.PixelPerMeterY); - header.Colors = os::Byteswap::byteswap(header.Colors); - header.ImportantColors = os::Byteswap::byteswap(header.ImportantColors); -#endif - - s32 pitch = 0; - - //! return if the header is false - - if (header.Id != 0x4d42) - return 0; - - if (header.Compression > 2) { // we'll only handle RLE-Compression - os::Printer::log("Compression mode not supported.", ELL_ERROR); - return 0; - } - - if (header.BPP > 32 || !checkImageDimensions(header.Width, header.Height)) { - os::Printer::log("Rejecting BMP with unreasonable size or BPP.", ELL_ERROR); - return 0; - } - - // adjust bitmap data size to dword boundary - header.BitmapDataSize += (4 - (header.BitmapDataSize % 4)) % 4; - - // read palette - - long pos = file->getPos(); - constexpr s32 paletteAllocSize = 256; - s32 paletteSize = (header.BitmapDataOffset - pos) / 4; - paletteSize = core::clamp(paletteSize, 0, paletteAllocSize); - - s32 *paletteData = 0; - if (paletteSize) { - // always allocate an 8-bit palette to ensure enough space - paletteData = new s32[paletteAllocSize]; - memset(paletteData, 0, paletteAllocSize * sizeof(s32)); - file->read(paletteData, paletteSize * sizeof(s32)); -#ifdef __BIG_ENDIAN__ - for (s32 i = 0; i < paletteSize; ++i) - paletteData[i] = os::Byteswap::byteswap(paletteData[i]); -#endif - } - - // read image data - - if (!header.BitmapDataSize) { - // okay, lets guess the size - // some tools simply don't set it - header.BitmapDataSize = static_cast(file->getSize()) - header.BitmapDataOffset; - } - - file->seek(header.BitmapDataOffset); - - s32 widthInBytes; - { - f32 t = (header.Width) * (header.BPP / 8.0f); - widthInBytes = (s32)t; - t -= widthInBytes; - if (t != 0.0f) - ++widthInBytes; - } - - const s32 lineSize = widthInBytes + ((4 - (widthInBytes % 4))) % 4; - pitch = lineSize - widthInBytes; - - u8 *bmpData = new u8[header.BitmapDataSize]; - file->read(bmpData, header.BitmapDataSize); - - // decompress data if needed - switch (header.Compression) { - case 1: // 8 bit rle - decompress8BitRLE(bmpData, header.BitmapDataSize, header.Width, header.Height, pitch); - header.BitmapDataSize = (header.Width + pitch) * header.Height; - break; - case 2: // 4 bit rle - decompress4BitRLE(bmpData, header.BitmapDataSize, header.Width, header.Height, pitch); - header.BitmapDataSize = ((header.Width + 1) / 2 + pitch) * header.Height; - break; - } - - if (header.BitmapDataSize < lineSize * header.Height) { - os::Printer::log("Bitmap data is cut off.", ELL_ERROR); - - delete[] paletteData; - delete[] bmpData; - return 0; - } - - // create surface - core::dimension2d dim; - dim.Width = header.Width; - dim.Height = header.Height; - - IImage *image = 0; - switch (header.BPP) { - case 1: - image = new CImage(ECF_A1R5G5B5, dim); - if (image) - CColorConverter::convert1BitTo16Bit(bmpData, (s16 *)image->getData(), header.Width, header.Height, pitch, true); - break; - case 4: - image = new CImage(ECF_A1R5G5B5, dim); - if (image) - CColorConverter::convert4BitTo16Bit(bmpData, (s16 *)image->getData(), header.Width, header.Height, paletteData, pitch, true); - break; - case 8: - image = new CImage(ECF_A1R5G5B5, dim); - if (image) - CColorConverter::convert8BitTo16Bit(bmpData, (s16 *)image->getData(), header.Width, header.Height, paletteData, pitch, true); - break; - case 16: - image = new CImage(ECF_A1R5G5B5, dim); - if (image) - CColorConverter::convert16BitTo16Bit((s16 *)bmpData, (s16 *)image->getData(), header.Width, header.Height, pitch, true); - break; - case 24: - image = new CImage(ECF_R8G8B8, dim); - if (image) - CColorConverter::convert24BitTo24Bit(bmpData, (u8 *)image->getData(), header.Width, header.Height, pitch, true, true); - break; - case 32: // thx to Reinhard Ostermeier - image = new CImage(ECF_A8R8G8B8, dim); - if (image) - CColorConverter::convert32BitTo32Bit((s32 *)bmpData, (s32 *)image->getData(), header.Width, header.Height, pitch, true); - break; - }; - - // clean up - - delete[] paletteData; - delete[] bmpData; - - return image; -} - -//! creates a loader which is able to load windows bitmaps -IImageLoader *createImageLoaderBMP() -{ - return new CImageLoaderBMP; -} - -} // end namespace video -} // end namespace irr diff --git a/irr/src/CImageLoaderBMP.h b/irr/src/CImageLoaderBMP.h deleted file mode 100644 index e7ef8ed2b..000000000 --- a/irr/src/CImageLoaderBMP.h +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright (C) 2002-2012 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#pragma once - -#include "IImageLoader.h" - -namespace irr -{ -namespace video -{ - -// byte-align structures -#include "irrpack.h" - -struct SBMPHeader -{ - u16 Id; // BM - Windows 3.1x, 95, NT, 98, 2000, ME, XP - // BA - OS/2 Bitmap Array - // CI - OS/2 Color Icon - // CP - OS/2 Color Pointer - // IC - OS/2 Icon - // PT - OS/2 Pointer - u32 FileSize; - u32 Reserved; - u32 BitmapDataOffset; - u32 BitmapHeaderSize; // should be 28h for windows bitmaps or - // 0Ch for OS/2 1.x or F0h for OS/2 2.x - u32 Width; - u32 Height; - u16 Planes; - u16 BPP; // 1: Monochrome bitmap - // 4: 16 color bitmap - // 8: 256 color bitmap - // 16: 16bit (high color) bitmap - // 24: 24bit (true color) bitmap - // 32: 32bit (true color) bitmap - - u32 Compression; // 0: none (Also identified by BI_RGB) - // 1: RLE 8-bit / pixel (Also identified by BI_RLE4) - // 2: RLE 4-bit / pixel (Also identified by BI_RLE8) - // 3: Bitfields (Also identified by BI_BITFIELDS) - - u32 BitmapDataSize; // Size of the bitmap data in bytes. This number must be rounded to the next 4 byte boundary. - u32 PixelPerMeterX; - u32 PixelPerMeterY; - u32 Colors; - u32 ImportantColors; -} PACK_STRUCT; - -// Default alignment -#include "irrunpack.h" - -/*! - Surface Loader for Windows bitmaps -*/ -class CImageLoaderBMP : public IImageLoader -{ -public: - //! constructor - CImageLoaderBMP(); - - //! returns true if the file maybe is able to be loaded by this class - //! based on the file extension (e.g. ".tga") - bool isALoadableFileExtension(const io::path &filename) const override; - - //! returns true if the file maybe is able to be loaded by this class - bool isALoadableFileFormat(io::IReadFile *file) const override; - - //! creates a surface from the file - IImage *loadImage(io::IReadFile *file) const override; - -private: - void decompress8BitRLE(u8 *&BmpData, s32 size, s32 width, s32 height, s32 pitch) const; - - void decompress4BitRLE(u8 *&BmpData, s32 size, s32 width, s32 height, s32 pitch) const; -}; - -} // end namespace video -} // end namespace irr diff --git a/irr/src/CMakeLists.txt b/irr/src/CMakeLists.txt index b95c3ef73..1fbfe5c9f 100644 --- a/irr/src/CMakeLists.txt +++ b/irr/src/CMakeLists.txt @@ -370,7 +370,6 @@ endif() set(IRRIMAGEOBJ CColorConverter.cpp CImage.cpp - CImageLoaderBMP.cpp CImageLoaderJPG.cpp CImageLoaderPNG.cpp CImageLoaderTGA.cpp diff --git a/irr/src/CNullDriver.cpp b/irr/src/CNullDriver.cpp index 74e8cb0f4..f17f6f454 100644 --- a/irr/src/CNullDriver.cpp +++ b/irr/src/CNullDriver.cpp @@ -22,9 +22,6 @@ namespace irr namespace video { -//! creates a loader which is able to load windows bitmaps -IImageLoader *createImageLoaderBMP(); - //! creates a loader which is able to load jpeg images IImageLoader *createImageLoaderJPG(); @@ -93,7 +90,6 @@ CNullDriver::CNullDriver(io::IFileSystem *io, const core::dimension2d &scre SurfaceLoader.push_back(video::createImageLoaderTGA()); SurfaceLoader.push_back(video::createImageLoaderPNG()); SurfaceLoader.push_back(video::createImageLoaderJPG()); - SurfaceLoader.push_back(video::createImageLoaderBMP()); SurfaceWriter.push_back(video::createImageWriterJPG()); SurfaceWriter.push_back(video::createImageWriterPNG()); diff --git a/src/client/client.cpp b/src/client/client.cpp index 6d42e7551..b308a9276 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -765,7 +765,7 @@ bool Client::loadMedia(const std::string &data, const std::string &filename, std::string name; const char *image_ext[] = { - ".png", ".jpg", ".bmp", ".tga", + ".png", ".jpg", ".tga", NULL }; name = removeStringEnd(filename, image_ext); diff --git a/src/client/texturepaths.cpp b/src/client/texturepaths.cpp index 960171859..f2efa6038 100644 --- a/src/client/texturepaths.cpp +++ b/src/client/texturepaths.cpp @@ -22,10 +22,8 @@ void clearTextureNameCache() // If failed, return "". std::string getImagePath(std::string_view path) { - // A NULL-ended list of possible image extensions - // (In newer C++ versions a fixed size array and ranges::subrange could be used - // or just modernise removeStringEnd.) - static const char *extensions[] = {".png", ".jpg", ".bmp", ".tga", nullptr}; + // possible image extensions + static const char *extensions[] = {".png", ".jpg", ".tga", nullptr}; // Remove present extension std::string_view stripped_path = removeStringEnd(path, extensions); diff --git a/src/server.cpp b/src/server.cpp index 46bc31ae7..a636364ed 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2521,7 +2521,7 @@ bool Server::addMediaFile(const std::string &filename, } // If name is not in a supported format, ignore it const char *supported_ext[] = { - ".png", ".jpg", ".bmp", ".tga", + ".png", ".jpg", ".tga", ".ogg", ".x", ".b3d", ".obj", ".gltf", ".glb", // Translation file formats @@ -2547,13 +2547,6 @@ bool Server::addMediaFile(const std::string &filename, return false; } - const char *deprecated_ext[] = { ".bmp", nullptr }; - if (!removeStringEnd(filename, deprecated_ext).empty()) - { - warningstream << "Media file \"" << filename << "\" is using a" - " deprecated format and will stop working in the future." << std::endl; - } - SHA1 sha1; sha1.addBytes(filedata); From 3c42cc868467e683b1d79852d30fa9966fed2a69 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 8 Nov 2024 12:08:48 +0100 Subject: [PATCH 064/136] Revive texture download code and fix it on GLES --- irr/include/ITexture.h | 4 +--- irr/src/COpenGLCoreTexture.h | 34 +++++++++++++++------------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/irr/include/ITexture.h b/irr/include/ITexture.h index 533271b39..64b42ee54 100644 --- a/irr/include/ITexture.h +++ b/irr/include/ITexture.h @@ -74,9 +74,7 @@ enum E_TEXTURE_CREATION_FLAG //! Allow the driver to keep a copy of the texture in memory /** Enabling this makes calls to ITexture::lock a lot faster, but costs main memory. - Currently only used in combination with OpenGL drivers. - NOTE: Disabling this does not yet work correctly with alpha-textures. - So the default is on for now (but might change with Irrlicht 1.9 if we get the alpha-troubles fixed). + This is enabled by default. */ ETCF_ALLOW_MEMORY_COPY = 0x00000080, diff --git a/irr/src/COpenGLCoreTexture.h b/irr/src/COpenGLCoreTexture.h index 86ed4f73a..35c8f472a 100644 --- a/irr/src/COpenGLCoreTexture.h +++ b/irr/src/COpenGLCoreTexture.h @@ -261,7 +261,14 @@ public: if (LockImage && mode != ETLM_WRITE_ONLY) { bool passed = true; -#ifdef IRR_COMPILE_GL_COMMON +#ifdef IRR_COMPILE_GL_COMMON // legacy driver + constexpr bool use_gl_impl = true; +#else + const bool use_gl_impl = Driver->Version.Spec != OpenGLSpec::ES; +#endif + + if (use_gl_impl) { + IImage *tmpImage = LockImage; // not sure yet if the size required by glGetTexImage is always correct, if not we might have to allocate a different tmpImage and convert colors later on. Driver->getCacheHandler()->getTextureCache().set(0, this); @@ -296,38 +303,26 @@ public: delete[] tmpBuffer; } -#elif defined(IRR_COMPILE_GLES2_COMMON) - // TODO: revive this code - COpenGLCoreTexture *tmpTexture = new COpenGLCoreTexture("OGL_CORE_LOCK_TEXTURE", Size, ETT_2D, ColorFormat, Driver); + + } else { GLuint tmpFBO = 0; Driver->irrGlGenFramebuffers(1, &tmpFBO); - GLint prevViewportX = 0; - GLint prevViewportY = 0; - GLsizei prevViewportWidth = 0; - GLsizei prevViewportHeight = 0; - Driver->getCacheHandler()->getViewport(prevViewportX, prevViewportY, prevViewportWidth, prevViewportHeight); - Driver->getCacheHandler()->setViewport(0, 0, Size.Width, Size.Height); - GLuint prevFBO = 0; Driver->getCacheHandler()->getFBO(prevFBO); Driver->getCacheHandler()->setFBO(tmpFBO); - Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmpTexture->getOpenGLTextureName(), 0); - - GL.Clear(GL_COLOR_BUFFER_BIT); - - Driver->draw2DImage(this, layer, true); + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, getOpenGLTextureName(), 0); IImage *tmpImage = Driver->createImage(ECF_A8R8G8B8, Size); GL.ReadPixels(0, 0, Size.Width, Size.Height, GL_RGBA, GL_UNSIGNED_BYTE, tmpImage->getData()); + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + Driver->getCacheHandler()->setFBO(prevFBO); - Driver->getCacheHandler()->setViewport(prevViewportX, prevViewportY, prevViewportWidth, prevViewportHeight); Driver->irrGlDeleteFramebuffers(1, &tmpFBO); - delete tmpTexture; void *src = tmpImage->getData(); void *dest = LockImage->getData(); @@ -350,7 +345,8 @@ public: break; } tmpImage->drop(); -#endif + + } if (!passed) { LockImage->drop(); From 4aae31ad5e093308d10bbc956f42a6bfe98e516d Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 8 Nov 2024 12:27:51 +0100 Subject: [PATCH 065/136] Add support for ECF_D24 texture format and prefer it over D32 for our depth buffer, this can have performance benefits --- irr/include/IImage.h | 3 +++ irr/include/SColor.h | 4 ++++ irr/src/OpenGL3/Driver.cpp | 1 + irr/src/OpenGLES2/Driver.cpp | 1 + src/client/render/plain.cpp | 4 ++-- src/client/render/secondstage.cpp | 4 ++++ 6 files changed, 15 insertions(+), 2 deletions(-) diff --git a/irr/include/IImage.h b/irr/include/IImage.h index f3c29b71d..47349ed1a 100644 --- a/irr/include/IImage.h +++ b/irr/include/IImage.h @@ -328,6 +328,8 @@ public: return 32; case ECF_D16: return 16; + case ECF_D24: + return 32; case ECF_D32: return 32; case ECF_D24S8: @@ -378,6 +380,7 @@ public: { switch (format) { case ECF_D16: + case ECF_D24: case ECF_D32: case ECF_D24S8: return true; diff --git a/irr/include/SColor.h b/irr/include/SColor.h index 284ab3351..a2dd52603 100644 --- a/irr/include/SColor.h +++ b/irr/include/SColor.h @@ -77,6 +77,9 @@ enum ECOLOR_FORMAT //! 16 bit format using 16 bits for depth. ECF_D16, + //! 32 bit(?) format using 24 bits for depth. + ECF_D24, + //! 32 bit format using 32 bits for depth. ECF_D32, @@ -104,6 +107,7 @@ const c8 *const ColorFormatNames[ECF_UNKNOWN + 2] = { "R16", "R16G16", "D16", + "D24", "D32", "D24S8", "UNKNOWN", diff --git a/irr/src/OpenGL3/Driver.cpp b/irr/src/OpenGL3/Driver.cpp index 53cb8c7ed..a58e1542f 100644 --- a/irr/src/OpenGL3/Driver.cpp +++ b/irr/src/OpenGL3/Driver.cpp @@ -59,6 +59,7 @@ void COpenGL3Driver::initFeatures() TextureFormats[ECF_R16] = {GL_R16, GL_RED, GL_UNSIGNED_SHORT}; TextureFormats[ECF_R16G16] = {GL_RG16, GL_RG, GL_UNSIGNED_SHORT}; TextureFormats[ECF_D16] = {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; + TextureFormats[ECF_D24] = {GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}; TextureFormats[ECF_D32] = {GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}; // WARNING: may not be renderable (?!) TextureFormats[ECF_D24S8] = {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}; diff --git a/irr/src/OpenGLES2/Driver.cpp b/irr/src/OpenGLES2/Driver.cpp index 9a99601fd..e423abb2e 100644 --- a/irr/src/OpenGLES2/Driver.cpp +++ b/irr/src/OpenGLES2/Driver.cpp @@ -50,6 +50,7 @@ void COpenGLES2Driver::initFeatures() TextureFormats[ECF_R8] = {GL_R8, GL_RED, GL_UNSIGNED_BYTE}; TextureFormats[ECF_R8G8] = {GL_RG8, GL_RG, GL_UNSIGNED_BYTE}; TextureFormats[ECF_D16] = {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; + TextureFormats[ECF_D24] = {GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}; TextureFormats[ECF_D24S8] = {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}; if (FeatureAvailable[IRR_GL_EXT_texture_format_BGRA8888]) diff --git a/src/client/render/plain.cpp b/src/client/render/plain.cpp index 22b167518..fd3e0b9ba 100644 --- a/src/client/render/plain.cpp +++ b/src/client/render/plain.cpp @@ -162,8 +162,8 @@ video::ECOLOR_FORMAT selectColorFormat(video::IVideoDriver *driver) video::ECOLOR_FORMAT selectDepthFormat(video::IVideoDriver *driver) { - if (driver->queryTextureFormat(video::ECF_D32)) - return video::ECF_D32; + if (driver->queryTextureFormat(video::ECF_D24)) + return video::ECF_D24; if (driver->queryTextureFormat(video::ECF_D24S8)) return video::ECF_D24S8; return video::ECF_D16; // fallback depth format diff --git a/src/client/render/secondstage.cpp b/src/client/render/secondstage.cpp index 212074535..26ce6888e 100644 --- a/src/client/render/secondstage.cpp +++ b/src/client/render/secondstage.cpp @@ -90,6 +90,10 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep video::ECOLOR_FORMAT color_format = selectColorFormat(driver); video::ECOLOR_FORMAT depth_format = selectDepthFormat(driver); + verbosestream << "addPostProcessing(): color = " + << video::ColorFormatNames[color_format] << " depth = " + << video::ColorFormatNames[depth_format] << std::endl; + // init post-processing buffer static const u8 TEXTURE_COLOR = 0; static const u8 TEXTURE_DEPTH = 1; From 58ccf0ba82212bfe923f001057d02c2331a2f10a Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 8 Nov 2024 13:15:20 +0100 Subject: [PATCH 066/136] Fix some smaller issues with texture/image handling --- irr/include/ITexture.h | 2 +- src/client/minimap.cpp | 10 +++---- src/client/render/interlaced.cpp | 4 +-- src/client/sky.cpp | 46 +++++++++++++++++++---------- src/client/sky.h | 9 +++--- src/irrlicht_changes/CGUITTFont.cpp | 1 + 6 files changed, 44 insertions(+), 28 deletions(-) diff --git a/irr/include/ITexture.h b/irr/include/ITexture.h index 64b42ee54..6cbf64bd3 100644 --- a/irr/include/ITexture.h +++ b/irr/include/ITexture.h @@ -182,7 +182,7 @@ public: //! Lock function. /** Locks the Texture and returns a pointer to access the pixels. After lock() has been called and all operations on the pixels - are done, you must call unlock(). + are done, you must call unlock(). Afterwards the pointer becomes invalid. Locks are not accumulating, hence one unlock will do for an arbitrary number of previous locks. You should avoid locking different levels without unlocking in between, though, because only the last level locked will be diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp index f28f6a39a..b11d8b345 100644 --- a/src/client/minimap.cpp +++ b/src/client/minimap.cpp @@ -474,17 +474,15 @@ video::ITexture *Minimap::getMinimapTexture() blitMinimapPixelsToImageRadar(map_image); break; case MINIMAP_TYPE_TEXTURE: - // Want to use texture source, to : 1 find texture, 2 cache it + // FIXME: this is a pointless roundtrip through the gpu video::ITexture* texture = m_tsrc->getTexture(data->mode.texture); video::IImage* image = driver->createImageFromData( - texture->getColorFormat(), texture->getSize(), - texture->lock(video::ETLM_READ_ONLY), true, false); - texture->unlock(); + texture->getColorFormat(), texture->getSize(), + texture->lock(video::ETLM_READ_ONLY), true, false); auto dim = image->getDimension(); map_image->fill(video::SColor(255, 0, 0, 0)); - image->copyTo(map_image, irr::core::vector2d { ((data->mode.map_size - (static_cast(dim.Width))) >> 1) @@ -492,7 +490,9 @@ video::ITexture *Minimap::getMinimapTexture() ((data->mode.map_size - (static_cast(dim.Height))) >> 1) + data->pos.Z / data->mode.scale }); + image->drop(); + texture->unlock(); } map_image->copyToScaling(minimap_image); diff --git a/src/client/render/interlaced.cpp b/src/client/render/interlaced.cpp index 7399d9242..f56d8a3d9 100644 --- a/src/client/render/interlaced.cpp +++ b/src/client/render/interlaced.cpp @@ -24,7 +24,7 @@ void InitInterlacedMaskStep::run(PipelineContext &context) last_mask = mask; auto size = mask->getSize(); - u8 *data = reinterpret_cast(mask->lock()); + u8 *data = reinterpret_cast(mask->lock(video::ETLM_WRITE_ONLY)); for (u32 j = 0; j < size.Height; j++) { u8 val = j % 2 ? 0xff : 0x00; memset(data, val, 4 * size.Width); @@ -74,4 +74,4 @@ void populateInterlacedPipeline(RenderPipeline *pipeline, Client *client) merge->setRenderSource(buffer); merge->setRenderTarget(pipeline->createOwned()); pipeline->addStep(); -} \ No newline at end of file +} diff --git a/src/client/sky.cpp b/src/client/sky.cpp index cfce57ef3..8da7fc68e 100644 --- a/src/client/sky.cpp +++ b/src/client/sky.cpp @@ -145,21 +145,15 @@ void Sky::render() float offset = (1.0 - fabs(sin((m_time_of_day - 0.5) * irr::core::PI))) * 511; if (m_sun_tonemap) { - u8 * texels = (u8 *)m_sun_tonemap->lock(); - video::SColor* texel = (video::SColor *)(texels + (u32)offset * 4); - video::SColor texel_color (255, texel->getRed(), - texel->getGreen(), texel->getBlue()); - m_sun_tonemap->unlock(); + auto texel_color = m_sun_tonemap->getPixel(offset, 0); + texel_color.setAlpha(255); // Only accessed by our code later, not used by a shader m_materials[3].ColorParam = texel_color; } if (m_moon_tonemap) { - u8 * texels = (u8 *)m_moon_tonemap->lock(); - video::SColor* texel = (video::SColor *)(texels + (u32)offset * 4); - video::SColor texel_color (255, texel->getRed(), - texel->getGreen(), texel->getBlue()); - m_moon_tonemap->unlock(); + auto texel_color = m_moon_tonemap->getPixel(offset, 0); + texel_color.setAlpha(255); // Only accessed by our code later, not used by a shader m_materials[4].ColorParam = texel_color; } @@ -711,14 +705,33 @@ void Sky::place_sky_body( } } +// FIXME: stupid helper that does a pointless texture upload/download +static void getTextureAsImage(video::IImage *&dst, const std::string &name, ITextureSource *tsrc) +{ + if (dst) { + dst->drop(); + dst = nullptr; + } + if (tsrc->isKnownSourceImage(name)) { + auto *texture = tsrc->getTexture(name); + assert(texture); + auto *driver = RenderingEngine::get_video_driver(); + dst = driver->createImageFromData( + texture->getColorFormat(), texture->getSize(), + texture->lock(video::ETLM_READ_ONLY)); + texture->unlock(); + } +} + void Sky::setSunTexture(const std::string &sun_texture, const std::string &sun_tonemap, ITextureSource *tsrc) { // Ignore matching textures (with modifiers) entirely, // but lets at least update the tonemap before hand. - m_sun_params.tonemap = sun_tonemap; - m_sun_tonemap = tsrc->isKnownSourceImage(sun_tonemap) ? - tsrc->getTexture(sun_tonemap) : nullptr; + if (m_sun_params.tonemap != sun_tonemap) { + m_sun_params.tonemap = sun_tonemap; + getTextureAsImage(m_sun_tonemap, sun_tonemap, tsrc); + } if (m_sun_params.texture == sun_texture && !m_first_update) return; @@ -758,9 +771,10 @@ void Sky::setMoonTexture(const std::string &moon_texture, { // Ignore matching textures (with modifiers) entirely, // but lets at least update the tonemap before hand. - m_moon_params.tonemap = moon_tonemap; - m_moon_tonemap = tsrc->isKnownSourceImage(moon_tonemap) ? - tsrc->getTexture(moon_tonemap) : nullptr; + if (m_moon_params.tonemap != moon_tonemap) { + m_moon_params.tonemap = moon_tonemap; + getTextureAsImage(m_moon_tonemap, moon_tonemap, tsrc); + } if (m_moon_params.texture == moon_texture && !m_first_update) return; diff --git a/src/client/sky.h b/src/client/sky.h index 73f377ae2..0ba3ee62c 100644 --- a/src/client/sky.h +++ b/src/client/sky.h @@ -17,6 +17,7 @@ namespace irr::video { class IVideoDriver; + class IImage; } class IShaderSource; @@ -200,10 +201,10 @@ private: u64 m_seed = 0; irr_ptr m_stars; - video::ITexture *m_sun_texture; - video::ITexture *m_moon_texture; - video::ITexture *m_sun_tonemap; - video::ITexture *m_moon_tonemap; + video::ITexture *m_sun_texture = nullptr; + video::ITexture *m_moon_texture = nullptr; + video::IImage *m_sun_tonemap = nullptr; + video::IImage *m_moon_tonemap = nullptr; void updateStars(); diff --git a/src/irrlicht_changes/CGUITTFont.cpp b/src/irrlicht_changes/CGUITTFont.cpp index ee5ec6b35..8337390c1 100644 --- a/src/irrlicht_changes/CGUITTFont.cpp +++ b/src/irrlicht_changes/CGUITTFont.cpp @@ -1020,6 +1020,7 @@ video::IImage* CGUITTFont::createTextureFromChar(const char32_t& ch) pageholder->copyTo(image, core::position2di(0, 0), glyph.source_rect); tex->unlock(); + pageholder->drop(); return image; } From cc8c3d501c6cacf86501900b74e2a666d8d33ab0 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 8 Nov 2024 13:20:02 +0100 Subject: [PATCH 067/136] Don't keep a copy of all texture images around --- irr/include/ITexture.h | 2 +- irr/src/CNullDriver.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/irr/include/ITexture.h b/irr/include/ITexture.h index 6cbf64bd3..8760c9f2a 100644 --- a/irr/include/ITexture.h +++ b/irr/include/ITexture.h @@ -74,7 +74,7 @@ enum E_TEXTURE_CREATION_FLAG //! Allow the driver to keep a copy of the texture in memory /** Enabling this makes calls to ITexture::lock a lot faster, but costs main memory. - This is enabled by default. + This is disabled by default. */ ETCF_ALLOW_MEMORY_COPY = 0x00000080, diff --git a/irr/src/CNullDriver.cpp b/irr/src/CNullDriver.cpp index f17f6f454..46a2d9f7b 100644 --- a/irr/src/CNullDriver.cpp +++ b/irr/src/CNullDriver.cpp @@ -76,7 +76,7 @@ CNullDriver::CNullDriver(io::IFileSystem *io, const core::dimension2d &scre setTextureCreationFlag(ETCF_ALWAYS_32_BIT, true); setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, true); setTextureCreationFlag(ETCF_AUTO_GENERATE_MIP_MAPS, true); - setTextureCreationFlag(ETCF_ALLOW_MEMORY_COPY, true); + setTextureCreationFlag(ETCF_ALLOW_MEMORY_COPY, false); ViewPort = core::rect(core::position2d(0, 0), core::dimension2di(screenSize)); From 8d2e7703619205dd76ee9cc12fb0b660868c910b Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 15 Nov 2024 13:37:16 +0100 Subject: [PATCH 068/136] Minor corrections in gl3/gles2 drivers --- irr/src/CNullDriver.cpp | 7 ++++--- irr/src/OpenGL/Driver.cpp | 14 +++----------- irr/src/OpenGL/MaterialRenderer.cpp | 2 +- irr/src/OpenGL3/Driver.cpp | 14 +++++++++----- irr/src/OpenGLES2/Driver.cpp | 18 ++++++++++++++---- 5 files changed, 31 insertions(+), 24 deletions(-) diff --git a/irr/src/CNullDriver.cpp b/irr/src/CNullDriver.cpp index 46a2d9f7b..acce8383b 100644 --- a/irr/src/CNullDriver.cpp +++ b/irr/src/CNullDriver.cpp @@ -936,9 +936,10 @@ void CNullDriver::setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag, bool enab setTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED, false); } - // set flag - TextureCreationFlags = (TextureCreationFlags & (~flag)) | - ((((u32)!enabled) - 1) & flag); + if (enabled) + TextureCreationFlags |= flag; + else + TextureCreationFlags &= ~flag; } //! Returns if a texture creation flag is enabled or disabled. diff --git a/irr/src/OpenGL/Driver.cpp b/irr/src/OpenGL/Driver.cpp index 4f3ac627a..4b85b1345 100644 --- a/irr/src/OpenGL/Driver.cpp +++ b/irr/src/OpenGL/Driver.cpp @@ -144,7 +144,7 @@ void COpenGL3DriverBase::debugCb(GLenum source, GLenum type, GLuint id, GLenum s ll = ELL_ERROR; else if (severity == GL_DEBUG_SEVERITY_MEDIUM) ll = ELL_WARNING; - char buf[256]; + char buf[300]; snprintf_irr(buf, sizeof(buf), "%04x %04x %.*s", source, type, length, message); os::Printer::log("GL", buf, ll); } @@ -700,15 +700,7 @@ void COpenGL3DriverBase::drawVertexPrimitiveList(const void *vertices, u32 verte break; } case (EIT_32BIT): { -#ifdef GL_OES_element_index_uint -#ifndef GL_UNSIGNED_INT -#define GL_UNSIGNED_INT 0x1405 -#endif - if (FeatureAvailable[COGLESCoreExtensionHandler::IRR_GL_OES_element_index_uint]) - indexSize = GL_UNSIGNED_INT; - else -#endif - indexSize = GL_UNSIGNED_SHORT; + indexSize = GL_UNSIGNED_INT; break; } } @@ -1683,7 +1675,7 @@ ITexture *COpenGL3DriverBase::addRenderTargetTextureCubemap(const irr::u32 sideL //! Returns the maximum amount of primitives u32 COpenGL3DriverBase::getMaximalPrimitiveCount() const { - return 65535; + return Version.Spec == OpenGLSpec::ES ? 65535 : 0x7fffffff; } bool COpenGL3DriverBase::setRenderTargetEx(IRenderTarget *target, u16 clearFlag, SColor clearColor, f32 clearDepth, u8 clearStencil) diff --git a/irr/src/OpenGL/MaterialRenderer.cpp b/irr/src/OpenGL/MaterialRenderer.cpp index 3c32ba318..d5bf9004a 100644 --- a/irr/src/OpenGL/MaterialRenderer.cpp +++ b/irr/src/OpenGL/MaterialRenderer.cpp @@ -411,7 +411,7 @@ bool COpenGL3MaterialRenderer::setPixelShaderConstant(s32 index, const s32 *ints bool COpenGL3MaterialRenderer::setPixelShaderConstant(s32 index, const u32 *ints, int count) { - os::Printer::log("Unsigned int support needs at least GLES 3.0", ELL_WARNING); + os::Printer::log("Unsigned int support is unimplemented", ELL_WARNING); return false; } diff --git a/irr/src/OpenGL3/Driver.cpp b/irr/src/OpenGL3/Driver.cpp index a58e1542f..ac0816445 100644 --- a/irr/src/OpenGL3/Driver.cpp +++ b/irr/src/OpenGL3/Driver.cpp @@ -4,6 +4,7 @@ #include "Driver.h" #include +#include #include "mt_opengl.h" namespace irr @@ -18,7 +19,7 @@ E_DRIVER_TYPE COpenGL3Driver::getDriverType() const OpenGLVersion COpenGL3Driver::getVersionFromOpenGL() const { - GLint major, minor, profile; + GLint major = 0, minor = 0, profile = 0; GL.GetIntegerv(GL_MAJOR_VERSION, &major); GL.GetIntegerv(GL_MINOR_VERSION, &minor); GL.GetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile); @@ -35,18 +36,21 @@ OpenGLVersion COpenGL3Driver::getVersionFromOpenGL() const void COpenGL3Driver::initFeatures() { if (Version.Spec != OpenGLSpec::Compat) { - os::Printer::log("OpenGL 3 driver requires Compatibility Mode", ELL_ERROR); - throw std::exception(); + auto msg = "OpenGL 3 driver requires Compatibility context"; + os::Printer::log(msg, ELL_ERROR); + throw std::runtime_error(msg); } if (!isVersionAtLeast(3, 2)) { - os::Printer::log("OpenGL 3 driver requires OpenGL >= 3.2 ", ELL_ERROR); - throw std::exception(); + auto msg = "OpenGL 3 driver requires OpenGL >= 3.2"; + os::Printer::log(msg, ELL_ERROR); + throw std::runtime_error(msg); } initExtensions(); TextureFormats[ECF_A1R5G5B5] = {GL_RGB5_A1, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV}; // WARNING: may not be renderable TextureFormats[ECF_R5G6B5] = {GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}; // GL_RGB565 is an extension until 4.1 TextureFormats[ECF_R8G8B8] = {GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE}; // WARNING: may not be renderable + // FIXME: shouldn't this simply be GL_UNSIGNED_BYTE? TextureFormats[ECF_A8R8G8B8] = {GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV}; TextureFormats[ECF_R16F] = {GL_R16F, GL_RED, GL_HALF_FLOAT}; TextureFormats[ECF_G16R16F] = {GL_RG16F, GL_RG, GL_HALF_FLOAT}; diff --git a/irr/src/OpenGLES2/Driver.cpp b/irr/src/OpenGLES2/Driver.cpp index e423abb2e..430be736d 100644 --- a/irr/src/OpenGLES2/Driver.cpp +++ b/irr/src/OpenGLES2/Driver.cpp @@ -3,8 +3,10 @@ // For conditions of distribution and use, see copyright notice in Irrlicht.h #include "Driver.h" +#include #include -#include +#include "mt_opengl.h" +#include "CColorConverter.h" namespace irr { @@ -19,7 +21,7 @@ E_DRIVER_TYPE COpenGLES2Driver::getDriverType() const OpenGLVersion COpenGLES2Driver::getVersionFromOpenGL() const { auto version_string = reinterpret_cast(GL.GetString(GL_VERSION)); - int major, minor; + int major = 0, minor = 0; if (sscanf(version_string, "OpenGL ES %d.%d", &major, &minor) != 2) { os::Printer::log("Failed to parse OpenGL ES version string", version_string, ELL_ERROR); return {OpenGLSpec::ES, 0, 0, 0}; @@ -29,8 +31,16 @@ OpenGLVersion COpenGLES2Driver::getVersionFromOpenGL() const void COpenGLES2Driver::initFeatures() { - assert(Version.Spec == OpenGLSpec::ES); - assert(Version.Major >= 2); + if (Version.Spec != OpenGLSpec::ES) { + auto msg = "Context isn't OpenGL ES"; + os::Printer::log(msg, ELL_ERROR); + throw std::runtime_error(msg); + } + if (!isVersionAtLeast(2, 0)) { + auto msg = "Open GL ES 2.0 is required"; + os::Printer::log(msg, ELL_ERROR); + throw std::runtime_error(msg); + } initExtensions(); static const GLenum BGRA8_EXT = 0x93A1; From 7295b6c88cbadb188871162d4d76e7c50faef9d1 Mon Sep 17 00:00:00 2001 From: HybridDog <3192173+HybridDog@users.noreply.github.com> Date: Mon, 18 Nov 2024 00:02:53 +0100 Subject: [PATCH 069/136] Remove unused and rarely used irrlicht color functions (#15442) SColor.h contains many functions which are unused and/or perform linear operations on non-linear 8 bit sRGB color values, such as the plus operator and `SColor::getInterpolated()`, and there is no documentation about missing gamma correction. Some of these functions are not called or called only once: * `getAverage(s16 color)`: Unused * `SColor::getLightness()`: Unused * `SColor::getAverage()`: Claims to determine a color's average intensity but calculates something significantly different since SColor represents non-linear sRGB values. * `SColor::getInterpolated_quadratic()`: Claims to interpolate between colors but uses the sRGB color space, which is neither physically nor perceptually linear. * `SColorf::getInterpolated_quadratic()`: Unused * `SColorf::setColorComponentValue()`: Unused Removing or inlining these functions can simplify the code and documenting gamma-incorrect operations can reduce confusion about what the functions do. This commit does the following: * Remove the above-mentioned unused functions * Inline `SColor::getAverage()` into `CIrrDeviceLinux::TextureToMonochromeCursor()` * Rename `SColor::getLuminance()` into `SColor::getBrightness()` since it does not determine a color's luminance but calculates something which differs significantly from physical luminance since SColor represents non-linear sRGB values. * Inline `SColor::getInterpolated_quadratic()` into `GameUI::update()`, where it is only used for the alpha value calculation for fading * Document gamma-incorrect behaviour in docstrings --- irr/include/SColor.h | 105 +++++------------------------------- irr/src/CIrrDeviceLinux.cpp | 3 +- src/client/camera.h | 2 +- src/client/gameui.cpp | 8 +-- src/client/imagesource.cpp | 2 +- 5 files changed, 20 insertions(+), 100 deletions(-) diff --git a/irr/include/SColor.h b/irr/include/SColor.h index a2dd52603..41bca1a8c 100644 --- a/irr/include/SColor.h +++ b/irr/include/SColor.h @@ -224,12 +224,6 @@ inline u32 getBlue(u16 color) return (color & 0x1F); } -//! Returns the average from a 16 bit A1R5G5B5 color -inline s32 getAverage(s16 color) -{ - return ((getRed(color) << 3) + (getGreen(color) << 3) + (getBlue(color) << 3)) / 3; -} - //! Class representing a 32 bit ARGB color. /** The color values for alpha, red, green, and blue are stored in a single u32. So all four values may be between 0 and 255. @@ -275,24 +269,12 @@ public: 0 means no blue, 255 means full blue. */ u32 getBlue() const { return color & 0xff; } - //! Get lightness of the color in the range [0,255] - f32 getLightness() const - { - return 0.5f * (core::max_(core::max_(getRed(), getGreen()), getBlue()) + core::min_(core::min_(getRed(), getGreen()), getBlue())); - } - - //! Get luminance of the color in the range [0,255]. - f32 getLuminance() const + //! Get an approximate brightness value of the color in the range [0,255] + f32 getBrightness() const { return 0.3f * getRed() + 0.59f * getGreen() + 0.11f * getBlue(); } - //! Get average intensity of the color in the range [0,255]. - u32 getAverage() const - { - return (getRed() + getGreen() + getBlue()) / 3; - } - //! Sets the alpha component of the Color. /** The alpha component defines how transparent a color should be. \param a The alpha value of the color. 0 is fully transparent, 255 is fully opaque. */ @@ -362,9 +344,9 @@ public: /** \return True if this color is smaller than the other one */ bool operator<(const SColor &other) const { return (color < other.color); } - //! Adds two colors, result is clamped to 0..255 values + //! Adds two colors in a gamma-incorrect way /** \param other Color to add to this color - \return Addition of the two colors, clamped to 0..255 values */ + \return Sum of the two non-linear colors, clamped to 0..255 values */ SColor operator+(const SColor &other) const { return SColor(core::min_(getAlpha() + other.getAlpha(), 255u), @@ -374,7 +356,9 @@ public: } //! Interpolates the color with a f32 value to another color - /** \param other: Other color + /** Note that the interpolation is neither physically nor perceptually + linear since it happens directly in the sRGB color space. + \param other: Other color \param d: value between 0.0f and 1.0f. d=0 returns other, d=1 returns this, values between interpolate. \return Interpolated color. */ SColor getInterpolated(const SColor &other, f32 d) const @@ -387,34 +371,6 @@ public: (u32)core::round32(other.getBlue() * inv + getBlue() * d)); } - //! Returns interpolated color. ( quadratic ) - /** \param c1: first color to interpolate with - \param c2: second color to interpolate with - \param d: value between 0.0f and 1.0f. */ - SColor getInterpolated_quadratic(const SColor &c1, const SColor &c2, f32 d) const - { - // this*(1-d)*(1-d) + 2 * c1 * (1-d) + c2 * d * d; - d = core::clamp(d, 0.f, 1.f); - const f32 inv = 1.f - d; - const f32 mul0 = inv * inv; - const f32 mul1 = 2.f * d * inv; - const f32 mul2 = d * d; - - return SColor( - core::clamp(core::floor32( - getAlpha() * mul0 + c1.getAlpha() * mul1 + c2.getAlpha() * mul2), - 0, 255), - core::clamp(core::floor32( - getRed() * mul0 + c1.getRed() * mul1 + c2.getRed() * mul2), - 0, 255), - core::clamp(core::floor32( - getGreen() * mul0 + c1.getGreen() * mul1 + c2.getGreen() * mul2), - 0, 255), - core::clamp(core::floor32( - getBlue() * mul0 + c1.getBlue() * mul1 + c2.getBlue() * mul2), - 0, 255)); - } - //! set the color by expecting data in the given format /** \param data: must point to valid memory containing color information in the given format \param format: tells the format in which data is available @@ -508,7 +464,7 @@ public: SColorf(f32 r, f32 g, f32 b, f32 a = 1.0f) : r(r), g(g), b(b), a(a) {} - //! Constructs a color from 32 bit Color. + //! Constructs a color from 32 bit Color without gamma correction /** \param c: 32 bit color from which this SColorf class is constructed from. */ SColorf(SColor c) @@ -520,7 +476,7 @@ public: a = c.getAlpha() * inv; } - //! Converts this color to a SColor without floats. + //! Converts this color to a SColor without gamma correction SColor toSColor() const { return SColor((u32)core::round32(a * 255.0f), (u32)core::round32(r * 255.0f), (u32)core::round32(g * 255.0f), (u32)core::round32(b * 255.0f)); @@ -558,7 +514,9 @@ public: } //! Interpolates the color with a f32 value to another color - /** \param other: Other color + /** Note that the interpolation is neither physically nor perceptually + linear if it happens directly in the sRGB color space. + \param other: Other color \param d: value between 0.0f and 1.0f \return Interpolated color. */ SColorf getInterpolated(const SColorf &other, f32 d) const @@ -569,45 +527,6 @@ public: other.g * inv + g * d, other.b * inv + b * d, other.a * inv + a * d); } - //! Returns interpolated color. ( quadratic ) - /** \param c1: first color to interpolate with - \param c2: second color to interpolate with - \param d: value between 0.0f and 1.0f. */ - inline SColorf getInterpolated_quadratic(const SColorf &c1, const SColorf &c2, - f32 d) const - { - d = core::clamp(d, 0.f, 1.f); - // this*(1-d)*(1-d) + 2 * c1 * (1-d) + c2 * d * d; - const f32 inv = 1.f - d; - const f32 mul0 = inv * inv; - const f32 mul1 = 2.f * d * inv; - const f32 mul2 = d * d; - - return SColorf(r * mul0 + c1.r * mul1 + c2.r * mul2, - g * mul0 + c1.g * mul1 + c2.g * mul2, - b * mul0 + c1.b * mul1 + c2.b * mul2, - a * mul0 + c1.a * mul1 + c2.a * mul2); - } - - //! Sets a color component by index. R=0, G=1, B=2, A=3 - void setColorComponentValue(s32 index, f32 value) - { - switch (index) { - case 0: - r = value; - break; - case 1: - g = value; - break; - case 2: - b = value; - break; - case 3: - a = value; - break; - } - } - //! Returns the alpha component of the color in the range 0.0 (transparent) to 1.0 (opaque) f32 getAlpha() const { return a; } diff --git a/irr/src/CIrrDeviceLinux.cpp b/irr/src/CIrrDeviceLinux.cpp index e88902936..0b9ef5b71 100644 --- a/irr/src/CIrrDeviceLinux.cpp +++ b/irr/src/CIrrDeviceLinux.cpp @@ -1951,7 +1951,8 @@ Cursor CIrrDeviceLinux::TextureToMonochromeCursor(irr::video::ITexture *tex, con XPutPixel(sourceImage, x, y, 0); } else // color { - if (pixelCol.getAverage() >= 127) + if ((pixelCol.getRed() + pixelCol.getGreen() + + pixelCol.getBlue()) / 3 >= 127) XPutPixel(sourceImage, x, y, 1); else XPutPixel(sourceImage, x, y, 0); diff --git a/src/client/camera.h b/src/client/camera.h index 9a8e2d36a..3715bebad 100644 --- a/src/client/camera.h +++ b/src/client/camera.h @@ -48,7 +48,7 @@ struct Nametag return bgcolor.value(); else if (!use_fallback) return video::SColor(0, 0, 0, 0); - else if (textcolor.getLuminance() > 186) + else if (textcolor.getBrightness() > 186) // Dark background for light text return video::SColor(50, 50, 50, 50); else diff --git a/src/client/gameui.cpp b/src/client/gameui.cpp index 3408ba196..c2693c6ae 100644 --- a/src/client/gameui.cpp +++ b/src/client/gameui.cpp @@ -201,10 +201,10 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_ status_y - status_height, status_x + status_width, status_y)); // Fade out - video::SColor final_color = m_statustext_initial_color; - final_color.setAlpha(0); - video::SColor fade_color = m_statustext_initial_color.getInterpolated_quadratic( - m_statustext_initial_color, final_color, m_statustext_time / statustext_time_max); + video::SColor fade_color = m_statustext_initial_color; + f32 d = m_statustext_time / statustext_time_max; + fade_color.setAlpha(static_cast( + fade_color.getAlpha() * (1.0f - d * d))); guitext_status->setOverrideColor(fade_color); guitext_status->enableOverrideColor(true); } diff --git a/src/client/imagesource.cpp b/src/client/imagesource.cpp index 0f4e81f97..a14dac290 100644 --- a/src/client/imagesource.cpp +++ b/src/client/imagesource.cpp @@ -566,7 +566,7 @@ static void apply_hue_saturation(video::IImage *dst, v2u32 dst_pos, v2u32 size, for (u32 x = dst_pos.X; x < dst_pos.X + size.X; x++) { if (colorize) { - f32 lum = dst->getPixel(x, y).getLuminance() / 255.0f; + f32 lum = dst->getPixel(x, y).getBrightness() / 255.0f; if (norm_l < 0) { lum *= norm_l + 1.0f; From a8ea1650425f83a7573314effae061823ff52de8 Mon Sep 17 00:00:00 2001 From: veprogames <75524847+veprogames@users.noreply.github.com> Date: Mon, 18 Nov 2024 00:04:32 +0100 Subject: [PATCH 070/136] Replace occurences of 'wiki.minetest.net' with 'wiki.luanti.org' --- README.md | 2 +- builtin/mainmenu/settings/generate_from_settingtypes.lua | 2 +- doc/android.md | 2 +- doc/developing/README.md | 2 +- minetest.conf.example | 2 +- misc/net.minetest.minetest.metainfo.xml | 4 ++-- src/server.cpp | 2 +- src/serverenvironment.cpp | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index b21153d54..aa8faccd5 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Table of Contents Further documentation ---------------------- - Website: https://www.luanti.org/ -- Wiki: https://wiki.minetest.net/ +- Wiki: https://wiki.luanti.org/ - Forum: https://forum.luanti.org/ - GitHub: https://github.com/minetest/minetest/ - [Developer documentation](doc/developing/) diff --git a/builtin/mainmenu/settings/generate_from_settingtypes.lua b/builtin/mainmenu/settings/generate_from_settingtypes.lua index 198037776..52dfe71b1 100644 --- a/builtin/mainmenu/settings/generate_from_settingtypes.lua +++ b/builtin/mainmenu/settings/generate_from_settingtypes.lua @@ -16,7 +16,7 @@ local minetest_example_header = [[ # to the program, eg. "luanti.exe --config ../minetest.conf.example". # Further documentation: -# https://wiki.minetest.net/ +# https://wiki.luanti.org/ ]] diff --git a/doc/android.md b/doc/android.md index 65cc0440c..353a7d1c8 100644 --- a/doc/android.md +++ b/doc/android.md @@ -42,7 +42,7 @@ configuration file can usually be found at: * After 5.4.2: * `/sdcard/Android/data/net.minetest.minetest/` or `/storage/emulated/0/Android/data/net.minetest.minetest/` if stored on the device * `/storage/emulated/(varying folder name)/Android/data/net.minetest.minetest/` if stored on the SD card -* [Learn more about Android directory](https://wiki.minetest.net/Accessing_Android_Data_Directory) +* [Learn more about Android directory](https://wiki.luanti.org/Accessing_Android_Data_Directory) ## Useful settings diff --git a/doc/developing/README.md b/doc/developing/README.md index 7e84de904..1aa424b00 100644 --- a/doc/developing/README.md +++ b/doc/developing/README.md @@ -23,4 +23,4 @@ Notable pages: Oftentimes knowledge hasn't been written down (yet) and your best bet is to ask someone experienced and/or the core developers. -Feel free to join the [#minetest-dev IRC](https://wiki.minetest.net/IRC) and ask questions related to **engine development**. +Feel free to join the [#minetest-dev IRC](https://wiki.luanti.org/IRC) and ask questions related to **engine development**. diff --git a/minetest.conf.example b/minetest.conf.example index 6e3e698be..f5fefbcf3 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -10,7 +10,7 @@ # to the program, eg. "luanti.exe --config ../minetest.conf.example". # Further documentation: -# https://wiki.minetest.net/ +# https://wiki.luanti.org/ # # Controls diff --git a/misc/net.minetest.minetest.metainfo.xml b/misc/net.minetest.minetest.metainfo.xml index ca61fe80c..9e7d927f1 100644 --- a/misc/net.minetest.minetest.metainfo.xml +++ b/misc/net.minetest.minetest.metainfo.xml @@ -135,8 +135,8 @@ https://www.minetest.net/get-involved/#reporting-issues https://dev.minetest.net/Translation https://www.minetest.net/get-involved/#donate - https://wiki.minetest.net/FAQ - https://wiki.minetest.net + https://wiki.luanti.org/FAQ + https://wiki.luanti.org https://github.com/minetest/minetest https://www.minetest.net/get-involved diff --git a/src/server.cpp b/src/server.cpp index a636364ed..d2aaf3432 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -4191,7 +4191,7 @@ ModStorageDatabase *Server::openModStorageDatabase(const std::string &world_path warningstream << "/!\\ You are using the old mod storage files backend. " << "This backend is deprecated and may be removed in a future release /!\\" << std::endl << "Switching to SQLite3 is advised, " - << "please read http://wiki.minetest.net/Database_backends." << std::endl; + << "please read https://wiki.luanti.org/Database_backends." << std::endl; return openModStorageDatabase(backend, world_path, world_mt); } diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index d60e41ad9..44645ca34 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -526,14 +526,14 @@ void ServerEnvironment::init() warningstream << "/!\\ You are using old player file backend. " << "This backend is deprecated and will be removed in a future release /!\\" << std::endl << "Switching to SQLite3 or PostgreSQL is advised, " - << "please read http://wiki.minetest.net/Database_backends." << std::endl; + << "please read https://wiki.luanti.org/Database_backends." << std::endl; } if (auth_backend_name == "files") { warningstream << "/!\\ You are using old auth file backend. " << "This backend is deprecated and will be removed in a future release /!\\" << std::endl << "Switching to SQLite3 is advised, " - << "please read http://wiki.minetest.net/Database_backends." << std::endl; + << "please read https://wiki.luanti.org/Database_backends." << std::endl; } m_player_database = openPlayerDatabase(player_backend_name, world_path, conf); From 9b6a3990117c3e226031b8ad6a3679a35bc7ee6a Mon Sep 17 00:00:00 2001 From: grorp Date: Mon, 18 Nov 2024 14:06:48 +0100 Subject: [PATCH 071/136] Implement support for FSAA in combination with post-processing (#15392) - Actually it's MSAA I think, or perhaps the terms are equivalent - I've made it fit into the existing Irrlicht architecture, but that has resulted in code duplication compared to my original "hacky" approach - OpenGL 3.2+ and OpenGL ES 3.1+ are supported - EDT_OPENGL3 is not required, EDT_OPENGL works too - Helpful tutorial: https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing, section "Off-screen MSAA" - This may be rough around the edges, but in general it works --- builtin/settingtypes.txt | 6 ++-- irr/include/EDriverFeatures.h | 3 ++ irr/include/IRenderTarget.h | 1 + irr/include/ITexture.h | 3 ++ irr/include/IVideoDriver.h | 12 +++++++ irr/src/CNullDriver.cpp | 6 ++++ irr/src/CNullDriver.h | 6 ++++ irr/src/COpenGLCoreCacheHandler.h | 15 ++++++--- irr/src/COpenGLCoreRenderTarget.h | 44 +++++++++++++++++++----- irr/src/COpenGLCoreTexture.h | 50 +++++++++++++++++++++------ irr/src/COpenGLDriver.cpp | 35 +++++++++++++++++-- irr/src/COpenGLDriver.h | 5 +++ irr/src/COpenGLExtensionHandler.cpp | 2 ++ irr/src/OpenGL/Driver.cpp | 33 +++++++++++++++++- irr/src/OpenGL/Driver.h | 5 +++ irr/src/OpenGL/ExtensionHandler.h | 3 ++ irr/src/OpenGL3/Driver.cpp | 1 + irr/src/OpenGLES2/Driver.cpp | 1 + src/client/render/pipeline.cpp | 22 +++++++++--- src/client/render/pipeline.h | 8 +++-- src/client/render/secondstage.cpp | 52 +++++++++++++++++++++++++---- src/client/render/secondstage.h | 14 ++++++++ src/client/renderingengine.cpp | 5 ++- 23 files changed, 290 insertions(+), 42 deletions(-) diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index f8f1dec05..418e883d1 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -410,10 +410,12 @@ anisotropic_filter (Anisotropic filtering) bool false # * None - No antialiasing (default) # # * FSAA - Hardware-provided full-screen antialiasing -# (incompatible with Post Processing and Undersampling) # A.K.A multi-sample antialiasing (MSAA) # Smoothens out block edges but does not affect the insides of textures. -# A restart is required to change this option. +# +# If Post Processing is disabled, changing FSAA requires a restart. +# Also, if Post Processing is disabled, FSAA will not work together with +# undersampling or a non-default "3d_mode" setting. # # * FXAA - Fast approximate antialiasing # Applies a post-processing filter to detect and smoothen high-contrast edges. diff --git a/irr/include/EDriverFeatures.h b/irr/include/EDriverFeatures.h index bde2c7698..0a35161cf 100644 --- a/irr/include/EDriverFeatures.h +++ b/irr/include/EDriverFeatures.h @@ -129,6 +129,9 @@ enum E_VIDEO_DRIVER_FEATURE //! Support for clamping vertices beyond far-plane to depth instead of capping them. EVDF_DEPTH_CLAMP, + //! Support for multisample textures. + EVDF_TEXTURE_MULTISAMPLE, + //! Only used for counting the elements of this enum EVDF_COUNT }; diff --git a/irr/include/IRenderTarget.h b/irr/include/IRenderTarget.h index 1e70c1e06..85b9738dc 100644 --- a/irr/include/IRenderTarget.h +++ b/irr/include/IRenderTarget.h @@ -26,6 +26,7 @@ enum E_CUBE_SURFACE }; //! Interface of a Render Target. +/** This is a framebuffer object (FBO) in OpenGL. */ class IRenderTarget : public virtual IReferenceCounted { public: diff --git a/irr/include/ITexture.h b/irr/include/ITexture.h index 8760c9f2a..869a325e0 100644 --- a/irr/include/ITexture.h +++ b/irr/include/ITexture.h @@ -156,6 +156,9 @@ enum E_TEXTURE_TYPE //! 2D texture. ETT_2D, + //! 2D texture with multisampling. + ETT_2D_MS, + //! Cubemap texture. ETT_CUBEMAP }; diff --git a/irr/include/IVideoDriver.h b/irr/include/IVideoDriver.h index 035f5ad77..3d4deace5 100644 --- a/irr/include/IVideoDriver.h +++ b/irr/include/IVideoDriver.h @@ -273,6 +273,14 @@ public: virtual ITexture *addRenderTargetTexture(const core::dimension2d &size, const io::path &name = "rt", const ECOLOR_FORMAT format = ECF_UNKNOWN) = 0; + //! Adds a multisampled render target texture to the texture cache. + /** \param msaa The number of samples to use, values that make sense are > 1. + Only works if the driver supports the EVDF_TEXTURE_MULTISAMPLE feature, + check via queryFeature. + \see addRenderTargetTexture */ + virtual ITexture *addRenderTargetTextureMs(const core::dimension2d &size, u8 msaa, + const io::path &name = "rt", const ECOLOR_FORMAT format = ECF_UNKNOWN) = 0; + //! Adds a new render target texture with 6 sides for a cubemap map to the texture cache. /** \param sideLen Length of one cubemap side. \param name A name for the texture. Later calls of getTexture() with this name will return this texture. @@ -358,6 +366,10 @@ public: //! Remove all render targets. virtual void removeAllRenderTargets() = 0; + //! Blit contents of one render target to another one. + /** This is glBlitFramebuffer in OpenGL. */ + virtual void blitRenderTarget(IRenderTarget *from, IRenderTarget *to) = 0; + //! Sets a boolean alpha channel on the texture based on a color key. /** This makes the texture fully transparent at the texels where this color key can be found when using for example draw2DImage diff --git a/irr/src/CNullDriver.cpp b/irr/src/CNullDriver.cpp index acce8383b..b5da7ef29 100644 --- a/irr/src/CNullDriver.cpp +++ b/irr/src/CNullDriver.cpp @@ -1678,6 +1678,12 @@ ITexture *CNullDriver::addRenderTargetTexture(const core::dimension2d &size return 0; } +ITexture *CNullDriver::addRenderTargetTextureMs(const core::dimension2d &size, u8 msaa, + const io::path &name, const ECOLOR_FORMAT format) +{ + return 0; +} + ITexture *CNullDriver::addRenderTargetTextureCubemap(const irr::u32 sideLen, const io::path &name, const ECOLOR_FORMAT format) { diff --git a/irr/src/CNullDriver.h b/irr/src/CNullDriver.h index b8d45118f..5752b53cd 100644 --- a/irr/src/CNullDriver.h +++ b/irr/src/CNullDriver.h @@ -227,6 +227,10 @@ public: virtual ITexture *addRenderTargetTexture(const core::dimension2d &size, const io::path &name, const ECOLOR_FORMAT format = ECF_UNKNOWN) override; + //! Creates a multisampled render target texture. + virtual ITexture *addRenderTargetTextureMs(const core::dimension2d &size, u8 msaa, + const io::path &name, const ECOLOR_FORMAT format = ECF_UNKNOWN) override; + //! Creates a render target texture for a cubemap ITexture *addRenderTargetTextureCubemap(const irr::u32 sideLen, const io::path &name, const ECOLOR_FORMAT format) override; @@ -410,6 +414,8 @@ public: //! Create render target. IRenderTarget *addRenderTarget() override; + void blitRenderTarget(IRenderTarget *from, IRenderTarget *to) override {} + //! Remove render target. void removeRenderTarget(IRenderTarget *renderTarget) override; diff --git a/irr/src/COpenGLCoreCacheHandler.h b/irr/src/COpenGLCoreCacheHandler.h index a1277bfed..744511629 100644 --- a/irr/src/COpenGLCoreCacheHandler.h +++ b/irr/src/COpenGLCoreCacheHandler.h @@ -85,13 +85,19 @@ class COpenGLCoreCacheHandler GL.BindTexture(prevTextureType, 0); #if defined(IRR_COMPILE_GL_COMMON) - GL.Disable(prevTextureType); - GL.Enable(curTextureType); + // The "enable/disable texture" stuff is so legacy that + // it's not even allowed for multisample textures. + // (IRR_COMPILE_GL_COMMON is for the legacy driver.) + if (prevTextureType != GL_TEXTURE_2D_MULTISAMPLE) + GL.Disable(prevTextureType); + if (curTextureType != GL_TEXTURE_2D_MULTISAMPLE) + GL.Enable(curTextureType); #endif } #if defined(IRR_COMPILE_GL_COMMON) else if (!prevTexture) - GL.Enable(curTextureType); + if (curTextureType != GL_TEXTURE_2D_MULTISAMPLE) + GL.Enable(curTextureType); #endif GL.BindTexture(curTextureType, static_cast(texture)->getOpenGLTextureName()); @@ -110,7 +116,8 @@ class COpenGLCoreCacheHandler GL.BindTexture(prevTextureType, 0); #if defined(IRR_COMPILE_GL_COMMON) - GL.Disable(prevTextureType); + if (prevTextureType != GL_TEXTURE_2D_MULTISAMPLE) + GL.Disable(prevTextureType); #endif } diff --git a/irr/src/COpenGLCoreRenderTarget.h b/irr/src/COpenGLCoreRenderTarget.h index 6bfc98cc0..a174e926e 100644 --- a/irr/src/COpenGLCoreRenderTarget.h +++ b/irr/src/COpenGLCoreRenderTarget.h @@ -5,6 +5,7 @@ #pragma once #include "IRenderTarget.h" +#include #ifndef GL_FRAMEBUFFER_INCOMPLETE_FORMATS #define GL_FRAMEBUFFER_INCOMPLETE_FORMATS GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT @@ -122,7 +123,7 @@ public: TOpenGLTexture *currentTexture = (depthStencil && depthStencil->getDriverType() == DriverType) ? static_cast(depthStencil) : 0; if (currentTexture) { - if (currentTexture->getType() == ETT_2D) { + if (currentTexture->getType() == ETT_2D || currentTexture->getType() == ETT_2D_MS) { GLuint textureID = currentTexture->getOpenGLTextureName(); const ECOLOR_FORMAT textureFormat = (textureID != 0) ? depthStencil->getColorFormat() : ECF_UNKNOWN; @@ -172,7 +173,20 @@ public: if (textureID != 0) { AssignedTextures[i] = GL_COLOR_ATTACHMENT0 + i; - GLenum textarget = currentTexture->getType() == ETT_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_POSITIVE_X + (int)CubeSurfaces[i]; + GLenum textarget; + switch (currentTexture->getType()) { + case ETT_2D: + textarget = GL_TEXTURE_2D; + break; + case ETT_2D_MS: + textarget = GL_TEXTURE_2D_MULTISAMPLE; + break; + case ETT_CUBEMAP: + textarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + (int)CubeSurfaces[i]; + break; + default: + throw std::logic_error("not reachable"); + } Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, AssignedTextures[i], textarget, textureID, 0); TEST_GL_ERROR(Driver); } else if (AssignedTextures[i] != GL_NONE) { @@ -198,36 +212,50 @@ public: // Set depth and stencil attachments. if (RequestDepthStencilUpdate) { - const ECOLOR_FORMAT textureFormat = (DepthStencil) ? DepthStencil->getColorFormat() : ECF_UNKNOWN; + const ECOLOR_FORMAT textureFormat = DepthStencil ? DepthStencil->getColorFormat() : ECF_UNKNOWN; if (IImage::isDepthFormat(textureFormat)) { + GLenum textarget; + switch (DepthStencil->getType()) { + case ETT_2D: + textarget = GL_TEXTURE_2D; + break; + case ETT_2D_MS: + textarget = GL_TEXTURE_2D_MULTISAMPLE; + break; + default: + // ETT_CUBEMAP is rejected for depth/stencil by setTextures + throw std::logic_error("not reachable"); + } + GLuint textureID = static_cast(DepthStencil)->getOpenGLTextureName(); #ifdef _IRR_EMSCRIPTEN_PLATFORM_ // The WEBGL_depth_texture extension does not allow attaching stencil+depth separate. if (textureFormat == ECF_D24S8) { GLenum attachment = 0x821A; // GL_DEPTH_STENCIL_ATTACHMENT - Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, textureID, 0); + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, attachment, textarget, textureID, 0); AssignedStencil = true; } else { - Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textureID, 0); + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, textarget, textureID, 0); AssignedStencil = false; } #else - Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, textureID, 0); + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, textarget, textureID, 0); if (textureFormat == ECF_D24S8) { - Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, textureID, 0); + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, textarget, textureID, 0); AssignedStencil = true; } else { if (AssignedStencil) - Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); + Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, textarget, 0, 0); AssignedStencil = false; } #endif AssignedDepth = true; } else { + // No (valid) depth/stencil texture. if (AssignedDepth) Driver->irrGlFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0); diff --git a/irr/src/COpenGLCoreTexture.h b/irr/src/COpenGLCoreTexture.h index 35c8f472a..a37562543 100644 --- a/irr/src/COpenGLCoreTexture.h +++ b/irr/src/COpenGLCoreTexture.h @@ -45,12 +45,13 @@ public: COpenGLCoreTexture(const io::path &name, const std::vector &srcImages, E_TEXTURE_TYPE type, TOpenGLDriver *driver) : ITexture(name, type), Driver(driver), TextureType(GL_TEXTURE_2D), - TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_RGBA), PixelType(GL_UNSIGNED_BYTE), Converter(0), LockReadOnly(false), LockImage(0), LockLayer(0), + TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_RGBA), PixelType(GL_UNSIGNED_BYTE), MSAA(0), Converter(0), LockReadOnly(false), LockImage(0), LockLayer(0), KeepImage(false), MipLevelStored(0), LegacyAutoGenerateMipMaps(false) { _IRR_DEBUG_BREAK_IF(srcImages.empty()) DriverType = Driver->getDriverType(); + _IRR_DEBUG_BREAK_IF(Type == ETT_2D_MS); // not supported by this constructor TextureType = TextureTypeIrrToGL(Type); HasMipMaps = Driver->getTextureCreationFlag(ETCF_CREATE_MIP_MAPS); KeepImage = Driver->getTextureCreationFlag(ETCF_ALLOW_MEMORY_COPY); @@ -141,10 +142,10 @@ public: TEST_GL_ERROR(Driver); } - COpenGLCoreTexture(const io::path &name, const core::dimension2d &size, E_TEXTURE_TYPE type, ECOLOR_FORMAT format, TOpenGLDriver *driver) : + COpenGLCoreTexture(const io::path &name, const core::dimension2d &size, E_TEXTURE_TYPE type, ECOLOR_FORMAT format, TOpenGLDriver *driver, u8 msaa = 0) : ITexture(name, type), Driver(driver), TextureType(GL_TEXTURE_2D), - TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_RGBA), PixelType(GL_UNSIGNED_BYTE), Converter(0), LockReadOnly(false), LockImage(0), LockLayer(0), KeepImage(false), + TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_RGBA), PixelType(GL_UNSIGNED_BYTE), MSAA(msaa), Converter(0), LockReadOnly(false), LockImage(0), LockLayer(0), KeepImage(false), MipLevelStored(0), LegacyAutoGenerateMipMaps(false) { DriverType = Driver->getDriverType(); @@ -184,23 +185,47 @@ public: const COpenGLCoreTexture *prevTexture = Driver->getCacheHandler()->getTextureCache().get(0); Driver->getCacheHandler()->getTextureCache().set(0, this); - GL.TexParameteri(TextureType, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - GL.TexParameteri(TextureType, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - GL.TexParameteri(TextureType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - GL.TexParameteri(TextureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // An INVALID_ENUM error is generated by TexParameter* if target is either + // TEXTURE_2D_MULTISAMPLE or TEXTURE_2D_MULTISAMPLE_ARRAY, and pname is any + // sampler state from table 23.18. + // ~ https://registry.khronos.org/OpenGL/specs/gl/glspec46.core.pdf + if (Type != ETT_2D_MS) { + GL.TexParameteri(TextureType, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + GL.TexParameteri(TextureType, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + GL.TexParameteri(TextureType, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + GL.TexParameteri(TextureType, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); #if defined(GL_VERSION_1_2) - GL.TexParameteri(TextureType, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + GL.TexParameteri(TextureType, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); #endif - StatesCache.WrapU = ETC_CLAMP_TO_EDGE; - StatesCache.WrapV = ETC_CLAMP_TO_EDGE; - StatesCache.WrapW = ETC_CLAMP_TO_EDGE; + StatesCache.WrapU = ETC_CLAMP_TO_EDGE; + StatesCache.WrapV = ETC_CLAMP_TO_EDGE; + StatesCache.WrapW = ETC_CLAMP_TO_EDGE; + } switch (Type) { case ETT_2D: GL.TexImage2D(GL_TEXTURE_2D, 0, InternalFormat, Size.Width, Size.Height, 0, PixelFormat, PixelType, 0); break; + case ETT_2D_MS: { + // glTexImage2DMultisample is supported by OpenGL 3.2+ + // glTexStorage2DMultisample is supported by OpenGL 4.3+ and OpenGL ES 3.1+ +#ifdef IRR_COMPILE_GL_COMMON // legacy driver + constexpr bool use_gl_impl = true; +#else + const bool use_gl_impl = Driver->Version.Spec != OpenGLSpec::ES; +#endif + GLint max_samples = 0; + GL.GetIntegerv(GL_MAX_SAMPLES, &max_samples); + MSAA = std::min(MSAA, (u8)max_samples); + + if (use_gl_impl) + GL.TexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, MSAA, InternalFormat, Size.Width, Size.Height, GL_TRUE); + else + GL.TexStorage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, MSAA, InternalFormat, Size.Width, Size.Height, GL_TRUE); + break; + } case ETT_CUBEMAP: GL.TexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, InternalFormat, Size.Width, Size.Height, 0, PixelFormat, PixelType, 0); GL.TexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, InternalFormat, Size.Width, Size.Height, 0, PixelFormat, PixelType, 0); @@ -595,6 +620,8 @@ protected: switch (type) { case ETT_2D: return GL_TEXTURE_2D; + case ETT_2D_MS: + return GL_TEXTURE_2D_MULTISAMPLE; case ETT_CUBEMAP: return GL_TEXTURE_CUBE_MAP; } @@ -610,6 +637,7 @@ protected: GLint InternalFormat; GLenum PixelFormat; GLenum PixelType; + u8 MSAA; void (*Converter)(const void *, s32, void *); bool LockReadOnly; diff --git a/irr/src/COpenGLDriver.cpp b/irr/src/COpenGLDriver.cpp index 2cbf6d8e6..07d7f7bb1 100644 --- a/irr/src/COpenGLDriver.cpp +++ b/irr/src/COpenGLDriver.cpp @@ -651,6 +651,29 @@ IRenderTarget *COpenGLDriver::addRenderTarget() return renderTarget; } +void COpenGLDriver::blitRenderTarget(IRenderTarget *from, IRenderTarget *to) +{ + if (Version < 300) { + os::Printer::log("glBlitFramebuffer not supported by OpenGL < 3.0", ELL_ERROR); + return; + } + + GLuint prev_fbo_id; + CacheHandler->getFBO(prev_fbo_id); + + COpenGLRenderTarget *src = static_cast(from); + COpenGLRenderTarget *dst = static_cast(to); + GL.BindFramebuffer(GL.READ_FRAMEBUFFER, src->getBufferID()); + GL.BindFramebuffer(GL.DRAW_FRAMEBUFFER, dst->getBufferID()); + GL.BlitFramebuffer( + 0, 0, src->getSize().Width, src->getSize().Height, + 0, 0, dst->getSize().Width, dst->getSize().Height, + GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT | GL.STENCIL_BUFFER_BIT, GL.NEAREST); + + // This resets both read and draw framebuffer. Note that we bypass CacheHandler here. + GL.BindFramebuffer(GL.FRAMEBUFFER, prev_fbo_id); +} + // small helper function to create vertex buffer object address offsets static inline const GLvoid *buffer_offset(const size_t offset) { @@ -2091,7 +2114,9 @@ void COpenGLDriver::setBasicRenderStates(const SMaterial &material, const SMater else if (lastmaterial.AntiAliasing & EAAM_ALPHA_TO_COVERAGE) glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); - if ((AntiAlias >= 2) && (material.AntiAliasing & (EAAM_SIMPLE | EAAM_QUALITY))) { + // Enable MSAA even if it's not enabled in the OpenGL context, we might + // be rendering to an FBO with multisampling. + if (material.AntiAliasing & (EAAM_SIMPLE | EAAM_QUALITY)) { glEnable(GL_MULTISAMPLE_ARB); #ifdef GL_NV_multisample_filter_hint if (FeatureAvailable[IRR_NV_multisample_filter_hint]) { @@ -2694,6 +2719,12 @@ IVideoDriver *COpenGLDriver::getVideoDriver() ITexture *COpenGLDriver::addRenderTargetTexture(const core::dimension2d &size, const io::path &name, const ECOLOR_FORMAT format) +{ + return addRenderTargetTextureMs(size, 0, name, format); +} + +ITexture *COpenGLDriver::addRenderTargetTextureMs(const core::dimension2d &size, u8 msaa, + const io::path &name, const ECOLOR_FORMAT format) { if (IImage::isCompressedFormat(format)) return 0; @@ -2711,7 +2742,7 @@ ITexture *COpenGLDriver::addRenderTargetTexture(const core::dimension2d &si destSize = destSize.getOptimalSize((size == size.getOptimalSize()), false, false); } - COpenGLTexture *renderTargetTexture = new COpenGLTexture(name, destSize, ETT_2D, format, this); + COpenGLTexture *renderTargetTexture = new COpenGLTexture(name, destSize, msaa > 0 ? ETT_2D_MS : ETT_2D, format, this, msaa); addTexture(renderTargetTexture); renderTargetTexture->drop(); diff --git a/irr/src/COpenGLDriver.h b/irr/src/COpenGLDriver.h index 9c4ecd3b3..126f7aadc 100644 --- a/irr/src/COpenGLDriver.h +++ b/irr/src/COpenGLDriver.h @@ -108,6 +108,8 @@ public: //! Create render target. IRenderTarget *addRenderTarget() override; + void blitRenderTarget(IRenderTarget *from, IRenderTarget *to) override; + //! draws a vertex primitive list virtual void drawVertexPrimitiveList(const void *vertices, u32 vertexCount, const void *indexList, u32 primitiveCount, @@ -270,6 +272,9 @@ public: virtual ITexture *addRenderTargetTexture(const core::dimension2d &size, const io::path &name, const ECOLOR_FORMAT format = ECF_UNKNOWN) override; + virtual ITexture *addRenderTargetTextureMs(const core::dimension2d &size, u8 msaa, + const io::path &name = "rt", const ECOLOR_FORMAT format = ECF_UNKNOWN) override; + //! Creates a render target texture for a cubemap ITexture *addRenderTargetTextureCubemap(const irr::u32 sideLen, const io::path &name, const ECOLOR_FORMAT format) override; diff --git a/irr/src/COpenGLExtensionHandler.cpp b/irr/src/COpenGLExtensionHandler.cpp index a20932c8f..4c7fe69b7 100644 --- a/irr/src/COpenGLExtensionHandler.cpp +++ b/irr/src/COpenGLExtensionHandler.cpp @@ -612,6 +612,8 @@ bool COpenGLExtensionHandler::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const return FeatureAvailable[IRR_ARB_seamless_cube_map]; case EVDF_DEPTH_CLAMP: return FeatureAvailable[IRR_NV_depth_clamp] || FeatureAvailable[IRR_ARB_depth_clamp]; + case EVDF_TEXTURE_MULTISAMPLE: + return (Version >= 302) || FeatureAvailable[IRR_ARB_texture_multisample]; default: return false; diff --git a/irr/src/OpenGL/Driver.cpp b/irr/src/OpenGL/Driver.cpp index 4b85b1345..ee272ceee 100644 --- a/irr/src/OpenGL/Driver.cpp +++ b/irr/src/OpenGL/Driver.cpp @@ -675,6 +675,29 @@ IRenderTarget *COpenGL3DriverBase::addRenderTarget() return renderTarget; } +void COpenGL3DriverBase::blitRenderTarget(IRenderTarget *from, IRenderTarget *to) +{ + if (Version.Spec == OpenGLSpec::ES && Version.Major < 3) { + os::Printer::log("glBlitFramebuffer not supported by OpenGL ES < 3.0", ELL_ERROR); + return; + } + + GLuint prev_fbo_id; + CacheHandler->getFBO(prev_fbo_id); + + COpenGL3RenderTarget *src = static_cast(from); + COpenGL3RenderTarget *dst = static_cast(to); + GL.BindFramebuffer(GL.READ_FRAMEBUFFER, src->getBufferID()); + GL.BindFramebuffer(GL.DRAW_FRAMEBUFFER, dst->getBufferID()); + GL.BlitFramebuffer( + 0, 0, src->getSize().Width, src->getSize().Height, + 0, 0, dst->getSize().Width, dst->getSize().Height, + GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT | GL.STENCIL_BUFFER_BIT, GL.NEAREST); + + // This resets both read and draw framebuffer. Note that we bypass CacheHandler here. + GL.BindFramebuffer(GL.FRAMEBUFFER, prev_fbo_id); +} + //! draws a vertex primitive list void COpenGL3DriverBase::drawVertexPrimitiveList(const void *vertices, u32 vertexCount, const void *indexList, u32 primitiveCount, @@ -1317,6 +1340,8 @@ void COpenGL3DriverBase::setBasicRenderStates(const SMaterial &material, const S GL.LineWidth(core::clamp(static_cast(material.Thickness), DimAliasedLine[0], DimAliasedLine[1])); // Anti aliasing + // Deal with MSAA even if it's not enabled in the OpenGL context, we might be + // rendering to an FBO with multisampling. if (resetAllRenderStates || lastmaterial.AntiAliasing != material.AntiAliasing) { if (material.AntiAliasing & EAAM_ALPHA_TO_COVERAGE) GL.Enable(GL_SAMPLE_ALPHA_TO_COVERAGE); @@ -1631,12 +1656,18 @@ IGPUProgrammingServices *COpenGL3DriverBase::getGPUProgrammingServices() ITexture *COpenGL3DriverBase::addRenderTargetTexture(const core::dimension2d &size, const io::path &name, const ECOLOR_FORMAT format) +{ + return addRenderTargetTextureMs(size, 0, name, format); +} + +ITexture *COpenGL3DriverBase::addRenderTargetTextureMs(const core::dimension2d &size, u8 msaa, + const io::path &name, const ECOLOR_FORMAT format) { // disable mip-mapping bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS); setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, false); - COpenGL3Texture *renderTargetTexture = new COpenGL3Texture(name, size, ETT_2D, format, this); + COpenGL3Texture *renderTargetTexture = new COpenGL3Texture(name, size, msaa > 0 ? ETT_2D_MS : ETT_2D, format, this, msaa); addTexture(renderTargetTexture); renderTargetTexture->drop(); diff --git a/irr/src/OpenGL/Driver.h b/irr/src/OpenGL/Driver.h index 3104b164d..f00ffa8af 100644 --- a/irr/src/OpenGL/Driver.h +++ b/irr/src/OpenGL/Driver.h @@ -74,6 +74,8 @@ public: IRenderTarget *addRenderTarget() override; + void blitRenderTarget(IRenderTarget *from, IRenderTarget *to) override; + //! draws a vertex primitive list virtual void drawVertexPrimitiveList(const void *vertices, u32 vertexCount, const void *indexList, u32 primitiveCount, @@ -209,6 +211,9 @@ public: virtual ITexture *addRenderTargetTexture(const core::dimension2d &size, const io::path &name, const ECOLOR_FORMAT format = ECF_UNKNOWN) override; + virtual ITexture *addRenderTargetTextureMs(const core::dimension2d &size, u8 msaa, + const io::path &name, const ECOLOR_FORMAT format = ECF_UNKNOWN) override; + //! Creates a render target texture for a cubemap ITexture *addRenderTargetTextureCubemap(const irr::u32 sideLen, const io::path &name, const ECOLOR_FORMAT format) override; diff --git a/irr/src/OpenGL/ExtensionHandler.h b/irr/src/OpenGL/ExtensionHandler.h index 8f76c0eea..403b828b3 100644 --- a/irr/src/OpenGL/ExtensionHandler.h +++ b/irr/src/OpenGL/ExtensionHandler.h @@ -74,6 +74,8 @@ public: return false; case EVDF_STENCIL_BUFFER: return StencilBuffer; + case EVDF_TEXTURE_MULTISAMPLE: + return TextureMultisampleSupported; default: return false; }; @@ -161,6 +163,7 @@ public: bool AnisotropicFilterSupported = false; bool BlendMinMaxSupported = false; + bool TextureMultisampleSupported = false; }; } diff --git a/irr/src/OpenGL3/Driver.cpp b/irr/src/OpenGL3/Driver.cpp index ac0816445..b397846aa 100644 --- a/irr/src/OpenGL3/Driver.cpp +++ b/irr/src/OpenGL3/Driver.cpp @@ -69,6 +69,7 @@ void COpenGL3Driver::initFeatures() AnisotropicFilterSupported = isVersionAtLeast(4, 6) || queryExtension("GL_ARB_texture_filter_anisotropic") || queryExtension("GL_EXT_texture_filter_anisotropic"); BlendMinMaxSupported = true; + TextureMultisampleSupported = true; // COGLESCoreExtensionHandler::Feature static_assert(MATERIAL_MAX_TEXTURES <= 16, "Only up to 16 textures are guaranteed"); diff --git a/irr/src/OpenGLES2/Driver.cpp b/irr/src/OpenGLES2/Driver.cpp index 430be736d..3c034522c 100644 --- a/irr/src/OpenGLES2/Driver.cpp +++ b/irr/src/OpenGLES2/Driver.cpp @@ -124,6 +124,7 @@ void COpenGLES2Driver::initFeatures() const bool MRTSupported = Version.Major >= 3 || queryExtension("GL_EXT_draw_buffers"); AnisotropicFilterSupported = queryExtension("GL_EXT_texture_filter_anisotropic"); BlendMinMaxSupported = (Version.Major >= 3) || FeatureAvailable[IRR_GL_EXT_blend_minmax]; + TextureMultisampleSupported = isVersionAtLeast(3, 1); const bool TextureLODBiasSupported = queryExtension("GL_EXT_texture_lod_bias"); // COGLESCoreExtensionHandler::Feature diff --git a/src/client/render/pipeline.cpp b/src/client/render/pipeline.cpp index a37fd32fd..d24aa3ce8 100644 --- a/src/client/render/pipeline.cpp +++ b/src/client/render/pipeline.cpp @@ -26,7 +26,7 @@ video::ITexture *TextureBuffer::getTexture(u8 index) } -void TextureBuffer::setTexture(u8 index, core::dimension2du size, const std::string &name, video::ECOLOR_FORMAT format, bool clear) +void TextureBuffer::setTexture(u8 index, core::dimension2du size, const std::string &name, video::ECOLOR_FORMAT format, bool clear, u8 msaa) { assert(index != NO_DEPTH_TEXTURE); @@ -41,9 +41,10 @@ void TextureBuffer::setTexture(u8 index, core::dimension2du size, const std::str definition.name = name; definition.format = format; definition.clear = clear; + definition.msaa = msaa; } -void TextureBuffer::setTexture(u8 index, v2f scale_factor, const std::string &name, video::ECOLOR_FORMAT format, bool clear) +void TextureBuffer::setTexture(u8 index, v2f scale_factor, const std::string &name, video::ECOLOR_FORMAT format, bool clear, u8 msaa) { assert(index != NO_DEPTH_TEXTURE); @@ -58,6 +59,7 @@ void TextureBuffer::setTexture(u8 index, v2f scale_factor, const std::string &na definition.name = name; definition.format = format; definition.clear = clear; + definition.msaa = msaa; } void TextureBuffer::reset(PipelineContext &context) @@ -125,13 +127,19 @@ bool TextureBuffer::ensureTexture(video::ITexture **texture, const TextureDefini if (definition.valid) { if (definition.clear) { + // We're not able to clear a render target texture + // We're not able to create a normal texture with MSAA + // (could be solved by more refactoring in Irrlicht, but not needed for now) + sanity_check(definition.msaa < 1); + video::IImage *image = m_driver->createImage(definition.format, size); // Cannot use image->fill because it's not implemented for all formats. std::memset(image->getData(), 0, image->getDataSizeFromFormat(definition.format, size.Width, size.Height)); *texture = m_driver->addTexture(definition.name.c_str(), image); image->drop(); - } - else { + } else if (definition.msaa > 0) { + *texture = m_driver->addRenderTargetTextureMs(size, definition.msaa, definition.name.c_str(), definition.format); + } else { *texture = m_driver->addRenderTargetTexture(size, definition.name.c_str(), definition.format); } } @@ -189,6 +197,12 @@ void TextureBufferOutput::activate(PipelineContext &context) RenderTarget::activate(context); } +video::IRenderTarget *TextureBufferOutput::getIrrRenderTarget(PipelineContext &context) +{ + activate(context); // Needed to make sure that render_target is set up. + return render_target; +} + u8 DynamicSource::getTextureCount() { assert(isConfigured()); diff --git a/src/client/render/pipeline.h b/src/client/render/pipeline.h index 9fa47c329..17bed8b7b 100644 --- a/src/client/render/pipeline.h +++ b/src/client/render/pipeline.h @@ -117,7 +117,7 @@ public: * @param name unique name of the texture * @param format color format */ - void setTexture(u8 index, core::dimension2du size, const std::string& name, video::ECOLOR_FORMAT format, bool clear = false); + void setTexture(u8 index, core::dimension2du size, const std::string& name, video::ECOLOR_FORMAT format, bool clear = false, u8 msaa = 0); /** * Configure relative-size texture for the specific index @@ -127,7 +127,7 @@ public: * @param name unique name of the texture * @param format color format */ - void setTexture(u8 index, v2f scale_factor, const std::string& name, video::ECOLOR_FORMAT format, bool clear = false); + void setTexture(u8 index, v2f scale_factor, const std::string& name, video::ECOLOR_FORMAT format, bool clear = false, u8 msaa = 0); virtual u8 getTextureCount() override { return m_textures.size(); } virtual video::ITexture *getTexture(u8 index) override; @@ -146,6 +146,7 @@ private: core::dimension2du size; std::string name; video::ECOLOR_FORMAT format; + u8 msaa; }; /** @@ -174,6 +175,9 @@ public: TextureBufferOutput(TextureBuffer *buffer, const std::vector &texture_map, u8 depth_stencil); virtual ~TextureBufferOutput() override; void activate(PipelineContext &context) override; + + video::IRenderTarget *getIrrRenderTarget(PipelineContext &context); + private: static const u8 NO_DEPTH_TEXTURE = 255; diff --git a/src/client/render/secondstage.cpp b/src/client/render/secondstage.cpp index 26ce6888e..f6a0cf78e 100644 --- a/src/client/render/secondstage.cpp +++ b/src/client/render/secondstage.cpp @@ -9,6 +9,7 @@ #include "client/shader.h" #include "client/tile.h" #include "settings.h" +#include "mt_opengl.h" PostProcessingStep::PostProcessingStep(u32 _shader_id, const std::vector &_texture_map) : shader_id(_shader_id), texture_map(_texture_map) @@ -102,21 +103,45 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep static const u8 TEXTURE_EXPOSURE_2 = 4; static const u8 TEXTURE_FXAA = 5; static const u8 TEXTURE_VOLUME = 6; + + static const u8 TEXTURE_MSAA_COLOR = 7; + static const u8 TEXTURE_MSAA_DEPTH = 8; + static const u8 TEXTURE_SCALE_DOWN = 10; static const u8 TEXTURE_SCALE_UP = 20; - // Super-sampling is simply rendering into a larger texture. - // Downscaling is done by the final step when rendering to the screen. - const std::string antialiasing = g_settings->get("antialiasing"); const bool enable_bloom = g_settings->getBool("enable_bloom"); + const bool enable_volumetric_light = g_settings->getBool("enable_volumetric_lighting") && enable_bloom; const bool enable_auto_exposure = g_settings->getBool("enable_auto_exposure"); + + const std::string antialiasing = g_settings->get("antialiasing"); + const u16 antialiasing_scale = MYMAX(2, g_settings->getU16("fsaa")); + + // This code only deals with MSAA in combination with post-processing. MSAA without + // post-processing works via a flag at OpenGL context creation instead. + // To make MSAA work with post-processing, we need multisample texture support, + // which has higher OpenGL (ES) version requirements. + // Note: This is not about renderbuffer objects, but about textures, + // since that's what we use and what Irrlicht allows us to use. + + const bool msaa_available = driver->queryFeature(video::EVDF_TEXTURE_MULTISAMPLE); + const bool enable_msaa = antialiasing == "fsaa" && msaa_available; + if (antialiasing == "fsaa" && !msaa_available) + warningstream << "Ignoring configured FSAA. FSAA is not supported in " + << "combination with post-processing by the current video driver." << std::endl; + const bool enable_ssaa = antialiasing == "ssaa"; const bool enable_fxaa = antialiasing == "fxaa"; - const bool enable_volumetric_light = g_settings->getBool("enable_volumetric_lighting") && enable_bloom; + // Super-sampling is simply rendering into a larger texture. + // Downscaling is done by the final step when rendering to the screen. if (enable_ssaa) { - u16 ssaa_scale = MYMAX(2, g_settings->getU16("fsaa")); - scale *= ssaa_scale; + scale *= antialiasing_scale; + } + + if (enable_msaa) { + buffer->setTexture(TEXTURE_MSAA_COLOR, scale, "3d_render_msaa", color_format, false, antialiasing_scale); + buffer->setTexture(TEXTURE_MSAA_DEPTH, scale, "3d_depthmap_msaa", depth_format, false, antialiasing_scale); } buffer->setTexture(TEXTURE_COLOR, scale, "3d_render", color_format); @@ -125,7 +150,14 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep buffer->setTexture(TEXTURE_DEPTH, scale, "3d_depthmap", depth_format); // attach buffer to the previous step - previousStep->setRenderTarget(pipeline->createOwned(buffer, std::vector { TEXTURE_COLOR }, TEXTURE_DEPTH)); + if (enable_msaa) { + TextureBufferOutput *msaa = pipeline->createOwned(buffer, std::vector { TEXTURE_MSAA_COLOR }, TEXTURE_MSAA_DEPTH); + previousStep->setRenderTarget(msaa); + TextureBufferOutput *normal = pipeline->createOwned(buffer, std::vector { TEXTURE_COLOR }, TEXTURE_DEPTH); + pipeline->addStep(msaa, normal); + } else { + previousStep->setRenderTarget(pipeline->createOwned(buffer, std::vector { TEXTURE_COLOR }, TEXTURE_DEPTH)); + } // shared variables u32 shader_id; @@ -234,3 +266,9 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep return effect; } + +void ResolveMSAAStep::run(PipelineContext &context) +{ + context.device->getVideoDriver()->blitRenderTarget(msaa_fbo->getIrrRenderTarget(context), + target_fbo->getIrrRenderTarget(context)); +} diff --git a/src/client/render/secondstage.h b/src/client/render/secondstage.h index 6b0e42289..1765a5ed8 100644 --- a/src/client/render/secondstage.h +++ b/src/client/render/secondstage.h @@ -44,4 +44,18 @@ private: void configureMaterial(); }; + +class ResolveMSAAStep : public TrivialRenderStep +{ +public: + ResolveMSAAStep(TextureBufferOutput *_msaa_fbo, TextureBufferOutput *_target_fbo) : + msaa_fbo(_msaa_fbo), target_fbo(_target_fbo) {}; + void run(PipelineContext &context) override; + +private: + TextureBufferOutput *msaa_fbo; + TextureBufferOutput *target_fbo; +}; + + RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep, v2f scale, Client *client); diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp index 4e45bd4cd..c3cb49eed 100644 --- a/src/client/renderingengine.cpp +++ b/src/client/renderingengine.cpp @@ -179,7 +179,10 @@ RenderingEngine::RenderingEngine(MyEventReceiver *receiver) // bpp, fsaa, vsync bool vsync = g_settings->getBool("vsync"); - bool enable_fsaa = g_settings->get("antialiasing") == "fsaa"; + // Don't enable MSAA in OpenGL context creation if post-processing is enabled, + // the post-processing pipeline handles it. + bool enable_fsaa = g_settings->get("antialiasing") == "fsaa" && + !g_settings->getBool("enable_post_processing"); u16 fsaa = enable_fsaa ? MYMAX(2, g_settings->getU16("fsaa")) : 0; // Determine driver From f493e73aeb65a0f4f4ad8a93ef4f4dbf197d606d Mon Sep 17 00:00:00 2001 From: sfan5 Date: Mon, 18 Nov 2024 23:58:42 +0100 Subject: [PATCH 072/136] Fix changing secure settings from mainmenu forgotten in ea4ae55e24d2c27524490cb8e0d3c34aa46e3da3 closes #15454 --- src/script/lua_api/l_settings.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/script/lua_api/l_settings.cpp b/src/script/lua_api/l_settings.cpp index f3f1a57bf..c4395e390 100644 --- a/src/script/lua_api/l_settings.cpp +++ b/src/script/lua_api/l_settings.cpp @@ -12,11 +12,12 @@ #include "log.h" -/* This protects the following from being set: - * 'secure.*' settings - * some security-relevant settings +/* + * This protects the following from being set: + * - 'secure.*' settings + * - some security-relevant settings * (better solution pending) - * some mapgen settings + * - some mapgen settings * (not security-criticial, just to avoid messing up user configs) */ #define CHECK_SETTING_SECURITY(L, name) \ @@ -27,14 +28,16 @@ static inline int checkSettingSecurity(lua_State* L, const std::string &name) { +#if CHECK_CLIENT_BUILD() + // Main menu is allowed everything + if (ModApiBase::getGuiEngine(L) != nullptr) + return 0; +#endif + if (ScriptApiSecurity::isSecure(L) && name.compare(0, 7, "secure.") == 0) throw LuaError("Attempted to set secure setting."); - bool is_mainmenu = false; -#if CHECK_CLIENT_BUILD() - is_mainmenu = ModApiBase::getGuiEngine(L) != nullptr; -#endif - if (!is_mainmenu && (name == "mg_name" || name == "mg_flags")) { + if (name == "mg_name" || name == "mg_flags") { errorstream << "Tried to set global setting " << name << ", ignoring. " "minetest.set_mapgen_setting() should be used instead." << std::endl; infostream << script_get_backtrace(L) << std::endl; @@ -45,11 +48,9 @@ static inline int checkSettingSecurity(lua_State* L, const std::string &name) "main_menu_script", "shader_path", "texture_path", "screenshot_path", "serverlist_file", "serverlist_url", "map-dir", "contentdb_url", }; - if (!is_mainmenu) { - for (const char *name2 : disallowed) { - if (name == name2) - throw LuaError("Attempted to set disallowed setting."); - } + for (const char *name2 : disallowed) { + if (name == name2) + throw LuaError("Attempted to set disallowed setting."); } return 0; From 138052adfc2074fc6e42d0f8856d6cdca37dbd77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Tue, 19 Nov 2024 13:30:17 +0100 Subject: [PATCH 073/136] Add particle blend mode "clip" (#15444) This lets modders avoid alpha blending rendering bugs as well as potential (future) performance issues. The appropriate blend modes are also used for node dig particles. --------- Co-authored-by: sfan5 --- builtin/game/features.lua | 1 + doc/breakages.md | 1 + doc/lua_api.md | 10 +++ games/devtest/mods/testtools/particles.lua | 28 ++++++-- .../textures/testtools_particle_clip.png | Bin 0 -> 179 bytes src/client/particles.cpp | 62 +++++++++++------- src/client/particles.h | 5 +- src/network/networkprotocol.cpp | 5 +- src/particles.cpp | 8 ++- src/particles.h | 3 +- src/script/lua_api/l_particleparams.h | 3 +- 11 files changed, 93 insertions(+), 33 deletions(-) create mode 100644 games/devtest/mods/testtools/textures/testtools_particle_clip.png diff --git a/builtin/game/features.lua b/builtin/game/features.lua index 8d7753839..ea80a09fb 100644 --- a/builtin/game/features.lua +++ b/builtin/game/features.lua @@ -44,6 +44,7 @@ core.features = { bulk_lbms = true, abm_without_neighbors = true, biome_weights = true, + particle_blend_clip = true, } function core.has_feature(arg) diff --git a/doc/breakages.md b/doc/breakages.md index 0aded3d92..2d2994385 100644 --- a/doc/breakages.md +++ b/doc/breakages.md @@ -21,3 +21,4 @@ This list is largely advisory and items may be reevaluated once the time comes. * merge `sound` and `sounds` table in itemdef * remove `DIR_DELIM` from Lua * stop reading initial properties from bare entity def +* change particle default blend mode to `clip` diff --git a/doc/lua_api.md b/doc/lua_api.md index 48ef798c4..e82b075fb 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -5657,6 +5657,8 @@ Utilities abm_without_neighbors = true, -- biomes have a weight parameter (5.11.0) biome_weights = true, + -- Particles can specify a "clip" blend mode (5.11.0) + particle_blend_clip = true, } ``` @@ -11483,6 +11485,14 @@ texture = { -- (default) blends transparent pixels with those they are drawn atop -- according to the alpha channel of the source texture. useful for -- e.g. material objects like rocks, dirt, smoke, or node chunks + -- note: there will be rendering bugs when particles interact with + -- translucent nodes. particles are also not transparency-sorted + -- relative to each other. + blend = "clip", + -- pixels are either fully opaque or fully transparent, + -- depending on whether alpha is greater than or less than 50% + -- (just like `use_texture_alpha = "clip"` for nodes). + -- you should prefer this if you don't need semi-transparency, as it's faster. blend = "add", -- adds the value of pixels to those underneath them, modulo the sources -- alpha channel. useful for e.g. bright light effects like sparks or fire diff --git a/games/devtest/mods/testtools/particles.lua b/games/devtest/mods/testtools/particles.lua index 17f4f5c80..da6b6cab9 100644 --- a/games/devtest/mods/testtools/particles.lua +++ b/games/devtest/mods/testtools/particles.lua @@ -1,14 +1,27 @@ +local function spawn_clip_test_particle(pos) + core.add_particle({ + pos = pos, + size = 5, + expirationtime = 10, + texture = { + name = "testtools_particle_clip.png", + blend = "clip", + }, + }) +end + core.register_tool("testtools:particle_spawner", { - description = "Particle Spawner".."\n".. + description = table.concat({ + "Particle Spawner", "Punch: Spawn random test particle", + "Place: Spawn clip test particle", + }, "\n"), inventory_image = "testtools_particle_spawner.png", groups = { testtool = 1, disable_repair = 1 }, on_use = function(itemstack, user, pointed_thing) local pos = core.get_pointed_thing_position(pointed_thing, true) if pos == nil then - if user then - pos = user:get_pos() - end + pos = assert(user):get_pos() end pos = vector.add(pos, {x=0, y=0.5, z=0}) local tex, anim @@ -32,5 +45,12 @@ core.register_tool("testtools:particle_spawner", { glow = math.random(0, 5), }) end, + on_place = function(itemstack, user, pointed_thing) + local pos = assert(core.get_pointed_thing_position(pointed_thing, true)) + spawn_clip_test_particle(pos) + end, + on_secondary_use = function(_, user) + spawn_clip_test_particle(assert(user):get_pos()) + end, }) diff --git a/games/devtest/mods/testtools/textures/testtools_particle_clip.png b/games/devtest/mods/testtools/textures/testtools_particle_clip.png new file mode 100644 index 0000000000000000000000000000000000000000..5fb9ad09a6c8596e60004b045007fdecb5039c08 GIT binary patch literal 179 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|ay?xfLoEE0 zQx*sqG=166BmR%y*uCay^f6}r*8kQW`&mynHhegJ`v3i|*GBt9=JAHJ3yIgyKE+|q zutabf<9tR1-vsa0^#Agv4QC7-`bxW)1k(g=UbM(!P|_<%Q=1_au*~V4&xSn>LLF0{ aWH5Bde-YerZTTjk#SEUVelF{r5}E*N6h21) literal 0 HcmV?d00001 diff --git a/src/client/particles.cpp b/src/client/particles.cpp index 6ba7fa701..c6891f8ef 100644 --- a/src/client/particles.cpp +++ b/src/client/particles.cpp @@ -22,6 +22,8 @@ #include "settings.h" #include "profiler.h" +using BlendMode = ParticleParamTypes::BlendMode; + ClientParticleTexture::ClientParticleTexture(const ServerParticleTexture& p, ITextureSource *tsrc) { tex = p; @@ -603,8 +605,11 @@ video::S3DVertex *ParticleBuffer::getVertices(u16 index) void ParticleBuffer::OnRegisterSceneNode() { - if (IsVisible) - SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT_EFFECT); + if (IsVisible) { + SceneManager->registerNodeForRendering(this, + m_mesh_buffer->getMaterial().MaterialType == video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF + ? scene::ESNRP_SOLID : scene::ESNRP_TRANSPARENT_EFFECT); + } scene::ISceneNode::OnRegisterSceneNode(); } @@ -906,6 +911,9 @@ void ParticleManager::addNodeParticle(IGameDef *gamedef, if (!getNodeParticleParams(n, f, p, &ref, texpos, texsize, &color)) return; + p.texture.blendmode = f.alpha == ALPHAMODE_BLEND + ? BlendMode::alpha : BlendMode::clip; + p.expirationtime = myrand_range(0, 100) / 100.0f; // Physics @@ -940,40 +948,47 @@ void ParticleManager::reserveParticleSpace(size_t max_estimate) m_particles.reserve(m_particles.size() + max_estimate); } -video::SMaterial ParticleManager::getMaterialForParticle(const ClientParticleTexRef &texture) +static void setBlendMode(video::SMaterial &material, BlendMode blendmode) { - // translate blend modes to GL blend functions video::E_BLEND_FACTOR bfsrc, bfdst; video::E_BLEND_OPERATION blendop; - const auto blendmode = texture.tex ? texture.tex->blendmode : - ParticleParamTypes::BlendMode::alpha; - switch (blendmode) { - case ParticleParamTypes::BlendMode::add: + case BlendMode::add: bfsrc = video::EBF_SRC_ALPHA; bfdst = video::EBF_DST_ALPHA; blendop = video::EBO_ADD; break; - case ParticleParamTypes::BlendMode::sub: + case BlendMode::sub: bfsrc = video::EBF_SRC_ALPHA; bfdst = video::EBF_DST_ALPHA; blendop = video::EBO_REVSUBTRACT; break; - case ParticleParamTypes::BlendMode::screen: + case BlendMode::screen: bfsrc = video::EBF_ONE; bfdst = video::EBF_ONE_MINUS_SRC_COLOR; blendop = video::EBO_ADD; break; - default: // includes ParticleParamTypes::BlendMode::alpha + default: // includes BlendMode::alpha bfsrc = video::EBF_SRC_ALPHA; bfdst = video::EBF_ONE_MINUS_SRC_ALPHA; blendop = video::EBO_ADD; break; } + material.MaterialTypeParam = video::pack_textureBlendFunc( + bfsrc, bfdst, + video::EMFN_MODULATE_1X, + video::EAS_TEXTURE | video::EAS_VERTEX_COLOR); + material.BlendOperation = blendop; +} + +video::SMaterial ParticleManager::getMaterialForParticle(const Particle *particle) +{ + const ClientParticleTexRef &texture = particle->getTextureRef(); + video::SMaterial material; // Texture @@ -984,17 +999,18 @@ video::SMaterial ParticleManager::getMaterialForParticle(const ClientParticleTex tex.MagFilter = video::ETMAGF_NEAREST; }); - // We don't have working transparency sorting. Disable Z-Write for - // correct results for clipped-alpha at least. - material.ZWriteEnable = video::EZW_OFF; - - // enable alpha blending and set blend mode - material.MaterialType = video::EMT_ONETEXTURE_BLEND; - material.MaterialTypeParam = video::pack_textureBlendFunc( - bfsrc, bfdst, - video::EMFN_MODULATE_1X, - video::EAS_TEXTURE | video::EAS_VERTEX_COLOR); - material.BlendOperation = blendop; + const auto blendmode = particle->getBlendMode(); + if (blendmode == BlendMode::clip) { + material.ZWriteEnable = video::EZW_ON; + material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF; + material.MaterialTypeParam = 0.5f; + } else { + // We don't have working transparency sorting. Disable Z-Write for + // correct results for clipped-alpha at least. + material.ZWriteEnable = video::EZW_OFF; + material.MaterialType = video::EMT_ONETEXTURE_BLEND; + setBlendMode(material, blendmode); + } material.setTexture(0, texture.ref); return material; @@ -1004,7 +1020,7 @@ bool ParticleManager::addParticle(std::unique_ptr toadd) { MutexAutoLock lock(m_particle_list_lock); - auto material = getMaterialForParticle(toadd->getTextureRef()); + auto material = getMaterialForParticle(toadd.get()); ParticleBuffer *found = nullptr; // simple shortcut when multiple particles of the same type get added diff --git a/src/client/particles.h b/src/client/particles.h index 6a8d09a47..619877744 100644 --- a/src/client/particles.h +++ b/src/client/particles.h @@ -77,6 +77,9 @@ public: const ClientParticleTexRef &getTextureRef() const { return m_texture; } + ParticleParamTypes::BlendMode getBlendMode() const + { return m_texture.tex ? m_texture.tex->blendmode : m_p.texture.blendmode; } + ParticleBuffer *getBuffer() const { return m_buffer; } bool attachToBuffer(ParticleBuffer *buffer); @@ -231,7 +234,7 @@ protected: ParticleParameters &p, video::ITexture **texture, v2f &texpos, v2f &texsize, video::SColor *color, u8 tilenum = 0); - static video::SMaterial getMaterialForParticle(const ClientParticleTexRef &texture); + static video::SMaterial getMaterialForParticle(const Particle *texture); bool addParticle(std::unique_ptr toadd); diff --git a/src/network/networkprotocol.cpp b/src/network/networkprotocol.cpp index 40f8acef1..f77e85d3c 100644 --- a/src/network/networkprotocol.cpp +++ b/src/network/networkprotocol.cpp @@ -59,9 +59,12 @@ Rename TOSERVER_RESPAWN to TOSERVER_RESPAWN_LEGACY Support float animation frame numbers in TOCLIENT_LOCAL_PLAYER_ANIMATIONS [scheduled bump for 5.10.0] + PROTOCOL VERSION 47 + Add particle blend mode "clip" + [scheduled bump for 5.11.0] */ -const u16 LATEST_PROTOCOL_VERSION = 46; +const u16 LATEST_PROTOCOL_VERSION = 47; // See also formspec [Version History] in doc/lua_api.md const u16 FORMSPEC_API_VERSION = 8; diff --git a/src/particles.cpp b/src/particles.cpp index 2c470d2d3..660ea8d2f 100644 --- a/src/particles.cpp +++ b/src/particles.cpp @@ -190,8 +190,10 @@ void ServerParticleTexture::serialize(std::ostream &os, u16 protocol_ver, FlagT flags = 0; if (animated) flags |= FlagT(ParticleTextureFlags::animated); - if (blendmode != BlendMode::alpha) - flags |= FlagT(blendmode) << 1; + // Default to `blend = "alpha"` for older clients that don't support `blend = "clip"` + auto sent_blendmode = (protocol_ver < 47 && blendmode == BlendMode::clip) + ? BlendMode::alpha : blendmode; + flags |= FlagT(sent_blendmode) << 1; serializeParameterValue(os, flags); alpha.serialize(os); @@ -215,6 +217,8 @@ void ServerParticleTexture::deSerialize(std::istream &is, u16 protocol_ver, animated = !!(flags & FlagT(ParticleTextureFlags::animated)); blendmode = BlendMode((flags & FlagT(ParticleTextureFlags::blend)) >> 1); + if (blendmode >= BlendMode::BlendMode_END) + throw SerializationError("invalid blend mode"); alpha.deSerialize(is); scale.deSerialize(is); diff --git a/src/particles.h b/src/particles.h index 52fe26661..00d04dbeb 100644 --- a/src/particles.h +++ b/src/particles.h @@ -233,7 +233,8 @@ namespace ParticleParamTypes } enum class AttractorKind : u8 { none, point, line, plane }; - enum class BlendMode : u8 { alpha, add, sub, screen }; + // Note: Allows at most 8 enum members (due to how this is serialized) + enum class BlendMode : u8 { alpha, add, sub, screen, clip, BlendMode_END }; // these are consistently-named convenience aliases to make code more readable without `using ParticleParamTypes` declarations using v3fRange = RangedParameter; diff --git a/src/script/lua_api/l_particleparams.h b/src/script/lua_api/l_particleparams.h index 7303081db..0e508148f 100644 --- a/src/script/lua_api/l_particleparams.h +++ b/src/script/lua_api/l_particleparams.h @@ -118,13 +118,14 @@ namespace LuaParticleParams {(int)BlendMode::add, "add"}, {(int)BlendMode::sub, "sub"}, {(int)BlendMode::screen, "screen"}, + {(int)BlendMode::clip, "clip"}, {0, nullptr}, }; luaL_checktype(L, -1, LUA_TSTRING); int v = (int)BlendMode::alpha; if (!string_to_enum(opts, v, lua_tostring(L, -1))) { - throw LuaError("blend mode must be one of ('alpha', 'add', 'sub', 'screen')"); + throw LuaError("blend mode must be one of ('alpha', 'clip', 'add', 'sub', 'screen')"); } ret = (BlendMode)v; } From 15e8f9e6a06c3ad87bae3ffaf4ec58f551612ff6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Tue, 19 Nov 2024 13:37:05 +0100 Subject: [PATCH 074/136] Fix rendering regression with TGA type 1 files with BGRA8 color (#15402) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TGA uses BGR(A)8, stored in memory in that order. Irrlicht typically expects 0xAARRGGBB, which depends on endianness. (This means that on little endian, no [B][G][R][A] -> 0xAARRGGBB conversion needs to be done, but Irrlicht was swapping the bytes.) This makes both conversion functions consistently convert from [B][G][R]([A]) to 0xAARRGGBB (SColor), documents them properly and moves them to CImageLoaderTGA.cpp so no poor soul shall be fooled by them in the near future. --------- Co-authored-by: Ælla Chiana Moskopp --- irr/src/CColorConverter.cpp | 38 +++++++++---------------------------- irr/src/CColorConverter.h | 2 -- irr/src/CImage.cpp | 2 ++ irr/src/CImageLoaderTGA.cpp | 23 ++++++++++++++++++++-- 4 files changed, 32 insertions(+), 33 deletions(-) diff --git a/irr/src/CColorConverter.cpp b/irr/src/CColorConverter.cpp index 7749ececf..d1bd302c7 100644 --- a/irr/src/CColorConverter.cpp +++ b/irr/src/CColorConverter.cpp @@ -7,6 +7,15 @@ #include "os.h" #include "irrString.h" +// Warning: The naming of Irrlicht color formats +// is not consistent regarding actual component order in memory. +// E.g. in CImage, ECF_R8G8B8 is handled per-byte and stored as [R][G][B] in memory +// while ECF_A8R8G8B8 is handled as an u32 0xAARRGGBB so [B][G][R][A] (little endian) in memory. +// The conversions suffer from the same inconsistencies, e.g. +// convert_R8G8B8toA8R8G8B8 converts [R][G][B] into 0xFFRRGGBB = [B][G][R][FF] (little endian); +// convert_A1R5G5B5toR8G8B8 converts 0bARRRRRGGGGGBBBBB into [R][G][B]. +// This also means many conversions may be broken on big endian. + namespace irr { namespace video @@ -393,19 +402,6 @@ void CColorConverter::convert_R8G8B8toA1R5G5B5(const void *sP, s32 sN, void *dP) } } -void CColorConverter::convert_B8G8R8toA8R8G8B8(const void *sP, s32 sN, void *dP) -{ - u8 *sB = (u8 *)sP; - u32 *dB = (u32 *)dP; - - for (s32 x = 0; x < sN; ++x) { - *dB = 0xff000000 | (sB[2] << 16) | (sB[1] << 8) | sB[0]; - - sB += 3; - ++dB; - } -} - void CColorConverter::convert_A8R8G8B8toR8G8B8A8(const void *sP, s32 sN, void *dP) { const u32 *sB = (const u32 *)sP; @@ -428,22 +424,6 @@ void CColorConverter::convert_A8R8G8B8toA8B8G8R8(const void *sP, s32 sN, void *d } } -void CColorConverter::convert_B8G8R8A8toA8R8G8B8(const void *sP, s32 sN, void *dP) -{ - u8 *sB = (u8 *)sP; - u8 *dB = (u8 *)dP; - - for (s32 x = 0; x < sN; ++x) { - dB[0] = sB[3]; - dB[1] = sB[2]; - dB[2] = sB[1]; - dB[3] = sB[0]; - - sB += 4; - dB += 4; - } -} - void CColorConverter::convert_R8G8B8toB8G8R8(const void *sP, s32 sN, void *dP) { u8 *sB = (u8 *)sP; diff --git a/irr/src/CColorConverter.h b/irr/src/CColorConverter.h index af7b13726..8db7af097 100644 --- a/irr/src/CColorConverter.h +++ b/irr/src/CColorConverter.h @@ -66,8 +66,6 @@ public: static void convert_R8G8B8toA1R5G5B5(const void *sP, s32 sN, void *dP); static void convert_R8G8B8toB8G8R8(const void *sP, s32 sN, void *dP); static void convert_R8G8B8toR5G6B5(const void *sP, s32 sN, void *dP); - static void convert_B8G8R8toA8R8G8B8(const void *sP, s32 sN, void *dP); - static void convert_B8G8R8A8toA8R8G8B8(const void *sP, s32 sN, void *dP); static void convert_A8R8G8B8toR8G8B8A8(const void *sP, s32 sN, void *dP); static void convert_A8R8G8B8toA8B8G8R8(const void *sP, s32 sN, void *dP); diff --git a/irr/src/CImage.cpp b/irr/src/CImage.cpp index 209590174..0c6d705f3 100644 --- a/irr/src/CImage.cpp +++ b/irr/src/CImage.cpp @@ -95,6 +95,8 @@ SColor CImage::getPixel(u32 x, u32 y) const case ECF_A8R8G8B8: return ((u32 *)Data)[y * Size.Width + x]; case ECF_R8G8B8: { + // FIXME this interprets the memory as [R][G][B], whereas SColor is stored as + // 0xAARRGGBB, meaning it is lies in memory as [B][G][R][A] on a little endian machine. u8 *p = Data + (y * 3) * Size.Width + (x * 3); return SColor(255, p[0], p[1], p[2]); } diff --git a/irr/src/CImageLoaderTGA.cpp b/irr/src/CImageLoaderTGA.cpp index 274b15543..75b0b5679 100644 --- a/irr/src/CImageLoaderTGA.cpp +++ b/irr/src/CImageLoaderTGA.cpp @@ -93,6 +93,25 @@ bool CImageLoaderTGA::isALoadableFileFormat(io::IReadFile *file) const return (!strcmp(footer.Signature, "TRUEVISION-XFILE.")); // very old tgas are refused. } +/// Converts *byte order* BGR to *endianness order* ARGB (SColor "=" u32) +static void convert_BGR8_to_SColor(const u8 *src, u32 n, u32 *dst) +{ + for (u32 i = 0; i < n; ++i) { + const u8 *bgr = &src[3 * i]; + dst[i] = 0xff000000 | (bgr[2] << 16) | (bgr[1] << 8) | bgr[0]; + } +} + +/// Converts *byte order* BGRA to *endianness order* ARGB (SColor "=" u32) +/// Note: This just copies from src to dst on little endian. +static void convert_BGRA8_to_SColor(const u8 *src, u32 n, u32 *dst) +{ + for (u32 i = 0; i < n; ++i) { + const u8 *bgra = &src[4 * i]; + dst[i] = (bgra[3] << 24) | (bgra[2] << 16) | (bgra[1] << 8) | bgra[0]; + } +} + //! creates a surface from the file IImage *CImageLoaderTGA::loadImage(io::IReadFile *file) const { @@ -139,10 +158,10 @@ IImage *CImageLoaderTGA::loadImage(io::IReadFile *file) const CColorConverter::convert_A1R5G5B5toA8R8G8B8(colorMap, header.ColorMapLength, palette); break; case 24: - CColorConverter::convert_B8G8R8toA8R8G8B8(colorMap, header.ColorMapLength, palette); + convert_BGR8_to_SColor(colorMap, header.ColorMapLength, palette); break; case 32: - CColorConverter::convert_B8G8R8A8toA8R8G8B8(colorMap, header.ColorMapLength, palette); + convert_BGRA8_to_SColor(colorMap, header.ColorMapLength, palette); break; } delete[] colorMap; From b63e988bd60089b5f0595442b974886c17d5e1c9 Mon Sep 17 00:00:00 2001 From: Christian Betancourt Dias <128722328+PichiBeta@users.noreply.github.com> Date: Tue, 19 Nov 2024 07:38:19 -0500 Subject: [PATCH 075/136] Fix naming conventions for `CMatrix4::set(Inverse)RotationRadians()` (#15204) --- irr/include/matrix4.h | 68 +++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/irr/include/matrix4.h b/irr/include/matrix4.h index 8fce0157a..36f98bb70 100644 --- a/irr/include/matrix4.h +++ b/irr/include/matrix4.h @@ -856,27 +856,27 @@ inline CMatrix4 &CMatrix4::setInverseRotationDegrees(const vector3d &ro template inline CMatrix4 &CMatrix4::setRotationRadians(const vector3d &rotation) { - const f64 cr = cos(rotation.X); - const f64 sr = sin(rotation.X); - const f64 cp = cos(rotation.Y); - const f64 sp = sin(rotation.Y); - const f64 cy = cos(rotation.Z); - const f64 sy = sin(rotation.Z); + const f64 cPitch = cos(rotation.X); + const f64 sPitch = sin(rotation.X); + const f64 cYaw = cos(rotation.Y); + const f64 sYaw = sin(rotation.Y); + const f64 cRoll = cos(rotation.Z); + const f64 sRoll = sin(rotation.Z); - M[0] = (T)(cp * cy); - M[1] = (T)(cp * sy); - M[2] = (T)(-sp); + M[0] = (T)(cYaw * cRoll); + M[1] = (T)(cYaw * sRoll); + M[2] = (T)(-sYaw); - const f64 srsp = sr * sp; - const f64 crsp = cr * sp; + const f64 sPitch_sYaw = sPitch * sYaw; + const f64 cPitch_sYaw = cPitch * sYaw; - M[4] = (T)(srsp * cy - cr * sy); - M[5] = (T)(srsp * sy + cr * cy); - M[6] = (T)(sr * cp); + M[4] = (T)(sPitch_sYaw * cRoll - cPitch * sRoll); + M[5] = (T)(sPitch_sYaw * sRoll + cPitch * cRoll); + M[6] = (T)(sPitch * cYaw); - M[8] = (T)(crsp * cy + sr * sy); - M[9] = (T)(crsp * sy - sr * cy); - M[10] = (T)(cr * cp); + M[8] = (T)(cPitch_sYaw * cRoll + sPitch * sRoll); + M[9] = (T)(cPitch_sYaw * sRoll - sPitch * cRoll); + M[10] = (T)(cPitch * cYaw); #if defined(USE_MATRIX_TEST) definitelyIdentityMatrix = false; #endif @@ -960,27 +960,27 @@ inline core::vector3d CMatrix4::getRotationDegrees() const template inline CMatrix4 &CMatrix4::setInverseRotationRadians(const vector3d &rotation) { - f64 cr = cos(rotation.X); - f64 sr = sin(rotation.X); - f64 cp = cos(rotation.Y); - f64 sp = sin(rotation.Y); - f64 cy = cos(rotation.Z); - f64 sy = sin(rotation.Z); + f64 cPitch = cos(rotation.X); + f64 sPitch = sin(rotation.X); + f64 cYaw = cos(rotation.Y); + f64 sYaw = sin(rotation.Y); + f64 cRoll = cos(rotation.Z); + f64 sRoll = sin(rotation.Z); - M[0] = (T)(cp * cy); - M[4] = (T)(cp * sy); - M[8] = (T)(-sp); + M[0] = (T)(cYaw * cRoll); + M[4] = (T)(cYaw * sRoll); + M[8] = (T)(-sYaw); - f64 srsp = sr * sp; - f64 crsp = cr * sp; + f64 sPitch_sYaw = sPitch * sYaw; + f64 cPitch_sYaw = cPitch * sYaw; - M[1] = (T)(srsp * cy - cr * sy); - M[5] = (T)(srsp * sy + cr * cy); - M[9] = (T)(sr * cp); + M[1] = (T)(sPitch_sYaw * cRoll - cPitch * sRoll); + M[5] = (T)(sPitch_sYaw * sRoll + cPitch * cRoll); + M[9] = (T)(sPitch * cYaw); - M[2] = (T)(crsp * cy + sr * sy); - M[6] = (T)(crsp * sy - sr * cy); - M[10] = (T)(cr * cp); + M[2] = (T)(cPitch_sYaw * cRoll + sPitch * sRoll); + M[6] = (T)(cPitch_sYaw * sRoll - sPitch * cRoll); + M[10] = (T)(cPitch * cYaw); #if defined(USE_MATRIX_TEST) definitelyIdentityMatrix = false; #endif From 946b3a422272d680d5d9d9a208bb0ffedce0291f Mon Sep 17 00:00:00 2001 From: Richard Try Date: Wed, 20 Nov 2024 21:36:35 +0300 Subject: [PATCH 076/136] Typo in lua_api.md (#15440) Duplicate text removed. --- doc/lua_api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index e82b075fb..b4ef79088 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -8892,7 +8892,7 @@ For `core.get_perlin_map()`, the actual seed used is the noiseparams seed plus the world seed, to create world-specific noise. Format of `size` is `{x=dimx, y=dimy, z=dimz}`. The `z` component is omitted -for 2D noise, and it must be must be larger than 1 for 3D noise (otherwise +for 2D noise, and it must be larger than 1 for 3D noise (otherwise `nil` is returned). For each of the functions with an optional `buffer` parameter: If `buffer` is From b6eaf7b5a4d8c2d818a0fc744d2c6db64e204efe Mon Sep 17 00:00:00 2001 From: siliconsniffer <97843108+siliconsniffer@users.noreply.github.com> Date: Thu, 21 Nov 2024 20:34:40 +0100 Subject: [PATCH 077/136] Main menu: Player list for public servers (#15425) --- LICENSE.txt | 1 + builtin/mainmenu/dlg_clients_list.lua | 49 +++++++++++++++++++++ builtin/mainmenu/init.lua | 1 + builtin/mainmenu/tab_online.lua | 42 +++++++++++++++--- textures/base/pack/server_view_clients.png | Bin 0 -> 218 bytes 5 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 builtin/mainmenu/dlg_clients_list.lua create mode 100644 textures/base/pack/server_view_clients.png diff --git a/LICENSE.txt b/LICENSE.txt index e562a0b4c..fb055807b 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -63,6 +63,7 @@ Zughy: textures/base/pack/settings_btn.png textures/base/pack/settings_info.png textures/base/pack/settings_reset.png + textures/base/pack/server_view_clients.png appgurueu: textures/base/pack/server_incompatible.png diff --git a/builtin/mainmenu/dlg_clients_list.lua b/builtin/mainmenu/dlg_clients_list.lua new file mode 100644 index 000000000..2ea021c5e --- /dev/null +++ b/builtin/mainmenu/dlg_clients_list.lua @@ -0,0 +1,49 @@ +-- Luanti +-- Copyright (C) 2024 siliconsniffer +-- SPDX-License-Identifier: LGPL-2.1-or-later + + +local function clients_list_formspec(dialogdata) + local TOUCH_GUI = core.settings:get_bool("touch_gui") + local clients_list = dialogdata.server.clients_list + local servername = dialogdata.server.name + + local function fmt_formspec_list(clients_list) + local escaped = {} + for i, str in ipairs(clients_list) do + escaped[i] = core.formspec_escape(str) + end + return table.concat(escaped, ",") + end + + local formspec = { + "formspec_version[8]", + "size[6,9.5]", + TOUCH_GUI and "padding[0.01,0.01]" or "", + "hypertext[0,0;6,1.5;;", + fgettext("This is the list of clients connected to\n$1", + "" .. core.hypertext_escape(servername) .. "") .. "]", + "textlist[0.5,1.5;5,6.8;;" .. fmt_formspec_list(clients_list) .. "]", + "button[1.5,8.5;3,0.8;quit;OK]" + } + return table.concat(formspec, "") +end + + +local function clients_list_buttonhandler(this, fields) + if fields.quit then + this:delete() + return true + end + return false +end + + +function create_clientslist_dialog(server) + local retval = dialog_create("dlg_clients_list", + clients_list_formspec, + clients_list_buttonhandler, + nil) + retval.data.server = server + return retval +end diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua index 41519b2ee..4e1c201cd 100644 --- a/builtin/mainmenu/init.lua +++ b/builtin/mainmenu/init.lua @@ -55,6 +55,7 @@ dofile(menupath .. DIR_DELIM .. "dlg_register.lua") dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua") dofile(menupath .. DIR_DELIM .. "dlg_version_info.lua") dofile(menupath .. DIR_DELIM .. "dlg_reinstall_mtg.lua") +dofile(menupath .. DIR_DELIM .. "dlg_clients_list.lua") local tabs = { content = dofile(menupath .. DIR_DELIM .. "tab_content.lua"), diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua index a73b863ce..558e2aff2 100644 --- a/builtin/mainmenu/tab_online.lua +++ b/builtin/mainmenu/tab_online.lua @@ -108,16 +108,38 @@ local function get_formspec(tabview, name, tabdata) end if tabdata.selected then - if gamedata.fav then - retval = retval .. "tooltip[btn_delete_favorite;" .. fgettext("Remove favorite") .. "]" - retval = retval .. "style[btn_delete_favorite;padding=6]" - retval = retval .. "image_button[5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir .. - "server_favorite_delete.png") .. ";btn_delete_favorite;]" - end if gamedata.serverdescription then retval = retval .. "textarea[0.25,1.85;5.25,2.7;;;" .. core.formspec_escape(gamedata.serverdescription) .. "]" end + + local server = tabdata.lookup[tabdata.selected] + + local clients_list = server and server.clients_list + local can_view_clients_list = clients_list and #clients_list > 0 + if can_view_clients_list then + table.sort(clients_list, function(a, b) + return a:lower() < b:lower() + end) + local max_clients = 5 + if #clients_list > max_clients then + retval = retval .. "tooltip[btn_view_clients;" .. + fgettext("Clients:\n$1", table.concat(clients_list, "\n", 1, max_clients)) .. "\n..." .. "]" + else + retval = retval .. "tooltip[btn_view_clients;" .. + fgettext("Clients:\n$1", table.concat(clients_list, "\n")) .. "]" + end + retval = retval .. "style[btn_view_clients;padding=6]" + retval = retval .. "image_button[5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir .. + "server_view_clients.png") .. ";btn_view_clients;]" + end + + if gamedata.fav then + retval = retval .. "tooltip[btn_delete_favorite;" .. fgettext("Remove favorite") .. "]" + retval = retval .. "style[btn_delete_favorite;padding=6]" + retval = retval .. "image_button[" .. (can_view_clients_list and "4.5" or "5") .. ",1.3;0.5,0.5;" .. + core.formspec_escape(defaulttexturedir .. "server_favorite_delete.png") .. ";btn_delete_favorite;]" + end end retval = retval .. "container_end[]" @@ -315,6 +337,14 @@ local function main_button_handler(tabview, fields, name, tabdata) return true end + if fields.btn_view_clients then + local dlg = create_clientslist_dialog(tabdata.lookup[tabdata.selected]) + dlg:set_parent(tabview) + tabview:hide() + dlg:show() + return true + end + if fields.btn_mp_clear then tabdata.search_for = "" menudata.search_result = nil diff --git a/textures/base/pack/server_view_clients.png b/textures/base/pack/server_view_clients.png new file mode 100644 index 0000000000000000000000000000000000000000..87b569f93129e5add2d820f3c47d987a99ac2db1 GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`3q4&NLo9leQw}iklzjP@EWE$q zsgUw632w8qfxr2aFP}f~Amg|ET>%lkxU&Hp&Ri5bs_OGYBq@0@^Bgt-?gFWXH=;H7 z4jCl;{N`;TnmqY%hZwW$-v2$R!IDb0UkyzDzdv=X!;6PGp>2V+wC$IVyBMa=-zeE6 z#AfjPF%wXgVUXt0iyY;AyWZYl5@egeEUc`baJhj$;0>#Y_@DQu)NV2`giQ0$m?ix@ Q5a?J2Pgg&ebxsLQ0K_FxY5)KL literal 0 HcmV?d00001 From 4faa16fe0ddf98659bfa3f852cb1d9b8ff95eb93 Mon Sep 17 00:00:00 2001 From: luk3yx Date: Sat, 23 Nov 2024 05:56:35 +1300 Subject: [PATCH 078/136] Clarify behaviour of core.hypertext_escape (#15464) --- doc/lua_api.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/lua_api.md b/doc/lua_api.md index b4ef79088..709bf2984 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -6699,6 +6699,9 @@ Formspec * `core.hypertext_escape(string)`: returns a string * escapes the characters "\", "<", and ">" to show text in a hypertext element. * not safe for use with tag attributes. + * this function does not do formspec escaping, you will likely need to do + `core.formspec_escape(core.hypertext_escape(string))` if the hypertext is + not already being formspec escaped. * `core.explode_table_event(string)`: returns a table * returns e.g. `{type="CHG", row=1, column=2}` * `type` is one of: From 6a1d22b2c516abbb9ce9670dedff47451317706f Mon Sep 17 00:00:00 2001 From: grorp Date: Sun, 24 Nov 2024 11:33:39 +0100 Subject: [PATCH 079/136] Implement an editor to customize the touchscreen controls (#14933) - The editor is accessible via the pause menu and the settings menu. - Buttons can be moved via drag & drop. - Buttons can be added/removed. The grid menu added by #14918 is used to show all buttons not included in the layout. - Custom layouts are responsive and adapt to changed screen size / DPI / hud_scaling. - The layout is saved as JSON in the "touch_layout" setting. --- builtin/mainmenu/settings/dlg_settings.lua | 18 + doc/menu_lua_api.md | 1 + src/client/game.cpp | 21 +- src/client/hud.cpp | 1 + src/defaultsettings.cpp | 1 + src/gui/CMakeLists.txt | 2 + src/gui/mainmenumanager.h | 7 + src/gui/touchcontrols.cpp | 203 ++++------- src/gui/touchcontrols.h | 81 ++--- src/gui/touchscreeneditor.cpp | 404 +++++++++++++++++++++ src/gui/touchscreeneditor.h | 81 +++++ src/gui/touchscreenlayout.cpp | 345 ++++++++++++++++++ src/gui/touchscreenlayout.h | 104 ++++++ src/irr_gui_ptr.h | 28 ++ src/script/lua_api/l_mainmenu.cpp | 18 + src/script/lua_api/l_mainmenu.h | 2 + textures/base/pack/down.png | Bin 1618 -> 3647 bytes textures/base/pack/jump_btn.png | Bin 1633 -> 3625 bytes 18 files changed, 1122 insertions(+), 195 deletions(-) create mode 100644 src/gui/touchscreeneditor.cpp create mode 100644 src/gui/touchscreeneditor.h create mode 100644 src/gui/touchscreenlayout.cpp create mode 100644 src/gui/touchscreenlayout.h create mode 100644 src/irr_gui_ptr.h diff --git a/builtin/mainmenu/settings/dlg_settings.lua b/builtin/mainmenu/settings/dlg_settings.lua index ef28398b1..f1861879a 100644 --- a/builtin/mainmenu/settings/dlg_settings.lua +++ b/builtin/mainmenu/settings/dlg_settings.lua @@ -123,6 +123,22 @@ local function load() end, } + local touchscreen_layout = { + query_text = "Touchscreen layout", + requires = { + touchscreen = true, + }, + get_formspec = function(self, avail_w) + local btn_w = math.min(avail_w, 6) + return ("button[0,0;%f,0.8;btn_touch_layout;%s]"):format(btn_w, fgettext("Touchscreen layout")), 0.8 + end, + on_submit = function(self, fields) + if fields.btn_touch_layout then + core.show_touchscreen_layout() + end + end, + } + add_page({ id = "accessibility", title = fgettext_ne("Accessibility"), @@ -151,6 +167,8 @@ local function load() load_settingtypes() table.insert(page_by_id.controls_keyboard_and_mouse.content, 1, change_keys) + -- insert after "touch_controls" + table.insert(page_by_id.controls_touchscreen.content, 2, touchscreen_layout) do local content = page_by_id.graphics_and_audio_effects.content local idx = table.indexof(content, "enable_dynamic_shadows") diff --git a/doc/menu_lua_api.md b/doc/menu_lua_api.md index ae4afd998..b17e4b1c8 100644 --- a/doc/menu_lua_api.md +++ b/doc/menu_lua_api.md @@ -223,6 +223,7 @@ GUI * `core.set_clouds()` * `core.set_topleft_text(text)` * `core.show_keys_menu()` +* `core.show_touchscreen_layout()` * `core.show_path_select_dialog(formname, caption, is_file_select)` * shows a path select dialog * `formname` is base name of dialog response returned in fields diff --git a/src/client/game.cpp b/src/client/game.cpp index f9f175d1b..dc13095d1 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -26,6 +26,7 @@ #include "client/event_manager.h" #include "fontengine.h" #include "gui/touchcontrols.h" +#include "gui/touchscreeneditor.h" #include "itemdef.h" #include "log.h" #include "log_internal.h" @@ -144,6 +145,11 @@ struct LocalFormspecHandler : public TextDest return; } + if (fields.find("btn_touchscreen_layout") != fields.end()) { + g_gamecallback->touchscreenLayout(); + return; + } + if (fields.find("btn_exit_menu") != fields.end()) { g_gamecallback->disconnect(); return; @@ -1844,6 +1850,12 @@ inline bool Game::handleCallbacks() g_gamecallback->keyconfig_requested = false; } + if (g_gamecallback->touchscreenlayout_requested) { + (new GUITouchscreenLayout(guienv, guiroot, -1, + &g_menumgr, texture_src))->drop(); + g_gamecallback->touchscreenlayout_requested = false; + } + if (!g_gamecallback->show_open_url_dialog.empty()) { (void)make_irr(guienv, guiroot, -1, &g_menumgr, texture_src, g_gamecallback->show_open_url_dialog); @@ -4510,9 +4522,14 @@ void Game::showPauseMenu() << strgettext("Sound Volume") << "]"; } #endif - os << "button_exit[4," << (ypos++) << ";3,0.5;btn_key_config;" - << strgettext("Controls") << "]"; #endif + if (g_touchcontrols) { + os << "button_exit[4," << (ypos++) << ";3,0.5;btn_touchscreen_layout;" + << strgettext("Touchscreen Layout") << "]"; + } else { + os << "button_exit[4," << (ypos++) << ";3,0.5;btn_key_config;" + << strgettext("Controls") << "]"; + } os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_menu;" << strgettext("Exit to Menu") << "]"; os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_os;" diff --git a/src/client/hud.cpp b/src/client/hud.cpp index 6929d4c9e..e49327d30 100644 --- a/src/client/hud.cpp +++ b/src/client/hud.cpp @@ -24,6 +24,7 @@ #include "wieldmesh.h" #include "client/renderingengine.h" #include "client/minimap.h" +#include "client/texturesource.h" #include "gui/touchcontrols.h" #include "util/enriched_string.h" #include "irrlicht_changes/CGUITTFont.h" diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 2142615e2..345e4a07b 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -542,6 +542,7 @@ void set_default_settings() settings->setDefault("keymap_sneak", "KEY_SHIFT"); #endif + settings->setDefault("touch_layout", ""); settings->setDefault("touchscreen_sensitivity", "0.2"); settings->setDefault("touchscreen_threshold", "20"); settings->setDefault("touch_long_tap_delay", "400"); diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 04a03609d..876acab74 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -25,5 +25,7 @@ set(gui_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/modalMenu.cpp ${CMAKE_CURRENT_SOURCE_DIR}/profilergraph.cpp ${CMAKE_CURRENT_SOURCE_DIR}/touchcontrols.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/touchscreenlayout.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/touchscreeneditor.cpp PARENT_SCOPE ) diff --git a/src/gui/mainmenumanager.h b/src/gui/mainmenumanager.h index d5f43796d..9d10e3960 100644 --- a/src/gui/mainmenumanager.h +++ b/src/gui/mainmenumanager.h @@ -21,6 +21,7 @@ public: virtual void changeVolume() = 0; virtual void showOpenURLDialog(const std::string &url) = 0; virtual void signalKeyConfigChange() = 0; + virtual void touchscreenLayout() = 0; }; extern gui::IGUIEnvironment *guienv; @@ -133,6 +134,11 @@ public: keyconfig_changed = true; } + void touchscreenLayout() override + { + touchscreenlayout_requested = true; + } + void showOpenURLDialog(const std::string &url) override { show_open_url_dialog = url; @@ -142,6 +148,7 @@ public: bool changepassword_requested = false; bool changevolume_requested = false; bool keyconfig_requested = false; + bool touchscreenlayout_requested = false; bool shutdown_requested = false; bool keyconfig_changed = false; std::string show_open_url_dialog = ""; diff --git a/src/gui/touchcontrols.cpp b/src/gui/touchcontrols.cpp index d7e46787b..17352264d 100644 --- a/src/gui/touchcontrols.cpp +++ b/src/gui/touchcontrols.cpp @@ -5,6 +5,7 @@ // Copyright (C) 2024 grorp, Gregor Parzefall #include "touchcontrols.h" +#include "touchscreenlayout.h" #include "gettime.h" #include "irr_v2d.h" @@ -14,8 +15,10 @@ #include "client/guiscalingfilter.h" #include "client/keycode.h" #include "client/renderingengine.h" +#include "client/texturesource.h" #include "util/numeric.h" -#include "gettext.h" +#include "irr_gui_ptr.h" +#include "IGUIImage.h" #include "IGUIStaticText.h" #include "IGUIFont.h" #include @@ -26,59 +29,6 @@ TouchControls *g_touchcontrols; -static const char *button_image_names[] = { - "jump_btn.png", - "down.png", - "zoom.png", - "aux1_btn.png", - "overflow_btn.png", - - "fly_btn.png", - "noclip_btn.png", - "fast_btn.png", - "debug_btn.png", - "camera_btn.png", - "rangeview_btn.png", - "minimap_btn.png", - "", - - "chat_btn.png", - "inventory_btn.png", - "drop_btn.png", - "exit_btn.png", - - "joystick_off.png", - "joystick_bg.png", - "joystick_center.png", -}; - -// compare with GUIKeyChangeMenu::init_keys -static const char *button_titles[] = { - N_("Jump"), - N_("Sneak"), - N_("Zoom"), - N_("Aux1"), - N_("Overflow menu"), - - N_("Toggle fly"), - N_("Toggle noclip"), - N_("Toggle fast"), - N_("Toggle debug"), - N_("Change camera"), - N_("Range select"), - N_("Toggle minimap"), - N_("Toggle chat log"), - - N_("Chat"), - N_("Inventory"), - N_("Drop"), - N_("Exit"), - - N_("Joystick"), - N_("Joystick"), - N_("Joystick"), -}; - static void load_button_texture(IGUIImage *gui_button, const std::string &path, const recti &button_rect, ISimpleTextureSource *tsrc, video::IVideoDriver *driver) { @@ -268,10 +218,22 @@ TouchControls::TouchControls(IrrlichtDevice *device, ISimpleTextureSource *tsrc) m_long_tap_delay = g_settings->getU16("touch_long_tap_delay"); m_fixed_joystick = g_settings->getBool("fixed_virtual_joystick"); m_joystick_triggers_aux1 = g_settings->getBool("virtual_joystick_triggers_aux1"); + m_screensize = m_device->getVideoDriver()->getScreenSize(); - m_button_size = MYMIN(m_screensize.Y / 4.5f, - RenderingEngine::getDisplayDensity() * 65.0f * - g_settings->getFloat("hud_scaling")); + m_button_size = ButtonLayout::getButtonSize(m_screensize); + applyLayout(ButtonLayout::loadFromSettings()); +} + +void TouchControls::applyLayout(const ButtonLayout &layout) +{ + m_layout = layout; + + m_buttons.clear(); + m_overflow_btn = nullptr; + m_overflow_bg = nullptr; + m_overflow_buttons.clear(); + m_overflow_button_titles.clear(); + m_overflow_button_rects.clear(); // Initialize joystick display "button". // Joystick is placed on the bottom left of screen. @@ -298,47 +260,21 @@ TouchControls::TouchControls(IrrlichtDevice *device, ISimpleTextureSource *tsrc) m_joystick_btn_center = grab_gui_element(makeButtonDirect(joystick_center_id, recti(0, 0, m_button_size, m_button_size), false)); - // init jump button - addButton(m_buttons, jump_id, button_image_names[jump_id], - recti(m_screensize.X - 1.75f * m_button_size, - m_screensize.Y - m_button_size, - m_screensize.X - 0.25f * m_button_size, - m_screensize.Y)); + for (const auto &[id, meta] : m_layout.layout) { + if (!mayAddButton(id)) + continue; - // init sneak button - addButton(m_buttons, sneak_id, button_image_names[sneak_id], - recti(m_screensize.X - 3.25f * m_button_size, - m_screensize.Y - m_button_size, - m_screensize.X - 1.75f * m_button_size, - m_screensize.Y)); - - // init zoom button - addButton(m_buttons, zoom_id, button_image_names[zoom_id], - recti(m_screensize.X - 1.25f * m_button_size, - m_screensize.Y - 4 * m_button_size, - m_screensize.X - 0.25f * m_button_size, - m_screensize.Y - 3 * m_button_size)); - - // init aux1 button - if (!m_joystick_triggers_aux1) - addButton(m_buttons, aux1_id, button_image_names[aux1_id], - recti(m_screensize.X - 1.25f * m_button_size, - m_screensize.Y - 2.5f * m_button_size, - m_screensize.X - 0.25f * m_button_size, - m_screensize.Y - 1.5f * m_button_size)); - - // init overflow button - m_overflow_btn = grab_gui_element(makeButtonDirect(overflow_id, - recti(m_screensize.X - 1.25f * m_button_size, - m_screensize.Y - 5.5f * m_button_size, - m_screensize.X - 0.25f * m_button_size, - m_screensize.Y - 4.5f * m_button_size), true)); - - const static touch_gui_button_id overflow_buttons[] { - chat_id, inventory_id, drop_id, exit_id, - fly_id, noclip_id, fast_id, debug_id, camera_id, range_id, minimap_id, - toggle_chat_id, - }; + recti rect = m_layout.getRect(id, m_screensize, m_button_size, m_texturesource); + if (id == toggle_chat_id) + // Chat is shown by default, so chat_hide_btn.png is shown first. + addToggleButton(m_buttons, id, "chat_hide_btn.png", + "chat_show_btn.png", rect, true); + else if (id == overflow_id) + m_overflow_btn = grab_gui_element( + makeButtonDirect(id, rect, true)); + else + addButton(m_buttons, id, button_image_names[id], rect, true); + } IGUIStaticText *background = m_guienv->addStaticText(L"", recti(v2s32(0, 0), dimension2du(m_screensize))); @@ -346,32 +282,17 @@ TouchControls::TouchControls(IrrlichtDevice *device, ISimpleTextureSource *tsrc) background->setVisible(false); m_overflow_bg = grab_gui_element(background); - s32 cols = 4; - s32 rows = 3; - f32 screen_aspect = (f32)m_screensize.X / (f32)m_screensize.Y; - while ((s32)ARRLEN(overflow_buttons) > cols * rows) { - f32 aspect = (f32)cols / (f32)rows; - if (aspect > screen_aspect) - rows++; - else - cols++; - } - - v2s32 size(m_button_size, m_button_size); - v2s32 spacing(m_screensize.X / (cols + 1), m_screensize.Y / (rows + 1)); - v2s32 pos(spacing); - - for (auto id : overflow_buttons) { - if (id_to_keycode(id) == KEY_UNKNOWN) - continue; - - recti rect(pos - size / 2, dimension2du(size.X, size.Y)); - if (rect.LowerRightCorner.X > (s32)m_screensize.X) { - pos.X = spacing.X; - pos.Y += spacing.Y; - rect = recti(pos - size / 2, dimension2du(size.X, size.Y)); - } + auto overflow_buttons = m_layout.getMissingButtons(); + overflow_buttons.erase(std::remove_if( + overflow_buttons.begin(), overflow_buttons.end(), + [&](touch_gui_button_id id) { + // There's no sense in adding the overflow button to the overflow + // menu (also, it's impossible since it doesn't have a keycode). + return !mayAddButton(id) || id == overflow_id; + }), overflow_buttons.end()); + layout_button_grid(m_screensize, m_texturesource, overflow_buttons, + [&] (touch_gui_button_id id, v2s32 pos, recti rect) { if (id == toggle_chat_id) // Chat is shown by default, so chat_hide_btn.png is shown first. addToggleButton(m_overflow_buttons, id, "chat_hide_btn.png", @@ -379,27 +300,23 @@ TouchControls::TouchControls(IrrlichtDevice *device, ISimpleTextureSource *tsrc) else addButton(m_overflow_buttons, id, button_image_names[id], rect, false); - std::wstring str = wstrgettext(button_titles[id]); - IGUIStaticText *text = m_guienv->addStaticText(str.c_str(), recti()); - IGUIFont *font = text->getActiveFont(); - dimension2du dim = font->getDimension(str.c_str()); - dim = dimension2du(dim.Width * 1.25f, dim.Height * 1.25f); // avoid clipping - text->setRelativePosition(recti(pos.X - dim.Width / 2, pos.Y + size.Y / 2, - pos.X + dim.Width / 2, pos.Y + size.Y / 2 + dim.Height)); - text->setTextAlignment(EGUIA_CENTER, EGUIA_UPPERLEFT); + IGUIStaticText *text = m_guienv->addStaticText(L"", recti()); + make_button_grid_title(text, id, pos, rect); text->setVisible(false); m_overflow_button_titles.push_back(grab_gui_element(text)); rect.addInternalPoint(text->getRelativePosition().UpperLeftCorner); rect.addInternalPoint(text->getRelativePosition().LowerRightCorner); m_overflow_button_rects.push_back(rect); - - pos.X += spacing.X; - } + }); m_status_text = grab_gui_element( m_guienv->addStaticText(L"", recti(), false, false)); m_status_text->setVisible(false); + + // applyLayout can be called at any time, also e.g. while the overflow menu + // is open, so this is necessary to restore correct visibility. + updateVisibility(); } TouchControls::~TouchControls() @@ -407,6 +324,17 @@ TouchControls::~TouchControls() releaseAll(); } +bool TouchControls::mayAddButton(touch_gui_button_id id) +{ + if (!ButtonLayout::isButtonAllowed(id)) + return false; + if (id == aux1_id && m_joystick_triggers_aux1) + return false; + if (id != overflow_id && id_to_keycode(id) == KEY_UNKNOWN) + return false; + return true; +} + void TouchControls::addButton(std::vector &buttons, touch_gui_button_id id, const std::string &image, const recti &rect, bool visible) { @@ -701,6 +629,15 @@ void TouchControls::applyJoystickStatus() void TouchControls::step(float dtime) { + v2u32 screensize = m_device->getVideoDriver()->getScreenSize(); + s32 button_size = ButtonLayout::getButtonSize(screensize); + + if (m_screensize != screensize || m_button_size != button_size) { + m_screensize = screensize; + m_button_size = button_size; + applyLayout(m_layout); + } + // simulate keyboard repeats buttons_step(m_buttons, dtime, m_device->getVideoDriver(), m_receiver, m_texturesource); buttons_step(m_overflow_buttons, dtime, m_device->getVideoDriver(), m_receiver, m_texturesource); diff --git a/src/gui/touchcontrols.h b/src/gui/touchcontrols.h index cb3e8e8bf..701baba42 100644 --- a/src/gui/touchcontrols.h +++ b/src/gui/touchcontrols.h @@ -5,11 +5,8 @@ #pragma once -#include "IGUIStaticText.h" #include "irrlichttypes.h" -#include -#include -#include +#include "IEventReceiver.h" #include #include @@ -17,41 +14,29 @@ #include #include "itemdef.h" -#include "client/game.h" +#include "touchscreenlayout.h" #include "util/basic_macros.h" -#include "client/texturesource.h" namespace irr { class IrrlichtDevice; + namespace gui + { + class IGUIEnvironment; + class IGUIImage; + class IGUIStaticText; + } + namespace video + { + class IVideoDriver; + } } +class ISimpleTextureSource; using namespace irr::core; using namespace irr::gui; -// We cannot use irr_ptr for Irrlicht GUI elements we own. -// Option 1: Pass IGUIElement* returned by IGUIEnvironment::add* into irr_ptr -// constructor. -// -> We steal the reference owned by IGUIEnvironment and drop it later, -// causing the IGUIElement to be deleted while IGUIEnvironment still -// references it. -// Option 2: Pass IGUIElement* returned by IGUIEnvironment::add* into irr_ptr::grab. -// -> We add another reference and drop it later, but since IGUIEnvironment -// still references the IGUIElement, it is never deleted. -// To make IGUIEnvironment drop its reference to the IGUIElement, we have to call -// IGUIElement::remove, so that's what we'll do. -template -std::shared_ptr grab_gui_element(T *element) -{ - static_assert(std::is_base_of_v, - "grab_gui_element only works for IGUIElement"); - return std::shared_ptr(element, [](T *e) { - e->remove(); - }); -} - - enum class TapState { None, @@ -59,36 +44,6 @@ enum class TapState LongTap, }; -enum touch_gui_button_id -{ - jump_id = 0, - sneak_id, - zoom_id, - aux1_id, - overflow_id, - - // usually in the "settings bar" - fly_id, - noclip_id, - fast_id, - debug_id, - camera_id, - range_id, - minimap_id, - toggle_chat_id, - - // usually in the "rare controls bar" - chat_id, - inventory_id, - drop_id, - exit_id, - - // the joystick - joystick_off_id, - joystick_bg_id, - joystick_center_id, -}; - #define BUTTON_REPEAT_DELAY 0.5f #define BUTTON_REPEAT_INTERVAL 0.333f @@ -168,6 +123,9 @@ public: bool isStatusTextOverriden() { return m_overflow_open; } IGUIStaticText *getStatusText() { return m_status_text.get(); } + ButtonLayout getLayout() { return m_layout; } + void applyLayout(const ButtonLayout &layout); + private: IrrlichtDevice *m_device = nullptr; IGUIEnvironment *m_guienv = nullptr; @@ -233,13 +191,14 @@ private: void releaseAll(); // initialize a button + bool mayAddButton(touch_gui_button_id id); void addButton(std::vector &buttons, touch_gui_button_id id, const std::string &image, - const recti &rect, bool visible=true); + const recti &rect, bool visible); void addToggleButton(std::vector &buttons, touch_gui_button_id id, const std::string &image_1, const std::string &image_2, - const recti &rect, bool visible=true); + const recti &rect, bool visible); IGUIImage *makeButtonDirect(touch_gui_button_id id, const recti &rect, bool visible); @@ -268,6 +227,8 @@ private: bool m_place_pressed = false; u64 m_place_pressed_until = 0; + + ButtonLayout m_layout; }; extern TouchControls *g_touchcontrols; diff --git a/src/gui/touchscreeneditor.cpp b/src/gui/touchscreeneditor.cpp new file mode 100644 index 000000000..b30ce5a20 --- /dev/null +++ b/src/gui/touchscreeneditor.cpp @@ -0,0 +1,404 @@ +// Luanti +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright (C) 2024 grorp, Gregor Parzefall + +#include "touchscreeneditor.h" +#include "touchcontrols.h" +#include "touchscreenlayout.h" + +#include "client/renderingengine.h" +#include "gettext.h" +#include "irr_gui_ptr.h" +#include "settings.h" + +#include "IGUIButton.h" +#include "IGUIFont.h" +#include "IGUIImage.h" +#include "IGUIStaticText.h" + +GUITouchscreenLayout::GUITouchscreenLayout(gui::IGUIEnvironment* env, + gui::IGUIElement* parent, s32 id, + IMenuManager *menumgr, ISimpleTextureSource *tsrc +): + GUIModalMenu(env, parent, id, menumgr), + m_tsrc(tsrc) +{ + if (g_touchcontrols) + m_layout = g_touchcontrols->getLayout(); + else + m_layout = ButtonLayout::loadFromSettings(); + + m_gui_help_text = grab_gui_element(Environment->addStaticText( + L"", core::recti(), false, false, this, -1)); + m_gui_help_text->setTextAlignment(EGUIA_CENTER, EGUIA_CENTER); + + m_gui_add_btn = grab_gui_element(Environment->addButton( + core::recti(), this, -1, wstrgettext("Add button").c_str())); + m_gui_reset_btn = grab_gui_element(Environment->addButton( + core::recti(), this, -1, wstrgettext("Reset").c_str())); + m_gui_done_btn = grab_gui_element(Environment->addButton( + core::recti(), this, -1, wstrgettext("Done").c_str())); + + m_gui_remove_btn = grab_gui_element(Environment->addButton( + core::recti(), this, -1, wstrgettext("Remove").c_str())); +} + +GUITouchscreenLayout::~GUITouchscreenLayout() +{ + ButtonLayout::clearTextureCache(); +} + +void GUITouchscreenLayout::regenerateGui(v2u32 screensize) +{ + DesiredRect = core::recti(0, 0, screensize.X, screensize.Y); + recalculateAbsolutePosition(false); + + s32 button_size = ButtonLayout::getButtonSize(screensize); + if (m_last_screensize != screensize || m_button_size != button_size) { + m_last_screensize = screensize; + m_button_size = button_size; + // Prevent interpolation when the layout scales. + clearGUIImages(); + } + + // Discard invalid selection. May happen when... + // 1. a button is removed. + // 2. adding a button fails and it disappears from the layout again. + if (m_selected_btn != touch_gui_button_id_END && + m_layout.layout.count(m_selected_btn) == 0) + m_selected_btn = touch_gui_button_id_END; + + if (m_mode == Mode::Add) + regenerateGUIImagesAddMode(screensize); + else + regenerateGUIImagesRegular(screensize); + regenerateMenu(screensize); +} + +void GUITouchscreenLayout::clearGUIImages() +{ + m_gui_images.clear(); + m_gui_images_target_pos.clear(); + + m_add_layout.layout.clear(); + m_add_button_titles.clear(); +} + +void GUITouchscreenLayout::regenerateGUIImagesRegular(v2u32 screensize) +{ + assert(m_mode != Mode::Add); + + auto old_gui_images = m_gui_images; + clearGUIImages(); + + for (const auto &[btn, meta] : m_layout.layout) { + core::recti rect = m_layout.getRect(btn, screensize, m_button_size, m_tsrc); + std::shared_ptr img; + + if (old_gui_images.count(btn) > 0) { + img = old_gui_images.at(btn); + // Update size, keep position. Position is interpolated in interpolateGUIImages. + img->setRelativePosition(core::recti( + img->getRelativePosition().UpperLeftCorner, rect.getSize())); + } else { + img = grab_gui_element(Environment->addImage(rect, this, -1)); + img->setImage(ButtonLayout::getTexture(btn, m_tsrc)); + img->setScaleImage(true); + } + + m_gui_images[btn] = img; + m_gui_images_target_pos[btn] = rect.UpperLeftCorner; + } +} + +void GUITouchscreenLayout::regenerateGUIImagesAddMode(v2u32 screensize) +{ + assert(m_mode == Mode::Add); + + clearGUIImages(); + + auto missing_buttons = m_layout.getMissingButtons(); + + layout_button_grid(screensize, m_tsrc, missing_buttons, + [&] (touch_gui_button_id btn, v2s32 pos, core::recti rect) { + auto img = grab_gui_element(Environment->addImage(rect, this, -1)); + img->setImage(ButtonLayout::getTexture(btn, m_tsrc)); + img->setScaleImage(true); + m_gui_images[btn] = img; + + ButtonMeta meta; + meta.setPos(pos, screensize, m_button_size); + m_add_layout.layout[btn] = meta; + + IGUIStaticText *text = Environment->addStaticText(L"", core::recti(), + false, false,this, -1); + make_button_grid_title(text, btn, pos, rect); + m_add_button_titles.push_back(grab_gui_element(text)); + }); +} + +void GUITouchscreenLayout::interpolateGUIImages() +{ + if (m_mode == Mode::Add) + return; + + for (auto &[btn, gui_image] : m_gui_images) { + bool interpolate = m_mode != Mode::Dragging || m_selected_btn != btn; + + v2s32 cur_pos_int = gui_image->getRelativePosition().UpperLeftCorner; + v2s32 tgt_pos_int = m_gui_images_target_pos.at(btn); + v2f cur_pos(cur_pos_int.X, cur_pos_int.Y); + v2f tgt_pos(tgt_pos_int.X, tgt_pos_int.Y); + + if (interpolate && cur_pos.getDistanceFrom(tgt_pos) > 2.0f) { + v2f pos = cur_pos.getInterpolated(tgt_pos, 0.5f); + gui_image->setRelativePosition(v2s32(core::round32(pos.X), core::round32(pos.Y))); + } else { + gui_image->setRelativePosition(tgt_pos_int); + } + } +} + +static void layout_menu_row(v2u32 screensize, + const std::vector> &row, + const std::vector> &full_row, bool bottom) +{ + s32 spacing = RenderingEngine::getDisplayDensity() * 4.0f; + + s32 btn_w = 0; + s32 btn_h = 0; + for (const auto &btn : full_row) { + IGUIFont *font = btn->getActiveFont(); + core::dimension2du dim = font->getDimension(btn->getText()); + btn_w = std::max(btn_w, (s32)(dim.Width * 1.5f)); + btn_h = std::max(btn_h, (s32)(dim.Height * 2.5f)); + } + + const s32 row_width = ((btn_w + spacing) * row.size()) - spacing; + s32 x = screensize.X / 2 - row_width / 2; + const s32 y = bottom ? screensize.Y - spacing - btn_h : spacing; + + for (const auto &btn : row) { + btn->setRelativePosition(core::recti( + v2s32(x, y), core::dimension2du(btn_w, btn_h))); + x += btn_w + spacing; + } +} + +void GUITouchscreenLayout::regenerateMenu(v2u32 screensize) +{ + bool have_selection = m_selected_btn != touch_gui_button_id_END; + + if (m_mode == Mode::Add) + m_gui_help_text->setText(wstrgettext("Start dragging a button to add. Tap outside to cancel.").c_str()); + else if (!have_selection) + m_gui_help_text->setText(wstrgettext("Tap a button to select it. Drag a button to move it.").c_str()); + else + m_gui_help_text->setText(wstrgettext("Tap outside to deselect.").c_str()); + + IGUIFont *font = m_gui_help_text->getActiveFont(); + core::dimension2du dim = font->getDimension(m_gui_help_text->getText()); + s32 height = dim.Height * 2.5f; + s32 pos_y = (m_mode == Mode::Add || have_selection) ? 0 : screensize.Y - height; + m_gui_help_text->setRelativePosition(core::recti( + v2s32(0, pos_y), + core::dimension2du(screensize.X, height))); + + bool normal_buttons_visible = m_mode != Mode::Add && !have_selection; + bool add_visible = normal_buttons_visible && !m_layout.getMissingButtons().empty(); + + m_gui_add_btn->setVisible(add_visible); + m_gui_reset_btn->setVisible(normal_buttons_visible); + m_gui_done_btn->setVisible(normal_buttons_visible); + + if (normal_buttons_visible) { + std::vector row1{m_gui_add_btn, m_gui_reset_btn, m_gui_done_btn}; + if (add_visible) { + layout_menu_row(screensize, row1, row1, false); + } else { + std::vector row1_reduced{m_gui_reset_btn, m_gui_done_btn}; + layout_menu_row(screensize, row1_reduced, row1, false); + } + } + + bool remove_visible = m_mode != Mode::Add && have_selection && + !ButtonLayout::isButtonRequired(m_selected_btn); + + m_gui_remove_btn->setVisible(remove_visible); + + if (remove_visible) { + std::vector row2{m_gui_remove_btn}; + layout_menu_row(screensize, row2, row2, true); + } +} + +void GUITouchscreenLayout::drawMenu() +{ + video::IVideoDriver *driver = Environment->getVideoDriver(); + + video::SColor bgcolor(140, 0, 0, 0); + video::SColor selection_color(255, 128, 128, 128); + video::SColor error_color(255, 255, 0, 0); + + driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect); + + // Done here instead of in OnPostRender to avoid drag&drop lagging behind + // input by one frame. + // Must be done before drawing selection rectangle. + interpolateGUIImages(); + + bool draw_selection = m_gui_images.count(m_selected_btn) > 0; + if (draw_selection) + driver->draw2DRectangle(selection_color, + m_gui_images.at(m_selected_btn)->getAbsolutePosition(), + &AbsoluteClippingRect); + + if (m_mode == Mode::Dragging) { + for (const auto &rect : m_error_rects) + driver->draw2DRectangle(error_color, rect, &AbsoluteClippingRect); + } + + IGUIElement::draw(); +} + +void GUITouchscreenLayout::updateDragState(v2u32 screensize, v2s32 mouse_movement) +{ + assert(m_mode == Mode::Dragging); + + core::recti rect = m_layout.getRect(m_selected_btn, screensize, m_button_size, m_tsrc); + rect += mouse_movement; + rect.constrainTo(core::recti(v2s32(0, 0), core::dimension2du(screensize))); + + ButtonMeta &meta = m_layout.layout.at(m_selected_btn); + meta.setPos(rect.getCenter(), screensize, m_button_size); + + rect = m_layout.getRect(m_selected_btn, screensize, m_button_size, m_tsrc); + + m_error_rects.clear(); + for (const auto &[other_btn, other_meta] : m_layout.layout) { + if (other_btn == m_selected_btn) + continue; + core::recti other_rect = m_layout.getRect(other_btn, screensize, m_button_size, m_tsrc); + if (other_rect.isRectCollided(rect)) + m_error_rects.push_back(other_rect); + } + if (m_error_rects.empty()) + m_last_good_layout = m_layout; +} + +bool GUITouchscreenLayout::OnEvent(const SEvent& event) +{ + if (event.EventType == EET_KEY_INPUT_EVENT) { + if (event.KeyInput.Key == KEY_ESCAPE && event.KeyInput.PressedDown) { + quitMenu(); + return true; + } + } + + core::dimension2du screensize = Environment->getVideoDriver()->getScreenSize(); + + if (event.EventType == EET_MOUSE_INPUT_EVENT) { + v2s32 mouse_pos = v2s32(event.MouseInput.X, event.MouseInput.Y); + + switch (event.MouseInput.Event) { + case EMIE_LMOUSE_PRESSED_DOWN: { + m_mouse_down = true; + m_last_mouse_pos = mouse_pos; + + IGUIElement *el = Environment->getRootGUIElement()->getElementFromPoint(mouse_pos); + // Clicking on nothing deselects. + m_selected_btn = touch_gui_button_id_END; + for (const auto &[btn, gui_image] : m_gui_images) { + if (el == gui_image.get()) { + m_selected_btn = btn; + break; + } + } + + if (m_mode == Mode::Add) { + if (m_selected_btn != touch_gui_button_id_END) { + m_mode = Mode::Dragging; + m_last_good_layout = m_layout; + m_layout.layout[m_selected_btn] = m_add_layout.layout.at(m_selected_btn); + updateDragState(screensize, v2s32(0, 0)); + } else { + // Clicking on nothing quits add mode without adding a button. + m_mode = Mode::Default; + } + } + + regenerateGui(screensize); + return true; + } + case EMIE_MOUSE_MOVED: { + if (m_mouse_down && m_selected_btn != touch_gui_button_id_END) { + if (m_mode != Mode::Dragging) { + m_mode = Mode::Dragging; + m_last_good_layout = m_layout; + } + updateDragState(screensize, mouse_pos - m_last_mouse_pos); + + regenerateGui(screensize); + } + + m_last_mouse_pos = mouse_pos; + return true; + } + case EMIE_LMOUSE_LEFT_UP: { + m_mouse_down = false; + + if (m_mode == Mode::Dragging) { + m_mode = Mode::Default; + if (!m_error_rects.empty()) + m_layout = m_last_good_layout; + + regenerateGui(screensize); + } + + return true; + } + default: + break; + } + } + + if (event.EventType == EET_GUI_EVENT) { + switch (event.GUIEvent.EventType) { + case EGET_BUTTON_CLICKED: { + if (event.GUIEvent.Caller == m_gui_add_btn.get()) { + m_mode = Mode::Add; + regenerateGui(screensize); + return true; + } + + if (event.GUIEvent.Caller == m_gui_reset_btn.get()) { + m_layout = ButtonLayout::predefined; + regenerateGui(screensize); + return true; + } + + if (event.GUIEvent.Caller == m_gui_done_btn.get()) { + if (g_touchcontrols) + g_touchcontrols->applyLayout(m_layout); + std::ostringstream oss; + m_layout.serializeJson(oss); + g_settings->set("touch_layout", oss.str()); + quitMenu(); + return true; + } + + if (event.GUIEvent.Caller == m_gui_remove_btn.get()) { + m_layout.layout.erase(m_selected_btn); + regenerateGui(screensize); + return true; + } + + break; + } + default: + break; + } + } + + return Parent ? Parent->OnEvent(event) : false; +} diff --git a/src/gui/touchscreeneditor.h b/src/gui/touchscreeneditor.h new file mode 100644 index 000000000..dc06fb224 --- /dev/null +++ b/src/gui/touchscreeneditor.h @@ -0,0 +1,81 @@ +// Luanti +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright (C) 2024 grorp, Gregor Parzefall + +#pragma once + +#include "touchscreenlayout.h" +#include "modalMenu.h" + +#include +#include + +class ISimpleTextureSource; +namespace irr::gui +{ + class IGUIImage; +} + +class GUITouchscreenLayout : public GUIModalMenu +{ +public: + GUITouchscreenLayout(gui::IGUIEnvironment* env, + gui::IGUIElement* parent, s32 id, + IMenuManager *menumgr, ISimpleTextureSource *tsrc); + ~GUITouchscreenLayout(); + + void regenerateGui(v2u32 screensize); + void drawMenu(); + bool OnEvent(const SEvent& event); + +protected: + std::wstring getLabelByID(s32 id) { return L""; } + std::string getNameByID(s32 id) { return ""; } + +private: + ISimpleTextureSource *m_tsrc; + + ButtonLayout m_layout; + v2u32 m_last_screensize; + s32 m_button_size; + + enum class Mode { + Default, + Dragging, + Add, + }; + Mode m_mode = Mode::Default; + + std::unordered_map> m_gui_images; + // unused if m_mode == Mode::Add + std::unordered_map m_gui_images_target_pos; + void clearGUIImages(); + void regenerateGUIImagesRegular(v2u32 screensize); + void regenerateGUIImagesAddMode(v2u32 screensize); + void interpolateGUIImages(); + + // interaction state + bool m_mouse_down = false; + v2s32 m_last_mouse_pos; + touch_gui_button_id m_selected_btn = touch_gui_button_id_END; + + // dragging + ButtonLayout m_last_good_layout; + std::vector m_error_rects; + void updateDragState(v2u32 screensize, v2s32 mouse_movement); + + // add mode + ButtonLayout m_add_layout; + std::vector> m_add_button_titles; + + // Menu GUI elements + std::shared_ptr m_gui_help_text; + + std::shared_ptr m_gui_add_btn; + std::shared_ptr m_gui_reset_btn; + std::shared_ptr m_gui_done_btn; + + std::shared_ptr m_gui_remove_btn; + + void regenerateMenu(v2u32 screensize); +}; diff --git a/src/gui/touchscreenlayout.cpp b/src/gui/touchscreenlayout.cpp new file mode 100644 index 000000000..0a88f5dd5 --- /dev/null +++ b/src/gui/touchscreenlayout.cpp @@ -0,0 +1,345 @@ +// Luanti +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright (C) 2024 grorp, Gregor Parzefall + +#include "touchscreenlayout.h" +#include "client/renderingengine.h" +#include "client/texturesource.h" +#include "convert_json.h" +#include "gettext.h" +#include "settings.h" +#include + +#include "IGUIFont.h" +#include "IGUIStaticText.h" + +const char *button_names[] = { + "jump", + "sneak", + "zoom", + "aux1", + "overflow", + + "chat", + "inventory", + "drop", + "exit", + + "fly", + "fast", + "noclip", + "debug", + "camera", + "range", + "minimap", + "toggle_chat", + + "joystick_off", + "joystick_bg", + "joystick_center", +}; + +// compare with GUIKeyChangeMenu::init_keys +const char *button_titles[] = { + N_("Jump"), + N_("Sneak"), + N_("Zoom"), + N_("Aux1"), + N_("Overflow menu"), + + N_("Chat"), + N_("Inventory"), + N_("Drop"), + N_("Exit"), + + N_("Toggle fly"), + N_("Toggle fast"), + N_("Toggle noclip"), + N_("Toggle debug"), + N_("Change camera"), + N_("Range select"), + N_("Toggle minimap"), + N_("Toggle chat log"), + + N_("Joystick"), + N_("Joystick"), + N_("Joystick"), +}; + +const char *button_image_names[] = { + "jump_btn.png", + "down.png", + "zoom.png", + "aux1_btn.png", + "overflow_btn.png", + + "chat_btn.png", + "inventory_btn.png", + "drop_btn.png", + "exit_btn.png", + + "fly_btn.png", + "fast_btn.png", + "noclip_btn.png", + "debug_btn.png", + "camera_btn.png", + "rangeview_btn.png", + "minimap_btn.png", + // toggle button: switches between "chat_hide_btn.png" and "chat_show_btn.png" + "chat_hide_btn.png", + + "joystick_off.png", + "joystick_bg.png", + "joystick_center.png", +}; + +v2s32 ButtonMeta::getPos(v2u32 screensize, s32 button_size) const +{ + return v2s32((position.X * screensize.X) + (offset.X * button_size), + (position.Y * screensize.Y) + (offset.Y * button_size)); +} + +void ButtonMeta::setPos(v2s32 pos, v2u32 screensize, s32 button_size) +{ + v2s32 third(screensize.X / 3, screensize.Y / 3); + + if (pos.X < third.X) + position.X = 0.0f; + else if (pos.X < 2 * third.X) + position.X = 0.5f; + else + position.X = 1.0f; + + if (pos.Y < third.Y) + position.Y = 0.0f; + else if (pos.Y < 2 * third.Y) + position.Y = 0.5f; + else + position.Y = 1.0f; + + offset.X = (pos.X - (position.X * screensize.X)) / button_size; + offset.Y = (pos.Y - (position.Y * screensize.Y)) / button_size; +} + +bool ButtonLayout::isButtonAllowed(touch_gui_button_id id) +{ + return id != joystick_off_id && id != joystick_bg_id && id != joystick_center_id && + id != touch_gui_button_id_END; +} + +bool ButtonLayout::isButtonRequired(touch_gui_button_id id) +{ + return id == overflow_id; +} + +s32 ButtonLayout::getButtonSize(v2u32 screensize) +{ + return std::min(screensize.Y / 4.5f, + RenderingEngine::getDisplayDensity() * 65.0f * + g_settings->getFloat("hud_scaling")); +} + +const ButtonLayout ButtonLayout::predefined {{ + {jump_id, { + v2f(1.0f, 1.0f), + v2f(-1.0f, -0.5f), + }}, + {sneak_id, { + v2f(1.0f, 1.0f), + v2f(-2.5f, -0.5f), + }}, + {zoom_id, { + v2f(1.0f, 1.0f), + v2f(-0.75f, -3.5f), + }}, + {aux1_id, { + v2f(1.0f, 1.0f), + v2f(-0.75f, -2.0f), + }}, + {overflow_id, { + v2f(1.0f, 1.0f), + v2f(-0.75f, -5.0f), + }}, +}}; + +ButtonLayout ButtonLayout::loadFromSettings() +{ + bool restored = false; + ButtonLayout layout; + + std::string str = g_settings->get("touch_layout"); + if (!str.empty()) { + std::istringstream iss(str); + try { + layout.deserializeJson(iss); + restored = true; + } catch (const Json::Exception &e) { + warningstream << "Could not parse touchscreen layout: " << e.what() << std::endl; + } + } + + if (!restored) + return predefined; + + return layout; +} + +std::unordered_map> ButtonLayout::texture_cache; + +video::ITexture *ButtonLayout::getTexture(touch_gui_button_id btn, ISimpleTextureSource *tsrc) +{ + if (texture_cache.count(btn) > 0) + return texture_cache.at(btn).get(); + + video::ITexture *tex = tsrc->getTexture(button_image_names[btn]); + if (!tex) + // necessary in the mainmenu + tex = tsrc->getTexture(porting::path_share + "/textures/base/pack/" + + button_image_names[btn]); + irr_ptr ptr; + ptr.grab(tex); + texture_cache[btn] = ptr; + return tex; +} + +void ButtonLayout::clearTextureCache() +{ + texture_cache.clear(); +} + +core::recti ButtonLayout::getRect(touch_gui_button_id btn, + v2u32 screensize, s32 button_size, ISimpleTextureSource *tsrc) +{ + const ButtonMeta &meta = layout.at(btn); + v2s32 pos = meta.getPos(screensize, button_size); + + v2u32 orig_size = getTexture(btn, tsrc)->getOriginalSize(); + v2s32 size((button_size * orig_size.X) / orig_size.Y, button_size); + + return core::recti(pos - size / 2, core::dimension2di(size)); +} + +std::vector ButtonLayout::getMissingButtons() +{ + std::vector missing_buttons; + for (u8 i = 0; i < touch_gui_button_id_END; i++) { + touch_gui_button_id btn = (touch_gui_button_id)i; + if (isButtonAllowed(btn) && layout.count(btn) == 0) + missing_buttons.push_back(btn); + } + return missing_buttons; +} + +void ButtonLayout::serializeJson(std::ostream &os) const +{ + Json::Value root = Json::objectValue; + root["layout"] = Json::objectValue; + + for (const auto &[id, meta] : layout) { + Json::Value button = Json::objectValue; + button["position_x"] = meta.position.X; + button["position_y"] = meta.position.Y; + button["offset_x"] = meta.offset.X; + button["offset_y"] = meta.offset.Y; + + root["layout"][button_names[id]] = button; + } + + fastWriteJson(root, os); +} + +static touch_gui_button_id button_name_to_id(const std::string &name) +{ + for (u8 i = 0; i < touch_gui_button_id_END; i++) { + if (name == button_names[i]) + return (touch_gui_button_id)i; + } + return touch_gui_button_id_END; +} + +void ButtonLayout::deserializeJson(std::istream &is) +{ + layout.clear(); + + Json::Value root; + is >> root; + + if (!root["layout"].isObject()) + throw Json::RuntimeError("invalid type for layout"); + + Json::Value &obj = root["layout"]; + Json::ValueIterator iter; + for (iter = obj.begin(); iter != obj.end(); iter++) { + touch_gui_button_id id = button_name_to_id(iter.name()); + if (!isButtonAllowed(id)) + throw Json::RuntimeError("invalid button name"); + + Json::Value &value = *iter; + if (!value.isObject()) + throw Json::RuntimeError("invalid type for button metadata"); + + ButtonMeta meta; + + if (!value["position_x"].isNumeric() || !value["position_y"].isNumeric()) + throw Json::RuntimeError("invalid type for position_x or position_y in button metadata"); + meta.position.X = value["position_x"].asFloat(); + meta.position.Y = value["position_y"].asFloat(); + + if (!value["offset_x"].isNumeric() || !value["offset_y"].isNumeric()) + throw Json::RuntimeError("invalid type for offset_x or offset_y in button metadata"); + meta.offset.X = value["offset_x"].asFloat(); + meta.offset.Y = value["offset_y"].asFloat(); + + layout.emplace(id, meta); + } +} + +void layout_button_grid(v2u32 screensize, ISimpleTextureSource *tsrc, + const std::vector &buttons, + // pos refers to the center of the button + const std::function &callback) +{ + s32 cols = 4; + s32 rows = 3; + f32 screen_aspect = (f32)screensize.X / (f32)screensize.Y; + while ((s32)buttons.size() > cols * rows) { + f32 aspect = (f32)cols / (f32)rows; + if (aspect > screen_aspect) + rows++; + else + cols++; + } + + s32 button_size = ButtonLayout::getButtonSize(screensize); + v2s32 spacing(screensize.X / (cols + 1), screensize.Y / (rows + 1)); + v2s32 pos(spacing); + + for (touch_gui_button_id btn : buttons) { + v2u32 orig_size = ButtonLayout::getTexture(btn, tsrc)->getOriginalSize(); + v2s32 size((button_size * orig_size.X) / orig_size.Y, button_size); + + core::recti rect(pos - size / 2, core::dimension2di(size)); + + if (rect.LowerRightCorner.X > (s32)screensize.X) { + pos.X = spacing.X; + pos.Y += spacing.Y; + rect = core::recti(pos - size / 2, core::dimension2di(size)); + } + + callback(btn, pos, rect); + + pos.X += spacing.X; + } +} + +void make_button_grid_title(gui::IGUIStaticText *text, touch_gui_button_id btn, v2s32 pos, core::recti rect) +{ + std::wstring str = wstrgettext(button_titles[btn]); + text->setText(str.c_str()); + gui::IGUIFont *font = text->getActiveFont(); + core::dimension2du dim = font->getDimension(str.c_str()); + dim = core::dimension2du(dim.Width * 1.25f, dim.Height * 1.25f); // avoid clipping + text->setRelativePosition(core::recti(pos.X - dim.Width / 2, rect.LowerRightCorner.Y, + pos.X + dim.Width / 2, rect.LowerRightCorner.Y + dim.Height)); + text->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_UPPERLEFT); +} diff --git a/src/gui/touchscreenlayout.h b/src/gui/touchscreenlayout.h new file mode 100644 index 000000000..9c7d72fbf --- /dev/null +++ b/src/gui/touchscreenlayout.h @@ -0,0 +1,104 @@ +// Luanti +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright (C) 2024 grorp, Gregor Parzefall + +#pragma once + +#include "irr_ptr.h" +#include "irrlichttypes_bloated.h" +#include "rect.h" +#include +#include + +class ISimpleTextureSource; +namespace irr::gui +{ + class IGUIStaticText; +} +namespace irr::video +{ + class ITexture; +} + +enum touch_gui_button_id : u8 +{ + jump_id = 0, + sneak_id, + zoom_id, + aux1_id, + overflow_id, + + // formerly "rare controls bar" + chat_id, + inventory_id, + drop_id, + exit_id, + + // formerly "settings bar" + fly_id, + fast_id, + noclip_id, + debug_id, + camera_id, + range_id, + minimap_id, + toggle_chat_id, + + // the joystick + joystick_off_id, + joystick_bg_id, + joystick_center_id, + + touch_gui_button_id_END, +}; + +extern const char *button_names[]; +extern const char *button_titles[]; +extern const char *button_image_names[]; + +struct ButtonMeta { + // Position, specified as a percentage of the screensize in the range [0,1]. + // The editor currently writes the values 0, 0.5 and 1. + v2f position; + // Offset, multiplied by the global button size before it is applied. + // Together, position and offset define the position of the button's center. + v2f offset; + + // Returns the button's effective center position in pixels. + v2s32 getPos(v2u32 screensize, s32 button_size) const; + // Sets the button's effective center position in pixels. + void setPos(v2s32 pos, v2u32 screensize, s32 button_size); +}; + +struct ButtonLayout { + static bool isButtonAllowed(touch_gui_button_id id); + static bool isButtonRequired(touch_gui_button_id id); + static s32 getButtonSize(v2u32 screensize); + static ButtonLayout loadFromSettings(); + + static video::ITexture *getTexture(touch_gui_button_id btn, ISimpleTextureSource *tsrc); + static void clearTextureCache(); + + std::unordered_map layout; + + core::recti getRect(touch_gui_button_id btn, + v2u32 screensize, s32 button_size, ISimpleTextureSource *tsrc); + + std::vector getMissingButtons(); + + void serializeJson(std::ostream &os) const; + void deserializeJson(std::istream &is); + + static const ButtonLayout predefined; + +private: + static std::unordered_map> texture_cache; +}; + +void layout_button_grid(v2u32 screensize, ISimpleTextureSource *tsrc, + const std::vector &buttons, + // pos refers to the center of the button. + const std::function &callback); + +void make_button_grid_title(gui::IGUIStaticText *text, + touch_gui_button_id btn,v2s32 pos, core::recti rect); diff --git a/src/irr_gui_ptr.h b/src/irr_gui_ptr.h new file mode 100644 index 000000000..8c16a5b1e --- /dev/null +++ b/src/irr_gui_ptr.h @@ -0,0 +1,28 @@ +// Luanti +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright (C) 2024 grorp, Gregor Parzefall + +#pragma once +#include +#include "IGUIElement.h" + +// We cannot use irr_ptr for Irrlicht GUI elements we own. +// Option 1: Pass IGUIElement* returned by IGUIEnvironment::add* into irr_ptr +// constructor. +// -> We steal the reference owned by IGUIEnvironment and drop it later, +// causing the IGUIElement to be deleted while IGUIEnvironment still +// references it. +// Option 2: Pass IGUIElement* returned by IGUIEnvironment::add* into irr_ptr::grab. +// -> We add another reference and drop it later, but since IGUIEnvironment +// still references the IGUIElement, it is never deleted. +// To make IGUIEnvironment drop its reference to the IGUIElement, we have to call +// IGUIElement::remove, so that's what we'll do. +template +std::shared_ptr grab_gui_element(T *element) +{ + static_assert(std::is_base_of_v, + "grab_gui_element only works for IGUIElement"); + return std::shared_ptr(element, [](T *e) { + e->remove(); + }); +} diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp index e8c969268..0353efe1d 100644 --- a/src/script/lua_api/l_mainmenu.cpp +++ b/src/script/lua_api/l_mainmenu.cpp @@ -11,6 +11,7 @@ #include "gui/guiMainMenu.h" #include "gui/guiKeyChangeMenu.h" #include "gui/guiPathSelectMenu.h" +#include "gui/touchscreeneditor.h" #include "version.h" #include "porting.h" #include "filesys.h" @@ -535,6 +536,22 @@ int ModApiMainMenu::l_show_keys_menu(lua_State *L) return 0; } +/******************************************************************************/ +int ModApiMainMenu::l_show_touchscreen_layout(lua_State *L) +{ + GUIEngine *engine = getGuiEngine(L); + sanity_check(engine != NULL); + + GUITouchscreenLayout *gui = new GUITouchscreenLayout( + engine->m_rendering_engine->get_gui_env(), + engine->m_parent, + -1, + engine->m_menumanager, + engine->m_texture_source.get()); + gui->drop(); + return 0; +} + /******************************************************************************/ int ModApiMainMenu::l_create_world(lua_State *L) { @@ -1080,6 +1097,7 @@ void ModApiMainMenu::Initialize(lua_State *L, int top) API_FCT(start); API_FCT(close); API_FCT(show_keys_menu); + API_FCT(show_touchscreen_layout); API_FCT(create_world); API_FCT(delete_world); API_FCT(set_background); diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h index d0f72b6c4..704924bf3 100644 --- a/src/script/lua_api/l_mainmenu.h +++ b/src/script/lua_api/l_mainmenu.h @@ -69,6 +69,8 @@ private: static int l_show_keys_menu(lua_State *L); + static int l_show_touchscreen_layout(lua_State *L); + static int l_show_path_select_dialog(lua_State *L); static int l_set_topleft_text(lua_State *L); diff --git a/textures/base/pack/down.png b/textures/base/pack/down.png index 7183ee5364c4f54d0f3dff7a6908ef36fe5a47a8..594863dba86ea4e9cbc563f9e8c574ac5830d2f5 100644 GIT binary patch literal 3647 zcmeH{*H;q=7REyeLXeJt6a__y1Ps!`5K0hX=pCd40YL&7iu4|WgLFg%snQH(=pZ4| z!-OVMl-@yHni&GpYhaz-hy4R~-*$fI+;h)&&$-{jcka3ICPvz<%mT~+0Dx6jN7D=d zpu_zv02BSsNphK~B>(_CG%>Ky`Y9_bD=8Gp#ozp$!2eAGy-zb@f1duCznPKw&kmpi z(t{W-F*1RfFSD?+v2$>8abMx#<-5u+ASiV0y0FNNo1(YG#38pOppsH|VA6MGWaZ=) z;EKN}A(T~A)sX7~_tEX>ZXk=_+YG!U>`M}EB#ujDw(BYAj^J5pZtDE~1 zjEAR}_fsEVKmUNhpx}_uu<(dTT-3AZ=P|Ky@d=4Z$uCk~zIvUS_9i_eGb=kMH!r`S z@EyLWxTLhKyrQzIx~8`7eLbOp_@S|>xuvzOoz(FMxwEUgr}tyur~ZM#q0e82M@GlS zCnl$+XJ+T-7Z$%Ref!7q%Iezscgmj|)Xl9Q+dI2^`v-?d$0w&}v~v?ZnGFB{e5$K? z&mwq+nj2PP^3h4#jlE0zl&~*LRi7-s#*L`BGd>_78YEq^kg@7bZhd&*YI6%wI_dQlP5| z0N2Tr`v4{Yoe0j2p&%K-dL)ey^+eIFm$XK|1Q+DLjBXX5Ap+g}Zc2dHV-p63XKZmB zOh&J(frew+kN>?10O0@}0HFH6Z2luU-T<0~n0{OUm)AX{)JI>%x(HboGS{J%4&st& zxCQ&crLpa5{0%y-cBq#<0jw0*msSKBtu$Hk%8+ zvn%F`eS@10v%|x~3lxSAvvyoZsw8oTpHk`HhzBaB+Y^+*QdP>Q!vt% zD%n;A#bE}ncdD=O`CI94PXx2~DyL+nTCH-D8XAieue;f?ggMz&K>;hR6f?;}wuXk~ zf8PAzxnc}C=N~EGTo=X~KjvvlPJ>}Ab{Nr_t zHrdfvpnsDTl zqmVUl=J!67;>cA3Zh@OA7c{3vGlHoE zcTlsjj=KKH-wjW*DHz*LEunC^%jmXE&7F-Ky2ku{*e_18)}C!W!=DZOJIH;oVFSTj;dE$0!=5y&RK5iGMVm z+gYJ82a=-8p|XdHw0mWfNB8VuBShN4F!gO~f2ykvrO@6qcgn zV%3IMb@w;Ud@4cQd00|*u!1*qN@dUxSHg-RYE~o5L}O?{DM;lkz8DeFsQSo}1wGNF zG|I@s1>TBuFovfV-M{DX(BoEDE}@R{HNgiKZZqTY7Vfp3hw_ZJ{4yW9-@pJ}%7j-= ze^W|yBkmm#BAcWoUOJeFr>|y^S3gT}(xjlopI0?iBb)QC zC<_YiPCReXIc~yfE61v4%&MP_DjZ{k{nsK(a@*QL$WwcT?SrYO2d?HSArQJ8>-eL- z*nlon#NcVg{rTu6g}UR^f;5`K@>w5*l-Vaa8Z(G#>h(CX)*ir&w`T}Ii&}a8(vu$& zwh+^Vrq*3f9&ZCdI4*Ji#79o19<{ysOc!2#Dl)^C3MX*gt&bwV-71Xa|o~0 zQ?7;aJe~Y?FGlc`p#DdSXb^}O=J)gu8TTEB+GB>bipzM@V7^~v?6#*7R&=EX(Rs^G zsWCESBLU`L1|`!8O(w}~i9M#@^BJ6lSnF$`F#JdR2M(kFTV0|Na#n59e2(T7fj*R$ zeln0XPdAr2pPtB=KxD2C#-;kEsK7p{YNFKS40=VJ8VoPzT{2ZqhmQ~XG@pCg?Lbbr z^k510If<1Pdr#`(8t=1cb-hiC;6vdzPVM<=kY(8u!7UZo3)xVZfbgfFL19x^`{&e5 znyq{NefifcANJQcFIOSkI}NRr?In3g*^5H;Sx-UK{34EF6J*kXaX*#7hlLFV&MYaa zugxor0%+u-LV5K?%xxsPr0{Gnlv6RyZx_^Yvi^sWwMyCDC!iEZ|I7%GGe?QxBK~Gh zd`iNXT+7%zX6_68%}#mG@QjW2VO{K{)sE6A-65oKeG^!6mHR z2d5E1pVvH#c*X+vjdxpD;*=R(X6&AbXTh(HM>_EOU#z^zrP1jxw$B?O?%V2VdK0Z> zp!;v%e>b2XCX@{svYt0Pca-GNV;e8vGHo-#H$+2|Sn$YTu-(mxToJWF=StOA0_RBZ z)KY%q&U&uVh^j^gDWqH!c~|)vBr4vyT(zz4V%R?L2$Ca*nu4Uya~!escFDF>xD9!4 z&RP~-H_c&=L-zwtd9G?$2-M2=Z!{sai?iJiy08!>ofoM=k4pw;Cv{%A7^8-x=(UzJ z8&o8R9ipltiz?I=f_ldTNAPWz=p|+sP4lvT@2Tn+5ct^IPSXQ_AGRm|P<+#lnAMK) zuOBzaaofSS(W5tsy`dj#kFCcES=ql1++ECQ!TKNuc-at8@`O;0%y4=PX>;t$oZwy1 zsQBY;ju(47z!H}u3>*XbC>j} zW1?1Mb6M>nRXNh?SW$oe1l#Q_MaBwd!OI&Lu~joK%bdd_(gn2C;1PtNQHJ@p-_zif zX+8VQJ47r&5qjsaebz=U;nbx)iTno)^L3GPwDtKyZ`_I literal 1618 zcmbV_Ydq5n7{~v1Msf+IGm*>Dl|!gWE;}WorVN|4!Zg*Q879j$S-Eu5bfsx-Wek(c zsb;x5r=)`{mp?_QCTkeZ+9vnoyf`n;i}R-Mo9FpGzvuJ&UGqX8(p1w|0{}o1br^{O z0HxJc2~dTu4n;gs0stzTP)KK=m;uQUih?8Qz5J^WQ^dpkUcE1{+~!oM4SJsswgsLR zq2{*Uw(X8`b}Ej~)D%}!RQ-Chh~=(ql~39Xy`qvA?i0{oH*~tTq#ciW9}Gk;6 zv+A*z6q2>_)7+5qGL zAXRP78k34f!#e~3py@0CqC>3PCtF=y@VLjG70T=8o+)W5Olfa^OGh0 z zn@qpyPjzuBxPoREZ6lE6<5dqIkBEn@cX=1$X+Ndg_R$&x;2`aK=T{*euNQ_XOo~e$ z)9237FIoG1jg~t!Oj(_O!<;Y_&VnbN#;_dvLYjSAy)C7ZH$kP=lBBl8$sSAiysmA1 zfN}QJBNbY0{toJ0g&z8Yr~HZUOw#~Z;(15|T=3`5UDQvHdoR;bRPQPhw}R!k%It9k z4N#x*t;p9Xma3O2x8gda{&Eq~oO3L6&*xY#(bkbgH$)&8^m9%)%XLebfBw{$itm;* z5l$lG!NQjLS1}&(Zg*Z+;+zj@ZX77fc0sf_2nmukwYzH+{0V~a?%mWXPul%PJ4FBZ zks#gykfUkTootl$ktUi@#`f{Y7qV@|+cWPBSr8sazWIGf;4X)gJmKkJ7Hqm9(%1)v-H6S8|OjU_6nE7*LtU zx3>f)AUV>Ft*#h*Sj`&YvsbSRi0TYJ%1Z1%Ehs_>I8oW{Nq0t#X(ViYvvDS8xy14M zdX@U)1?zsSdu(=w-dCy5XsHEb5{|w|A$BDKYW#A9vCWU6=|fgyG~;^>$G$v!k*uR{4gpPKiL&naw25 z=|V)6-s+;7Gv+$fZ!*H`vCOpr$zp4W0$+NMxBRkAT<{cos6ee zn9Yq$oypk4(3X8EdldcgeiN|~M9@rDRN?2|%5YUf)mnIU8QCH}qi3!2S;xO5ST)Mb z%+HX}fq*Fs^x8=GMT@+vIy)ovJ?&mNmS&+xY?|+U3$TW zofDBlj5QN-#%42}+(^%_(J%D$-AX;WGPIY60jo@jhIXWkJ)gAwi?!OrR*bIhZ)0?9 zSv{u92}9O5v-2osbCgHxuTI32Z>ky25|}L!~g&Q diff --git a/textures/base/pack/jump_btn.png b/textures/base/pack/jump_btn.png index 17b7cb586dbb602e8f37fac463e5630b316826e0..dbb455b9598328eda2b68d4e3b903fbc29ace1c1 100644 GIT binary patch literal 3625 zcmeH_X*d*$8plVrL|5sMD2b3QI*PK*kR`jpU_$m8V~mt#jNM2GCCPd;smLzF*mq+| zmdThVV~~9t`_ABY?#KJ}e7yJfJn!>9|M$cH!|!?H%uV&ro)J0&007P!JkYTK09Yb^ z58yQG?@M9<7yhqqB>vn>!5df$&6n zp}ZgaJbCKt=O2I$!~_M0goZ~%VxL7nkBNSC7TtcGL%hf+Qi6SZi)Qve1YX&5-7i^>c{y ziEzh5*ix1#anqxcD<6CV2tI?9bee<^=#+VxkJvi$W40i zxbJ{(zxz+czs3J!1YU&)$?}URMg*V{9rBO zJx{q1hB6!)@ndvwjddGh2GklQ;i2?FS5f8>U*)?%>DHJx0HL*1blo0tE~Wc0;dHY# zwyA0`(SYF+@pB!|bYM0g(%2E>C0g&3ZJIR2N$m9zF%4wMZ6rDO=GzrYnS~7G8QUlY zQxH}oNMD_p5=cH+nK6}FWyp;aiW;JlK%ly1r;7Bc6&DK_b!U_J%y@>d`)Po zFV0|_N)u_&DwL3a1gv$Gce39Ll`2vDu05SyXUZQn2U*Ivyo`yS7qavgd0o6)e^92Y z+EjGp$Utw0mBaVjDsQ!Utp|I3!>Cp;H*i2fUAI*Gej(-&%F+B@QQ_vGBb>8lLUa&^ z<^aCil{g=kSh)0bOkD$AbZj@$8J|roF&Twc_#b=F`{viUqXfJg3*TFRVK7(Uu<}@4 ztf`A0Zx`;72(_xM3xMmL?xD2%WyrT@3|owpNG>7EG#IWrp@~cU8(}^g&|311#U1qv zGhF1^5txzH>^oR)X0c*foJv(&Z*i0XPy$KK6nXM}G43b(2@W0f>YGfRLGDpw;?=YL zuFiZqrFVxw1|(`oh)E@{aaKLdsBOT^Am2keYu8PWi?h~gIQ7gx;7J~qW`S2~HpU{9 zoT{!*r&NOD;wOV9K9tij>k(W)sNlg+sZdX=4I#}tgh*|*i>qOu=Ubc48*sN8{6GrG zOb@iL5D_@RU?`(0t|V&$2A0GM&y_>%28Z}UF7m(MS(Nw1u1bN7f3;kCY*hu`ty__` z!}0hGJth3``dTLWD)!|IpouVMT%Qe1+&3My`eAD5v)w4wS)(?lMSK}U`dm%@jsPxI z&rFFAkAFSfKtL5B_I2gRueK^(J%&&MkWq_OrFq@k?)l^VV}zIz%7q%HovGZYvZE01 zBia=a4TSBNOG+TBF1y0GaqCVqi(CiBS*d1tNwruu`+^pwfIhG^;qqIR_;b;FVc>(l<5dj!@X_jEkxDO@}oaH+vSX2ziH99jtWNcu2WXuq|Qn1 z4-@{@mr`vBGon(}2DSUr`0)+sEi8)g%=JCkKg64wcXoH~aG<$G8GxXDpe0Ym7Lc{t;bz)x0&&TRV6rB1!nhyOi_W|UD&?f z-pY)Im70WJ;^MCSOMI61&D2nx#xK>;#)lmp3Yzn%i5^8?o=NM=k0lj2N_2}pYA{-F zIYmdL<3i~=S@Qb$u3+9)7gs(VIiOEeLt^z`%;>&>@Cwxg^d!x!z%K3K_dPAxC!g3I zRjEk3z|MXSyoiLt5ydJ?8D-n{I^|H>fv0qTx6OP7sgly1<1@s(V&g%crO)c?DtppA zkn7}=K(Jo4<2vM+9C<%`wVYwwjM(hRs)$07DsSz@5FD$LfnH8I_Q`hJ+U2VysJ;A< z@K%z@+b9*gwyiLFPcdT(W{-Cg&pTVR69YWaYD~;UbC74A^QP$sLBp+s4zV9A8@XTR zaJ#;$34Gh3kPy{889cnkKfY)vDfvgO2!2^C4Z?r+N<}YH-raXB@nvC&va6qM)DyR4 z3Ocds;AZ138#gs;TSHvhM61<^gOls8Y*YHb^+qdYf{FM6+44lAJXx9ID(cQ-8rK4OD%s~ z9&r*rx~EB-H_6Wd?gZu1uW?-E;Z3$b-rSX2K;0die-)78nHdQ#1Q}`2meSiF&k9Rk zX6g`**9R)fe$MU9Wj}ei;X-n2yIaCVIqv4?+~xtD>`JJKM66uB0UXSSzYn1VDrwT< zr2q*S3upg^3}fMCalx%kf~W527+h@m?kf#9^&{bv$`b2>k914Lk2%Gc8%AyqR)W2a zwx%Hw5xM#hRa}&M_63Efq!@HM;sVb1;b+80)wn9^R7nP>aivD6YJANclIQKPSFGO)CJ2MgfD>PQ>WKVSk7EO2RH=+oCdIn0@xw|{~gke zBHC;tF9?Fp*?AyXrgf#yPqhHfOX~{ku-?_Tkl{cljgiX`EJl3utf&6d!Z3*VRm^u< zQIN$DkHzq}0H>19INuSWA^;Wc)2b3 u?(5EGX22ctOT9q~rTz0z4!}RhsgKERidg#jpf!SJ_rE(8J7>YEX+&BwhA*X*TFjrP zr!*6Tx)^nmZ~xu;MrUJ8_n}ad&975lr&Nq7_3J#8N~Zm7+A9lt)rMM0GrvaNIxZ`} zt5@fsT5{}f((@{pS9BT5CBy!E^}Qit)AoChb#D_A7^y z@x1Np(I2V?e=4t96pfet&Dv=)cSu8~@9k7Gs>a9uF8yLKbwWLvOeUjsI%@d#uX-G1 z<6!<=Z8e?K?`g@u+gzo$OxtWzJqr76|8jj{Fmh6TI`_2gW~o;v4O<@6ov7@q`LmS& zXN12vU#Vlp?SF68=Z39MssHrwfFJfR(ypMFar58DZY@P|zwEc&$Q{vRCHJ(}dIPB% zboayj1`V6e+g-MaUs|ZwP5XOEm!N+1_IK*LYIo+SMm;)V*z1p4g#%HVf4=%kOz`-d zQQc7XzT5SYVb4?As@XUZjs4aM9s|0d!g$#Rl0MP(xPRf=eCtK}kRA;5JNKA|l20nn z1QM6_FVG97bN}VwlRDI>=S;u#s;T~E* z9gbC3`hRAX{@B_S>JlBP-odHkw|E zG}s@TzBjFQ-7lGZ^P9}Q@0WYgUWX$SX|Uf`%71ynrvh$s@p-_p$>f`#HIKkw=Uv;| z^kJB@6VhP+vUtzIDPw-pjkx{)i>R%X^9SAU^>K9STgpw#mu;cmNXk51HRxH>vAoUV zl+%)}EvJ+-CJ(Vys!~Y4`Sx0zC9yiLMUs~I1hFOy#O*?I;}+vhr5FwvUS2lO4jF&+k}^(hr3!ou|oe0S47*Cw}<2Z zpJ(CY^i7&ni#|yBdgV-;E}@Tg+WUcMrhmN$J2-pcM5^D@RrDQZ@hvx{bgB%kl2>j@ z@ni*xjhn_sy5o@NCro*Mm-6W|u9>#-_h-C*)wOQZeil#&aMxs80OKw{4}c|9f@^q- zc?lffCXld*Qk8VHFM_qqr)JwqIgjX3EHW?y3=MYE<0^rErc^ncQ* zo61tE;pl2#3ipBN8fjfjxxiw|73mxDV%R~O*Q$c)j&-xLm|3C5S#36+Vy&*5)^6(U zV~M2TO0U$ILFvP4cl!^u$Iz%9YQ#Wix7m9fJ`*TcvN^}->94BdmI);8UUIDsyjIP5 z1eR)d3Dq~aYs|)?Z{^%XPk$(?*Dh&O(a!dbJ_LYQtA?w5v2s%n0x58+e2Dh_C*b&w`UBy?Tl>FD4Ki3sG3~&N7rkM zCQ#l3CbT7@*K2Bya_Zz0=_eQ47fJvC000000002MU+uvG2><{9fS~`c+YzV$00000 elePpK7F+}k^M@G+J9DQ10000 Date: Sun, 24 Nov 2024 19:23:32 +0100 Subject: [PATCH 080/136] Doc: Add missing jpeg package for Arch Linux (#15461) --- doc/compiling/linux.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/compiling/linux.md b/doc/compiling/linux.md index 573c6908e..54f7de2a0 100644 --- a/doc/compiling/linux.md +++ b/doc/compiling/linux.md @@ -33,7 +33,7 @@ For openSUSE users: For Arch users: - sudo pacman -S --needed base-devel libcurl-gnutls cmake libpng sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses zstd gettext sdl2 + sudo pacman -S --needed base-devel libcurl-gnutls cmake libpng libjpeg-turbo sqlite libogg libvorbis openal freetype2 jsoncpp gmp luajit leveldb ncurses zstd gettext sdl2 For Alpine users: From b77ad82fb952e728b43307d1f3fc13671d0f0236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Sun, 24 Nov 2024 19:23:53 +0100 Subject: [PATCH 081/136] Sanitize invalid particle spawner time (#15465) --- src/client/particles.cpp | 1 + src/network/clientpackethandler.cpp | 3 +++ src/script/lua_api/l_particles.cpp | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/src/client/particles.cpp b/src/client/particles.cpp index c6891f8ef..472ac0321 100644 --- a/src/client/particles.cpp +++ b/src/client/particles.cpp @@ -270,6 +270,7 @@ ParticleSpawner::ParticleSpawner( } size_t max_particles = 0; // maximum number of particles likely to be visible at any given time + assert(p.time >= 0); if (p.time != 0) { auto maxGenerations = p.time / std::min(p.exptime.start.min, p.exptime.end.min); max_particles = p.amount / maxGenerations; diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 9f987ccea..fbd7bdd9e 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -4,6 +4,7 @@ #include "client/client.h" +#include "exceptions.h" #include "irr_v2d.h" #include "util/base64.h" #include "client/camera.h" @@ -1007,6 +1008,8 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt) p.amount = readU16(is); p.time = readF32(is); + if (p.time < 0) + throw SerializationError("particle spawner time < 0"); bool missing_end_values = false; if (m_proto_ver >= 42) { diff --git a/src/script/lua_api/l_particles.cpp b/src/script/lua_api/l_particles.cpp index 80c3f27c2..efcf3725e 100644 --- a/src/script/lua_api/l_particles.cpp +++ b/src/script/lua_api/l_particles.cpp @@ -3,6 +3,7 @@ // Copyright (C) 2013 celeron55, Perttu Ahola #include "lua_api/l_particles.h" +#include "common/c_types.h" #include "lua_api/l_object.h" #include "lua_api/l_internal.h" #include "lua_api/l_particleparams.h" @@ -280,6 +281,9 @@ int ModApiParticles::l_add_particlespawner(lua_State *L) p.node_tile = getintfield_default(L, 1, "node_tile", p.node_tile); } + if (p.time < 0) + throw LuaError("particle spawner 'time' must be >= 0"); + u32 id = getServer(L)->addParticleSpawner(p, attached, playername); lua_pushnumber(L, id); From 8c56434bd3e93e89e258d82171b9af71b558145e Mon Sep 17 00:00:00 2001 From: lhofhansl Date: Mon, 25 Nov 2024 11:56:32 -0800 Subject: [PATCH 082/136] Clamp pre-bloom color to valid range (#15453) That avoids flashing artifacts when combining MSAA and bloom. --- client/shaders/extract_bloom/opengl_fragment.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/shaders/extract_bloom/opengl_fragment.glsl b/client/shaders/extract_bloom/opengl_fragment.glsl index 36671b06c..281884cee 100644 --- a/client/shaders/extract_bloom/opengl_fragment.glsl +++ b/client/shaders/extract_bloom/opengl_fragment.glsl @@ -23,7 +23,7 @@ void main(void) vec2 uv = varTexCoord.st; vec3 color = texture2D(rendered, uv).rgb; // translate to linear colorspace (approximate) - color = pow(color, vec3(2.2)); + color = pow(clamp(color, 0.0, 1.0), vec3(2.2)); color *= exposureParams.compensationFactor * bloomStrength; From 6c324cb871dc04aff487dd3330aa79ab902dc1b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Wed, 27 Nov 2024 18:39:28 +0100 Subject: [PATCH 083/136] Main menu: Fix server selection (#15466) Server selections are now always correct (no more arbitrarily changing selections if the order of the serverlist changes) and consistent with the address + port in the sidebar. --- builtin/mainmenu/tab_online.lua | 96 +++++++++++++++++---------------- 1 file changed, 49 insertions(+), 47 deletions(-) diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua index 558e2aff2..6545569b2 100644 --- a/builtin/mainmenu/tab_online.lua +++ b/builtin/mainmenu/tab_online.lua @@ -55,6 +55,36 @@ local function get_sorted_servers() return servers end +-- Persists the selected server in the "address" and "remote_port" settings +local function set_selected_server(server) + local address = server.address + local port = server.port + gamedata.serverdescription = server.description + + gamedata.fav = false + for _, fav in ipairs(serverlistmgr.get_favorites()) do + if address == fav.address and port == fav.port then + gamedata.fav = true + break + end + end + + if address and port then + core.settings:set("address", address) + core.settings:set("remote_port", port) + end +end + +local function find_selected_server() + local address = core.settings:get("address") + local port = tonumber(core.settings:get("remote_port")) + for _, server in ipairs(serverlistmgr.servers) do + if server.address == address and server.port == port then + return server + end + end +end + local function get_formspec(tabview, name, tabdata) -- Update the cached supported proto info, -- it may have changed after a change by the settings menu. @@ -107,15 +137,15 @@ local function get_formspec(tabview, name, tabdata) retval = retval .. "button[0.25,6;2.5,0.75;btn_mp_register;" .. fgettext("Register") .. "]" end - if tabdata.selected then + local selected_server = find_selected_server() + + if selected_server then if gamedata.serverdescription then retval = retval .. "textarea[0.25,1.85;5.25,2.7;;;" .. core.formspec_escape(gamedata.serverdescription) .. "]" end - local server = tabdata.lookup[tabdata.selected] - - local clients_list = server and server.clients_list + local clients_list = selected_server.clients_list local can_view_clients_list = clients_list and #clients_list > 0 if can_view_clients_list then table.sort(clients_list, function(a, b) @@ -197,11 +227,17 @@ local function get_formspec(tabview, name, tabdata) retval = retval .. table.concat(rows, ",") - if tabdata.selected then - retval = retval .. ";" .. tabdata.selected .. "]" - else - retval = retval .. ";0]" + local selected_row_idx = 0 + if selected_server then + for i, server in pairs(tabdata.lookup) do + if selected_server.address == server.address and + selected_server.port == server.port then + selected_row_idx = i + break + end + end end + retval = retval .. ";" .. selected_row_idx .. "]" return retval end @@ -253,35 +289,6 @@ local function search_server_list(input) menudata.search_result = search_result end -local function set_selected_server(tabdata, idx, server) - -- reset selection - if idx == nil or server == nil then - tabdata.selected = nil - - core.settings:set("address", "") - core.settings:set("remote_port", "30000") - return - end - - local address = server.address - local port = server.port - gamedata.serverdescription = server.description - - gamedata.fav = false - for _, fav in ipairs(serverlistmgr.get_favorites()) do - if address == fav.address and port == fav.port then - gamedata.fav = true - break - end - end - - if address and port then - core.settings:set("address", address) - core.settings:set("remote_port", port) - end - tabdata.selected = idx -end - local function main_button_handler(tabview, fields, name, tabdata) if fields.te_name then gamedata.playername = fields.te_name @@ -312,14 +319,13 @@ local function main_button_handler(tabview, fields, name, tabdata) gamedata.serverdescription = server.description if gamedata.address and gamedata.port then - core.settings:set("address", gamedata.address) - core.settings:set("remote_port", gamedata.port) + set_selected_server(server) core.start() end return true end if event.type == "CHG" then - set_selected_server(tabdata, event.row, server) + set_selected_server(server) return true end end @@ -332,13 +338,12 @@ local function main_button_handler(tabview, fields, name, tabdata) if not server then return end serverlistmgr.delete_favorite(server) - -- the server at [idx+1] will be at idx once list is refreshed - set_selected_server(tabdata, idx, tabdata.lookup[idx+1]) + set_selected_server(server) return true end if fields.btn_view_clients then - local dlg = create_clientslist_dialog(tabdata.lookup[tabdata.selected]) + local dlg = create_clientslist_dialog(find_selected_server()) dlg:set_parent(tabview) tabview:hide() dlg:show() @@ -355,8 +360,7 @@ local function main_button_handler(tabview, fields, name, tabdata) tabdata.search_for = fields.te_search search_server_list(fields.te_search:lower()) if menudata.search_result then - -- first server in row 2 due to header - set_selected_server(tabdata, 2, menudata.search_result[1]) + set_selected_server(menudata.search_result[1]) end return true @@ -383,8 +387,6 @@ local function main_button_handler(tabview, fields, name, tabdata) local idx = core.get_table_index("servers") local server = idx and tabdata.lookup[idx] - set_selected_server(tabdata) - if server and server.address == gamedata.address and server.port == gamedata.port then From c175046d300b98213598d2373e750ee07fba8a21 Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Wed, 27 Nov 2024 18:39:57 +0100 Subject: [PATCH 084/136] Network: Fix serialization version checks (#15477) This fixes some incorrect assumptions that the read and write version ranges are identical - whereas they're in fact not. --- src/client/client.cpp | 2 +- src/main.cpp | 1 + src/mapblock.cpp | 6 ++---- src/mapnode.cpp | 20 +++++++------------ src/network/clientpackethandler.cpp | 6 +++--- src/network/serverpackethandler.cpp | 31 ++++++++++++----------------- src/serialization.h | 19 ++++++++++++------ src/server.cpp | 1 + src/server.h | 1 - src/server/clientiface.cpp | 3 +++ src/server/clientiface.h | 5 ++--- 11 files changed, 46 insertions(+), 49 deletions(-) diff --git a/src/client/client.cpp b/src/client/client.cpp index b308a9276..f17d4debf 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -1128,7 +1128,7 @@ void Client::sendInit(const std::string &playerName) { NetworkPacket pkt(TOSERVER_INIT, 1 + 2 + 2 + (1 + playerName.size())); - pkt << (u8) SER_FMT_VER_HIGHEST_READ << (u16) 0; + pkt << SER_FMT_VER_HIGHEST_READ << (u16) 0 /* unused */; pkt << CLIENT_PROTOCOL_VERSION_MIN << LATEST_PROTOCOL_VERSION; pkt << playerName; diff --git a/src/main.cpp b/src/main.cpp index 6d30b2f07..2d0c2aa79 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,6 +24,7 @@ #include "config.h" #include "player.h" #include "porting.h" +#include "serialization.h" // SER_FMT_VER_HIGHEST_* #include "network/socket.h" #include "mapblock.h" #if USE_CURSES diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 9ead0fa5a..f68657d9d 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -307,11 +307,9 @@ static void correctBlockNodeIds(const NameIdMapping *nimap, MapNode *nodes, void MapBlock::serialize(std::ostream &os_compressed, u8 version, bool disk, int compression_level) { - if(!ser_ver_supported(version)) + if (!ser_ver_supported_write(version)) throw VersionMismatchException("ERROR: MapBlock format not supported"); - FATAL_ERROR_IF(version < SER_FMT_VER_LOWEST_WRITE, "Serialization version error"); - std::ostringstream os_raw(std::ios_base::binary); std::ostream &os = version >= 29 ? os_raw : os_compressed; @@ -423,7 +421,7 @@ void MapBlock::serializeNetworkSpecific(std::ostream &os) void MapBlock::deSerialize(std::istream &in_compressed, u8 version, bool disk) { - if(!ser_ver_supported(version)) + if (!ser_ver_supported_read(version)) throw VersionMismatchException("ERROR: MapBlock format not supported"); TRACESTREAM(<<"MapBlock::deSerialize "< MapNode::serializeBulk(int version, const MapNode *nodes, u32 nodecount, u8 content_width, u8 params_width) { - if (!ser_ver_supported(version)) + if (!ser_ver_supported_write(version)) throw VersionMismatchException("ERROR: MapNode format not supported"); sanity_check(content_width == 2); sanity_check(params_width == 2); - // Can't do this anymore; we have 16-bit dynamically allocated node IDs - // in memory; conversion just won't work in this direction. - if (version < 24) - throw SerializationError("MapNode::serializeBulk: serialization to " - "version < 24 not possible"); - Buffer databuf(nodecount * (content_width + params_width)); // Writing to the buffer linearly is faster @@ -712,13 +706,13 @@ void MapNode::deSerializeBulk(std::istream &is, int version, MapNode *nodes, u32 nodecount, u8 content_width, u8 params_width) { - if(!ser_ver_supported(version)) + if (!ser_ver_supported_read(version)) throw VersionMismatchException("ERROR: MapNode format not supported"); if (version < 22 || (content_width != 1 && content_width != 2) || params_width != 2) - FATAL_ERROR("Deserialize bulk node data error"); + throw SerializationError("Deserialize bulk node data error"); // read data const u32 len = nodecount * (content_width + params_width); diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index fbd7bdd9e..4b899e598 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -63,7 +63,7 @@ void Client::handleCommand_Hello(NetworkPacket* pkt) if (pkt->getSize() < 1) return; - u8 serialization_ver; + u8 serialization_ver; // negotiated value u16 proto_ver; u16 unused_compression_mode; u32 auth_mechs; @@ -80,9 +80,9 @@ void Client::handleCommand_Hello(NetworkPacket* pkt) << ", proto_ver=" << proto_ver << ". Doing auth with mech " << chosen_auth_mechanism << std::endl; - if (!ser_ver_supported(serialization_ver)) { + if (!ser_ver_supported_read(serialization_ver)) { infostream << "Client: TOCLIENT_HELLO: Server sent " - << "unsupported ser_fmt_ver"<< std::endl; + << "unsupported ser_fmt_ver=" << (int)serialization_ver << std::endl; return; } diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index 47fd8ef5b..cf1dcacb1 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -12,6 +12,7 @@ #include "remoteplayer.h" #include "rollback_interface.h" #include "scripting_server.h" +#include "serialization.h" #include "settings.h" #include "tool.h" #include "version.h" @@ -83,34 +84,27 @@ void Server::handleCommand_Init(NetworkPacket* pkt) if (denyIfBanned(peer_id)) return; - // First byte after command is maximum supported - // serialization version - u8 client_max; + u8 max_ser_ver; // SER_FMT_VER_HIGHEST_READ (of client) u16 unused; - u16 min_net_proto_version = 0; + u16 min_net_proto_version; u16 max_net_proto_version; std::string playerName; - *pkt >> client_max >> unused >> min_net_proto_version - >> max_net_proto_version >> playerName; + *pkt >> max_ser_ver >> unused + >> min_net_proto_version >> max_net_proto_version + >> playerName; - u8 our_max = SER_FMT_VER_HIGHEST_READ; // Use the highest version supported by both - u8 depl_serial_v = std::min(client_max, our_max); - // If it's lower than the lowest supported, give up. -#if SER_FMT_VER_LOWEST_READ > 0 - if (depl_serial_v < SER_FMT_VER_LOWEST_READ) - depl_serial_v = SER_FMT_VER_INVALID; -#endif + const u8 serialization_ver = std::min(max_ser_ver, SER_FMT_VER_HIGHEST_WRITE); - if (depl_serial_v == SER_FMT_VER_INVALID) { + if (!ser_ver_supported_write(serialization_ver)) { actionstream << "Server: A mismatched client tried to connect from " << - addr_s << " ser_fmt_max=" << (int)client_max << std::endl; + addr_s << " ser_fmt_max=" << (int)serialization_ver << std::endl; DenyAccess(peer_id, SERVER_ACCESSDENIED_WRONG_VERSION); return; } - client->setPendingSerializationVersion(depl_serial_v); + client->setPendingSerializationVersion(serialization_ver); /* Read and check network protocol version @@ -263,8 +257,9 @@ void Server::handleCommand_Init(NetworkPacket* pkt) NetworkPacket resp_pkt(TOCLIENT_HELLO, 0, peer_id); - resp_pkt << depl_serial_v << u16(0) << net_proto_version - << auth_mechs << std::string_view(); + resp_pkt << serialization_ver << u16(0) /* unused */ + << net_proto_version + << auth_mechs << std::string_view() /* unused */; Send(&resp_pkt); diff --git a/src/serialization.h b/src/serialization.h index 7e63ec23c..48c7464c1 100644 --- a/src/serialization.h +++ b/src/serialization.h @@ -50,23 +50,30 @@ 28: Added "private" flag to NodeMetadata 29: Switched compression to zstd, a bit of reorganization */ + // This represents an uninitialized or invalid format -#define SER_FMT_VER_INVALID 255 +constexpr u8 SER_FMT_VER_INVALID = 255; // Highest supported serialization version -#define SER_FMT_VER_HIGHEST_READ 29 +constexpr u8 SER_FMT_VER_HIGHEST_READ = 29; // Saved on disk version -#define SER_FMT_VER_HIGHEST_WRITE 29 +constexpr u8 SER_FMT_VER_HIGHEST_WRITE = 29; // Lowest supported serialization version -#define SER_FMT_VER_LOWEST_READ 0 +constexpr u8 SER_FMT_VER_LOWEST_READ = 0; // Lowest serialization version for writing // Can't do < 24 anymore; we have 16-bit dynamically allocated node IDs // in memory; conversion just won't work in this direction. -#define SER_FMT_VER_LOWEST_WRITE 24 +constexpr u8 SER_FMT_VER_LOWEST_WRITE = 24; -inline bool ser_ver_supported(s32 v) { +inline bool ser_ver_supported_read(s32 v) +{ return v >= SER_FMT_VER_LOWEST_READ && v <= SER_FMT_VER_HIGHEST_READ; } +inline bool ser_ver_supported_write(s32 v) +{ + return v >= SER_FMT_VER_LOWEST_WRITE && v <= SER_FMT_VER_HIGHEST_WRITE; +} + /* Compression functions */ diff --git a/src/server.cpp b/src/server.cpp index d2aaf3432..ee9b0a859 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -21,6 +21,7 @@ #include "filesys.h" #include "mapblock.h" #include "server/serveractiveobject.h" +#include "serialization.h" // SER_FMT_VER_INVALID #include "settings.h" #include "profiler.h" #include "log.h" diff --git a/src/server.h b/src/server.h index f2d767e99..a9ba35c63 100644 --- a/src/server.h +++ b/src/server.h @@ -8,7 +8,6 @@ #include "map.h" #include "hud.h" #include "gamedef.h" -#include "serialization.h" // For SER_FMT_VER_INVALID #include "content/mods.h" #include "inventorymanager.h" #include "content/subgames.h" diff --git a/src/server/clientiface.cpp b/src/server/clientiface.cpp index f50b4273f..b114c6c84 100644 --- a/src/server/clientiface.cpp +++ b/src/server/clientiface.cpp @@ -8,6 +8,7 @@ #include "network/connection.h" #include "network/serveropcodes.h" #include "remoteplayer.h" +#include "serialization.h" // SER_FMT_VER_INVALID #include "settings.h" #include "mapblock.h" #include "serverenvironment.h" @@ -51,6 +52,8 @@ std::string ClientInterface::state2Name(ClientState state) } RemoteClient::RemoteClient() : + serialization_version(SER_FMT_VER_INVALID), + m_pending_serialization_version(SER_FMT_VER_INVALID), m_max_simul_sends(g_settings->getU16("max_simultaneous_block_sends_per_client")), m_min_time_from_building( g_settings->getFloat("full_block_send_enable_min_time_from_building")), diff --git a/src/server/clientiface.h b/src/server/clientiface.h index 4546f045e..294bcbd26 100644 --- a/src/server/clientiface.h +++ b/src/server/clientiface.h @@ -7,7 +7,6 @@ #include "irr_v3d.h" // for irrlicht datatypes #include "constants.h" -#include "serialization.h" // for SER_FMT_VER_INVALID #include "network/networkpacket.h" #include "network/networkprotocol.h" #include "network/address.h" @@ -219,7 +218,7 @@ public: // Also, the client must be moved to some other container. session_t peer_id = PEER_ID_INEXISTENT; // The serialization version to use with the client - u8 serialization_version = SER_FMT_VER_INVALID; + u8 serialization_version; // u16 net_proto_version = 0; @@ -333,7 +332,7 @@ public: private: // Version is stored in here after INIT before INIT2 - u8 m_pending_serialization_version = SER_FMT_VER_INVALID; + u8 m_pending_serialization_version; /* current state of client */ ClientState m_state = CS_Created; From df4e70b2c7631317430bd78061507270d23db67b Mon Sep 17 00:00:00 2001 From: DS Date: Thu, 28 Nov 2024 14:22:53 +0100 Subject: [PATCH 085/136] Add a setting to group transparency sorted triangles by buffer (#15115) --- builtin/settingtypes.txt | 5 ++++ src/client/clientmap.cpp | 7 ++++- src/client/clientmap.h | 1 + src/client/mapblock_mesh.cpp | 56 +++++++++++++++++++++++++++++------- src/client/mapblock_mesh.h | 10 +++++-- src/defaultsettings.cpp | 1 + 6 files changed, 66 insertions(+), 14 deletions(-) diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 418e883d1..d23704694 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -1843,6 +1843,11 @@ video_driver (Video driver) enum ,opengl,opengl3,ogles2 # Set to 0 to disable it entirely. transparency_sorting_distance (Transparency Sorting Distance) int 16 0 128 +# Draw transparency sorted triangles grouped by their mesh buffers. +# This breaks transparency sorting between mesh buffers, but avoids situations +# where transparency sorting would be very slow otherwise. +transparency_sorting_group_by_buffers (Transparency Sorting Group by Buffers) bool true + # Radius of cloud area stated in number of 64 node cloud squares. # Values larger than 26 will start to produce sharp cutoffs at cloud area corners. cloud_radius (Cloud radius) int 12 1 62 diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index 9a788e3cc..c3207efd1 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -73,6 +73,7 @@ static const std::string ClientMap_settings[] = { "trilinear_filter", "bilinear_filter", "anisotropic_filter", + "transparency_sorting_group_by_buffers", "transparency_sorting_distance", "occlusion_culler", "enable_raytraced_culling", @@ -115,6 +116,9 @@ void ClientMap::onSettingChanged(std::string_view name, bool all) m_cache_bilinear_filter = g_settings->getBool("bilinear_filter"); if (all || name == "anisotropic_filter") m_cache_anistropic_filter = g_settings->getBool("anisotropic_filter"); + if (all || name == "transparency_sorting_group_by_buffers") + m_cache_transparency_sorting_group_by_buffers = + g_settings->getBool("transparency_sorting_group_by_buffers"); if (all || name == "transparency_sorting_distance") m_cache_transparency_sorting_distance = g_settings->getU16("transparency_sorting_distance"); if (all || name == "occlusion_culler") @@ -1337,7 +1341,8 @@ void ClientMap::updateTransparentMeshBuffers() } if (do_sort_block) { - blockmesh->updateTransparentBuffers(m_camera_position, block->getPos()); + blockmesh->updateTransparentBuffers(m_camera_position, block->getPos(), + m_cache_transparency_sorting_group_by_buffers); ++sorted_blocks; } else { blockmesh->consolidateTransparentBuffers(); diff --git a/src/client/clientmap.h b/src/client/clientmap.h index 4855575f6..a72b6f50d 100644 --- a/src/client/clientmap.h +++ b/src/client/clientmap.h @@ -182,6 +182,7 @@ private: bool m_cache_trilinear_filter; bool m_cache_bilinear_filter; bool m_cache_anistropic_filter; + bool m_cache_transparency_sorting_group_by_buffers; u16 m_cache_transparency_sorting_distance; bool m_loops_occlusion_culler; diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index c212bd148..c8cd79248 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -3,6 +3,7 @@ // Copyright (C) 2010-2013 celeron55, Perttu Ahola #include "mapblock_mesh.h" +#include "CMeshBuffer.h" #include "client.h" #include "mapblock.h" #include "map.h" @@ -818,7 +819,8 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack, return true; } -void MapBlockMesh::updateTransparentBuffers(v3f camera_pos, v3s16 block_pos) +void MapBlockMesh::updateTransparentBuffers(v3f camera_pos, v3s16 block_pos, + bool group_by_buffers) { // nothing to do if the entire block is opaque if (m_transparent_triangles.empty()) @@ -834,24 +836,56 @@ void MapBlockMesh::updateTransparentBuffers(v3f camera_pos, v3s16 block_pos) m_transparent_buffers_consolidated = false; m_transparent_buffers.clear(); + std::vector>> ordered_strains; + std::unordered_map strain_idxs; + + if (group_by_buffers) { + // find (reversed) order for strains, by iterating front-to-back + // (if a buffer A has a triangle nearer than all triangles of another + // buffer B, A should be drawn in front of (=after) B) + scene::SMeshBuffer *current_buffer = nullptr; + for (auto it = triangle_refs.rbegin(); it != triangle_refs.rend(); ++it) { + const auto &t = m_transparent_triangles[*it]; + if (current_buffer == t.buffer) + continue; + current_buffer = t.buffer; + auto [_it2, is_new] = + strain_idxs.emplace(current_buffer, ordered_strains.size()); + if (is_new) + ordered_strains.emplace_back(current_buffer, std::vector{}); + } + } + + // find order for triangles, by iterating back-to-front scene::SMeshBuffer *current_buffer = nullptr; - std::vector current_strain; + std::vector *current_strain = nullptr; for (auto i : triangle_refs) { const auto &t = m_transparent_triangles[i]; if (current_buffer != t.buffer) { - if (current_buffer) { - m_transparent_buffers.emplace_back(current_buffer, std::move(current_strain)); - current_strain.clear(); - } current_buffer = t.buffer; + if (group_by_buffers) { + auto it = strain_idxs.find(current_buffer); + assert(it != strain_idxs.end()); + current_strain = &ordered_strains[it->second].second; + } else { + ordered_strains.emplace_back(current_buffer, std::vector{}); + current_strain = &ordered_strains.back().second; + } } - current_strain.push_back(t.p1); - current_strain.push_back(t.p2); - current_strain.push_back(t.p3); + current_strain->push_back(t.p1); + current_strain->push_back(t.p2); + current_strain->push_back(t.p3); } - if (!current_strain.empty()) - m_transparent_buffers.emplace_back(current_buffer, std::move(current_strain)); + m_transparent_buffers.reserve(ordered_strains.size()); + if (group_by_buffers) { + // the order was reversed + for (auto it = ordered_strains.rbegin(); it != ordered_strains.rend(); ++it) + m_transparent_buffers.emplace_back(it->first, std::move(it->second)); + } else { + for (auto it = ordered_strains.begin(); it != ordered_strains.end(); ++it) + m_transparent_buffers.emplace_back(it->first, std::move(it->second)); + } } void MapBlockMesh::consolidateTransparentBuffers() diff --git a/src/client/mapblock_mesh.h b/src/client/mapblock_mesh.h index 5a8daf50c..e7cadb3db 100644 --- a/src/client/mapblock_mesh.h +++ b/src/client/mapblock_mesh.h @@ -209,8 +209,14 @@ public: /// Center of the bounding-sphere, in BS-space, relative to block pos. v3f getBoundingSphereCenter() const { return m_bounding_sphere_center; } - /// update transparent buffers to render towards the camera - void updateTransparentBuffers(v3f camera_pos, v3s16 block_pos); + /** Update transparent buffers to render towards the camera. + * @param group_by_buffers If true, triangles in the same buffer are batched + * into the same PartialMeshBuffer, resulting in fewer draw calls, but + * wrong order. Triangles within a single buffer are still ordered, and + * buffers are ordered relative to each other (with respect to their nearest + * triangle). + */ + void updateTransparentBuffers(v3f camera_pos, v3s16 block_pos, bool group_by_buffers); void consolidateTransparentBuffers(); /// get the list of transparent buffers diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 345e4a07b..e6b26bd4a 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -302,6 +302,7 @@ void set_default_settings() settings->setDefault("arm_inertia", "true"); settings->setDefault("show_nametag_backgrounds", "true"); settings->setDefault("show_block_bounds_radius_near", "4"); + settings->setDefault("transparency_sorting_group_by_buffers", "true"); settings->setDefault("transparency_sorting_distance", "16"); settings->setDefault("enable_minimap", "true"); From d068f34753ee187f5adccbf31e214ab034766d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Fri, 29 Nov 2024 12:00:09 +0100 Subject: [PATCH 086/136] Get rid of `definitelyIdentityMatrix` (#15480) --- irr/include/matrix4.h | 177 +-------------------------------------- irr/include/quaternion.h | 6 -- 2 files changed, 4 insertions(+), 179 deletions(-) diff --git a/irr/include/matrix4.h b/irr/include/matrix4.h index 36f98bb70..7897b9acb 100644 --- a/irr/include/matrix4.h +++ b/irr/include/matrix4.h @@ -13,11 +13,6 @@ #include "rect.h" #include "IrrCompileConfig.h" // for IRRLICHT_API -// enable this to keep track of changes to the matrix -// and make simpler identity check for seldom changing matrices -// otherwise identity check will always compare the elements -// #define USE_MATRIX_TEST - namespace irr { namespace core @@ -81,9 +76,6 @@ public: //! Simple operator for directly accessing every element of the matrix. T &operator()(const s32 row, const s32 col) { -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return M[row * 4 + col]; } @@ -93,9 +85,6 @@ public: //! Simple operator for linearly accessing every element of the matrix. T &operator[](u32 index) { -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return M[index]; } @@ -112,19 +101,12 @@ public: const T *pointer() const { return M; } T *pointer() { -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return M; } //! Returns true if other matrix is equal to this matrix. constexpr bool operator==(const CMatrix4 &other) const { -#if defined(USE_MATRIX_TEST) - if (definitelyIdentityMatrix && other.definitelyIdentityMatrix) - return true; -#endif for (s32 i = 0; i < 16; ++i) if (M[i] != other.M[i]) return false; @@ -443,31 +425,17 @@ public: //! Sets all matrix data members at once CMatrix4 &setM(const T *data); - //! Sets if the matrix is definitely identity matrix - void setDefinitelyIdentityMatrix(bool isDefinitelyIdentityMatrix); - - //! Gets if the matrix is definitely identity matrix - bool getDefinitelyIdentityMatrix() const; - //! Compare two matrices using the equal method bool equals(const core::CMatrix4 &other, const T tolerance = (T)ROUNDING_ERROR_f64) const; private: //! Matrix data, stored in row-major order T M[16]; -#if defined(USE_MATRIX_TEST) - //! Flag is this matrix is identity matrix - mutable u32 definitelyIdentityMatrix; -#endif }; // Default constructor template inline CMatrix4::CMatrix4(eConstructor constructor) -#if defined(USE_MATRIX_TEST) - : - definitelyIdentityMatrix(BIT_UNTESTED) -#endif { switch (constructor) { case EM4CONST_NOTHING: @@ -484,10 +452,6 @@ inline CMatrix4::CMatrix4(eConstructor constructor) // Copy constructor template inline CMatrix4::CMatrix4(const CMatrix4 &other, eConstructor constructor) -#if defined(USE_MATRIX_TEST) - : - definitelyIdentityMatrix(BIT_UNTESTED) -#endif { switch (constructor) { case EM4CONST_IDENTITY: @@ -713,9 +677,6 @@ inline CMatrix4 &CMatrix4::setbyproduct_nocheck(const CMatrix4 &other_a M[13] = m1[1] * m2[12] + m1[5] * m2[13] + m1[9] * m2[14] + m1[13] * m2[15]; M[14] = m1[2] * m2[12] + m1[6] * m2[13] + m1[10] * m2[14] + m1[14] * m2[15]; M[15] = m1[3] * m2[12] + m1[7] * m2[13] + m1[11] * m2[14] + m1[15] * m2[15]; -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return *this; } @@ -787,9 +748,6 @@ inline CMatrix4 &CMatrix4::setTranslation(const vector3d &translation) M[12] = translation.X; M[13] = translation.Y; M[14] = translation.Z; -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return *this; } @@ -799,9 +757,6 @@ inline CMatrix4 &CMatrix4::setInverseTranslation(const vector3d &transl M[12] = -translation.X; M[13] = -translation.Y; M[14] = -translation.Z; -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return *this; } @@ -811,9 +766,6 @@ inline CMatrix4 &CMatrix4::setScale(const vector3d &scale) M[0] = scale.X; M[5] = scale.Y; M[10] = scale.Z; -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return *this; } @@ -877,9 +829,6 @@ inline CMatrix4 &CMatrix4::setRotationRadians(const vector3d &rotation) M[8] = (T)(cPitch_sYaw * cRoll + sPitch * sRoll); M[9] = (T)(cPitch_sYaw * sRoll - sPitch * cRoll); M[10] = (T)(cPitch * cYaw); -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return *this; } @@ -981,9 +930,6 @@ inline CMatrix4 &CMatrix4::setInverseRotationRadians(const vector3d &ro M[2] = (T)(cPitch_sYaw * cRoll + sPitch * sRoll); M[6] = (T)(cPitch_sYaw * sRoll - sPitch * cRoll); M[10] = (T)(cPitch * cYaw); -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return *this; } @@ -1015,9 +961,6 @@ inline CMatrix4 &CMatrix4::setRotationAxisRadians(const T &angle, const ve M[9] = (T)(tz * axis.Y - sx); M[10] = (T)(tz * axis.Z + c); -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return *this; } @@ -1028,9 +971,6 @@ inline CMatrix4 &CMatrix4::makeIdentity() { memset(M, 0, 16 * sizeof(T)); M[0] = M[5] = M[10] = M[15] = (T)1; -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = true; -#endif return *this; } @@ -1041,10 +981,6 @@ inline CMatrix4 &CMatrix4::makeIdentity() template inline bool CMatrix4::isIdentity() const { -#if defined(USE_MATRIX_TEST) - if (definitelyIdentityMatrix) - return true; -#endif if (!core::equals(M[12], (T)0) || !core::equals(M[13], (T)0) || !core::equals(M[14], (T)0) || !core::equals(M[15], (T)1)) return false; @@ -1068,9 +1004,6 @@ inline bool CMatrix4::isIdentity() const if ((j != i) && (!iszero((*this)(i,j)))) return false; */ -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = true; -#endif return true; } @@ -1106,10 +1039,6 @@ inline bool CMatrix4::isOrthogonal() const template inline bool CMatrix4::isIdentity_integer_base() const { -#if defined(USE_MATRIX_TEST) - if (definitelyIdentityMatrix) - return true; -#endif if (IR(M[0]) != F32_VALUE_1) return false; if (IR(M[1]) != 0) @@ -1146,9 +1075,6 @@ inline bool CMatrix4::isIdentity_integer_base() const if (IR(M[15]) != F32_VALUE_1) return false; -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = true; -#endif return true; } @@ -1402,9 +1328,6 @@ inline bool CMatrix4::getInverse(CMatrix4 &out) const m[1] * (m[6] * m[8] - m[4] * m[10]) + m[2] * (m[4] * m[9] - m[5] * m[8])); -#if defined(USE_MATRIX_TEST) - out.definitelyIdentityMatrix = definitelyIdentityMatrix; -#endif return true; } @@ -1433,9 +1356,6 @@ inline bool CMatrix4::getInversePrimitive(CMatrix4 &out) const out.M[14] = (T) - (M[12] * M[8] + M[13] * M[9] + M[14] * M[10]); out.M[15] = 1; -#if defined(USE_MATRIX_TEST) - out.definitelyIdentityMatrix = definitelyIdentityMatrix; -#endif return true; } @@ -1444,10 +1364,6 @@ inline bool CMatrix4::getInversePrimitive(CMatrix4 &out) const template inline bool CMatrix4::makeInverse() { -#if defined(USE_MATRIX_TEST) - if (definitelyIdentityMatrix) - return true; -#endif CMatrix4 temp(EM4CONST_NOTHING); if (getInverse(temp)) { @@ -1464,9 +1380,6 @@ inline CMatrix4 &CMatrix4::operator=(const T &scalar) for (s32 i = 0; i < 16; ++i) M[i] = scalar; -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return *this; } @@ -1509,9 +1422,6 @@ inline CMatrix4 &CMatrix4::buildProjectionMatrixPerspectiveFovRH( M[14] = (T)(2.0f * zNear * zFar / (zNear - zFar)); } -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return *this; } @@ -1554,9 +1464,6 @@ inline CMatrix4 &CMatrix4::buildProjectionMatrixPerspectiveFovLH( M[14] = (T)(2.0f * zNear * zFar / (zNear - zFar)); } -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return *this; } @@ -1589,9 +1496,6 @@ inline CMatrix4 &CMatrix4::buildProjectionMatrixPerspectiveFovInfinityLH( M[14] = (T)(zNear * (epsilon - 1.f)); M[15] = 0; -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return *this; } @@ -1631,9 +1535,6 @@ inline CMatrix4 &CMatrix4::buildProjectionMatrixOrthoLH( M[14] = (T) - (zFar + zNear) / (zFar - zNear); } -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return *this; } @@ -1673,9 +1574,6 @@ inline CMatrix4 &CMatrix4::buildProjectionMatrixOrthoRH( M[14] = (T) - (zFar + zNear) / (zFar - zNear); } -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return *this; } @@ -1716,9 +1614,6 @@ inline CMatrix4 &CMatrix4::buildProjectionMatrixPerspectiveRH( M[14] = (T)(2.0f * zNear * zFar / (zNear - zFar)); } -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return *this; } @@ -1759,9 +1654,6 @@ inline CMatrix4 &CMatrix4::buildProjectionMatrixPerspectiveLH( M[14] = (T)(2.0f * zNear * zFar / (zNear - zFar)); } -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return *this; } @@ -1791,9 +1683,7 @@ inline CMatrix4 &CMatrix4::buildShadowMatrix(const core::vector3df &light, M[13] = (T)(-plane.D * light.Y); M[14] = (T)(-plane.D * light.Z); M[15] = (T)(-plane.D * point + d); -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif + return *this; } @@ -1831,9 +1721,7 @@ inline CMatrix4 &CMatrix4::buildCameraLookAtMatrixLH( M[13] = (T)-yaxis.dotProduct(position); M[14] = (T)-zaxis.dotProduct(position); M[15] = 1; -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif + return *this; } @@ -1871,9 +1759,7 @@ inline CMatrix4 &CMatrix4::buildCameraLookAtMatrixRH( M[13] = (T)-yaxis.dotProduct(position); M[14] = (T)-zaxis.dotProduct(position); M[15] = 1; -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif + return *this; } @@ -1924,9 +1810,6 @@ inline void CMatrix4::getTransposed(CMatrix4 &o) const o[13] = M[7]; o[14] = M[11]; o[15] = M[15]; -#if defined(USE_MATRIX_TEST) - o.definitelyIdentityMatrix = definitelyIdentityMatrix; -#endif } // used to scale <-1,-1><1,1> to viewport @@ -2064,9 +1947,6 @@ inline void CMatrix4::setRotationCenter(const core::vector3df ¢er, const M[13] = -M[1] * center.X - M[5] * center.Y - M[9] * center.Z + (center.Y - translation.Y); M[14] = -M[2] * center.X - M[6] * center.Y - M[10] * center.Z + (center.Z - translation.Z); M[15] = (T)1.0; -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif } /*! @@ -2108,9 +1988,7 @@ inline CMatrix4 &CMatrix4::buildTextureTransform(f32 rotateRad, M[13] = 0; M[14] = 0; M[15] = 1; -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif + return *this; } @@ -2129,9 +2007,6 @@ inline CMatrix4 &CMatrix4::setTextureRotationCenter(f32 rotateRad) M[8] = (T)(0.5f * (s - c) + 0.5f); M[9] = (T)(-0.5f * (s + c) + 0.5f); -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = definitelyIdentityMatrix && (rotateRad == 0.0f); -#endif return *this; } @@ -2141,9 +2016,6 @@ inline CMatrix4 &CMatrix4::setTextureTranslate(f32 x, f32 y) M[8] = (T)x; M[9] = (T)y; -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = definitelyIdentityMatrix && (x == 0.0f) && (y == 0.0f); -#endif return *this; } @@ -2159,10 +2031,6 @@ inline CMatrix4 &CMatrix4::setTextureTranslateTransposed(f32 x, f32 y) { M[2] = (T)x; M[6] = (T)y; - -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = definitelyIdentityMatrix && (x == 0.0f) && (y == 0.0f); -#endif return *this; } @@ -2171,9 +2039,6 @@ inline CMatrix4 &CMatrix4::setTextureScale(f32 sx, f32 sy) { M[0] = (T)sx; M[5] = (T)sy; -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = definitelyIdentityMatrix && (sx == 1.0f) && (sy == 1.0f); -#endif return *this; } @@ -2191,10 +2056,6 @@ inline CMatrix4 &CMatrix4::setTextureScaleCenter(f32 sx, f32 sy) M[5] = (T)sy; M[8] = (T)(0.5f - 0.5f * sx); M[9] = (T)(0.5f - 0.5f * sy); - -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = definitelyIdentityMatrix && (sx == 1.0f) && (sy == 1.0f); -#endif return *this; } @@ -2203,43 +2064,13 @@ template inline CMatrix4 &CMatrix4::setM(const T *data) { memcpy(M, data, 16 * sizeof(T)); - -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = false; -#endif return *this; } -// sets if the matrix is definitely identity matrix -template -inline void CMatrix4::setDefinitelyIdentityMatrix(bool isDefinitelyIdentityMatrix) -{ -#if defined(USE_MATRIX_TEST) - definitelyIdentityMatrix = isDefinitelyIdentityMatrix; -#else - (void)isDefinitelyIdentityMatrix; // prevent compiler warning -#endif -} - -// gets if the matrix is definitely identity matrix -template -inline bool CMatrix4::getDefinitelyIdentityMatrix() const -{ -#if defined(USE_MATRIX_TEST) - return definitelyIdentityMatrix; -#else - return false; -#endif -} - //! Compare two matrices using the equal method template inline bool CMatrix4::equals(const core::CMatrix4 &other, const T tolerance) const { -#if defined(USE_MATRIX_TEST) - if (definitelyIdentityMatrix && other.definitelyIdentityMatrix) - return true; -#endif for (s32 i = 0; i < 16; ++i) if (!core::equals(M[i], other.M[i], tolerance)) return false; diff --git a/irr/include/quaternion.h b/irr/include/quaternion.h index 4e90fa067..e23b1317d 100644 --- a/irr/include/quaternion.h +++ b/irr/include/quaternion.h @@ -358,8 +358,6 @@ inline void quaternion::getMatrixFast(matrix4 &dest) const dest[13] = 0.f; dest[14] = 0.f; dest[15] = 1.f; - - dest.setDefinitelyIdentityMatrix(false); } /*! @@ -397,8 +395,6 @@ inline void quaternion::getMatrix(matrix4 &dest, dest[13] = center.Y; dest[14] = center.Z; dest[15] = 1.f; - - dest.setDefinitelyIdentityMatrix(false); } /*! @@ -471,8 +467,6 @@ inline void quaternion::getMatrix_transposed(matrix4 &dest) const dest[7] = 0.f; dest[11] = 0.f; dest[15] = 1.f; - - dest.setDefinitelyIdentityMatrix(false); } // Inverts this quaternion From c3db9492a75b72d764ed3d2893ea87fb34eea861 Mon Sep 17 00:00:00 2001 From: JosiahWI <41302989+JosiahWI@users.noreply.github.com> Date: Fri, 29 Nov 2024 05:02:48 -0600 Subject: [PATCH 087/136] Update CMakeLists to use `add_compile_definitions` (#15483) This is a newer feature introduced in CMake 3.12, which is now our minimum version. It supercedes `add_definitions`. I've also replaced some calls to set `CMAKE__FLAGS` that were used to set definitions. This is a fairly trivial routine build maintenance that is not intended to have any behavioral effects. --- irr/src/CMakeLists.txt | 46 ++++++++++++++++++++---------------------- src/CMakeLists.txt | 23 ++++++++++++--------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/irr/src/CMakeLists.txt b/irr/src/CMakeLists.txt index 1fbfe5c9f..a05607830 100644 --- a/irr/src/CMakeLists.txt +++ b/irr/src/CMakeLists.txt @@ -9,7 +9,7 @@ option(USE_SDL2 "Use the SDL2 backend" ${DEFAULT_SDL2}) # Compiler flags if(CMAKE_BUILD_TYPE STREQUAL "Debug") - add_definitions(-D_DEBUG) + add_compile_definitions(_DEBUG) endif() set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) @@ -43,9 +43,7 @@ elseif(MSVC) endif() # Platform-independent configuration (hard-coded currently) -add_definitions( - -DIRR_ENABLE_BUILTIN_FONT -) +add_compile_definitions(IRR_ENABLE_BUILTIN_FONT) # Platform-specific configuration @@ -56,35 +54,35 @@ endif() # Device if(WIN32) - add_definitions(-D_IRR_WINDOWS_ -D_IRR_WINDOWS_API_) + add_compile_definitions(_IRR_WINDOWS_ _IRR_WINDOWS_API_) set(DEVICE "WINDOWS") elseif(APPLE) - add_definitions(-D_IRR_OSX_PLATFORM_) + add_compile_definitions(_IRR_OSX_PLATFORM_) set(DEVICE "OSX") elseif(ANDROID) - add_definitions(-D_IRR_ANDROID_PLATFORM_) + add_compile_definitions(_IRR_ANDROID_PLATFORM_) if(NOT USE_SDL2) message(FATAL_ERROR "The Android build requires SDL2") endif() elseif(EMSCRIPTEN) - add_definitions(-D_IRR_EMSCRIPTEN_PLATFORM_ -D_IRR_COMPILE_WITH_EGL_MANAGER_) + add_compile_definitions(_IRR_EMSCRIPTEN_PLATFORM_ _IRR_COMPILE_WITH_EGL_MANAGER_) set(LINUX_PLATFORM TRUE) set(DEVICE "SDL") elseif(SOLARIS) - add_definitions(-D_IRR_SOLARIS_PLATFORM_ -D_IRR_POSIX_API_) + add_compile_definitions(_IRR_SOLARIS_PLATFORM_ _IRR_POSIX_API_) set(DEVICE "X11") else() - add_definitions(-D_IRR_POSIX_API_) + add_compile_definitions(_IRR_POSIX_API_) set(LINUX_PLATFORM TRUE) set(DEVICE "X11") endif() if(LINUX_PLATFORM) - add_definitions(-D_IRR_LINUX_PLATFORM_) + add_compile_definitions(_IRR_LINUX_PLATFORM_) endif() if(MSVC) - add_definitions(-D_CRT_SECURE_NO_WARNINGS) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) endif() if(USE_SDL2) @@ -93,7 +91,7 @@ elseif(DEVICE STREQUAL "SDL") message(FATAL_ERROR "SDL was used but not enabled?!") endif() -add_definitions("-D_IRR_COMPILE_WITH_${DEVICE}_DEVICE_") +add_compile_definitions("_IRR_COMPILE_WITH_${DEVICE}_DEVICE_") # X11 @@ -114,7 +112,7 @@ endif() # Joystick if(NOT (BSD OR SOLARIS OR EMSCRIPTEN)) - add_definitions(-D_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) + add_compile_definitions(_IRR_COMPILE_WITH_JOYSTICK_EVENTS_) endif() # OpenGL @@ -154,15 +152,15 @@ endif() if(ENABLE_OPENGL OR (ENABLE_OPENGL3 AND NOT USE_SDL2)) if(ENABLE_OPENGL) - add_definitions(-D_IRR_COMPILE_WITH_OPENGL_) + add_compile_definitions(_IRR_COMPILE_WITH_OPENGL_) set(OPENGL_DIRECT_LINK TRUE) # driver relies on this endif() if(DEVICE STREQUAL "WINDOWS") - add_definitions(-D_IRR_COMPILE_WITH_WGL_MANAGER_) + add_compile_definitions(_IRR_COMPILE_WITH_WGL_MANAGER_) elseif(DEVICE STREQUAL "X11") - add_definitions(-D_IRR_COMPILE_WITH_GLX_MANAGER_) + add_compile_definitions(_IRR_COMPILE_WITH_GLX_MANAGER_) elseif(DEVICE STREQUAL "OSX") - add_definitions(-D_IRR_COMPILE_WITH_NSOGL_MANAGER_) + add_compile_definitions(_IRR_COMPILE_WITH_NSOGL_MANAGER_) endif() endif() @@ -177,14 +175,14 @@ if(ENABLE_OPENGL3) endif() if(ENABLE_GLES2) - add_definitions(-D_IRR_COMPILE_WITH_OGLES2_) + add_compile_definitions(_IRR_COMPILE_WITH_OGLES2_) if(DEVICE MATCHES "^(WINDOWS|X11)$" OR EMSCRIPTEN) - add_definitions(-D_IRR_COMPILE_WITH_EGL_MANAGER_) + add_compile_definitions(_IRR_COMPILE_WITH_EGL_MANAGER_) endif() endif() if(ENABLE_WEBGL1) - add_definitions(-D_IRR_COMPILE_WITH_WEBGL1_) + add_compile_definitions(_IRR_COMPILE_WITH_WEBGL1_) endif() # Misc @@ -192,7 +190,7 @@ endif() include(TestBigEndian) TEST_BIG_ENDIAN(BIG_ENDIAN) if(BIG_ENDIAN) - add_definitions(-D__BIG_ENDIAN__) + add_compile_definitions(__BIG_ENDIAN__) endif() # Configuration report @@ -263,7 +261,7 @@ if(ENABLE_OPENGL AND DEVICE STREQUAL "SDL") #endif\n\ int main() {}" CHECK_GL_VERSION_4_5) if(CHECK_GL_VERSION_4_5) - add_definitions(-DIRR_PREFER_SDL_GL_HEADER) + add_compile_definitions(IRR_PREFER_SDL_GL_HEADER) endif() endif() @@ -275,7 +273,7 @@ elseif(APPLE) find_library(COCOA_LIB Cocoa REQUIRED) find_library(IOKIT_LIB IOKit REQUIRED) - add_definitions(-DGL_SILENCE_DEPRECATION) + add_compile_definitions(GL_SILENCE_DEPRECATION) elseif(NOT USE_SDL2) # Unix probably find_package(X11 REQUIRED) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 65e5ab6bc..e6e493184 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -260,12 +260,11 @@ endif() # Haiku endian support if(HAIKU) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_BSD_SOURCE") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_BSD_SOURCE") + add_compile_definitions(_BSD_SOURCE) endif() # Use cmake_config.h -add_definitions(-DUSE_CMAKE_CONFIG_H) +add_compile_definitions(USE_CMAKE_CONFIG_H) set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) @@ -276,11 +275,15 @@ if(WIN32) if(MSVC) # MSVC Specifics set(PLATFORM_LIBS dbghelp.lib ${PLATFORM_LIBS}) # Surpress some useless warnings - add_definitions ( /D "_CRT_SECURE_NO_DEPRECATE" /W1 ) - # Get M_PI to work - add_definitions(/D "_USE_MATH_DEFINES") - # Don't define min/max macros in minwindef.h - add_definitions(/D "NOMINMAX") + add_compile_options(/W1) + add_compile_definitions( + # Suppress some useless warnings + _CRT_SECURE_NO_DEPRECATE + # Get M_PI to work + _USE_MATH_DEFINES + # Don't define min/max macros in minwindef.h + NOMINMAX + ) endif() set(PLATFORM_LIBS ws2_32.lib version.lib shlwapi.lib winmm.lib ${PLATFORM_LIBS}) @@ -871,7 +874,7 @@ endif() if(MSVC) # Visual Studio - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /D _WIN32_WINNT=0x0601 /D WIN32_LEAN_AND_MEAN /D _CRT_SECURE_NO_WARNINGS") + add_compile_definitions(_WIN32_WINNT=0x0601 WIN32_LEAN_AND_MEAN _CRT_SECURE_NO_WARNINGS) # EHa enables SEH exceptions (used for catching segfaults) set(CMAKE_CXX_FLAGS_RELEASE "/EHa /Ox /MD /GS- /Zi /fp:fast /D NDEBUG /D _HAS_ITERATOR_DEBUGGING=0") if(CMAKE_SIZEOF_VOID_P EQUAL 4) @@ -915,7 +918,7 @@ else() if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") set(OTHER_FLAGS "${OTHER_FLAGS} -mthreads") endif() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_WIN32_WINNT=0x0601 -DWIN32_LEAN_AND_MEAN") + add_compile_definitions(_WIN32_WINNT=0x0601 WIN32_LEAN_AND_MEAN) endif() # Use a safe subset of flags to speed up math calculations: From 7cc5a6ec687d34338cd7608d18b656527883daf8 Mon Sep 17 00:00:00 2001 From: "Kevin @ Sesam Solutions" <56027840+KevinAtSesam@users.noreply.github.com> Date: Sun, 1 Dec 2024 20:51:33 +0100 Subject: [PATCH 088/136] Add Minetest keyword for backwards compatibility (#15491) This helps people looking for `minetest` --- misc/net.minetest.minetest.desktop | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/net.minetest.minetest.desktop b/misc/net.minetest.minetest.desktop index c6c99c469..571eb58a9 100644 --- a/misc/net.minetest.minetest.desktop +++ b/misc/net.minetest.minetest.desktop @@ -11,4 +11,4 @@ PrefersNonDefaultGPU=true Type=Application Categories=Game;Simulation; StartupNotify=false -Keywords=sandbox;world;mining;crafting;blocks;nodes;multiplayer;roleplaying; +Keywords=sandbox;world;mining;crafting;blocks;nodes;multiplayer;roleplaying;minetest; From e9080f91f28af50a649c146ea34c371ef19affc3 Mon Sep 17 00:00:00 2001 From: wrrrzr <161970349+wrrrzr@users.noreply.github.com> Date: Sun, 1 Dec 2024 22:52:13 +0300 Subject: [PATCH 089/136] Cleanup ban.cpp/h (#15496) Make BanManager more const correctly Delete unused includes --- src/server/ban.cpp | 13 ++++++------- src/server/ban.h | 13 +++++-------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/server/ban.cpp b/src/server/ban.cpp index 737f5a57e..e63c4708f 100644 --- a/src/server/ban.cpp +++ b/src/server/ban.cpp @@ -7,11 +7,11 @@ #include #include "threading/mutex_auto_lock.h" #include -#include #include "util/strfnd.h" #include "util/string.h" #include "log.h" #include "filesys.h" +#include "exceptions.h" BanManager::BanManager(const std::string &banfilepath): m_banfilepath(banfilepath) @@ -68,13 +68,13 @@ void BanManager::save() m_modified = false; } -bool BanManager::isIpBanned(const std::string &ip) +bool BanManager::isIpBanned(const std::string &ip) const { MutexAutoLock lock(m_mutex); return m_ips.find(ip) != m_ips.end(); } -std::string BanManager::getBanDescription(const std::string &ip_or_name) +std::string BanManager::getBanDescription(const std::string &ip_or_name) const { MutexAutoLock lock(m_mutex); std::string s; @@ -88,10 +88,10 @@ std::string BanManager::getBanDescription(const std::string &ip_or_name) return s; } -std::string BanManager::getBanName(const std::string &ip) +std::string BanManager::getBanName(const std::string &ip) const { MutexAutoLock lock(m_mutex); - StringMap::iterator it = m_ips.find(ip); + StringMap::const_iterator it = m_ips.find(ip); if (it == m_ips.end()) return ""; return it->second; @@ -118,9 +118,8 @@ void BanManager::remove(const std::string &ip_or_name) } -bool BanManager::isModified() +bool BanManager::isModified() const { MutexAutoLock lock(m_mutex); return m_modified; } - diff --git a/src/server/ban.h b/src/server/ban.h index 146f3210a..4acd58fba 100644 --- a/src/server/ban.h +++ b/src/server/ban.h @@ -5,9 +5,6 @@ #pragma once #include "util/string.h" -#include "threading/thread.h" -#include "exceptions.h" -#include #include #include @@ -18,16 +15,16 @@ public: ~BanManager(); void load(); void save(); - bool isIpBanned(const std::string &ip); + bool isIpBanned(const std::string &ip) const; // Supplying ip_or_name = "" lists all bans. - std::string getBanDescription(const std::string &ip_or_name); - std::string getBanName(const std::string &ip); + std::string getBanDescription(const std::string &ip_or_name) const; + std::string getBanName(const std::string &ip) const; void add(const std::string &ip, const std::string &name); void remove(const std::string &ip_or_name); - bool isModified(); + bool isModified() const; private: - std::mutex m_mutex; + mutable std::mutex m_mutex; std::string m_banfilepath = ""; StringMap m_ips; bool m_modified = false; From a4d1b5b155566cb90961f6b75cf97b3ef21f20f8 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Tue, 3 Dec 2024 16:51:34 +0100 Subject: [PATCH 090/136] Fix script security path normalization in presence of links (#15481) --- src/filesys.cpp | 37 ++++++++++++++++++++++- src/filesys.h | 6 ++++ src/porting.cpp | 4 +++ src/porting.h | 3 +- src/script/cpp_api/s_security.cpp | 49 ++++++++++++------------------- src/script/scripting_mainmenu.cpp | 7 +++-- src/unittest/test_filesys.cpp | 44 ++++++++++++++++++++++++++- 7 files changed, 112 insertions(+), 38 deletions(-) diff --git a/src/filesys.cpp b/src/filesys.cpp index 8881eb2ca..a368bc697 100644 --- a/src/filesys.cpp +++ b/src/filesys.cpp @@ -833,16 +833,51 @@ std::string RemoveRelativePathComponents(std::string path) std::string AbsolutePath(const std::string &path) { #ifdef _WIN32 + // handle behavior differences on windows + if (path.empty()) + return ""; + else if (!PathExists(path)) + return ""; char *abs_path = _fullpath(NULL, path.c_str(), MAX_PATH); #else char *abs_path = realpath(path.c_str(), NULL); #endif - if (!abs_path) return ""; + if (!abs_path) + return ""; std::string abs_path_str(abs_path); free(abs_path); return abs_path_str; } +std::string AbsolutePathPartial(const std::string &path) +{ + if (path.empty()) + return ""; + // Try to determine absolute path + std::string abs_path = fs::AbsolutePath(path); + if (!abs_path.empty()) + return abs_path; + // Remove components until it works + std::string cur_path = path; + std::string removed; + while (abs_path.empty() && !cur_path.empty()) { + std::string component; + cur_path = RemoveLastPathComponent(cur_path, &component); + removed = component + (removed.empty() ? "" : DIR_DELIM + removed); + abs_path = AbsolutePath(cur_path); + } + // If we had a relative path that does not exist, it needs to be joined with cwd + if (cur_path.empty() && !IsPathAbsolute(path)) + abs_path = AbsolutePath("."); + // or there's an error + if (abs_path.empty()) + return ""; + // Put them back together and resolve the remaining relative components + if (!removed.empty()) + abs_path.append(DIR_DELIM).append(removed); + return RemoveRelativePathComponents(abs_path); +} + const char *GetFilenameFromPath(const char *path) { const char *filename = strrchr(path, DIR_DELIM_CHAR); diff --git a/src/filesys.h b/src/filesys.h index dededcdb3..0e974d822 100644 --- a/src/filesys.h +++ b/src/filesys.h @@ -131,6 +131,12 @@ std::string RemoveRelativePathComponents(std::string path); // components and symlinks removed. Returns "" on error. std::string AbsolutePath(const std::string &path); +// This is a combination of RemoveRelativePathComponents() and AbsolutePath() +// It will resolve symlinks for the leading path components that exist and +// still remove "." and ".." in the rest of the path. +// Returns "" on error. +std::string AbsolutePathPartial(const std::string &path); + // Returns the filename from a path or the entire path if no directory // delimiter is found. const char *GetFilenameFromPath(const char *path); diff --git a/src/porting.cpp b/src/porting.cpp index f0e2bee0b..faef75b7c 100644 --- a/src/porting.cpp +++ b/src/porting.cpp @@ -688,6 +688,10 @@ void initializePaths() #endif // RUN_IN_PLACE + assert(!path_share.empty()); + assert(!path_user.empty()); + assert(!path_cache.empty()); + infostream << "Detected share path: " << path_share << std::endl; infostream << "Detected user path: " << path_user << std::endl; infostream << "Detected cache path: " << path_cache << std::endl; diff --git a/src/porting.h b/src/porting.h index edbc236a8..d6cec6c1a 100644 --- a/src/porting.h +++ b/src/porting.h @@ -109,8 +109,7 @@ extern std::string path_cache; bool getCurrentExecPath(char *buf, size_t len); /* - Get full path of stuff in data directory. - Example: "stone.png" -> "../data/stone.png" + Concatenate subpath to path_share. */ std::string getDataPath(const char *subpath); diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index 40a95ca1a..38094ab8c 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -566,38 +566,23 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path, if (write_allowed) *write_allowed = false; - std::string abs_path = fs::AbsolutePath(path); - - // If we couldn't find the absolute path (path doesn't exist) then - // try removing the last components until it works (to allow - // non-existent files/folders for mkdir). - std::string cur_path = path; - std::string removed; - while (abs_path.empty() && !cur_path.empty()) { - std::string component; - cur_path = fs::RemoveLastPathComponent(cur_path, &component); - if (component == "..") { - // Parent components can't be allowed or we could allow something like - // /home/user/minetest/worlds/foo/noexist/../../../../../../etc/passwd. - // If we have previous non-relative elements in the path we might be - // able to remove them so that things like worlds/foo/noexist/../auth.txt - // could be allowed, but those paths will be interpreted as nonexistent - // by the operating system anyways. - return false; - } - removed = component + (removed.empty() ? "" : DIR_DELIM + removed); - abs_path = fs::AbsolutePath(cur_path); - } - if (abs_path.empty()) - return false; - // Add the removed parts back so that you can e.g. create a - // directory in worldmods if worldmods doesn't exist. - if (!removed.empty()) - abs_path += DIR_DELIM + removed; - + // We can't use AbsolutePath() here since we want to allow creating paths that + // do not yet exist. But RemoveRelativePathComponents() would also be incorrect + // since that wouldn't normalize subpaths that *do* exist. + // This is required so that comparisons with other normalized paths work correctly. + std::string abs_path = fs::AbsolutePathPartial(path); tracestream << "ScriptApiSecurity: path \"" << path << "\" resolved to \"" << abs_path << "\"" << std::endl; + if (abs_path.empty()) + return false; + + // Note: abs_path can be a valid path while path isn't, e.g. + // abs_path = "/home/user/.luanti" + // path = "/home/user/.luanti/noexist/.." + // Letting this through the sandbox isn't a concern as any actual attempts to + // use the path would fail. + // Ask the environment-specific implementation auto *sec = ModApiBase::getScriptApi(L); return sec->checkPathInternal(abs_path, write_required, write_allowed); @@ -617,9 +602,11 @@ bool ScriptApiSecurity::checkPathWithGamedef(lua_State *L, if (!gamedef) return false; - if (!abs_path.empty()) { + assert(!abs_path.empty()); + + if (!g_settings_path.empty()) { // Don't allow accessing the settings file - str = fs::AbsolutePath(g_settings_path); + str = fs::AbsolutePathPartial(g_settings_path); if (str == abs_path) return false; } diff --git a/src/script/scripting_mainmenu.cpp b/src/script/scripting_mainmenu.cpp index d5434c325..88f80a001 100644 --- a/src/script/scripting_mainmenu.cpp +++ b/src/script/scripting_mainmenu.cpp @@ -76,10 +76,11 @@ void MainMenuScripting::registerLuaClasses(lua_State *L, int top) bool MainMenuScripting::mayModifyPath(const std::string &path) { - if (fs::PathStartsWith(path, fs::TempPath())) + std::string path_temp = fs::AbsolutePathPartial(fs::TempPath()); + if (fs::PathStartsWith(path, path_temp)) return true; - std::string path_user = fs::RemoveRelativePathComponents(porting::path_user); + std::string path_user = fs::AbsolutePathPartial(porting::path_user); if (fs::PathStartsWith(path, path_user + DIR_DELIM "client")) return true; @@ -92,7 +93,7 @@ bool MainMenuScripting::mayModifyPath(const std::string &path) if (fs::PathStartsWith(path, path_user + DIR_DELIM "worlds")) return true; - if (fs::PathStartsWith(path, fs::RemoveRelativePathComponents(porting::path_cache))) + if (fs::PathStartsWith(path, fs::AbsolutePathPartial(porting::path_cache))) return true; return false; diff --git a/src/unittest/test_filesys.cpp b/src/unittest/test_filesys.cpp index 9bab4fb5d..34666f611 100644 --- a/src/unittest/test_filesys.cpp +++ b/src/unittest/test_filesys.cpp @@ -24,6 +24,7 @@ public: void testRemoveLastPathComponent(); void testRemoveLastPathComponentWithTrailingDelimiter(); void testRemoveRelativePathComponent(); + void testAbsolutePath(); void testSafeWriteToFile(); void testCopyFileContents(); void testNonExist(); @@ -39,6 +40,7 @@ void TestFileSys::runTests(IGameDef *gamedef) TEST(testRemoveLastPathComponent); TEST(testRemoveLastPathComponentWithTrailingDelimiter); TEST(testRemoveRelativePathComponent); + TEST(testAbsolutePath); TEST(testSafeWriteToFile); TEST(testCopyFileContents); TEST(testNonExist); @@ -55,7 +57,7 @@ static std::string p(std::string path) for (size_t i = 0; i < path.size(); ++i) { if (path[i] == '/') { path.replace(i, 1, DIR_DELIM); - i += std::string(DIR_DELIM).size() - 1; // generally a no-op + i += strlen(DIR_DELIM) - 1; // generally a no-op } } @@ -259,6 +261,46 @@ void TestFileSys::testRemoveRelativePathComponent() } +void TestFileSys::testAbsolutePath() +{ + const auto dir_path = getTestTempDirectory(); + + /* AbsolutePath */ + UASSERTEQ(auto, fs::AbsolutePath(""), ""); // empty is a not valid path + const auto cwd = fs::AbsolutePath("."); + UASSERTCMP(auto, !=, cwd, ""); + { + const auto dir_path2 = getTestTempFile(); + UASSERTEQ(auto, fs::AbsolutePath(dir_path2), ""); // doesn't exist + fs::CreateDir(dir_path2); + UASSERTCMP(auto, !=, fs::AbsolutePath(dir_path2), ""); // now it does + UASSERTEQ(auto, fs::AbsolutePath(dir_path2 + DIR_DELIM ".."), fs::AbsolutePath(dir_path)); + } + + /* AbsolutePathPartial */ + // equivalent to AbsolutePath if it exists + UASSERTEQ(auto, fs::AbsolutePathPartial("."), cwd); + UASSERTEQ(auto, fs::AbsolutePathPartial(dir_path), fs::AbsolutePath(dir_path)); + // usual usage of the function with a partially existing path + auto expect = cwd + DIR_DELIM + p("does/not/exist"); + UASSERTEQ(auto, fs::AbsolutePathPartial("does/not/exist"), expect); + UASSERTEQ(auto, fs::AbsolutePathPartial(expect), expect); + + // a nonsense combination as you couldn't actually access it, but allowed by function + UASSERTEQ(auto, fs::AbsolutePathPartial("bla/blub/../.."), cwd); + UASSERTEQ(auto, fs::AbsolutePathPartial("./bla/blub/../.."), cwd); + +#ifdef __unix__ + // one way to produce the error case is to remove more components than there are + // but only if the path does not actually exist ("/.." does exist). + UASSERTEQ(auto, fs::AbsolutePathPartial("/.."), "/"); + UASSERTEQ(auto, fs::AbsolutePathPartial("/noexist/../.."), ""); +#endif + // or with an empty path + UASSERTEQ(auto, fs::AbsolutePathPartial(""), ""); +} + + void TestFileSys::testSafeWriteToFile() { const std::string dest_path = getTestTempFile(); From 818bca68d1633be775dc8c1a76a9325c03b9d977 Mon Sep 17 00:00:00 2001 From: JosiahWI <41302989+JosiahWI@users.noreply.github.com> Date: Tue, 3 Dec 2024 09:51:53 -0600 Subject: [PATCH 091/136] Use `add_compile_options` where appropriate --- src/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e6e493184..67f698b85 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -896,12 +896,12 @@ if(MSVC) # Flags that cannot be shared between cl and clang-cl # https://clang.llvm.org/docs/UsersManual.html#clang-cl if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=lld") + add_compile_options(-fuse-ld=lld) # Disable pragma-pack warning set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wno-pragma-pack") else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") + add_compile_options(/MP) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /TP /FD /GL") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") endif() From 03813a5b5e0b639ff9832148e3f9da34a65674e3 Mon Sep 17 00:00:00 2001 From: JosiahWI <41302989+JosiahWI@users.noreply.github.com> Date: Tue, 3 Dec 2024 09:52:15 -0600 Subject: [PATCH 092/136] Use CMake `list` directives where appropriate I think this communicates the intent a little better than using a `set` directive, and it makes the code a little less verbose, too. --- src/CMakeLists.txt | 35 +++++++++++++++++------------------ src/client/CMakeLists.txt | 2 +- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 67f698b85..d764e186e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -273,7 +273,7 @@ set(PLATFORM_LIBS Threads::Threads) if(WIN32) # Windows if(MSVC) # MSVC Specifics - set(PLATFORM_LIBS dbghelp.lib ${PLATFORM_LIBS}) + list(APPEND PLATFORM_LIBS dbghelp.lib) # Surpress some useless warnings add_compile_options(/W1) add_compile_definitions( @@ -285,7 +285,7 @@ if(WIN32) NOMINMAX ) endif() - set(PLATFORM_LIBS ws2_32.lib version.lib shlwapi.lib winmm.lib ${PLATFORM_LIBS}) + list(APPEND PLATFORM_LIBS ws2_32.lib version.lib shlwapi.lib winmm.lib) set(EXTRA_DLL "" CACHE FILEPATH "Optional paths to additional DLLs that should be packaged") @@ -312,28 +312,28 @@ if(WIN32) endif() else() # Unix probably - set(PLATFORM_LIBS ${PLATFORM_LIBS} ${CMAKE_DL_LIBS}) + list(APPEND PLATFORM_LIBS ${CMAKE_DL_LIBS}) if(APPLE) - set(PLATFORM_LIBS "-framework CoreFoundation" ${PLATFORM_LIBS}) + list(APPEND PLATFORM_LIBS "-framework CoreFoundation") else() check_library_exists(rt clock_gettime "" HAVE_LIBRT) if (HAVE_LIBRT) - set(PLATFORM_LIBS -lrt ${PLATFORM_LIBS}) + list(APPEND PLATFORM_LIBS -lrt) endif(HAVE_LIBRT) endif(APPLE) find_library(ICONV_LIBRARY iconv) mark_as_advanced(ICONV_LIBRARY) if (ICONV_LIBRARY) - set(PLATFORM_LIBS ${PLATFORM_LIBS} ${ICONV_LIBRARY}) + list(APPEND PLATFORM_LIBS ${ICONV_LIBRARY}) endif() if (HAIKU) - set(PLATFORM_LIBS ${PLATFORM_LIBS} network) + list(APPEND PLATFORM_LIBS network) endif() if (ANDROID) - set(PLATFORM_LIBS ${PLATFORM_LIBS} android log) + list(APPEND PLATFORM_LIBS android log) endif() endif() @@ -347,7 +347,7 @@ if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") check_c_source_compiles("int main(){}" HAVE_LINK_ATOMIC) set(CMAKE_REQUIRED_LIBRARIES "") if(HAVE_LINK_ATOMIC) - set(PLATFORM_LIBS ${PLATFORM_LIBS} "-latomic") + list(APPEND PLATFORM_LIBS "-latomic") endif() endif() @@ -471,21 +471,21 @@ set(common_SRCS ) if(ANDROID) - set(common_SRCS ${common_SRCS} porting_android.cpp) + list(APPEND common_SRCS porting_android.cpp) endif() if(BUILD_UNITTESTS) add_subdirectory(unittest) - set(common_SRCS ${common_SRCS} ${UNITTEST_SRCS}) + list(APPEND common_SRCS ${UNITTEST_SRCS}) endif() if(BUILD_BENCHMARKS) add_subdirectory(benchmark) - set(common_SRCS ${common_SRCS} ${BENCHMARK_SRCS}) + list(APPEND common_SRCS ${BENCHMARK_SRCS}) endif() if(BUILD_UNITTESTS OR BUILD_BENCHMARKS) - set(common_SRCS ${common_SRCS} catch.cpp) + list(APPEND common_SRCS catch.cpp) endif() # This gives us the icon and file version information @@ -516,8 +516,7 @@ if (BUILD_CLIENT) add_subdirectory(irrlicht_changes) endif(BUILD_CLIENT) -set(client_SRCS - ${client_SRCS} +list(APPEND client_SRCS ${common_SRCS} ${gui_SRCS} ${client_network_SRCS} @@ -526,11 +525,11 @@ set(client_SRCS ) if(BUILD_UNITTESTS) - set(client_SRCS ${client_SRCS} ${UNITTEST_CLIENT_SRCS}) + list(APPEND client_SRCS ${UNITTEST_CLIENT_SRCS}) endif() if(BUILD_BENCHMARKS) - set(client_SRCS ${client_SRCS} ${BENCHMARK_CLIENT_SRCS}) + list(APPEND client_SRCS ${BENCHMARK_CLIENT_SRCS}) endif() # Server sources @@ -1106,7 +1105,7 @@ elseif (USE_GETTEXT) COMMENT "mo-update [${LOCALE}]: Creating mo file." ) - set(MO_FILES ${MO_FILES} ${MO_FILE_PATH}) + list(APPEND MO_FILES ${MO_FILE_PATH}) endforeach() add_custom_target(translations ALL COMMENT "mo update" DEPENDS ${MO_FILES}) diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index d451d0911..0bcb667bc 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -1,7 +1,7 @@ set(sound_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/sound.cpp) if(USE_SOUND) - set(sound_SRCS ${sound_SRCS} + list(APPEND sound_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/sound/al_extensions.cpp ${CMAKE_CURRENT_SOURCE_DIR}/sound/al_helpers.cpp ${CMAKE_CURRENT_SOURCE_DIR}/sound/ogg_file.cpp From a45b04ffb4c0583ef3c8727ea0f73d40e3662e9d Mon Sep 17 00:00:00 2001 From: HybridDog <3192173+HybridDog@users.noreply.github.com> Date: Tue, 3 Dec 2024 16:52:48 +0100 Subject: [PATCH 093/136] Less explicit memory management in Irrlicht image writer classes (#15493) CImageWriterPNG::writeImage() and writeJPEGFile() explicitly allocate and deallocate memory with `new` and `delete`, which is prone to programming errors. The code also has non-functional error handling: When memory allocation fails, `new` throws an `std::bad_alloc` exception and never returns `nullptr`, so the check for `nullptr` is always false. Co-authored-by: DS --- irr/src/CImageWriterJPG.cpp | 33 ++++++++++++-------------- irr/src/CImageWriterPNG.cpp | 47 +++++++++++++++---------------------- 2 files changed, 34 insertions(+), 46 deletions(-) diff --git a/irr/src/CImageWriterJPG.cpp b/irr/src/CImageWriterJPG.cpp index fa8ad64bc..1220c47e6 100644 --- a/irr/src/CImageWriterJPG.cpp +++ b/irr/src/CImageWriterJPG.cpp @@ -10,6 +10,7 @@ #include "os.h" #include // IWYU pragma: keep (required for jpeglib.h) +#include #include #include @@ -130,32 +131,28 @@ static bool writeJPEGFile(io::IWriteFile *file, IImage *image, u32 quality) jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); - u8 *dest = new u8[dim.Width * 3]; + std::unique_ptr dest{new u8[dim.Width * 3]}; - if (dest) { - const u32 pitch = image->getPitch(); - JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ - row_pointer[0] = dest; + const u32 pitch = image->getPitch(); + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + row_pointer[0] = dest.get(); - u8 *src = (u8 *)image->getData(); + u8 *src = (u8 *)image->getData(); - while (cinfo.next_scanline < cinfo.image_height) { - // convert next line - format(src, dim.Width, dest); - src += pitch; - jpeg_write_scanlines(&cinfo, row_pointer, 1); - } - - delete[] dest; - - /* Step 6: Finish compression */ - jpeg_finish_compress(&cinfo); + while (cinfo.next_scanline < cinfo.image_height) { + // convert next line + format(src, dim.Width, dest.get()); + src += pitch; + jpeg_write_scanlines(&cinfo, row_pointer, 1); } + /* Step 6: Finish compression */ + jpeg_finish_compress(&cinfo); + /* Step 7: Destroy */ jpeg_destroy_compress(&cinfo); - return (dest != 0); + return true; } } // namespace video diff --git a/irr/src/CImageWriterPNG.cpp b/irr/src/CImageWriterPNG.cpp index 14c9f2d9c..35e33c3d5 100644 --- a/irr/src/CImageWriterPNG.cpp +++ b/irr/src/CImageWriterPNG.cpp @@ -10,6 +10,7 @@ #include "os.h" // for logging #include // use system lib png +#include namespace irr { @@ -94,22 +95,23 @@ bool CImageWriterPNG::writeImage(io::IWriteFile *file, IImage *image, u32 param) png_set_write_fn(png_ptr, file, user_write_data_fcn, NULL); // Set info + core::dimension2d img_dim = image->getDimension(); switch (image->getColorFormat()) { case ECF_A8R8G8B8: case ECF_A1R5G5B5: png_set_IHDR(png_ptr, info_ptr, - image->getDimension().Width, image->getDimension().Height, + img_dim.Width, img_dim.Height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); break; default: png_set_IHDR(png_ptr, info_ptr, - image->getDimension().Width, image->getDimension().Height, + img_dim.Width, img_dim.Height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); } - s32 lineWidth = image->getDimension().Width; + s32 lineWidth = img_dim.Width; switch (image->getColorFormat()) { case ECF_R8G8B8: case ECF_R5G6B5: @@ -123,61 +125,52 @@ bool CImageWriterPNG::writeImage(io::IWriteFile *file, IImage *image, u32 param) default: break; } - u8 *tmpImage = new u8[image->getDimension().Height * lineWidth]; - if (!tmpImage) { - os::Printer::log("PNGWriter: Internal PNG create image failure", file->getFileName(), ELL_ERROR); - png_destroy_write_struct(&png_ptr, &info_ptr); - return false; - } + std::unique_ptr tmpImage{new u8[img_dim.Height * lineWidth]}; + auto num_pixels = img_dim.Height * img_dim.Width; u8 *data = (u8 *)image->getData(); switch (image->getColorFormat()) { case ECF_R8G8B8: - CColorConverter::convert_R8G8B8toR8G8B8(data, image->getDimension().Height * image->getDimension().Width, tmpImage); + CColorConverter::convert_R8G8B8toR8G8B8(data, num_pixels, + tmpImage.get()); break; case ECF_A8R8G8B8: - CColorConverter::convert_A8R8G8B8toA8R8G8B8(data, image->getDimension().Height * image->getDimension().Width, tmpImage); + CColorConverter::convert_A8R8G8B8toA8R8G8B8(data, num_pixels, + tmpImage.get()); break; case ECF_R5G6B5: - CColorConverter::convert_R5G6B5toR8G8B8(data, image->getDimension().Height * image->getDimension().Width, tmpImage); + CColorConverter::convert_R5G6B5toR8G8B8(data, num_pixels, + tmpImage.get()); break; case ECF_A1R5G5B5: - CColorConverter::convert_A1R5G5B5toA8R8G8B8(data, image->getDimension().Height * image->getDimension().Width, tmpImage); + CColorConverter::convert_A1R5G5B5toA8R8G8B8(data, num_pixels, + tmpImage.get()); break; // TODO: Error handling in case of unsupported color format default: os::Printer::log("CImageWriterPNG does not support image format", ColorFormatNames[image->getColorFormat()], ELL_WARNING); png_destroy_write_struct(&png_ptr, &info_ptr); - delete[] tmpImage; return false; } // Create array of pointers to rows in image data // Used to point to image rows - u8 **RowPointers = new png_bytep[image->getDimension().Height]; - if (!RowPointers) { - os::Printer::log("PNGWriter: Internal PNG create row pointers failure", file->getFileName(), ELL_ERROR); - png_destroy_write_struct(&png_ptr, &info_ptr); - delete[] tmpImage; - return false; - } + std::unique_ptr RowPointers{new u8*[img_dim.Height]}; - data = tmpImage; + data = tmpImage.get(); // Fill array of pointers to rows in image data - for (u32 i = 0; i < image->getDimension().Height; ++i) { + for (u32 i = 0; i < img_dim.Height; ++i) { RowPointers[i] = data; data += lineWidth; } // for proper error handling if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); - delete[] RowPointers; - delete[] tmpImage; return false; } - png_set_rows(png_ptr, info_ptr, RowPointers); + png_set_rows(png_ptr, info_ptr, RowPointers.get()); if (image->getColorFormat() == ECF_A8R8G8B8 || image->getColorFormat() == ECF_A1R5G5B5) png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_BGR, NULL); @@ -185,8 +178,6 @@ bool CImageWriterPNG::writeImage(io::IWriteFile *file, IImage *image, u32 param) png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); } - delete[] RowPointers; - delete[] tmpImage; png_destroy_write_struct(&png_ptr, &info_ptr); return true; } From 18caf3a18dda95dbd9555cc16a5dcfc9f025cc35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Wed, 4 Dec 2024 18:19:12 +0100 Subject: [PATCH 094/136] Fix false positive compiler warning --- irr/src/CGLTFMeshFileLoader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/irr/src/CGLTFMeshFileLoader.cpp b/irr/src/CGLTFMeshFileLoader.cpp index fe67228a7..ce2c41f58 100644 --- a/irr/src/CGLTFMeshFileLoader.cpp +++ b/irr/src/CGLTFMeshFileLoader.cpp @@ -791,7 +791,8 @@ std::optional> SelfType::MeshExtractor::getIndices( index = std::get>(accessor).get(elemIdx); if (index == std::numeric_limits::max()) throw std::runtime_error("invalid index"); - } else if (std::holds_alternative>(accessor)) { + } else { + _IRR_DEBUG_BREAK_IF(!std::holds_alternative>(accessor)); u32 indexWide = std::get>(accessor).get(elemIdx); // Use >= here for consistency. if (indexWide >= std::numeric_limits::max()) From e545e96d2bc146765b3d663b24ab0fd7bf85abbd Mon Sep 17 00:00:00 2001 From: AFCMS Date: Wed, 4 Dec 2024 18:19:46 +0100 Subject: [PATCH 095/136] Make string to v3f parsing consistent, replace `core.setting_get_pos()` by `core.settings:get_pos()` (#15438) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: sfan5 Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> --- builtin/game/misc_s.lua | 6 +--- builtin/game/static_spawn.lua | 2 +- doc/lua_api.md | 8 ++++- src/client/hud.cpp | 4 +-- src/database/database-files.cpp | 2 +- src/gui/guiChatConsole.cpp | 2 +- src/gui/guiFormSpecMenu.cpp | 2 +- src/inventory.cpp | 4 +-- src/mapgen/mapgen_fractal.cpp | 13 ++++++-- src/script/lua_api/l_settings.cpp | 34 +++++++++++++++++++++ src/script/lua_api/l_settings.h | 6 ++++ src/server.cpp | 11 +++++-- src/settings.cpp | 10 +++++-- src/settings.h | 4 +-- src/unittest/test_settings.cpp | 49 +++++++++++++++++++++++++------ src/util/string.cpp | 45 ++++++++++++++++++++++------ src/util/string.h | 5 ++-- 17 files changed, 162 insertions(+), 45 deletions(-) diff --git a/builtin/game/misc_s.lua b/builtin/game/misc_s.lua index 90092952d..07ab09b37 100644 --- a/builtin/game/misc_s.lua +++ b/builtin/game/misc_s.lua @@ -36,11 +36,7 @@ end function core.setting_get_pos(name) - local value = core.settings:get(name) - if not value then - return nil - end - return core.string_to_pos(value) + return core.settings:get_pos(name) end diff --git a/builtin/game/static_spawn.lua b/builtin/game/static_spawn.lua index 5b834310f..2d535251a 100644 --- a/builtin/game/static_spawn.lua +++ b/builtin/game/static_spawn.lua @@ -1,7 +1,7 @@ local static_spawnpoint_string = core.settings:get("static_spawnpoint") if static_spawnpoint_string and static_spawnpoint_string ~= "" and - not core.setting_get_pos("static_spawnpoint") then + not core.settings:get_pos("static_spawnpoint") then error('The static_spawnpoint setting is invalid: "' .. static_spawnpoint_string .. '"') end diff --git a/doc/lua_api.md b/doc/lua_api.md index 709bf2984..2d5405090 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -6180,7 +6180,7 @@ Setting-related * `core.settings`: Settings object containing all of the settings from the main config file (`minetest.conf`). See [`Settings`]. * `core.setting_get_pos(name)`: Loads a setting from the main settings and - parses it as a position (in the format `(1,2,3)`). Returns a position or nil. + parses it as a position (in the format `(1,2,3)`). Returns a position or nil. **Deprecated: use `core.settings:get_pos()` instead** Authentication -------------- @@ -9051,6 +9051,9 @@ means that no defaults will be returned for mod settings. * Is currently limited to mapgen flags `mg_flags` and mapgen-specific flags like `mgv5_spflags`. * Returns `nil` if `key` is not found. +* `get_pos(key)`: + * Returns a `vector` + * Returns `nil` if no value is found or parsing failed. * `set(key, value)` * Setting names can't contain whitespace or any of `="{}#`. * Setting values can't contain the sequence `\n"""`. @@ -9061,6 +9064,9 @@ means that no defaults will be returned for mod settings. * `set_np_group(key, value)` * `value` is a NoiseParams table. * Also, see documentation for `set()` above. +* `set_pos(key, value)` + * `value` is a `vector`. + * Also, see documentation for `set()` above. * `remove(key)`: returns a boolean (`true` for success) * `get_names()`: returns `{key1,...}` * `has(key)`: diff --git a/src/client/hud.cpp b/src/client/hud.cpp index e49327d30..4fbd8740f 100644 --- a/src/client/hud.cpp +++ b/src/client/hud.cpp @@ -55,14 +55,14 @@ Hud::Hud(Client *client, LocalPlayer *player, tsrc = client->getTextureSource(); - v3f crosshair_color = g_settings->getV3F("crosshair_color"); + v3f crosshair_color = g_settings->getV3F("crosshair_color").value_or(v3f()); u32 cross_r = rangelim(myround(crosshair_color.X), 0, 255); u32 cross_g = rangelim(myround(crosshair_color.Y), 0, 255); u32 cross_b = rangelim(myround(crosshair_color.Z), 0, 255); u32 cross_a = rangelim(g_settings->getS32("crosshair_alpha"), 0, 255); crosshair_argb = video::SColor(cross_a, cross_r, cross_g, cross_b); - v3f selectionbox_color = g_settings->getV3F("selectionbox_color"); + v3f selectionbox_color = g_settings->getV3F("selectionbox_color").value_or(v3f()); u32 sbox_r = rangelim(myround(selectionbox_color.X), 0, 255); u32 sbox_g = rangelim(myround(selectionbox_color.Y), 0, 255); u32 sbox_b = rangelim(myround(selectionbox_color.Z), 0, 255); diff --git a/src/database/database-files.cpp b/src/database/database-files.cpp index e19d51108..5001a2810 100644 --- a/src/database/database-files.cpp +++ b/src/database/database-files.cpp @@ -43,7 +43,7 @@ void PlayerDatabaseFiles::deSerialize(RemotePlayer *p, std::istream &is, } try { - sao->setBasePosition(args.getV3F("position")); + sao->setBasePosition(args.getV3F("position").value_or(v3f())); } catch (SettingNotFoundException &e) {} try { diff --git a/src/gui/guiChatConsole.cpp b/src/gui/guiChatConsole.cpp index 28aea66c1..689ad22e0 100644 --- a/src/gui/guiChatConsole.cpp +++ b/src/gui/guiChatConsole.cpp @@ -55,7 +55,7 @@ GUIChatConsole::GUIChatConsole( m_background_color.setGreen(255); m_background_color.setBlue(255); } else { - v3f console_color = g_settings->getV3F("console_color"); + v3f console_color = g_settings->getV3F("console_color").value_or(v3f()); m_background_color.setRed(clamp_u8(myround(console_color.X))); m_background_color.setGreen(clamp_u8(myround(console_color.Y))); m_background_color.setBlue(clamp_u8(myround(console_color.Z))); diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp index ed1c3009d..2330f7c32 100644 --- a/src/gui/guiFormSpecMenu.cpp +++ b/src/gui/guiFormSpecMenu.cpp @@ -3010,7 +3010,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) m_tabheader_upper_edge = 0; { - v3f formspec_bgcolor = g_settings->getV3F("formspec_fullscreen_bg_color"); + v3f formspec_bgcolor = g_settings->getV3F("formspec_fullscreen_bg_color").value_or(v3f()); m_fullscreen_bgcolor = video::SColor( (u8) clamp_u8(g_settings->getS32("formspec_fullscreen_bg_opacity")), clamp_u8(myround(formspec_bgcolor.X)), diff --git a/src/inventory.cpp b/src/inventory.cpp index 0ba59ceea..246086d95 100644 --- a/src/inventory.cpp +++ b/src/inventory.cpp @@ -295,10 +295,8 @@ std::string ItemStack::getWieldOverlay(const IItemDefManager *itemdef) const v3f ItemStack::getWieldScale(const IItemDefManager *itemdef) const { std::string scale = metadata.getString("wield_scale"); - if (scale.empty()) - return getDefinition(itemdef).wield_scale; - return str_to_v3f(scale); + return str_to_v3f(scale).value_or(getDefinition(itemdef).wield_scale); } ItemStack ItemStack::addItem(ItemStack newitem, IItemDefManager *itemdef) diff --git a/src/mapgen/mapgen_fractal.cpp b/src/mapgen/mapgen_fractal.cpp index dcd62f63a..940fe0083 100644 --- a/src/mapgen/mapgen_fractal.cpp +++ b/src/mapgen/mapgen_fractal.cpp @@ -103,8 +103,17 @@ void MapgenFractalParams::readParams(const Settings *settings) settings->getS16NoEx("mgfractal_dungeon_ymax", dungeon_ymax); settings->getU16NoEx("mgfractal_fractal", fractal); settings->getU16NoEx("mgfractal_iterations", iterations); - settings->getV3FNoEx("mgfractal_scale", scale); - settings->getV3FNoEx("mgfractal_offset", offset); + + std::optional mgfractal_scale; + if (settings->getV3FNoEx("mgfractal_scale", mgfractal_scale) && mgfractal_scale.has_value()) { + scale = *mgfractal_scale; + } + + std::optional mgfractal_offset; + if (settings->getV3FNoEx("mgfractal_offset", mgfractal_offset) && mgfractal_offset.has_value()) { + offset = *mgfractal_offset; + } + settings->getFloatNoEx("mgfractal_slice_w", slice_w); settings->getFloatNoEx("mgfractal_julia_x", julia_x); settings->getFloatNoEx("mgfractal_julia_y", julia_y); diff --git a/src/script/lua_api/l_settings.cpp b/src/script/lua_api/l_settings.cpp index c4395e390..241eb2542 100644 --- a/src/script/lua_api/l_settings.cpp +++ b/src/script/lua_api/l_settings.cpp @@ -10,6 +10,7 @@ #include "settings.h" #include "noise.h" #include "log.h" +#include "common/c_converter.h" /* @@ -177,6 +178,21 @@ int LuaSettings::l_get_flags(lua_State *L) return 1; } +// get_pos(self, key) -> vector or nil +int LuaSettings::l_get_pos(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + LuaSettings *o = checkObject(L, 1); + std::string key = luaL_checkstring(L, 2); + + std::optional pos; + if (o->m_settings->getV3FNoEx(key, pos) && pos.has_value()) + push_v3f(L, *pos); + else + lua_pushnil(L); + return 1; +} + // set(self, key, value) int LuaSettings::l_set(lua_State* L) { @@ -227,6 +243,22 @@ int LuaSettings::l_set_np_group(lua_State *L) return 0; } +// set_pos(self, key, value) +int LuaSettings::l_set_pos(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + LuaSettings *o = checkObject(L, 1); + + std::string key = luaL_checkstring(L, 2); + v3f value = check_v3f(L, 3); + + CHECK_SETTING_SECURITY(L, key); + + o->m_settings->setV3F(key, value); + + return 0; +} + // remove(self, key) -> success int LuaSettings::l_remove(lua_State* L) { @@ -356,9 +388,11 @@ const luaL_Reg LuaSettings::methods[] = { luamethod(LuaSettings, get_bool), luamethod(LuaSettings, get_np_group), luamethod(LuaSettings, get_flags), + luamethod(LuaSettings, get_pos), luamethod(LuaSettings, set), luamethod(LuaSettings, set_bool), luamethod(LuaSettings, set_np_group), + luamethod(LuaSettings, set_pos), luamethod(LuaSettings, remove), luamethod(LuaSettings, get_names), luamethod(LuaSettings, has), diff --git a/src/script/lua_api/l_settings.h b/src/script/lua_api/l_settings.h index ca609fc1f..63741477a 100644 --- a/src/script/lua_api/l_settings.h +++ b/src/script/lua_api/l_settings.h @@ -29,6 +29,9 @@ private: // get_flags(self, key) -> key/value table static int l_get_flags(lua_State *L); + // get_pos(self, key) -> vector or nil + static int l_get_pos(lua_State *L); + // set(self, key, value) static int l_set(lua_State *L); @@ -38,6 +41,9 @@ private: // set_np_group(self, key, value) static int l_set_np_group(lua_State *L); + // set_pos(self, key, value) + static int l_set_pos(lua_State *L); + // remove(self, key) -> success static int l_remove(lua_State *L); diff --git a/src/server.cpp b/src/server.cpp index ee9b0a859..b21955170 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -3863,9 +3863,14 @@ void Server::addShutdownError(const ModError &e) v3f Server::findSpawnPos() { ServerMap &map = m_env->getServerMap(); - v3f nodeposf; - if (g_settings->getV3FNoEx("static_spawnpoint", nodeposf)) - return nodeposf * BS; + + std::optional staticSpawnPoint; + if (g_settings->getV3FNoEx("static_spawnpoint", staticSpawnPoint) && staticSpawnPoint.has_value()) + { + return *staticSpawnPoint * BS; + } + + v3f nodeposf; bool is_good = false; // Limit spawn range to mapgen edges (determined by 'mapgen_limit') diff --git a/src/settings.cpp b/src/settings.cpp index 02c84437d..cec3f5239 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -541,7 +541,7 @@ v2f Settings::getV2F(const std::string &name) const } -v3f Settings::getV3F(const std::string &name) const +std::optional Settings::getV3F(const std::string &name) const { return str_to_v3f(get(name)); } @@ -626,7 +626,11 @@ bool Settings::getNoiseParamsFromGroup(const std::string &name, group->getFloatNoEx("offset", np.offset); group->getFloatNoEx("scale", np.scale); - group->getV3FNoEx("spread", np.spread); + + std::optional spread; + if (group->getV3FNoEx("spread", spread) && spread.has_value()) + np.spread = *spread; + group->getS32NoEx("seed", np.seed); group->getU16NoEx("octaves", np.octaves); group->getFloatNoEx("persistence", np.persist); @@ -783,7 +787,7 @@ bool Settings::getV2FNoEx(const std::string &name, v2f &val) const } -bool Settings::getV3FNoEx(const std::string &name, v3f &val) const +bool Settings::getV3FNoEx(const std::string &name, std::optional &val) const { try { val = getV3F(name); diff --git a/src/settings.h b/src/settings.h index 0638dad2d..9bc0e80d9 100644 --- a/src/settings.h +++ b/src/settings.h @@ -150,7 +150,7 @@ public: float getFloat(const std::string &name) const; float getFloat(const std::string &name, float min, float max) const; v2f getV2F(const std::string &name) const; - v3f getV3F(const std::string &name) const; + std::optional getV3F(const std::string &name) const; u32 getFlagStr(const std::string &name, const FlagDesc *flagdesc, u32 *flagmask) const; bool getNoiseParams(const std::string &name, NoiseParams &np) const; @@ -179,7 +179,7 @@ public: bool getU64NoEx(const std::string &name, u64 &val) const; bool getFloatNoEx(const std::string &name, float &val) const; bool getV2FNoEx(const std::string &name, v2f &val) const; - bool getV3FNoEx(const std::string &name, v3f &val) const; + bool getV3FNoEx(const std::string &name, std::optional &val) const; // Like other getters, but handling each flag individualy: // 1) Read default flags (or 0) diff --git a/src/unittest/test_settings.cpp b/src/unittest/test_settings.cpp index 94b222c1f..411ecb8de 100644 --- a/src/unittest/test_settings.cpp +++ b/src/unittest/test_settings.cpp @@ -42,6 +42,14 @@ const char *TestSettings::config_text_before = "floaty_thing = 1.1\n" "stringy_thing = asd /( ¤%&(/\" BLÖÄRP\n" "coord = (1, 2, 4.5)\n" + "coord_invalid = (1,2,3\n" + "coord_invalid_2 = 1, 2, 3 test\n" + "coord_invalid_3 = (test, something, stupid)\n" + "coord_invalid_4 = (1, test, 3)\n" + "coord_invalid_5 = ()\n" + "coord_invalid_6 = (1, 2)\n" + "coord_invalid_7 = (1)\n" + "coord_no_parenthesis = 1,2,3\n" " # this is just a comment\n" "this is an invalid line\n" "asdf = {\n" @@ -94,7 +102,15 @@ const char *TestSettings::config_text_after = " spread = (250,250,250)\n" "}\n" "zoop = true\n" - "coord2 = (1,2,3.3)\n" + "coord2 = (1,2,3.25)\n" + "coord_invalid = (1,2,3\n" + "coord_invalid_2 = 1, 2, 3 test\n" + "coord_invalid_3 = (test, something, stupid)\n" + "coord_invalid_4 = (1, test, 3)\n" + "coord_invalid_5 = ()\n" + "coord_invalid_6 = (1, 2)\n" + "coord_invalid_7 = (1)\n" + "coord_no_parenthesis = 1,2,3\n" "floaty_thing_2 = 1.25\n" "groupy_thing = {\n" " animals = cute\n" @@ -140,18 +156,33 @@ void TestSettings::testAllSettings() // Not sure if 1.1 is an exact value as a float, but doesn't matter UASSERT(fabs(s.getFloat("floaty_thing") - 1.1) < 0.001); UASSERT(s.get("stringy_thing") == u8"asd /( ¤%&(/\" BLÖÄRP"); - UASSERT(fabs(s.getV3F("coord").X - 1.0) < 0.001); - UASSERT(fabs(s.getV3F("coord").Y - 2.0) < 0.001); - UASSERT(fabs(s.getV3F("coord").Z - 4.5) < 0.001); + UASSERT(s.getV3F("coord").value().X == 1.0); + UASSERT(s.getV3F("coord").value().Y == 2.0); + UASSERT(s.getV3F("coord").value().Z == 4.5); // Test the setting of settings too s.setFloat("floaty_thing_2", 1.25); - s.setV3F("coord2", v3f(1, 2, 3.3)); + s.setV3F("coord2", v3f(1, 2, 3.25)); UASSERT(s.get("floaty_thing_2").substr(0,4) == "1.25"); - UASSERT(fabs(s.getFloat("floaty_thing_2") - 1.25) < 0.001); - UASSERT(fabs(s.getV3F("coord2").X - 1.0) < 0.001); - UASSERT(fabs(s.getV3F("coord2").Y - 2.0) < 0.001); - UASSERT(fabs(s.getV3F("coord2").Z - 3.3) < 0.001); + UASSERT(s.getFloat("floaty_thing_2") == 1.25); + UASSERT(s.getV3F("coord2").value().X == 1.0); + UASSERT(s.getV3F("coord2").value().Y == 2.0); + UASSERT(s.getV3F("coord2").value().Z == 3.25); + + std::optional testNotExist; + UASSERT(!s.getV3FNoEx("coord_not_exist", testNotExist)); + EXCEPTION_CHECK(SettingNotFoundException, s.getV3F("coord_not_exist")); + + UASSERT(!s.getV3F("coord_invalid").has_value()); + UASSERT(!s.getV3F("coord_invalid_2").has_value()); + UASSERT(!s.getV3F("coord_invalid_3").has_value()); + UASSERT(!s.getV3F("coord_invalid_4").has_value()); + UASSERT(!s.getV3F("coord_invalid_5").has_value()); + UASSERT(!s.getV3F("coord_invalid_6").has_value()); + UASSERT(!s.getV3F("coord_invalid_7").has_value()); + + std::optional testNoParenthesis = s.getV3F("coord_no_parenthesis"); + UASSERT(testNoParenthesis.value() == v3f(1, 2, 3)); // Test settings groups Settings *group = s.getGroup("asdf"); diff --git a/src/util/string.cpp b/src/util/string.cpp index 43e936788..a0eee85c1 100644 --- a/src/util/string.cpp +++ b/src/util/string.cpp @@ -1068,14 +1068,41 @@ void safe_print_string(std::ostream &os, std::string_view str) os.setf(flags); } - -v3f str_to_v3f(std::string_view str) +std::optional str_to_v3f(std::string_view str) { - v3f value; - Strfnd f(str); - f.next("("); - value.X = stof(f.next(",")); - value.Y = stof(f.next(",")); - value.Z = stof(f.next(")")); - return value; + str = trim(str); + + if (str.empty()) + return std::nullopt; + + // Strip parentheses if they exist + if (str.front() == '(' && str.back() == ')') { + str.remove_prefix(1); + str.remove_suffix(1); + str = trim(str); + } + + std::istringstream iss((std::string(str))); + + const auto expect_delimiter = [&]() { + const auto c = iss.get(); + return c == ' ' || c == ','; + }; + + v3f value; + if (!(iss >> value.X)) + return std::nullopt; + if (!expect_delimiter()) + return std::nullopt; + if (!(iss >> value.Y)) + return std::nullopt; + if (!expect_delimiter()) + return std::nullopt; + if (!(iss >> value.Z)) + return std::nullopt; + + if (!iss.eof()) + return std::nullopt; + + return value; } diff --git a/src/util/string.h b/src/util/string.h index 1874ccd2a..16c337b7f 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -20,6 +20,7 @@ #include #include #include +#include class Translations; @@ -789,9 +790,9 @@ std::string sanitize_untrusted(std::string_view str, bool keep_escapes = true); void safe_print_string(std::ostream &os, std::string_view str); /** - * Parses a string of form `(1, 2, 3)` to a v3f + * Parses a string of form `(1, 2, 3)` or `1, 2, 4` to a v3f * * @param str string * @return float vector */ -v3f str_to_v3f(std::string_view str); +std::optional str_to_v3f(std::string_view str); From 36edc3f161de03e3c5e8b507d2d6699f0d728ab9 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Thu, 28 Nov 2024 10:38:51 +0100 Subject: [PATCH 096/136] Add 10-bit texture format and setting to chose PP color depth (and move some settings to the advanced category) --- builtin/settingtypes.txt | 47 ++++++++++++++++++++++-------------- irr/include/IImage.h | 2 ++ irr/include/SColor.h | 9 ++++++- irr/src/OpenGL3/Driver.cpp | 1 + irr/src/OpenGLES2/Driver.cpp | 1 + src/client/render/plain.cpp | 5 +++- src/defaultsettings.cpp | 3 +++ 7 files changed, 48 insertions(+), 20 deletions(-) diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index d23704694..b10f776ac 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -77,8 +77,11 @@ # Sections are marked by a single line in the format: [Section Name] # Sub-section are marked by adding * in front of the section name: [*Sub-section] # Sub-sub-sections have two * etc. -# There shouldn't be too much settings per category; settings that shouldn't be -# modified by the "average user" should be in (sub-)categories called "Advanced". +# There shouldn't be too many settings per category. +# +# The top-level categories "Advanced", "Client and Server" and "Mapgen" are +# handled specially and its contents only shown when a checkbox is checked. +# They contain settings not intended for the "average user". [Controls] @@ -471,6 +474,7 @@ performance_tradeoffs (Tradeoffs for performance) bool false # Adds particles when digging a node. enable_particles (Digging particles) bool true + [**Waving Nodes] # Set to true to enable waving leaves. @@ -534,12 +538,6 @@ shadow_map_texture_size (Shadow map texture size) int 2048 128 8192 # Requires: enable_dynamic_shadows, opengl shadow_map_texture_32bit (Shadow map texture in 32 bits) bool true -# Enable Poisson disk filtering. -# On true uses Poisson disk to make "soft shadows". Otherwise uses PCF filtering. -# -# Requires: enable_dynamic_shadows, opengl -shadow_poisson_filter (Poisson filtering) bool true - # Define shadow filtering quality. # This simulates the soft shadows effect by applying a PCF or Poisson disk # but also uses more resources. @@ -553,14 +551,6 @@ shadow_filters (Shadow filter quality) enum 1 0,1,2 # Requires: enable_dynamic_shadows, opengl shadow_map_color (Colored shadows) bool false -# Spread a complete update of shadow map over given number of frames. -# Higher values might make shadows laggy, lower values -# will consume more resources. -# Minimum value: 1; maximum value: 16 -# -# Requires: enable_dynamic_shadows, opengl -shadow_update_frames (Map shadows update frames) int 8 1 16 - # Set the soft shadow radius size. # Lower values mean sharper shadows, bigger values mean softer shadows. # Minimum value: 1.0; maximum value: 15.0 @@ -1830,6 +1820,9 @@ ignore_world_load_errors (Ignore world errors) bool false [**Graphics] +# Enables debug and error-checking in the OpenGL driver. +opengl_debug (OpenGL debug) bool false + # Path to shader directory. If no path is defined, default location will be used. shader_path (Shader path) path @@ -1901,8 +1894,26 @@ texture_min_size (Base texture size) int 64 1 32768 # Systems with a low-end GPU (or no GPU) would benefit from smaller values. client_mesh_chunk (Client Mesh Chunksize) int 1 1 16 -# Enables debug and error-checking in the OpenGL driver. -opengl_debug (OpenGL debug) bool false +# Decide the color depth of the texture used for the post-processing pipeline. +# Reducing this can improve performance, but might cause some effects (e.g. bloom) +# to not work. +# +# Requires: enable_post_processing +post_processing_texture_bits (Color depth for post-processing texture) enum 16 8,10,16 + +# Enable Poisson disk filtering. +# On true uses Poisson disk to make "soft shadows". Otherwise uses PCF filtering. +# +# Requires: enable_dynamic_shadows, opengl +shadow_poisson_filter (Poisson filtering) bool true + +# Spread a complete update of shadow map over given number of frames. +# Higher values might make shadows laggy, lower values +# will consume more resources. +# Minimum value: 1; maximum value: 16 +# +# Requires: enable_dynamic_shadows, opengl +shadow_update_frames (Map shadows update frames) int 8 1 16 # Set to true to render debugging breakdown of the bloom effect. # In debug mode, the screen is split into 4 quadrants: diff --git a/irr/include/IImage.h b/irr/include/IImage.h index 47349ed1a..a303201a9 100644 --- a/irr/include/IImage.h +++ b/irr/include/IImage.h @@ -342,6 +342,8 @@ public: return 16; case ECF_R16G16: return 32; + case ECF_A2R10G10B10: + return 32; case ECF_R16F: return 16; case ECF_G16R16F: diff --git a/irr/include/SColor.h b/irr/include/SColor.h index 41bca1a8c..0845b31f7 100644 --- a/irr/include/SColor.h +++ b/irr/include/SColor.h @@ -72,6 +72,9 @@ enum ECOLOR_FORMAT //! 32 bit format using 16 bits for the red and green channels. ECF_R16G16, + //! 32 bit format using 10 bits for R, G, B and 2 for alpha. + ECF_A2R10G10B10, + /** Depth and stencil formats. */ //! 16 bit format using 16 bits for depth. @@ -91,7 +94,7 @@ enum ECOLOR_FORMAT }; //! Names for ECOLOR_FORMAT types -const c8 *const ColorFormatNames[ECF_UNKNOWN + 2] = { +const c8 *const ColorFormatNames[] = { "A1R5G5B5", "R5G6B5", "R8G8B8", @@ -106,6 +109,7 @@ const c8 *const ColorFormatNames[ECF_UNKNOWN + 2] = { "R8G8", "R16", "R16G16", + "A2R10G10B10", "D16", "D24", "D32", @@ -114,6 +118,9 @@ const c8 *const ColorFormatNames[ECF_UNKNOWN + 2] = { 0, }; +static_assert(sizeof(ColorFormatNames) / sizeof(ColorFormatNames[0]) + == ECF_UNKNOWN + 2, "name table size mismatch"); + //! Creates a 16 bit A1R5G5B5 color inline u16 RGBA16(u32 r, u32 g, u32 b, u32 a = 0xFF) { diff --git a/irr/src/OpenGL3/Driver.cpp b/irr/src/OpenGL3/Driver.cpp index b397846aa..5277c4dde 100644 --- a/irr/src/OpenGL3/Driver.cpp +++ b/irr/src/OpenGL3/Driver.cpp @@ -62,6 +62,7 @@ void COpenGL3Driver::initFeatures() TextureFormats[ECF_R8G8] = {GL_RG8, GL_RG, GL_UNSIGNED_BYTE}; TextureFormats[ECF_R16] = {GL_R16, GL_RED, GL_UNSIGNED_SHORT}; TextureFormats[ECF_R16G16] = {GL_RG16, GL_RG, GL_UNSIGNED_SHORT}; + TextureFormats[ECF_A2R10G10B10] = {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV}; TextureFormats[ECF_D16] = {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; TextureFormats[ECF_D24] = {GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}; TextureFormats[ECF_D32] = {GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}; // WARNING: may not be renderable (?!) diff --git a/irr/src/OpenGLES2/Driver.cpp b/irr/src/OpenGLES2/Driver.cpp index 3c034522c..32bf0aee0 100644 --- a/irr/src/OpenGLES2/Driver.cpp +++ b/irr/src/OpenGLES2/Driver.cpp @@ -59,6 +59,7 @@ void COpenGLES2Driver::initFeatures() TextureFormats[ECF_A32B32G32R32F] = {GL_RGBA32F, GL_RGBA, GL_FLOAT}; TextureFormats[ECF_R8] = {GL_R8, GL_RED, GL_UNSIGNED_BYTE}; TextureFormats[ECF_R8G8] = {GL_RG8, GL_RG, GL_UNSIGNED_BYTE}; + TextureFormats[ECF_A2R10G10B10] = {GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV}; TextureFormats[ECF_D16] = {GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}; TextureFormats[ECF_D24] = {GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}; TextureFormats[ECF_D24S8] = {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}; diff --git a/src/client/render/plain.cpp b/src/client/render/plain.cpp index fd3e0b9ba..c24ba8837 100644 --- a/src/client/render/plain.cpp +++ b/src/client/render/plain.cpp @@ -155,8 +155,11 @@ void populatePlainPipeline(RenderPipeline *pipeline, Client *client) video::ECOLOR_FORMAT selectColorFormat(video::IVideoDriver *driver) { - if (driver->queryTextureFormat(video::ECF_A16B16G16R16F)) + u32 bits = g_settings->getU32("post_processing_texture_bits"); + if (bits >= 16 && driver->queryTextureFormat(video::ECF_A16B16G16R16F)) return video::ECF_A16B16G16R16F; + if (bits >= 10 && driver->queryTextureFormat(video::ECF_A2R10G10B10)) + return video::ECF_A2R10G10B10; return video::ECF_A8R8G8B8; } diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index e6b26bd4a..600058b5c 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -311,6 +311,7 @@ void set_default_settings() // Effects settings->setDefault("enable_post_processing", "true"); + settings->setDefault("post_processing_texture_bits", "16"); settings->setDefault("directional_colored_fog", "true"); settings->setDefault("inventory_items_animations", "false"); settings->setDefault("mip_map", "false"); @@ -567,6 +568,8 @@ void set_default_settings() settings->setDefault("active_block_range", "2"); settings->setDefault("viewing_range", "50"); settings->setDefault("leaves_style", "simple"); + // Note: OpenGL ES 2.0 is not guaranteed to provide depth textures, + // which we would need for PP. settings->setDefault("enable_post_processing", "false"); settings->setDefault("debanding", "false"); settings->setDefault("curl_verify_cert", "false"); From 1fb7202028ae67803f2c10c747cefacd18c35ee7 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Thu, 28 Nov 2024 10:39:07 +0100 Subject: [PATCH 097/136] GL: fix and clean up some code --- irr/include/IRenderTarget.h | 5 --- irr/include/ISceneManager.h | 12 ------- irr/include/IVideoDriver.h | 23 ------------- irr/src/CNullDriver.cpp | 29 ----------------- irr/src/CNullDriver.h | 23 ------------- irr/src/COpenGLCoreTexture.h | 11 +++++++ irr/src/COpenGLDriver.cpp | 18 ----------- irr/src/COpenGLDriver.h | 5 --- irr/src/COpenGLExtensionHandler.cpp | 4 +-- irr/src/COpenGLExtensionHandler.h | 2 -- irr/src/CSceneManager.cpp | 17 +--------- irr/src/CSceneManager.h | 9 ------ irr/src/OpenGL/Common.h | 2 +- irr/src/OpenGL/Driver.cpp | 50 +++++++++++++++++------------ irr/src/OpenGL/Driver.h | 5 +++ irr/src/OpenGLES2/Driver.cpp | 13 +++----- src/client/render/anaglyph.cpp | 3 +- 17 files changed, 54 insertions(+), 177 deletions(-) diff --git a/irr/include/IRenderTarget.h b/irr/include/IRenderTarget.h index 85b9738dc..d4e5960a2 100644 --- a/irr/include/IRenderTarget.h +++ b/irr/include/IRenderTarget.h @@ -109,11 +109,6 @@ protected: //! Driver type of render target. E_DRIVER_TYPE DriverType; - -private: - // no copying (IReferenceCounted still allows that for reasons which take some time to work around) - IRenderTarget(const IRenderTarget &); - IRenderTarget &operator=(const IRenderTarget &); }; } diff --git a/irr/include/ISceneManager.h b/irr/include/ISceneManager.h index 18521dbe9..7fbc0670c 100644 --- a/irr/include/ISceneManager.h +++ b/irr/include/ISceneManager.h @@ -55,9 +55,6 @@ enum E_SCENE_NODE_RENDER_PASS //! Camera pass. The active view is set up here. The very first pass. ESNRP_CAMERA = 1, - //! In this pass, lights are transformed into camera space and added to the driver - ESNRP_LIGHT = 2, - //! This is used for sky boxes. ESNRP_SKY_BOX = 4, @@ -85,9 +82,6 @@ enum E_SCENE_NODE_RENDER_PASS //! Transparent effect scene nodes, drawn after Transparent nodes. They are sorted from back to front and drawn in that order. ESNRP_TRANSPARENT_EFFECT = 32, - //! Drawn after the solid nodes, before the transparent nodes, the time for drawing shadow volumes - ESNRP_SHADOW = 64, - //! Drawn after transparent effect nodes. For custom gui's. Unsorted (in order nodes registered themselves). ESNRP_GUI = 128 @@ -602,12 +596,6 @@ public: for details. */ virtual ISkinnedMesh *createSkinnedMesh() = 0; - //! Sets ambient color of the scene - virtual void setAmbientLight(const video::SColorf &ambientColor) = 0; - - //! Get ambient color of the scene - virtual const video::SColorf &getAmbientLight() const = 0; - //! Get current render pass. virtual E_SCENE_NODE_RENDER_PASS getCurrentRenderPass() const = 0; diff --git a/irr/include/IVideoDriver.h b/irr/include/IVideoDriver.h index 3d4deace5..ebb39dfd9 100644 --- a/irr/include/IVideoDriver.h +++ b/irr/include/IVideoDriver.h @@ -131,7 +131,6 @@ public: /** The following names can be queried for the given types: MaxTextures (int) The maximum number of simultaneous textures supported by the driver. This can be less than the supported number of textures of the driver. Use _IRR_MATERIAL_MAX_TEXTURES_ to adapt the number. MaxSupportedTextures (int) The maximum number of simultaneous textures supported by the fixed function pipeline of the (hw) driver. The actual supported number of textures supported by the engine can be lower. - MaxLights (int) Number of hardware lights supported in the fixed function pipeline of the driver, typically 6-8. Use light manager or deferred shading for more. MaxAnisotropy (int) Number of anisotropy levels supported for filtering. At least 1, max is typically at 16 or 32. MaxAuxBuffers (int) Special render buffers, which are currently not really usable inside Irrlicht. Only supported by OpenGL MaxMultipleRenderTargets (int) Number of render targets which can be bound simultaneously. Rendering to MRTs is done via shaders. @@ -1110,15 +1109,6 @@ public: //! Get the graphics card vendor name. virtual core::stringc getVendorInfo() = 0; - //! Only used by the engine internally. - /** The ambient color is set in the scene manager, see - scene::ISceneManager::setAmbientLight(). - \param color New color of the ambient light. */ - virtual void setAmbientLight(const SColorf &color) = 0; - - //! Get the global ambient light currently used by the driver - virtual const SColorf &getAmbientLight() const = 0; - //! Only used by the engine internally. /** Passes the global material flag AllowZWriteOnTransparent. Use the SceneManager attribute to set this value from your app. @@ -1128,19 +1118,6 @@ public: //! Get the maximum texture size supported. virtual core::dimension2du getMaxTextureSize() const = 0; - //! Color conversion convenience function - /** Convert an image (as array of pixels) from source to destination - array, thereby converting the color format. The pixel size is - determined by the color formats. - \param sP Pointer to source - \param sF Color format of source - \param sN Number of pixels to convert, both array must be large enough - \param dP Pointer to destination - \param dF Color format of destination - */ - virtual void convertColor(const void *sP, ECOLOR_FORMAT sF, s32 sN, - void *dP, ECOLOR_FORMAT dF) const = 0; - //! Check if the driver supports creating textures with the given color format /** \return True if the format is available, false if not. */ virtual bool queryTextureFormat(ECOLOR_FORMAT format) const = 0; diff --git a/irr/src/CNullDriver.cpp b/irr/src/CNullDriver.cpp index b5da7ef29..efbad7598 100644 --- a/irr/src/CNullDriver.cpp +++ b/irr/src/CNullDriver.cpp @@ -743,19 +743,6 @@ SFrameStats CNullDriver::getFrameStats() const return FrameStats; } -//! Sets the dynamic ambient light color. The default color is -//! (0,0,0,0) which means it is dark. -//! \param color: New color of the ambient light. -void CNullDriver::setAmbientLight(const SColorf &color) -{ - AmbientLight = color; -} - -const SColorf &CNullDriver::getAmbientLight() const -{ - return AmbientLight; -} - //! \return Returns the name of the video driver. Example: In case of the DIRECT3D8 //! driver, it would return "Direct3D8". @@ -1774,21 +1761,5 @@ bool CNullDriver::needsTransparentRenderPass(const irr::video::SMaterial &materi return false; } -//! Color conversion convenience function -/** Convert an image (as array of pixels) from source to destination -array, thereby converting the color format. The pixel size is -determined by the color formats. -\param sP Pointer to source -\param sF Color format of source -\param sN Number of pixels to convert, both array must be large enough -\param dP Pointer to destination -\param dF Color format of destination -*/ -void CNullDriver::convertColor(const void *sP, ECOLOR_FORMAT sF, s32 sN, - void *dP, ECOLOR_FORMAT dF) const -{ - video::CColorConverter::convert_viaFormat(sP, sF, sN, dP, dF); -} - } // end namespace } // end namespace diff --git a/irr/src/CNullDriver.h b/irr/src/CNullDriver.h index 5752b53cd..e772dd8e8 100644 --- a/irr/src/CNullDriver.h +++ b/irr/src/CNullDriver.h @@ -201,14 +201,6 @@ public: //! driver, it would return "Direct3D8.1". const char *getName() const override; - //! Sets the dynamic ambient light color. The default color is - //! (0,0,0,0) which means it is dark. - //! \param color: New color of the ambient light. - void setAmbientLight(const SColorf &color) override; - - //! Get the global ambient light currently used by the driver - const SColorf &getAmbientLight() const override; - //! Adds an external image loader to the engine. void addExternalImageLoader(IImageLoader *loader) override; @@ -559,19 +551,6 @@ public: //! Used by some SceneNodes to check if a material should be rendered in the transparent render pass bool needsTransparentRenderPass(const irr::video::SMaterial &material) const override; - //! Color conversion convenience function - /** Convert an image (as array of pixels) from source to destination - array, thereby converting the color format. The pixel size is - determined by the color formats. - \param sP Pointer to source - \param sF Color format of source - \param sN Number of pixels to convert, both array must be large enough - \param dP Pointer to destination - \param dF Color format of destination - */ - virtual void convertColor(const void *sP, ECOLOR_FORMAT sF, s32 sN, - void *dP, ECOLOR_FORMAT dF) const override; - protected: //! deletes all textures void deleteAllTextures(); @@ -759,8 +738,6 @@ protected: bool AllowZWriteOnTransparent; bool FeatureEnabled[video::EVDF_COUNT]; - - SColorf AmbientLight; }; } // end namespace video diff --git a/irr/src/COpenGLCoreTexture.h b/irr/src/COpenGLCoreTexture.h index a37562543..d8a813d5d 100644 --- a/irr/src/COpenGLCoreTexture.h +++ b/irr/src/COpenGLCoreTexture.h @@ -170,6 +170,17 @@ public: return; } +#ifndef IRR_COMPILE_GL_COMMON + // On GLES 3.0 we must use sized internal formats for textures in certain + // cases (e.g. with ETT_2D_MS). However ECF_A8R8G8B8 is mapped to GL_BGRA + // (an unsized format). + // Since we don't upload to RTT we can safely pick a different combo that works. + if (InternalFormat == GL_BGRA && Driver->Version.Major >= 3) { + InternalFormat = GL_RGBA8; + PixelFormat = GL_RGBA; + } +#endif + #ifdef _DEBUG char lbuf[100]; snprintf_irr(lbuf, sizeof(lbuf), diff --git a/irr/src/COpenGLDriver.cpp b/irr/src/COpenGLDriver.cpp index 07d7f7bb1..f7c0be7dd 100644 --- a/irr/src/COpenGLDriver.cpp +++ b/irr/src/COpenGLDriver.cpp @@ -122,7 +122,6 @@ bool COpenGLDriver::genericDriverInit() os::Printer::log("GLSL not available.", ELL_INFORMATION); DriverAttributes->setAttribute("MaxTextures", (s32)Feature.MaxTextureUnits); DriverAttributes->setAttribute("MaxSupportedTextures", (s32)Feature.MaxTextureUnits); - DriverAttributes->setAttribute("MaxLights", MaxLights); DriverAttributes->setAttribute("MaxAnisotropy", MaxAnisotropy); DriverAttributes->setAttribute("MaxAuxBuffers", MaxAuxBuffers); DriverAttributes->setAttribute("MaxMultipleRenderTargets", (s32)Feature.MultipleRenderTarget); @@ -139,13 +138,6 @@ bool COpenGLDriver::genericDriverInit() for (i = 0; i < ETS_COUNT; ++i) setTransform(static_cast(i), core::IdentityMatrix); - setAmbientLight(SColorf(0.0f, 0.0f, 0.0f, 0.0f)); -#ifdef GL_EXT_separate_specular_color - if (FeatureAvailable[IRR_EXT_separate_specular_color]) - glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); -#endif - glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1); - // This is a fast replacement for NORMALIZE_NORMALS // if ((Version>101) || FeatureAvailable[IRR_EXT_rescale_normal]) // glEnable(GL_RESCALE_NORMAL_EXT); @@ -2420,16 +2412,6 @@ const char *COpenGLDriver::getName() const return Name.c_str(); } -//! Sets the dynamic ambient light color. The default color is -//! (0,0,0,0) which means it is dark. -//! \param color: New color of the ambient light. -void COpenGLDriver::setAmbientLight(const SColorf &color) -{ - CNullDriver::setAmbientLight(color); - GLfloat data[4] = {color.r, color.g, color.b, color.a}; - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, data); -} - // this code was sent in by Oliver Klems, thank you! (I modified the glViewport // method just a bit. void COpenGLDriver::setViewPort(const core::rect &area) diff --git a/irr/src/COpenGLDriver.h b/irr/src/COpenGLDriver.h index 126f7aadc..aa457b8ee 100644 --- a/irr/src/COpenGLDriver.h +++ b/irr/src/COpenGLDriver.h @@ -182,11 +182,6 @@ public: //! driver, it would return "Direct3D8.1". const char *getName() const override; - //! Sets the dynamic ambient light color. The default color is - //! (0,0,0,0) which means it is dark. - //! \param color: New color of the ambient light. - void setAmbientLight(const SColorf &color) override; - //! sets a viewport void setViewPort(const core::rect &area) override; diff --git a/irr/src/COpenGLExtensionHandler.cpp b/irr/src/COpenGLExtensionHandler.cpp index 4c7fe69b7..7eb4252a6 100644 --- a/irr/src/COpenGLExtensionHandler.cpp +++ b/irr/src/COpenGLExtensionHandler.cpp @@ -19,7 +19,7 @@ namespace video bool COpenGLExtensionHandler::needsDSAFramebufferHack = true; COpenGLExtensionHandler::COpenGLExtensionHandler() : - StencilBuffer(false), TextureCompressionExtension(false), MaxLights(1), + StencilBuffer(false), TextureCompressionExtension(false), MaxAnisotropy(1), MaxAuxBuffers(0), MaxIndices(65535), MaxTextureSize(1), MaxGeometryVerticesOut(0), MaxTextureLODBias(0.f), Version(0), ShaderLanguageVersion(0), @@ -399,8 +399,6 @@ void COpenGLExtensionHandler::initExtensions(video::IContextManager *cmgr, bool Feature.MaxTextureUnits = core::max_(Feature.MaxTextureUnits, static_cast(num)); } #endif - glGetIntegerv(GL_MAX_LIGHTS, &num); - MaxLights = static_cast(num); #ifdef GL_EXT_texture_filter_anisotropic if (FeatureAvailable[IRR_EXT_texture_filter_anisotropic]) { glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &num); diff --git a/irr/src/COpenGLExtensionHandler.h b/irr/src/COpenGLExtensionHandler.h index cdff911b9..a1754a328 100644 --- a/irr/src/COpenGLExtensionHandler.h +++ b/irr/src/COpenGLExtensionHandler.h @@ -1015,8 +1015,6 @@ public: bool TextureCompressionExtension; // Some non-boolean properties - //! Maximum hardware lights supported - u8 MaxLights; //! Maximal Anisotropy u8 MaxAnisotropy; //! Number of auxiliary buffers diff --git a/irr/src/CSceneManager.cpp b/irr/src/CSceneManager.cpp index d75abc284..04b3ec313 100644 --- a/irr/src/CSceneManager.cpp +++ b/irr/src/CSceneManager.cpp @@ -41,7 +41,7 @@ CSceneManager::CSceneManager(video::IVideoDriver *driver, ISceneNode(0, 0), Driver(driver), CursorControl(cursorControl), - ActiveCamera(0), ShadowColor(150, 0, 0, 0), AmbientLight(0, 0, 0, 0), Parameters(0), + ActiveCamera(0), Parameters(0), MeshCache(cache), CurrentRenderPass(ESNRP_NONE) { #ifdef _DEBUG @@ -445,9 +445,6 @@ u32 CSceneManager::registerNodeForRendering(ISceneNode *node, E_SCENE_NODE_RENDE taken = 1; } - // as of yet unused - case ESNRP_LIGHT: - case ESNRP_SHADOW: case ESNRP_NONE: // ignore this one break; } @@ -775,18 +772,6 @@ ISceneManager *CSceneManager::createNewSceneManager(bool cloneContent) return manager; } -//! Sets ambient color of the scene -void CSceneManager::setAmbientLight(const video::SColorf &ambientColor) -{ - AmbientLight = ambientColor; -} - -//! Returns ambient color of the scene -const video::SColorf &CSceneManager::getAmbientLight() const -{ - return AmbientLight; -} - //! Get a skinned mesh, which is not available as header-only code ISkinnedMesh *CSceneManager::createSkinnedMesh() { diff --git a/irr/src/CSceneManager.h b/irr/src/CSceneManager.h index 4ef6d64b0..0f1b2c716 100644 --- a/irr/src/CSceneManager.h +++ b/irr/src/CSceneManager.h @@ -170,12 +170,6 @@ public: //! Get a skinned mesh, which is not available as header-only code ISkinnedMesh *createSkinnedMesh() override; - //! Sets ambient color of the scene - void setAmbientLight(const video::SColorf &ambientColor) override; - - //! Returns ambient color of the scene - const video::SColorf &getAmbientLight() const override; - //! Get current render time. E_SCENE_NODE_RENDER_PASS getCurrentRenderPass() const override { return CurrentRenderPass; } @@ -291,9 +285,6 @@ private: ICameraSceneNode *ActiveCamera; core::vector3df camWorldPos; // Position of camera for transparent nodes. - video::SColor ShadowColor; - video::SColorf AmbientLight; - //! String parameters // NOTE: Attributes are slow and should only be used for debug-info and not in release io::CAttributes *Parameters; diff --git a/irr/src/OpenGL/Common.h b/irr/src/OpenGL/Common.h index 84b2ec3e4..75c213bb0 100644 --- a/irr/src/OpenGL/Common.h +++ b/irr/src/OpenGL/Common.h @@ -40,7 +40,7 @@ typedef COpenGLCoreTexture COpenGL3Texture; typedef COpenGLCoreRenderTarget COpenGL3RenderTarget; typedef COpenGLCoreCacheHandler COpenGL3CacheHandler; -enum class OpenGLSpec : u8 +enum OpenGLSpec : u8 { Core, Compat, diff --git a/irr/src/OpenGL/Driver.cpp b/irr/src/OpenGL/Driver.cpp index ee272ceee..da19b0bae 100644 --- a/irr/src/OpenGL/Driver.cpp +++ b/irr/src/OpenGL/Driver.cpp @@ -27,37 +27,32 @@ namespace irr { namespace video { + struct VertexAttribute { - enum class Mode + enum Mode : u8 { Regular, Normalized, - Integral, + Integer, }; - int Index; - int ComponentCount; + u8 Index; + u8 ComponentCount; GLenum ComponentType; Mode mode; - int Offset; + u32 Offset; }; struct VertexType { - int VertexSize; + u32 VertexSize; std::vector Attributes; + + // allow ranged for loops + inline auto begin() const { return Attributes.begin(); } + inline auto end() const { return Attributes.end(); } }; -static const VertexAttribute *begin(const VertexType &type) -{ - return type.Attributes.data(); -} - -static const VertexAttribute *end(const VertexType &type) -{ - return type.Attributes.data() + type.Attributes.size(); -} - static const VertexType vtStandard = { sizeof(S3DVertex), { @@ -68,6 +63,9 @@ static const VertexType vtStandard = { }, }; +// FIXME: this is actually UB because these vertex classes are not "standard-layout" +// they violate the following requirement: +// - only one class in the hierarchy has non-static data members #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Winvalid-offsetof" @@ -170,11 +168,15 @@ COpenGL3DriverBase::COpenGL3DriverBase(const SIrrlichtCreationParameters ¶ms ExposedData = ContextManager->getContext(); ContextManager->activateContext(ExposedData, false); GL.LoadAllProcedures(ContextManager); - if (EnableErrorTest) { + if (EnableErrorTest && GL.IsExtensionPresent("GL_KHR_debug")) { GL.Enable(GL_DEBUG_OUTPUT); GL.DebugMessageCallback(debugCb, this); + } else if (EnableErrorTest) { + os::Printer::log("GL debug extension not available"); } initQuadsIndices(); + + TEST_GL_ERROR(this); } COpenGL3DriverBase::~COpenGL3DriverBase() @@ -267,7 +269,6 @@ bool COpenGL3DriverBase::genericDriverInit(const core::dimension2d &screenS for (s32 i = 0; i < ETS_COUNT; ++i) setTransform(static_cast(i), core::IdentityMatrix); - setAmbientLight(SColorf(0.0f, 0.0f, 0.0f, 0.0f)); GL.ClearDepthf(1.0f); GL.Hint(GL_GENERATE_MIPMAP_HINT, GL_NICEST); @@ -760,6 +761,13 @@ void COpenGL3DriverBase::drawVertexPrimitiveList(const void *vertices, u32 verte endDraw(vTypeDesc); } +void COpenGL3DriverBase::draw2DVertexPrimitiveList(const void *vertices, u32 vertexCount, + const void *indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) +{ + os::Printer::log("draw2DVertexPrimitiveList unimplemented", ELL_ERROR); +} + void COpenGL3DriverBase::draw2DImage(const video::ITexture *texture, const core::position2d &destPos, const core::rect &sourceRect, const core::rect *clipRect, SColor color, bool useAlphaChannelOfTexture) @@ -1066,7 +1074,7 @@ void COpenGL3DriverBase::drawElements(GLenum primitiveType, const VertexType &ve void COpenGL3DriverBase::beginDraw(const VertexType &vertexType, uintptr_t verticesBase) { - for (auto attr : vertexType) { + for (auto &attr : vertexType) { GL.EnableVertexAttribArray(attr.Index); switch (attr.mode) { case VertexAttribute::Mode::Regular: @@ -1075,7 +1083,7 @@ void COpenGL3DriverBase::beginDraw(const VertexType &vertexType, uintptr_t verti case VertexAttribute::Mode::Normalized: GL.VertexAttribPointer(attr.Index, attr.ComponentCount, attr.ComponentType, GL_TRUE, vertexType.VertexSize, reinterpret_cast(verticesBase + attr.Offset)); break; - case VertexAttribute::Mode::Integral: + case VertexAttribute::Mode::Integer: GL.VertexAttribIPointer(attr.Index, attr.ComponentCount, attr.ComponentType, vertexType.VertexSize, reinterpret_cast(verticesBase + attr.Offset)); break; } @@ -1084,7 +1092,7 @@ void COpenGL3DriverBase::beginDraw(const VertexType &vertexType, uintptr_t verti void COpenGL3DriverBase::endDraw(const VertexType &vertexType) { - for (auto attr : vertexType) + for (auto &attr : vertexType) GL.DisableVertexAttribArray(attr.Index); } diff --git a/irr/src/OpenGL/Driver.h b/irr/src/OpenGL/Driver.h index f00ffa8af..e0787e560 100644 --- a/irr/src/OpenGL/Driver.h +++ b/irr/src/OpenGL/Driver.h @@ -81,6 +81,11 @@ public: const void *indexList, u32 primitiveCount, E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) override; + //! draws a vertex primitive list in 2d + virtual void draw2DVertexPrimitiveList(const void *vertices, u32 vertexCount, + const void *indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) override; + //! queries the features of the driver, returns true if feature is available bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const override { diff --git a/irr/src/OpenGLES2/Driver.cpp b/irr/src/OpenGLES2/Driver.cpp index 32bf0aee0..7b84675aa 100644 --- a/irr/src/OpenGLES2/Driver.cpp +++ b/irr/src/OpenGLES2/Driver.cpp @@ -43,8 +43,6 @@ void COpenGLES2Driver::initFeatures() } initExtensions(); - static const GLenum BGRA8_EXT = 0x93A1; - if (Version.Major >= 3) { // NOTE floating-point formats may not be suitable for render targets. TextureFormats[ECF_A1R5G5B5] = {GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, CColorConverter::convert_A1R5G5B5toR5G5B5A1}; @@ -64,10 +62,11 @@ void COpenGLES2Driver::initFeatures() TextureFormats[ECF_D24] = {GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT}; TextureFormats[ECF_D24S8] = {GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8}; - if (FeatureAvailable[IRR_GL_EXT_texture_format_BGRA8888]) + // NOTE a recent (2024) revision of EXT_texture_format_BGRA8888 also + // adds a sized format GL_BGRA8_EXT. We have a workaround in place to + // fix up the InternalFormat in case of render targets. + if (FeatureAvailable[IRR_GL_EXT_texture_format_BGRA8888] || FeatureAvailable[IRR_GL_APPLE_texture_format_BGRA8888]) TextureFormats[ECF_A8R8G8B8] = {GL_BGRA, GL_BGRA, GL_UNSIGNED_BYTE}; - else if (FeatureAvailable[IRR_GL_APPLE_texture_format_BGRA8888]) - TextureFormats[ECF_A8R8G8B8] = {BGRA8_EXT, GL_BGRA, GL_UNSIGNED_BYTE}; // OpenGL ES 3 doesn't include a GL_DEPTH_COMPONENT32, so still use // OES_depth_texture for 32-bit depth texture support. @@ -87,10 +86,8 @@ void COpenGLES2Driver::initFeatures() TextureFormats[ECF_R8G8B8] = {GL_RGB, GL_RGB, GL_UNSIGNED_BYTE}; TextureFormats[ECF_A8R8G8B8] = {GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, CColorConverter::convert_A8R8G8B8toA8B8G8R8}; - if (FeatureAvailable[IRR_GL_EXT_texture_format_BGRA8888]) + if (FeatureAvailable[IRR_GL_EXT_texture_format_BGRA8888] || FeatureAvailable[IRR_GL_APPLE_texture_format_BGRA8888]) TextureFormats[ECF_A8R8G8B8] = {GL_BGRA, GL_BGRA, GL_UNSIGNED_BYTE}; - else if (FeatureAvailable[IRR_GL_APPLE_texture_format_BGRA8888]) - TextureFormats[ECF_A8R8G8B8] = {BGRA8_EXT, GL_BGRA, GL_UNSIGNED_BYTE}; if (FeatureAvailable[IRR_GL_OES_texture_half_float]) { TextureFormats[ECF_A16B16G16R16F] = {GL_RGBA, GL_RGBA, HALF_FLOAT_OES}; diff --git a/src/client/render/anaglyph.cpp b/src/client/render/anaglyph.cpp index fe3a5f0f8..7baf40322 100644 --- a/src/client/render/anaglyph.cpp +++ b/src/client/render/anaglyph.cpp @@ -21,8 +21,7 @@ void SetColorMaskStep::run(PipelineContext &context) mat.Material.ColorMask = color_mask; mat.EnableProps = video::EMP_COLOR_MASK; mat.EnablePasses = scene::ESNRP_SKY_BOX | scene::ESNRP_SOLID | - scene::ESNRP_TRANSPARENT | scene::ESNRP_TRANSPARENT_EFFECT | - scene::ESNRP_SHADOW; + scene::ESNRP_TRANSPARENT | scene::ESNRP_TRANSPARENT_EFFECT; } /// ClearDepthBufferTarget From a799a54894c5913a57d7004366044f8c640a8c8c Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 24 Nov 2024 18:00:25 +0100 Subject: [PATCH 098/136] Fix some issues with mt_opengl --- irr/include/mt_opengl.h | 20 +++++++++++----- irr/scripts/BindingGenerator.lua | 39 +++++++++++++++++++++----------- irr/src/mt_opengl_loader.cpp | 11 +++++---- 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/irr/include/mt_opengl.h b/irr/include/mt_opengl.h index f69ba8c69..1a92cde56 100755 --- a/irr/include/mt_opengl.h +++ b/irr/include/mt_opengl.h @@ -15,11 +15,18 @@ #ifndef APIENTRYP #define APIENTRYP APIENTRY * #endif -#ifndef GLAPI - #define GLAPI extern +// undefine a few names that can easily clash with system headers +#ifdef NO_ERROR +#undef NO_ERROR +#endif +#ifdef ZERO +#undef ZERO +#endif +#ifdef ONE +#undef ONE #endif -class OpenGLProcedures { +class OpenGLProcedures final { private: // ./glcorearb.h typedef void GLvoid; @@ -49,8 +56,6 @@ private: typedef khronos_int64_t GLint64EXT; typedef void *GLeglClientBufferEXT; - // The script will miss this particular typedef thinking it's a PFN, - // so we have to paste it in manually. It's the only such type in OpenGL. typedef void (APIENTRY *GLDEBUGPROC) (GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); @@ -775,10 +780,12 @@ private: typedef void (APIENTRYP PFNGLTEXPAGECOMMITMENTPROC_MT) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLboolean commit); std::unordered_set extensions; + public: // Call this once after creating the context. void LoadAllProcedures(irr::video::IContextManager *cmgr); - // Check if an extension is supported. + /// Check if an extension is supported. + /// @param ext full extension name e.g. "GL_KHR_no_error" inline bool IsExtensionPresent(const std::string &ext) const { return extensions.count(ext) > 0; @@ -3185,6 +3192,7 @@ public: static constexpr const GLenum STATE_RESTORE = 0x8BDC; static constexpr const GLenum SHADER_BINARY_VIV = 0x8FC4; + static constexpr const GLenum NO_ERROR = 0; static constexpr const GLenum ZERO = 0; static constexpr const GLenum ONE = 1; static constexpr const GLenum NONE = 0; diff --git a/irr/scripts/BindingGenerator.lua b/irr/scripts/BindingGenerator.lua index d0be04293..1ca5b41d9 100755 --- a/irr/scripts/BindingGenerator.lua +++ b/irr/scripts/BindingGenerator.lua @@ -219,11 +219,11 @@ local function ParseHeader( path, into, apiRegex, defs, consts, nameSet, noNewNa }; end elseif ( line:find( "#" ) and not line:find( "#include" ) ) then - local rawName, value = line:match( "#define%s+GL_([_%w]+)%s+0x(%w+)" ); + local rawName, value = line:match( "#define%s+GL_([_%w]+)%s+(0x%w+)" ); if rawName and value then local name, vendor = StripVendorSuffix( rawName, true ); if not constBanned[vendor] then - consts:Add{ name = name, vendor = vendor, value = "0x"..value }; + consts:Add{ name = name, vendor = vendor, value = value }; end end ::skip:: @@ -359,21 +359,28 @@ f:write[[ #ifndef APIENTRYP #define APIENTRYP APIENTRY * #endif -#ifndef GLAPI - #define GLAPI extern +// undefine a few names that can easily clash with system headers +#ifdef NO_ERROR +#undef NO_ERROR +#endif +#ifdef ZERO +#undef ZERO +#endif +#ifdef ONE +#undef ONE #endif ]]; f:write[[ -class OpenGLProcedures { +class OpenGLProcedures final { private: ]]; f:write( definitions:Concat( "\n" ) ); f:write( "\n" ); +-- The script will miss this particular typedef thinking it's a PFN, +-- so we have to paste it in manually. It's the only such type in OpenGL. f:write[[ - // The script will miss this particular typedef thinking it's a PFN, - // so we have to paste it in manually. It's the only such type in OpenGL. typedef void (APIENTRY *GLDEBUGPROC) (GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); @@ -382,10 +389,12 @@ f:write( typedefs:Concat( "\n" ) ); f:write( "\n\n" ); f:write [[ std::unordered_set extensions; + public: // Call this once after creating the context. void LoadAllProcedures(irr::video::IContextManager *cmgr); - // Check if an extension is supported. + /// Check if an extension is supported. + /// @param ext full extension name e.g. "GL_KHR_no_error" inline bool IsExtensionPresent(const std::string &ext) const { return extensions.count(ext) > 0; @@ -396,7 +405,10 @@ f:write( pointers:Concat( "\n" ) ); f:write( "\n\n" ); f:write( cppConsts:Concat( "\n" ) ); f:write( "\n\n" ); +-- We filter constants not in hex format to avoid the VERSION_X_X and extension +-- defines, but that means we miss these. f:write[[ + static constexpr const GLenum NO_ERROR = 0; static constexpr const GLenum ZERO = 0; static constexpr const GLenum ONE = 1; static constexpr const GLenum NONE = 0; @@ -416,7 +428,7 @@ f:write[[ #include #include -OpenGLProcedures GL = OpenGLProcedures(); +OpenGLProcedures GL; void OpenGLProcedures::LoadAllProcedures(irr::video::IContextManager *cmgr) { @@ -425,9 +437,11 @@ void OpenGLProcedures::LoadAllProcedures(irr::video::IContextManager *cmgr) f:write( loader:Concat() ); f:write[[ - // OpenGL 3 way to enumerate extensions + /* OpenGL 3 & ES 3 way to enumerate extensions */ GLint ext_count = 0; GetIntegerv(NUM_EXTENSIONS, &ext_count); + // clear error which is raised if unsupported + while (GetError() != GL.NO_ERROR) {} extensions.reserve(ext_count); for (GLint k = 0; k < ext_count; k++) { auto tmp = GetStringi(EXTENSIONS, k); @@ -437,16 +451,15 @@ f:write[[ if (!extensions.empty()) return; - // OpenGL 2 / ES 2 way to enumerate extensions + /* OpenGL 2 / ES 2 way to enumerate extensions */ auto ext_str = GetString(EXTENSIONS); if (!ext_str) return; // get the extension string, chop it up - std::stringstream ext_ss((char*)ext_str); + std::istringstream ext_ss((char*)ext_str); std::string tmp; while (std::getline(ext_ss, tmp, ' ')) extensions.emplace(tmp); - } ]]; f:close(); diff --git a/irr/src/mt_opengl_loader.cpp b/irr/src/mt_opengl_loader.cpp index 084f83118..2b7184036 100755 --- a/irr/src/mt_opengl_loader.cpp +++ b/irr/src/mt_opengl_loader.cpp @@ -5,7 +5,7 @@ #include #include -OpenGLProcedures GL = OpenGLProcedures(); +OpenGLProcedures GL; void OpenGLProcedures::LoadAllProcedures(irr::video::IContextManager *cmgr) { @@ -758,9 +758,11 @@ void OpenGLProcedures::LoadAllProcedures(irr::video::IContextManager *cmgr) if (!NamedBufferPageCommitment) NamedBufferPageCommitment = (PFNGLNAMEDBUFFERPAGECOMMITMENTPROC_MT)cmgr->getProcAddress("glNamedBufferPageCommitmentARB"); if (!TexPageCommitment) TexPageCommitment = (PFNGLTEXPAGECOMMITMENTPROC_MT)cmgr->getProcAddress("glTexPageCommitmentARB"); - // OpenGL 3 way to enumerate extensions + /* OpenGL 3 & ES 3 way to enumerate extensions */ GLint ext_count = 0; GetIntegerv(NUM_EXTENSIONS, &ext_count); + // clear error which is raised if unsupported + while (GetError() != GL.NO_ERROR) {} extensions.reserve(ext_count); for (GLint k = 0; k < ext_count; k++) { auto tmp = GetStringi(EXTENSIONS, k); @@ -770,14 +772,13 @@ void OpenGLProcedures::LoadAllProcedures(irr::video::IContextManager *cmgr) if (!extensions.empty()) return; - // OpenGL 2 / ES 2 way to enumerate extensions + /* OpenGL 2 / ES 2 way to enumerate extensions */ auto ext_str = GetString(EXTENSIONS); if (!ext_str) return; // get the extension string, chop it up - std::stringstream ext_ss((char*)ext_str); + std::istringstream ext_ss((char*)ext_str); std::string tmp; while (std::getline(ext_ss, tmp, ' ')) extensions.emplace(tmp); - } From 810f39767cf4780cb050b409d660eed3ead17c81 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Mon, 25 Nov 2024 21:56:12 +0100 Subject: [PATCH 099/136] Move SMaterial std::hash impl to its header --- irr/include/SMaterial.h | 29 +++++++++++++++++++------ irr/src/CSceneManager.cpp | 4 +--- irr/src/CSceneManager.h | 45 ++++++++------------------------------- src/client/clientmap.cpp | 13 ++--------- 4 files changed, 35 insertions(+), 56 deletions(-) diff --git a/irr/include/SMaterial.h b/irr/include/SMaterial.h index 7a939317c..867557154 100644 --- a/irr/include/SMaterial.h +++ b/irr/include/SMaterial.h @@ -230,14 +230,14 @@ const c8 *const ZWriteNames[] = { /** SMaterial might ignore some textures in most function, like assignment and comparison, when SIrrlichtCreationParameters::MaxTextureUnits is set to a lower number. */ -const u32 MATERIAL_MAX_TEXTURES = 4; +constexpr static u32 MATERIAL_MAX_TEXTURES = 4; //! Struct for holding parameters for a material renderer // Note for implementors: Serialization is in CNullDriver class SMaterial { public: - //! Default constructor. Creates a solid, lit material with white colors + //! Default constructor. Creates a solid material SMaterial() : MaterialType(EMT_SOLID), ColorParam(0, 0, 0, 0), MaterialTypeParam(0.0f), Thickness(1.0f), ZBuffer(ECFN_LESSEQUAL), @@ -257,7 +257,7 @@ public: E_MATERIAL_TYPE MaterialType; //! Custom color parameter, can be used by custom shader materials. - // See MainShaderConstantSetter in Minetest. + // See MainShaderConstantSetter in Luanti. SColor ColorParam; //! Free parameter, dependent on the material type. @@ -427,10 +427,13 @@ public: PolygonOffsetDepthBias != b.PolygonOffsetDepthBias || PolygonOffsetSlopeScale != b.PolygonOffsetSlopeScale || UseMipMaps != b.UseMipMaps; - for (u32 i = 0; (i < MATERIAL_MAX_TEXTURES) && !different; ++i) { - different |= (TextureLayers[i] != b.TextureLayers[i]); + if (different) + return true; + for (u32 i = 0; i < MATERIAL_MAX_TEXTURES; ++i) { + if (TextureLayers[i] != b.TextureLayers[i]) + return true; } - return different; + return false; } //! Equality operator @@ -477,5 +480,19 @@ public: //! global const identity Material IRRLICHT_API extern SMaterial IdentityMaterial; + } // end namespace video } // end namespace irr + +template<> +struct std::hash +{ + /// @brief std::hash specialization for video::SMaterial + std::size_t operator()(const irr::video::SMaterial &m) const noexcept + { + // basic implementation that hashes the two things most likely to differ + auto h1 = std::hash{}(m.getTexture(0)); + auto h2 = std::hash{}(m.MaterialType); + return (h1 << 1) ^ h2; + } +}; diff --git a/irr/src/CSceneManager.cpp b/irr/src/CSceneManager.cpp index 04b3ec313..71ae7f962 100644 --- a/irr/src/CSceneManager.cpp +++ b/irr/src/CSceneManager.cpp @@ -469,14 +469,12 @@ void CSceneManager::drawAll() if (!Driver) return; - u32 i; // new ISO for scoping problem in some compilers - // reset all transforms Driver->setMaterial(video::SMaterial()); Driver->setTransform(video::ETS_PROJECTION, core::IdentityMatrix); Driver->setTransform(video::ETS_VIEW, core::IdentityMatrix); Driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); - for (i = video::ETS_COUNT - 1; i >= video::ETS_TEXTURE_0; --i) + for (u32 i = video::ETS_COUNT - 1; i >= video::ETS_TEXTURE_0; --i) Driver->setTransform((video::E_TRANSFORMATION_STATE)i, core::IdentityMatrix); // TODO: This should not use an attribute here but a real parameter when necessary (too slow!) Driver->setAllowZWriteOnTransparent(Parameters->getAttributeAsBool(ALLOW_ZWRITE_ON_TRANSPARENT)); diff --git a/irr/src/CSceneManager.h b/irr/src/CSceneManager.h index 0f1b2c716..4362ba04d 100644 --- a/irr/src/CSceneManager.h +++ b/irr/src/CSceneManager.h @@ -193,21 +193,21 @@ private: } DefaultNodeEntry(ISceneNode *n) : - Node(n), TextureValue(0) + Node(n) { if (n->getMaterialCount()) - TextureValue = (n->getMaterial(0).getTexture(0)); + Hash = std::hash{}(n->getMaterial(0)); } - bool operator<(const DefaultNodeEntry &other) const + bool operator<(const DefaultNodeEntry &other) const noexcept { - return (TextureValue < other.TextureValue); + return Hash < other.Hash; } - ISceneNode *Node; + ISceneNode *Node = nullptr; private: - void *TextureValue; + size_t Hash = 0; }; //! sort on distance (center) to camera @@ -223,42 +223,15 @@ private: Distance = Node->getAbsoluteTransformation().getTranslation().getDistanceFromSQ(camera); } - bool operator<(const TransparentNodeEntry &other) const + bool operator<(const TransparentNodeEntry &other) const noexcept { return Distance > other.Distance; } - ISceneNode *Node; + ISceneNode *Node = nullptr; private: - f64 Distance; - }; - - //! sort on distance (sphere) to camera - struct DistanceNodeEntry - { - DistanceNodeEntry(ISceneNode *n, const core::vector3df &cameraPos) : - Node(n) - { - setNodeAndDistanceFromPosition(n, cameraPos); - } - - bool operator<(const DistanceNodeEntry &other) const - { - return Distance < other.Distance; - } - - void setNodeAndDistanceFromPosition(ISceneNode *n, const core::vector3df &fromPosition) - { - Node = n; - Distance = Node->getAbsoluteTransformation().getTranslation().getDistanceFromSQ(fromPosition); - Distance -= Node->getBoundingBox().getExtent().getLengthSQ() * 0.5; - } - - ISceneNode *Node; - - private: - f64 Distance; + f32 Distance = 0; }; //! video driver diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index c3207efd1..f57a04b60 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -25,19 +25,10 @@ namespace { // A helper struct struct MeshBufListMaps { - struct MaterialHash - { - size_t operator()(const video::SMaterial &m) const noexcept - { - // Only hash first texture. Simple and fast. - return std::hash{}(m.TextureLayers[0].Texture); - } - }; - using MeshBufListMap = std::unordered_map< video::SMaterial, - std::vector>, - MaterialHash>; + std::vector> + >; std::array maps; From 3e10d9ccf5c5dc20d1ceb0e696ce543f3618e56e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Fri, 6 Dec 2024 18:03:44 +0100 Subject: [PATCH 100/136] Refactor: Merge `[IC]SkinnedMesh` into `SkinnedMesh` (#15511) --- irr/include/IBoneSceneNode.h | 2 +- irr/include/ISceneManager.h | 187 +------------- irr/include/ISkinnedMesh.h | 226 ---------------- .../CSkinnedMesh.h => include/SkinnedMesh.h} | 242 +++++++++++++----- irr/src/CAnimatedMeshSceneNode.cpp | 18 +- irr/src/CB3DMeshFileLoader.cpp | 24 +- irr/src/CB3DMeshFileLoader.h | 14 +- irr/src/CGLTFMeshFileLoader.cpp | 20 +- irr/src/CGLTFMeshFileLoader.h | 14 +- irr/src/CMakeLists.txt | 2 +- irr/src/CMeshManipulator.cpp | 6 +- irr/src/CMeshSceneNode.cpp | 4 +- irr/src/CSceneManager.cpp | 6 +- irr/src/CSceneManager.h | 7 +- irr/src/CXMeshFileLoader.cpp | 36 +-- irr/src/CXMeshFileLoader.h | 10 +- irr/src/{CSkinnedMesh.cpp => SkinnedMesh.cpp} | 144 +++++------ src/unittest/test_irr_gltf_mesh_loader.cpp | 10 +- 18 files changed, 326 insertions(+), 646 deletions(-) delete mode 100644 irr/include/ISkinnedMesh.h rename irr/{src/CSkinnedMesh.h => include/SkinnedMesh.h} (57%) rename irr/src/{CSkinnedMesh.cpp => SkinnedMesh.cpp} (89%) diff --git a/irr/include/IBoneSceneNode.h b/irr/include/IBoneSceneNode.h index 668289271..eef55f6e0 100644 --- a/irr/include/IBoneSceneNode.h +++ b/irr/include/IBoneSceneNode.h @@ -48,7 +48,7 @@ const c8 *const BoneAnimationModeNames[] = { }; //! Interface for bones used for skeletal animation. -/** Used with ISkinnedMesh and IAnimatedMeshSceneNode. */ +/** Used with SkinnedMesh and IAnimatedMeshSceneNode. */ class IBoneSceneNode : public ISceneNode { public: diff --git a/irr/include/ISceneManager.h b/irr/include/ISceneManager.h index 7fbc0670c..25e1e5fe4 100644 --- a/irr/include/ISceneManager.h +++ b/irr/include/ISceneManager.h @@ -11,7 +11,6 @@ #include "SColor.h" #include "ESceneNodeTypes.h" #include "SceneParameters.h" // IWYU pragma: export -#include "ISkinnedMesh.h" namespace irr { @@ -93,6 +92,7 @@ class IBillboardSceneNode; class ICameraSceneNode; class IDummyTransformationSceneNode; class IMesh; +class SkinnedMesh; class IMeshBuffer; class IMeshCache; class ISceneCollisionManager; @@ -121,189 +121,6 @@ public: //! Get pointer to an animatable mesh. Loads the file if not loaded already. /** * If you want to remove a loaded mesh from the cache again, use removeMesh(). - * Currently there are the following mesh formats supported: - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
FormatDescription
3D Studio (.3ds)Loader for 3D-Studio files which lots of 3D packages - * are able to export. Only static meshes are currently - * supported by this importer.
3D World Studio (.smf)Loader for Leadwerks SMF mesh files, a simple mesh format - * containing static geometry for games. The proprietary .STF texture format - * is not supported yet. This loader was originally written by Joseph Ellis.
Bliz Basic B3D (.b3d)Loader for blitz basic files, developed by Mark - * Sibly. This is the ideal animated mesh format for game - * characters as it is both rigidly defined and widely - * supported by modeling and animation software. - * As this format supports skeletal animations, an - * ISkinnedMesh will be returned by this importer.
Cartography shop 4 (.csm)Cartography Shop is a modeling program for creating - * architecture and calculating lighting. Irrlicht can - * directly import .csm files thanks to the IrrCSM library - * created by Saurav Mohapatra which is now integrated - * directly in Irrlicht. - *
Delgine DeleD (.dmf)DeleD (delgine.com) is a 3D editor and level-editor - * combined into one and is specifically designed for 3D - * game-development. With this loader, it is possible to - * directly load all geometry is as well as textures and - * lightmaps from .dmf files. To set texture and - * material paths, see scene::DMF_USE_MATERIALS_DIRS. - * It is also possible to flip the alpha texture by setting - * scene::DMF_FLIP_ALPHA_TEXTURES to true and to set the - * material transparent reference value by setting - * scene::DMF_ALPHA_CHANNEL_REF to a float between 0 and - * 1. The loader is based on Salvatore Russo's .dmf - * loader, I just changed some parts of it. Thanks to - * Salvatore for his work and for allowing me to use his - * code in Irrlicht and put it under Irrlicht's license. - * For newer and more enhanced versions of the loader, - * take a look at delgine.com. - *
DirectX (.x)Platform independent importer (so not D3D-only) for - * .x files. Most 3D packages can export these natively - * and there are several tools for them available, e.g. - * the Maya exporter included in the DX SDK. - * .x files can include skeletal animations and Irrlicht - * is able to play and display them, users can manipulate - * the joints via the ISkinnedMesh interface. Currently, - * Irrlicht only supports uncompressed .x files.
Half-Life model (.mdl)This loader opens Half-life 1 models, it was contributed - * by Fabio Concas and adapted by Thomas Alten.
LightWave (.lwo)Native to NewTek's LightWave 3D, the LWO format is well - * known and supported by many exporters. This loader will - * import LWO2 models including lightmaps, bumpmaps and - * reflection textures.
Maya (.obj)Most 3D software can create .obj files which contain - * static geometry without material data. The material - * files .mtl are also supported. This importer for - * Irrlicht can load them directly.
Milkshape (.ms3d).MS3D files contain models and sometimes skeletal - * animations from the Milkshape 3D modeling and animation - * software. Like the other skeletal mesh loaders, joints - * are exposed via the ISkinnedMesh animated mesh type.
My3D (.my3d).my3D is a flexible 3D file format. The My3DTools - * contains plug-ins to export .my3D files from several - * 3D packages. With this built-in importer, Irrlicht - * can read and display those files directly. This - * loader was written by Zhuck Dimitry who also created - * the whole My3DTools package. - *
OCT (.oct)The oct file format contains 3D geometry and - * lightmaps and can be loaded directly by Irrlicht. OCT - * files
can be created by FSRad, Paul Nette's - * radiosity processor or exported from Blender using - * OCTTools which can be found in the exporters/OCTTools - * directory of the SDK. Thanks to Murphy McCauley for - * creating all this.
OGRE Meshes (.mesh)Ogre .mesh files contain 3D data for the OGRE 3D - * engine. Irrlicht can read and display them directly - * with this importer. To define materials for the mesh, - * copy a .material file named like the corresponding - * .mesh file where the .mesh file is. (For example - * ogrehead.material for ogrehead.mesh). Thanks to - * Christian Stehno who wrote and contributed this - * loader.
Pulsar LMTools (.lmts)LMTools is a set of tools (Windows & Linux) for - * creating lightmaps. Irrlicht can directly read .lmts - * files thanks to
the importer created by Jonas - * Petersen. - * Notes for
this version of the loader:
- * - It does not recognize/support user data in the - * *.lmts files.
- * - The TGAs generated by LMTools don't work in - * Irrlicht for some reason (the textures are upside - * down). Opening and resaving them in a graphics app - * will solve the problem.
Quake 3 levels (.bsp)Quake 3 is a popular game by IDSoftware, and .pk3 - * files contain .bsp files and textures/lightmaps - * describing huge prelighted levels. Irrlicht can read - * .pk3 and .bsp files directly and thus render Quake 3 - * levels directly. Written by Nikolaus Gebhardt - * enhanced by Dean P. Macri with the curved surfaces - * feature.
Quake 2 models (.md2)Quake 2 models are characters with morph target - * animation. Irrlicht can read, display and animate - * them directly with this importer.
Quake 3 models (.md3)Quake 3 models are characters with morph target - * animation, they contain mount points for weapons and body - * parts and are typically made of several sections which are - * manually joined together.
Stanford Triangle (.ply)Invented by Stanford University and known as the native - * format of the infamous "Stanford Bunny" model, this is a - * popular static mesh format used by 3D scanning hardware - * and software. This loader supports extremely large models - * in both ASCII and binary format, but only has rudimentary - * material support in the form of vertex colors and texture - * coordinates.
Stereolithography (.stl)The STL format is used for rapid prototyping and - * computer-aided manufacturing, thus has no support for - * materials.
- * - * To load and display a mesh quickly, just do this: - * \code - * SceneManager->addAnimatedMeshSceneNode( - * SceneManager->getMesh("yourmesh.3ds")); - * \endcode * If you would like to implement and add your own file format loader to Irrlicht, * see addExternalMeshLoader(). * \param file File handle of the mesh to load. @@ -594,7 +411,7 @@ public: //! Get a skinned mesh, which is not available as header-only code /** Note: You need to drop() the pointer after use again, see IReferenceCounted::drop() for details. */ - virtual ISkinnedMesh *createSkinnedMesh() = 0; + virtual SkinnedMesh *createSkinnedMesh() = 0; //! Get current render pass. virtual E_SCENE_NODE_RENDER_PASS getCurrentRenderPass() const = 0; diff --git a/irr/include/ISkinnedMesh.h b/irr/include/ISkinnedMesh.h deleted file mode 100644 index af241f55d..000000000 --- a/irr/include/ISkinnedMesh.h +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright (C) 2002-2012 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#pragma once - -#include "irrArray.h" -#include "IAnimatedMesh.h" -#include "SSkinMeshBuffer.h" -#include "quaternion.h" - -#include -#include - -namespace irr -{ -namespace scene -{ - -enum E_INTERPOLATION_MODE -{ - // constant does use the current key-values without interpolation - EIM_CONSTANT = 0, - - // linear interpolation - EIM_LINEAR, - - //! count of all available interpolation modes - EIM_COUNT -}; - -//! Interface for using some special functions of Skinned meshes -class ISkinnedMesh : public IAnimatedMesh -{ -public: - //! Gets joint count. - /** \return Amount of joints in the skeletal animated mesh. */ - virtual u32 getJointCount() const = 0; - - //! Gets the name of a joint. - /** \param number: Zero based index of joint. The last joint - has the number getJointCount()-1; - \return Name of joint and null if an error happened. */ - virtual const std::optional &getJointName(u32 number) const = 0; - - //! Gets a joint number from its name - /** \param name: Name of the joint. - \return Number of the joint or std::nullopt if not found. */ - virtual std::optional getJointNumber(const std::string &name) const = 0; - - //! Use animation from another mesh - /** The animation is linked (not copied) based on joint names - so make sure they are unique. - \return True if all joints in this mesh were - matched up (empty names will not be matched, and it's case - sensitive). Unmatched joints will not be animated. */ - virtual bool useAnimationFrom(const ISkinnedMesh *mesh) = 0; - - //! Update Normals when Animating - /** \param on If false don't animate, which is faster. - Else update normals, which allows for proper lighting of - animated meshes. */ - virtual void updateNormalsWhenAnimating(bool on) = 0; - - //! Sets Interpolation Mode - virtual void setInterpolationMode(E_INTERPOLATION_MODE mode) = 0; - - //! Animates this mesh's joints based on frame input - virtual void animateMesh(f32 frame, f32 blend) = 0; - - //! Preforms a software skin on this mesh based of joint positions - virtual void skinMesh() = 0; - - //! converts the vertex type of all meshbuffers to tangents. - /** E.g. used for bump mapping. */ - virtual void convertMeshToTangents() = 0; - - //! Allows to enable hardware skinning. - /* This feature is not implemented in Irrlicht yet */ - virtual bool setHardwareSkinning(bool on) = 0; - - //! Refreshes vertex data cached in joints such as positions and normals - virtual void refreshJointCache() = 0; - - //! Moves the mesh into static position. - virtual void resetAnimation() = 0; - - //! A vertex weight - struct SWeight - { - //! Index of the mesh buffer - u16 buffer_id; // I doubt 32bits is needed - - //! Index of the vertex - u32 vertex_id; // Store global ID here - - //! Weight Strength/Percentage (0-1) - f32 strength; - - private: - //! Internal members used by CSkinnedMesh - friend class CSkinnedMesh; - char *Moved; - core::vector3df StaticPos; - core::vector3df StaticNormal; - }; - - //! Animation keyframe which describes a new position - struct SPositionKey - { - f32 frame; - core::vector3df position; - }; - - //! Animation keyframe which describes a new scale - struct SScaleKey - { - f32 frame; - core::vector3df scale; - }; - - //! Animation keyframe which describes a new rotation - struct SRotationKey - { - f32 frame; - core::quaternion rotation; - }; - - //! Joints - struct SJoint - { - SJoint() : - UseAnimationFrom(0), GlobalSkinningSpace(false), - positionHint(-1), scaleHint(-1), rotationHint(-1) - { - } - - //! The name of this joint - std::optional Name; - - //! Local matrix of this joint - core::matrix4 LocalMatrix; - - //! List of child joints - core::array Children; - - //! List of attached meshes - core::array AttachedMeshes; - - //! Animation keys causing translation change - core::array PositionKeys; - - //! Animation keys causing scale change - core::array ScaleKeys; - - //! Animation keys causing rotation change - core::array RotationKeys; - - //! Skin weights - core::array Weights; - - //! Unnecessary for loaders, will be overwritten on finalize - core::matrix4 GlobalMatrix; // loaders may still choose to set this (temporarily) to calculate absolute vertex data. - core::matrix4 GlobalAnimatedMatrix; - core::matrix4 LocalAnimatedMatrix; - - //! These should be set by loaders. - core::vector3df Animatedposition; - core::vector3df Animatedscale; - core::quaternion Animatedrotation; - - // The .x and .gltf formats pre-calculate this - std::optional GlobalInversedMatrix; - private: - //! Internal members used by CSkinnedMesh - friend class CSkinnedMesh; - - SJoint *UseAnimationFrom; - bool GlobalSkinningSpace; - - s32 positionHint; - s32 scaleHint; - s32 rotationHint; - }; - - // Interface for the mesh loaders (finalize should lock these functions, and they should have some prefix like loader_ - - // these functions will use the needed arrays, set values, etc to help the loaders - - //! exposed for loaders: to add mesh buffers - virtual core::array &getMeshBuffers() = 0; - - //! exposed for loaders: joints list - virtual core::array &getAllJoints() = 0; - - //! exposed for loaders: joints list - virtual const core::array &getAllJoints() const = 0; - - //! loaders should call this after populating the mesh - virtual void finalize() = 0; - - //! Adds a new meshbuffer to the mesh, access it as last one - virtual SSkinMeshBuffer *addMeshBuffer() = 0; - - //! Adds a new meshbuffer to the mesh, access it as last one - virtual void addMeshBuffer(SSkinMeshBuffer *meshbuf) = 0; - - //! Adds a new joint to the mesh, access it as last one - virtual SJoint *addJoint(SJoint *parent = 0) = 0; - - //! Adds a new weight to the mesh, access it as last one - virtual SWeight *addWeight(SJoint *joint) = 0; - - //! Adds a new position key to the mesh, access it as last one - virtual SPositionKey *addPositionKey(SJoint *joint) = 0; - //! Adds a new scale key to the mesh, access it as last one - virtual SScaleKey *addScaleKey(SJoint *joint) = 0; - //! Adds a new rotation key to the mesh, access it as last one - virtual SRotationKey *addRotationKey(SJoint *joint) = 0; - - //! Check if the mesh is non-animated - virtual bool isStatic() = 0; -}; - -} // end namespace scene -} // end namespace irr diff --git a/irr/src/CSkinnedMesh.h b/irr/include/SkinnedMesh.h similarity index 57% rename from irr/src/CSkinnedMesh.h rename to irr/include/SkinnedMesh.h index 576ae1217..54ce8ed2c 100644 --- a/irr/src/CSkinnedMesh.h +++ b/irr/include/SkinnedMesh.h @@ -2,32 +2,46 @@ // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h -// New skinned mesh - #pragma once +#include "IAnimatedMesh.h" #include "ISceneManager.h" -#include "ISkinnedMesh.h" #include "SMeshBuffer.h" +#include "SSkinMeshBuffer.h" #include "quaternion.h" +#include +#include + namespace irr { namespace scene { +enum E_INTERPOLATION_MODE +{ + // constant does use the current key-values without interpolation + EIM_CONSTANT = 0, + + // linear interpolation + EIM_LINEAR, + + //! count of all available interpolation modes + EIM_COUNT +}; + class IAnimatedMeshSceneNode; class IBoneSceneNode; class ISceneManager; -class CSkinnedMesh : public ISkinnedMesh +class SkinnedMesh : public IAnimatedMesh { public: //! constructor - CSkinnedMesh(); + SkinnedMesh(); //! destructor - virtual ~CSkinnedMesh(); + virtual ~SkinnedMesh(); //! If the duration is 0, it is a static (=non animated) mesh. f32 getMaxFrameNumber() const override; @@ -46,10 +60,10 @@ public: //! Animates this mesh's joints based on frame input //! blend: {0-old position, 1-New position} - void animateMesh(f32 frame, f32 blend) override; + void animateMesh(f32 frame, f32 blend); - //! Preforms a software skin on this mesh based of joint positions - void skinMesh() override; + //! Performs a software skin on this mesh based of joint positions + void skinMesh(); //! returns amount of mesh buffers. u32 getMeshBufferCount() const override; @@ -83,83 +97,53 @@ public: E_ANIMATED_MESH_TYPE getMeshType() const override; //! Gets joint count. - u32 getJointCount() const override; + u32 getJointCount() const; //! Gets the name of a joint. - const std::optional &getJointName(u32 number) const override; + /** \param number: Zero based index of joint. + \return Name of joint and null if an error happened. */ + const std::optional &getJointName(u32 number) const; //! Gets a joint number from its name - std::optional getJointNumber(const std::string &name) const override; - - //! uses animation from another mesh - bool useAnimationFrom(const ISkinnedMesh *mesh) override; + /** \param name: Name of the joint. + \return Number of the joint or std::nullopt if not found. */ + std::optional getJointNumber(const std::string &name) const; //! Update Normals when Animating - //! False= Don't (default) - //! True = Update normals, slower - void updateNormalsWhenAnimating(bool on) override; + /** \param on If false don't animate, which is faster. + Else update normals, which allows for proper lighting of + animated meshes. */ + void updateNormalsWhenAnimating(bool on); //! Sets Interpolation Mode - void setInterpolationMode(E_INTERPOLATION_MODE mode) override; + void setInterpolationMode(E_INTERPOLATION_MODE mode); - //! Convertes the mesh to contain tangent information - void convertMeshToTangents() override; + //! converts the vertex type of all meshbuffers to tangents. + /** E.g. used for bump mapping. */ + void convertMeshToTangents(); //! Does the mesh have no animation - bool isStatic() override; + bool isStatic() const; - //! (This feature is not implemented in irrlicht yet) - bool setHardwareSkinning(bool on) override; + //! Allows to enable hardware skinning. + /* This feature is not implemented in Irrlicht yet */ + bool setHardwareSkinning(bool on); //! Refreshes vertex data cached in joints such as positions and normals - void refreshJointCache() override; + void refreshJointCache(); //! Moves the mesh into static position. - void resetAnimation() override; + void resetAnimation(); - // Interface for the mesh loaders (finalize should lock these functions, and they should have some prefix like loader_ - // these functions will use the needed arrays, set values, etc to help the loaders - - //! exposed for loaders to add mesh buffers - core::array &getMeshBuffers() override; - - //! alternative method for adding joints - core::array &getAllJoints() override; - - //! alternative method for adding joints - const core::array &getAllJoints() const override; - - //! loaders should call this after populating the mesh - void finalize() override; - - //! Adds a new meshbuffer to the mesh, access it as last one - SSkinMeshBuffer *addMeshBuffer() override; - - //! Adds a new meshbuffer to the mesh, access it as last one - void addMeshBuffer(SSkinMeshBuffer *meshbuf) override; - - //! Adds a new joint to the mesh, access it as last one - SJoint *addJoint(SJoint *parent = 0) override; - - //! Adds a new position key to the mesh, access it as last one - SPositionKey *addPositionKey(SJoint *joint) override; - //! Adds a new rotation key to the mesh, access it as last one - SRotationKey *addRotationKey(SJoint *joint) override; - //! Adds a new scale key to the mesh, access it as last one - SScaleKey *addScaleKey(SJoint *joint) override; - - //! Adds a new weight to the mesh, access it as last one - SWeight *addWeight(SJoint *joint) override; - - virtual void updateBoundingBox(void); + virtual void updateBoundingBox(); //! Recovers the joints from the mesh void recoverJointsFromMesh(core::array &jointChildSceneNodes); - //! Tranfers the joint data to the mesh + //! Transfers the joint data to the mesh void transferJointsToMesh(const core::array &jointChildSceneNodes); - //! Tranfers the joint hints to the mesh + //! Transfers the joint hints to the mesh void transferOnlyJointsHintsToMesh(const core::array &jointChildSceneNodes); //! Creates an array of joints from this mesh as children of node @@ -167,6 +151,138 @@ public: IAnimatedMeshSceneNode *node, ISceneManager *smgr); + //! A vertex weight + struct SWeight + { + //! Index of the mesh buffer + u16 buffer_id; // I doubt 32bits is needed + + //! Index of the vertex + u32 vertex_id; // Store global ID here + + //! Weight Strength/Percentage (0-1) + f32 strength; + + private: + //! Internal members used by SkinnedMesh + friend class SkinnedMesh; + char *Moved; + core::vector3df StaticPos; + core::vector3df StaticNormal; + }; + + //! Animation keyframe which describes a new position + struct SPositionKey + { + f32 frame; + core::vector3df position; + }; + + //! Animation keyframe which describes a new scale + struct SScaleKey + { + f32 frame; + core::vector3df scale; + }; + + //! Animation keyframe which describes a new rotation + struct SRotationKey + { + f32 frame; + core::quaternion rotation; + }; + + //! Joints + struct SJoint + { + SJoint() : + UseAnimationFrom(0), GlobalSkinningSpace(false), + positionHint(-1), scaleHint(-1), rotationHint(-1) + { + } + + //! The name of this joint + std::optional Name; + + //! Local matrix of this joint + core::matrix4 LocalMatrix; + + //! List of child joints + core::array Children; + + //! List of attached meshes + core::array AttachedMeshes; + + //! Animation keys causing translation change + core::array PositionKeys; + + //! Animation keys causing scale change + core::array ScaleKeys; + + //! Animation keys causing rotation change + core::array RotationKeys; + + //! Skin weights + core::array Weights; + + //! Unnecessary for loaders, will be overwritten on finalize + core::matrix4 GlobalMatrix; // loaders may still choose to set this (temporarily) to calculate absolute vertex data. + core::matrix4 GlobalAnimatedMatrix; + core::matrix4 LocalAnimatedMatrix; + + //! These should be set by loaders. + core::vector3df Animatedposition; + core::vector3df Animatedscale; + core::quaternion Animatedrotation; + + // The .x and .gltf formats pre-calculate this + std::optional GlobalInversedMatrix; + private: + //! Internal members used by SkinnedMesh + friend class SkinnedMesh; + + SJoint *UseAnimationFrom; + bool GlobalSkinningSpace; + + s32 positionHint; + s32 scaleHint; + s32 rotationHint; + }; + + // Interface for the mesh loaders (finalize should lock these functions, and they should have some prefix like loader_ + // these functions will use the needed arrays, set values, etc to help the loaders + + //! exposed for loaders to add mesh buffers + core::array &getMeshBuffers(); + + //! alternative method for adding joints + core::array &getAllJoints(); + + //! alternative method for reading joints + const core::array &getAllJoints() const; + + //! loaders should call this after populating the mesh + void finalize(); + + //! Adds a new meshbuffer to the mesh, access it as last one + SSkinMeshBuffer *addMeshBuffer(); + + //! Adds a new meshbuffer to the mesh, access it as last one + void addMeshBuffer(SSkinMeshBuffer *meshbuf); + + //! Adds a new joint to the mesh, access it as last one + SJoint *addJoint(SJoint *parent = 0); + + //! Adds a new position key to the mesh, access it as last one + SPositionKey *addPositionKey(SJoint *joint); + //! Adds a new rotation key to the mesh, access it as last one + SRotationKey *addRotationKey(SJoint *joint); + //! Adds a new scale key to the mesh, access it as last one + SScaleKey *addScaleKey(SJoint *joint); + + //! Adds a new weight to the mesh, access it as last one + SWeight *addWeight(SJoint *joint); + private: void checkForAnimation(); diff --git a/irr/src/CAnimatedMeshSceneNode.cpp b/irr/src/CAnimatedMeshSceneNode.cpp index ba8bc3b78..5250fe889 100644 --- a/irr/src/CAnimatedMeshSceneNode.cpp +++ b/irr/src/CAnimatedMeshSceneNode.cpp @@ -7,7 +7,7 @@ #include "ISceneManager.h" #include "S3DVertex.h" #include "os.h" -#include "CSkinnedMesh.h" +#include "SkinnedMesh.h" #include "IDummyTransformationSceneNode.h" #include "IBoneSceneNode.h" #include "IMaterialRenderer.h" @@ -165,7 +165,7 @@ IMesh *CAnimatedMeshSceneNode::getMeshForCurrentFrame() // As multiple scene nodes may be sharing the same skinned mesh, we have to // re-animate it every frame to ensure that this node gets the mesh that it needs. - CSkinnedMesh *skinnedMesh = static_cast(Mesh); + SkinnedMesh *skinnedMesh = static_cast(Mesh); if (JointMode == EJUOR_CONTROL) // write to mesh skinnedMesh->transferJointsToMesh(JointChildSceneNodes); @@ -299,8 +299,8 @@ void CAnimatedMeshSceneNode::render() if (Mesh->getMeshType() == EAMT_SKINNED) { // draw skeleton - for (u32 g = 0; g < ((ISkinnedMesh *)Mesh)->getAllJoints().size(); ++g) { - ISkinnedMesh::SJoint *joint = ((ISkinnedMesh *)Mesh)->getAllJoints()[g]; + for (u32 g = 0; g < ((SkinnedMesh *)Mesh)->getAllJoints().size(); ++g) { + auto *joint = ((SkinnedMesh *)Mesh)->getAllJoints()[g]; for (u32 n = 0; n < joint->Children.size(); ++n) { driver->draw3DLine(joint->GlobalAnimatedMatrix.getTranslation(), @@ -404,7 +404,7 @@ IBoneSceneNode *CAnimatedMeshSceneNode::getJointNode(const c8 *jointName) checkJoints(); - ISkinnedMesh *skinnedMesh = (ISkinnedMesh *)Mesh; + auto *skinnedMesh = (SkinnedMesh *)Mesh; const std::optional number = skinnedMesh->getJointNumber(jointName); @@ -446,7 +446,7 @@ u32 CAnimatedMeshSceneNode::getJointCount() const if (!Mesh || Mesh->getMeshType() != EAMT_SKINNED) return 0; - ISkinnedMesh *skinnedMesh = (ISkinnedMesh *)Mesh; + auto *skinnedMesh = (SkinnedMesh *)Mesh; return skinnedMesh->getJointCount(); } @@ -596,7 +596,7 @@ void CAnimatedMeshSceneNode::animateJoints(bool CalculateAbsolutePositions) checkJoints(); const f32 frame = getFrameNr(); // old? - CSkinnedMesh *skinnedMesh = static_cast(Mesh); + SkinnedMesh *skinnedMesh = static_cast(Mesh); skinnedMesh->transferOnlyJointsHintsToMesh(JointChildSceneNodes); skinnedMesh->animateMesh(frame, 1.0f); @@ -671,8 +671,8 @@ void CAnimatedMeshSceneNode::checkJoints() JointChildSceneNodes.clear(); // Create joints for SkinnedMesh - ((CSkinnedMesh *)Mesh)->addJoints(JointChildSceneNodes, this, SceneManager); - ((CSkinnedMesh *)Mesh)->recoverJointsFromMesh(JointChildSceneNodes); + ((SkinnedMesh *)Mesh)->addJoints(JointChildSceneNodes, this, SceneManager); + ((SkinnedMesh *)Mesh)->recoverJointsFromMesh(JointChildSceneNodes); JointsUsed = true; JointMode = EJUOR_READ; diff --git a/irr/src/CB3DMeshFileLoader.cpp b/irr/src/CB3DMeshFileLoader.cpp index 6cb40cb95..6923cde04 100644 --- a/irr/src/CB3DMeshFileLoader.cpp +++ b/irr/src/CB3DMeshFileLoader.cpp @@ -51,7 +51,7 @@ IAnimatedMesh *CB3DMeshFileLoader::createMesh(io::IReadFile *file) return 0; B3DFile = file; - AnimatedMesh = new scene::CSkinnedMesh(); + AnimatedMesh = new scene::SkinnedMesh(); ShowWarning = true; // If true a warning is issued if too many textures are used VerticesStart = 0; @@ -111,7 +111,7 @@ bool CB3DMeshFileLoader::load() if (!readChunkBRUS()) return false; } else if (strncmp(B3dStack.getLast().name, "NODE", 4) == 0) { - if (!readChunkNODE((CSkinnedMesh::SJoint *)0)) + if (!readChunkNODE((SkinnedMesh::SJoint *)0)) return false; } else { os::Printer::log("Unknown chunk found in mesh base - skipping"); @@ -133,9 +133,9 @@ bool CB3DMeshFileLoader::load() return true; } -bool CB3DMeshFileLoader::readChunkNODE(CSkinnedMesh::SJoint *inJoint) +bool CB3DMeshFileLoader::readChunkNODE(SkinnedMesh::SJoint *inJoint) { - CSkinnedMesh::SJoint *joint = AnimatedMesh->addJoint(inJoint); + SkinnedMesh::SJoint *joint = AnimatedMesh->addJoint(inJoint); joint->Name = readString(); #ifdef _B3D_READER_DEBUG @@ -211,7 +211,7 @@ bool CB3DMeshFileLoader::readChunkNODE(CSkinnedMesh::SJoint *inJoint) return true; } -bool CB3DMeshFileLoader::readChunkMESH(CSkinnedMesh::SJoint *inJoint) +bool CB3DMeshFileLoader::readChunkMESH(SkinnedMesh::SJoint *inJoint) { #ifdef _B3D_READER_DEBUG core::stringc logStr; @@ -302,7 +302,7 @@ VRTS: float tex_coords[tex_coord_sets][tex_coord_set_size] ;tex coords } */ -bool CB3DMeshFileLoader::readChunkVRTS(CSkinnedMesh::SJoint *inJoint) +bool CB3DMeshFileLoader::readChunkVRTS(SkinnedMesh::SJoint *inJoint) { #ifdef _B3D_READER_DEBUG core::stringc logStr; @@ -521,7 +521,7 @@ bool CB3DMeshFileLoader::readChunkTRIS(scene::SSkinMeshBuffer *meshBuffer, u32 m return true; } -bool CB3DMeshFileLoader::readChunkBONE(CSkinnedMesh::SJoint *inJoint) +bool CB3DMeshFileLoader::readChunkBONE(SkinnedMesh::SJoint *inJoint) { #ifdef _B3D_READER_DEBUG core::stringc logStr; @@ -552,7 +552,7 @@ bool CB3DMeshFileLoader::readChunkBONE(CSkinnedMesh::SJoint *inJoint) if (AnimatedVertices_VertexID[globalVertexID] == -1) { os::Printer::log("B3dMeshLoader: Weight has bad vertex id (no link to meshbuffer index found)"); } else if (strength > 0) { - CSkinnedMesh::SWeight *weight = AnimatedMesh->addWeight(inJoint); + SkinnedMesh::SWeight *weight = AnimatedMesh->addWeight(inJoint); weight->strength = strength; // Find the meshbuffer and Vertex index from the Global Vertex ID: weight->vertex_id = AnimatedVertices_VertexID[globalVertexID]; @@ -565,7 +565,7 @@ bool CB3DMeshFileLoader::readChunkBONE(CSkinnedMesh::SJoint *inJoint) return true; } -bool CB3DMeshFileLoader::readChunkKEYS(CSkinnedMesh::SJoint *inJoint) +bool CB3DMeshFileLoader::readChunkKEYS(SkinnedMesh::SJoint *inJoint) { #ifdef _B3D_READER_DEBUG // Only print first, that's just too much output otherwise @@ -584,11 +584,11 @@ bool CB3DMeshFileLoader::readChunkKEYS(CSkinnedMesh::SJoint *inJoint) flags = os::Byteswap::byteswap(flags); #endif - CSkinnedMesh::SPositionKey *oldPosKey = 0; + SkinnedMesh::SPositionKey *oldPosKey = 0; core::vector3df oldPos[2]; - CSkinnedMesh::SScaleKey *oldScaleKey = 0; + SkinnedMesh::SScaleKey *oldScaleKey = 0; core::vector3df oldScale[2]; - CSkinnedMesh::SRotationKey *oldRotKey = 0; + SkinnedMesh::SRotationKey *oldRotKey = 0; core::quaternion oldRot[2]; bool isFirst[3] = {true, true, true}; while ((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats diff --git a/irr/src/CB3DMeshFileLoader.h b/irr/src/CB3DMeshFileLoader.h index 808b68170..711f2737f 100644 --- a/irr/src/CB3DMeshFileLoader.h +++ b/irr/src/CB3DMeshFileLoader.h @@ -10,7 +10,7 @@ #include "IMeshLoader.h" #include "ISceneManager.h" -#include "CSkinnedMesh.h" +#include "SkinnedMesh.h" #include "SB3DStructs.h" #include "IReadFile.h" @@ -39,12 +39,12 @@ public: private: bool load(); - bool readChunkNODE(CSkinnedMesh::SJoint *InJoint); - bool readChunkMESH(CSkinnedMesh::SJoint *InJoint); - bool readChunkVRTS(CSkinnedMesh::SJoint *InJoint); + bool readChunkNODE(SkinnedMesh::SJoint *InJoint); + bool readChunkMESH(SkinnedMesh::SJoint *InJoint); + bool readChunkVRTS(SkinnedMesh::SJoint *InJoint); bool readChunkTRIS(scene::SSkinMeshBuffer *MeshBuffer, u32 MeshBufferID, s32 Vertices_Start); - bool readChunkBONE(CSkinnedMesh::SJoint *InJoint); - bool readChunkKEYS(CSkinnedMesh::SJoint *InJoint); + bool readChunkBONE(SkinnedMesh::SJoint *InJoint); + bool readChunkKEYS(SkinnedMesh::SJoint *InJoint); bool readChunkANIM(); bool readChunkTEXS(); bool readChunkBRUS(); @@ -63,7 +63,7 @@ private: core::array BaseVertices; - CSkinnedMesh *AnimatedMesh; + SkinnedMesh *AnimatedMesh; io::IReadFile *B3DFile; // B3Ds have Vertex ID's local within the mesh I don't want this diff --git a/irr/src/CGLTFMeshFileLoader.cpp b/irr/src/CGLTFMeshFileLoader.cpp index ce2c41f58..9045569a6 100644 --- a/irr/src/CGLTFMeshFileLoader.cpp +++ b/irr/src/CGLTFMeshFileLoader.cpp @@ -5,7 +5,7 @@ #include "SMaterialLayer.h" #include "coreutil.h" -#include "CSkinnedMesh.h" +#include "SkinnedMesh.h" #include "IAnimatedMesh.h" #include "IReadFile.h" #include "irrTypes.h" @@ -344,7 +344,7 @@ IAnimatedMesh* SelfType::createMesh(io::IReadFile* file) const char *filename = file->getFileName().c_str(); try { tiniergltf::GlTF model = parseGLTF(file); - irr_ptr mesh(new CSkinnedMesh()); + irr_ptr mesh(new SkinnedMesh()); MeshExtractor extractor(std::move(model), mesh.get()); try { extractor.load(); @@ -410,7 +410,7 @@ static video::E_TEXTURE_CLAMP convertTextureWrap(const Wrap wrap) { void SelfType::MeshExtractor::addPrimitive( const tiniergltf::MeshPrimitive &primitive, const std::optional skinIdx, - CSkinnedMesh::SJoint *parent) + SkinnedMesh::SJoint *parent) { auto vertices = getVertices(primitive); if (!vertices.has_value()) @@ -510,7 +510,7 @@ void SelfType::MeshExtractor::addPrimitive( if (strength == 0) continue; - CSkinnedMesh::SWeight *weight = m_irr_model->addWeight(m_loaded_nodes.at(skin.joints.at(jointIdx))); + SkinnedMesh::SWeight *weight = m_irr_model->addWeight(m_loaded_nodes.at(skin.joints.at(jointIdx))); weight->buffer_id = meshbufNr; weight->vertex_id = v; weight->strength = strength; @@ -527,7 +527,7 @@ void SelfType::MeshExtractor::addPrimitive( void SelfType::MeshExtractor::deferAddMesh( const std::size_t meshIdx, const std::optional skinIdx, - CSkinnedMesh::SJoint *parent) + SkinnedMesh::SJoint *parent) { m_mesh_loaders.emplace_back([=] { for (std::size_t pi = 0; pi < getPrimitiveCount(meshIdx); ++pi) { @@ -547,7 +547,7 @@ static const core::matrix4 leftToRight = core::matrix4( ); static const core::matrix4 rightToLeft = leftToRight; -static core::matrix4 loadTransform(const tiniergltf::Node::Matrix &m, CSkinnedMesh::SJoint *joint) +static core::matrix4 loadTransform(const tiniergltf::Node::Matrix &m, SkinnedMesh::SJoint *joint) { // Note: Under the hood, this casts these doubles to floats. core::matrix4 mat = convertHandedness(core::matrix4( @@ -576,7 +576,7 @@ static core::matrix4 loadTransform(const tiniergltf::Node::Matrix &m, CSkinnedMe return mat; } -static core::matrix4 loadTransform(const tiniergltf::Node::TRS &trs, CSkinnedMesh::SJoint *joint) +static core::matrix4 loadTransform(const tiniergltf::Node::TRS &trs, SkinnedMesh::SJoint *joint) { const auto &trans = trs.translation; const auto &rot = trs.rotation; @@ -594,7 +594,7 @@ static core::matrix4 loadTransform(const tiniergltf::Node::TRS &trs, CSkinnedMes } static core::matrix4 loadTransform(std::optional> transform, - CSkinnedMesh::SJoint *joint) { + SkinnedMesh::SJoint *joint) { if (!transform.has_value()) { return core::matrix4(); } @@ -603,7 +603,7 @@ static core::matrix4 loadTransform(std::optionalat(nodeIdx); auto *joint = m_irr_model->addJoint(parent); @@ -626,7 +626,7 @@ void SelfType::MeshExtractor::loadNode( void SelfType::MeshExtractor::loadNodes() { - m_loaded_nodes = std::vector(m_gltf_model.nodes->size()); + m_loaded_nodes = std::vector(m_gltf_model.nodes->size()); std::vector isChild(m_gltf_model.nodes->size()); for (const auto &node : *m_gltf_model.nodes) { diff --git a/irr/src/CGLTFMeshFileLoader.h b/irr/src/CGLTFMeshFileLoader.h index ae178565d..35ee85726 100644 --- a/irr/src/CGLTFMeshFileLoader.h +++ b/irr/src/CGLTFMeshFileLoader.h @@ -3,7 +3,7 @@ #pragma once -#include "CSkinnedMesh.h" +#include "SkinnedMesh.h" #include "IMeshLoader.h" #include "IReadFile.h" #include "irrTypes.h" @@ -100,7 +100,7 @@ private: { public: MeshExtractor(tiniergltf::GlTF &&model, - CSkinnedMesh *mesh) noexcept + SkinnedMesh *mesh) noexcept : m_gltf_model(std::move(model)), m_irr_model(mesh) {}; /* Gets indices for the given mesh/primitive. @@ -124,10 +124,10 @@ private: private: const tiniergltf::GlTF m_gltf_model; - CSkinnedMesh *m_irr_model; + SkinnedMesh *m_irr_model; std::vector> m_mesh_loaders; - std::vector m_loaded_nodes; + std::vector m_loaded_nodes; std::vector warnings; void warn(const std::string &warning) { @@ -145,13 +145,13 @@ private: void addPrimitive(const tiniergltf::MeshPrimitive &primitive, const std::optional skinIdx, - CSkinnedMesh::SJoint *parent); + SkinnedMesh::SJoint *parent); void deferAddMesh(const std::size_t meshIdx, const std::optional skinIdx, - CSkinnedMesh::SJoint *parentJoint); + SkinnedMesh::SJoint *parentJoint); - void loadNode(const std::size_t nodeIdx, CSkinnedMesh::SJoint *parentJoint); + void loadNode(const std::size_t nodeIdx, SkinnedMesh::SJoint *parentJoint); void loadNodes(); diff --git a/irr/src/CMakeLists.txt b/irr/src/CMakeLists.txt index a05607830..7e0a3a3fa 100644 --- a/irr/src/CMakeLists.txt +++ b/irr/src/CMakeLists.txt @@ -308,7 +308,7 @@ set(IRRMESHLOADER ) add_library(IRRMESHOBJ OBJECT - CSkinnedMesh.cpp + SkinnedMesh.cpp CBoneSceneNode.cpp CMeshSceneNode.cpp CAnimatedMeshSceneNode.cpp diff --git a/irr/src/CMeshManipulator.cpp b/irr/src/CMeshManipulator.cpp index 67b22a07e..63157403b 100644 --- a/irr/src/CMeshManipulator.cpp +++ b/irr/src/CMeshManipulator.cpp @@ -3,7 +3,7 @@ // For conditions of distribution and use, see copyright notice in irrlicht.h #include "CMeshManipulator.h" -#include "ISkinnedMesh.h" +#include "SkinnedMesh.h" #include "SMesh.h" #include "CMeshBuffer.h" #include "SAnimatedMesh.h" @@ -101,7 +101,7 @@ void CMeshManipulator::recalculateNormals(scene::IMesh *mesh, bool smooth, bool return; if (mesh->getMeshType() == EAMT_SKINNED) { - ISkinnedMesh *smesh = (ISkinnedMesh *)mesh; + auto *smesh = (SkinnedMesh *)mesh; smesh->resetAnimation(); } @@ -110,7 +110,7 @@ void CMeshManipulator::recalculateNormals(scene::IMesh *mesh, bool smooth, bool recalculateNormals(mesh->getMeshBuffer(b), smooth, angleWeighted); if (mesh->getMeshType() == EAMT_SKINNED) { - ISkinnedMesh *smesh = (ISkinnedMesh *)mesh; + auto *smesh = (SkinnedMesh *)mesh; smesh->refreshJointCache(); } } diff --git a/irr/src/CMeshSceneNode.cpp b/irr/src/CMeshSceneNode.cpp index 030e1fd15..6d02eada5 100644 --- a/irr/src/CMeshSceneNode.cpp +++ b/irr/src/CMeshSceneNode.cpp @@ -5,10 +5,8 @@ #include "CMeshSceneNode.h" #include "IVideoDriver.h" #include "ISceneManager.h" -#include "S3DVertex.h" -#include "ICameraSceneNode.h" #include "IMeshCache.h" -#include "IAnimatedMesh.h" +#include "IMeshBuffer.h" #include "IMaterialRenderer.h" #include "IFileSystem.h" diff --git a/irr/src/CSceneManager.cpp b/irr/src/CSceneManager.cpp index 71ae7f962..a6716525a 100644 --- a/irr/src/CSceneManager.cpp +++ b/irr/src/CSceneManager.cpp @@ -16,7 +16,7 @@ #include "os.h" -#include "CSkinnedMesh.h" +#include "SkinnedMesh.h" #include "CXMeshFileLoader.h" #include "COBJMeshFileLoader.h" #include "CB3DMeshFileLoader.h" @@ -771,9 +771,9 @@ ISceneManager *CSceneManager::createNewSceneManager(bool cloneContent) } //! Get a skinned mesh, which is not available as header-only code -ISkinnedMesh *CSceneManager::createSkinnedMesh() +SkinnedMesh *CSceneManager::createSkinnedMesh() { - return new CSkinnedMesh(); + return new SkinnedMesh(); } // creates a scenemanager diff --git a/irr/src/CSceneManager.h b/irr/src/CSceneManager.h index 4362ba04d..2a4fb7f7b 100644 --- a/irr/src/CSceneManager.h +++ b/irr/src/CSceneManager.h @@ -4,6 +4,7 @@ #pragma once +#include "SkinnedMesh.h" #include "ISceneManager.h" #include "ISceneNode.h" #include "ICursorControl.h" @@ -22,6 +23,8 @@ namespace scene { class IMeshCache; +class SkinnedMesh; + /*! The Scene Manager manages scene nodes, mesh resources, cameras and all the other stuff. */ @@ -167,8 +170,8 @@ public: //! Returns type of the scene node ESCENE_NODE_TYPE getType() const override { return ESNT_SCENE_MANAGER; } - //! Get a skinned mesh, which is not available as header-only code - ISkinnedMesh *createSkinnedMesh() override; + //! Get a skinned mesh + SkinnedMesh *createSkinnedMesh() override; //! Get current render time. E_SCENE_NODE_RENDER_PASS getCurrentRenderPass() const override { return CurrentRenderPass; } diff --git a/irr/src/CXMeshFileLoader.cpp b/irr/src/CXMeshFileLoader.cpp index 967fc367c..19d4e5b01 100644 --- a/irr/src/CXMeshFileLoader.cpp +++ b/irr/src/CXMeshFileLoader.cpp @@ -57,7 +57,7 @@ IAnimatedMesh *CXMeshFileLoader::createMesh(io::IReadFile *file) u32 time = os::Timer::getRealTime(); #endif - AnimatedMesh = new CSkinnedMesh(); + AnimatedMesh = new SkinnedMesh(); if (load(file)) { AnimatedMesh->finalize(); @@ -203,8 +203,8 @@ bool CXMeshFileLoader::load(io::IReadFile *file) } for (u32 j = 0; j < mesh->WeightJoint.size(); ++j) { - ISkinnedMesh::SJoint *joint = AnimatedMesh->getAllJoints()[mesh->WeightJoint[j]]; - ISkinnedMesh::SWeight &weight = joint->Weights[mesh->WeightNum[j]]; + SkinnedMesh::SJoint *joint = AnimatedMesh->getAllJoints()[mesh->WeightJoint[j]]; + SkinnedMesh::SWeight &weight = joint->Weights[mesh->WeightNum[j]]; u32 id = weight.vertex_id; @@ -219,7 +219,7 @@ bool CXMeshFileLoader::load(io::IReadFile *file) weight.buffer_id = verticesLinkBuffer[id][0]; } else if (verticesLinkBuffer[id].size() != 0) { for (u32 k = 1; k < verticesLinkBuffer[id].size(); ++k) { - ISkinnedMesh::SWeight *WeightClone = AnimatedMesh->addWeight(joint); + SkinnedMesh::SWeight *WeightClone = AnimatedMesh->addWeight(joint); WeightClone->strength = weight.strength; WeightClone->vertex_id = verticesLinkIndex[id][k]; WeightClone->buffer_id = verticesLinkBuffer[id][k]; @@ -314,7 +314,7 @@ bool CXMeshFileLoader::load(io::IReadFile *file) } for (u32 j = 0; j < mesh->WeightJoint.size(); ++j) { - ISkinnedMesh::SWeight &weight = (AnimatedMesh->getAllJoints()[mesh->WeightJoint[j]]->Weights[mesh->WeightNum[j]]); + SkinnedMesh::SWeight &weight = (AnimatedMesh->getAllJoints()[mesh->WeightJoint[j]]->Weights[mesh->WeightNum[j]]); u32 id = weight.vertex_id; @@ -486,7 +486,7 @@ bool CXMeshFileLoader::parseDataObjectTemplate() return true; } -bool CXMeshFileLoader::parseDataObjectFrame(CSkinnedMesh::SJoint *Parent) +bool CXMeshFileLoader::parseDataObjectFrame(SkinnedMesh::SJoint *Parent) { #ifdef _XREADER_DEBUG os::Printer::log("CXFileReader: Reading frame", ELL_DEBUG); @@ -508,7 +508,7 @@ bool CXMeshFileLoader::parseDataObjectFrame(CSkinnedMesh::SJoint *Parent) SET_ERR_AND_RETURN(); } - CSkinnedMesh::SJoint *joint = 0; + SkinnedMesh::SJoint *joint = 0; if (name.size()) { auto n = AnimatedMesh->getJointNumber(name.c_str()); @@ -947,7 +947,7 @@ bool CXMeshFileLoader::parseDataObjectSkinWeights(SXMesh &mesh) mesh.HasSkinning = true; auto n = AnimatedMesh->getJointNumber(TransformNodeName.c_str()); - CSkinnedMesh::SJoint *joint = n.has_value() ? AnimatedMesh->getAllJoints()[*n] : nullptr; + SkinnedMesh::SJoint *joint = n.has_value() ? AnimatedMesh->getAllJoints()[*n] : nullptr; if (!joint) { #ifdef _XREADER_DEBUG @@ -974,7 +974,7 @@ bool CXMeshFileLoader::parseDataObjectSkinWeights(SXMesh &mesh) mesh.WeightJoint.push_back(*n); mesh.WeightNum.push_back(joint->Weights.size()); - CSkinnedMesh::SWeight *weight = AnimatedMesh->addWeight(joint); + SkinnedMesh::SWeight *weight = AnimatedMesh->addWeight(joint); weight->buffer_id = 0; weight->vertex_id = readInt(); @@ -1358,7 +1358,7 @@ bool CXMeshFileLoader::parseDataObjectAnimation() // anim.closed = true; // anim.linearPositionQuality = true; - CSkinnedMesh::SJoint animationDump; + SkinnedMesh::SJoint animationDump; core::stringc FrameName; @@ -1400,7 +1400,7 @@ bool CXMeshFileLoader::parseDataObjectAnimation() #endif auto n = AnimatedMesh->getJointNumber(FrameName.c_str()); - CSkinnedMesh::SJoint *joint; + SkinnedMesh::SJoint *joint; if (n.has_value()) { joint = AnimatedMesh->getAllJoints()[*n]; } else { @@ -1431,7 +1431,7 @@ bool CXMeshFileLoader::parseDataObjectAnimation() return true; } -bool CXMeshFileLoader::parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint) +bool CXMeshFileLoader::parseDataObjectAnimationKey(SkinnedMesh::SJoint *joint) { #ifdef _XREADER_DEBUG os::Printer::log("CXFileReader: reading animation key", ELL_DEBUG); @@ -1488,7 +1488,7 @@ bool CXMeshFileLoader::parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint) os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); } - ISkinnedMesh::SRotationKey *key = AnimatedMesh->addRotationKey(joint); + SkinnedMesh::SRotationKey *key = AnimatedMesh->addRotationKey(joint); key->frame = time; key->rotation.set(X, Y, Z, W); key->rotation.normalize(); @@ -1514,11 +1514,11 @@ bool CXMeshFileLoader::parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint) } if (keyType == 2) { - ISkinnedMesh::SPositionKey *key = AnimatedMesh->addPositionKey(joint); + SkinnedMesh::SPositionKey *key = AnimatedMesh->addPositionKey(joint); key->frame = time; key->position = vector; } else { - ISkinnedMesh::SScaleKey *key = AnimatedMesh->addScaleKey(joint); + SkinnedMesh::SScaleKey *key = AnimatedMesh->addScaleKey(joint); key->frame = time; key->scale = vector; } @@ -1547,14 +1547,14 @@ bool CXMeshFileLoader::parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint) // core::vector3df rotation = mat.getRotationDegrees(); - ISkinnedMesh::SRotationKey *keyR = AnimatedMesh->addRotationKey(joint); + SkinnedMesh::SRotationKey *keyR = AnimatedMesh->addRotationKey(joint); keyR->frame = time; // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from mat to mat.getTransposed() for downward compatibility. // Not tested so far if this was correct or wrong before quaternion fix! keyR->rotation = core::quaternion(mat.getTransposed()); - ISkinnedMesh::SPositionKey *keyP = AnimatedMesh->addPositionKey(joint); + SkinnedMesh::SPositionKey *keyP = AnimatedMesh->addPositionKey(joint); keyP->frame = time; keyP->position = mat.getTranslation(); @@ -1567,7 +1567,7 @@ bool CXMeshFileLoader::parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint) scale.Y=1; if (scale.Z==0) scale.Z=1; - ISkinnedMesh::SScaleKey *keyS=AnimatedMesh->addScaleKey(joint); + SkinnedMesh::SScaleKey *keyS=AnimatedMesh->addScaleKey(joint); keyS->frame=time; keyS->scale=scale; */ diff --git a/irr/src/CXMeshFileLoader.h b/irr/src/CXMeshFileLoader.h index 711806270..0902651a9 100644 --- a/irr/src/CXMeshFileLoader.h +++ b/irr/src/CXMeshFileLoader.h @@ -6,7 +6,7 @@ #include "IMeshLoader.h" #include "irrString.h" -#include "CSkinnedMesh.h" +#include "SkinnedMesh.h" namespace irr { @@ -86,7 +86,7 @@ private: bool parseDataObjectTemplate(); - bool parseDataObjectFrame(CSkinnedMesh::SJoint *parent); + bool parseDataObjectFrame(SkinnedMesh::SJoint *parent); bool parseDataObjectTransformationMatrix(core::matrix4 &mat); @@ -110,7 +110,7 @@ private: bool parseDataObjectAnimation(); - bool parseDataObjectAnimationKey(ISkinnedMesh::SJoint *joint); + bool parseDataObjectAnimationKey(SkinnedMesh::SJoint *joint); bool parseDataObjectTextureFilename(core::stringc &texturename); @@ -155,7 +155,7 @@ private: bool readRGB(video::SColor &color); bool readRGBA(video::SColor &color); - CSkinnedMesh *AnimatedMesh; + SkinnedMesh *AnimatedMesh; c8 *Buffer; const c8 *P; @@ -167,7 +167,7 @@ private: bool ErrorState; - CSkinnedMesh::SJoint *CurFrame; + SkinnedMesh::SJoint *CurFrame; core::array Meshes; diff --git a/irr/src/CSkinnedMesh.cpp b/irr/src/SkinnedMesh.cpp similarity index 89% rename from irr/src/CSkinnedMesh.cpp rename to irr/src/SkinnedMesh.cpp index 875fd8e7e..76bce0b87 100644 --- a/irr/src/CSkinnedMesh.cpp +++ b/irr/src/SkinnedMesh.cpp @@ -2,8 +2,8 @@ // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h -#include "CSkinnedMesh.h" -#include +#include "SkinnedMesh.h" +#include "IBoneSceneNode.h" #include "CBoneSceneNode.h" #include "IAnimatedMeshSceneNode.h" #include "SSkinMeshBuffer.h" @@ -63,17 +63,17 @@ irr::u32 dropMiddleKeys(irr::core::array &array, Cmp &cmp) return d; } -bool identicalPos(const irr::scene::ISkinnedMesh::SPositionKey &a, const irr::scene::ISkinnedMesh::SPositionKey &b) +bool identicalPos(const irr::scene::SkinnedMesh::SPositionKey &a, const irr::scene::SkinnedMesh::SPositionKey &b) { return a.position == b.position; } -bool identicalScale(const irr::scene::ISkinnedMesh::SScaleKey &a, const irr::scene::ISkinnedMesh::SScaleKey &b) +bool identicalScale(const irr::scene::SkinnedMesh::SScaleKey &a, const irr::scene::SkinnedMesh::SScaleKey &b) { return a.scale == b.scale; } -bool identicalRotation(const irr::scene::ISkinnedMesh::SRotationKey &a, const irr::scene::ISkinnedMesh::SRotationKey &b) +bool identicalRotation(const irr::scene::SkinnedMesh::SRotationKey &a, const irr::scene::SkinnedMesh::SRotationKey &b) { return a.rotation == b.rotation; } @@ -85,7 +85,7 @@ namespace scene { //! constructor -CSkinnedMesh::CSkinnedMesh() : +SkinnedMesh::SkinnedMesh() : SkinningBuffers(0), EndFrame(0.f), FramesPerSecond(25.f), LastAnimatedFrame(-1), SkinnedLastFrame(false), InterpolationMode(EIM_LINEAR), @@ -93,14 +93,14 @@ CSkinnedMesh::CSkinnedMesh() : AnimateNormals(true), HardwareSkinning(false) { #ifdef _DEBUG - setDebugName("CSkinnedMesh"); + setDebugName("SkinnedMesh"); #endif SkinningBuffers = &LocalBuffers; } //! destructor -CSkinnedMesh::~CSkinnedMesh() +SkinnedMesh::~SkinnedMesh() { for (u32 i = 0; i < AllJoints.size(); ++i) delete AllJoints[i]; @@ -111,14 +111,14 @@ CSkinnedMesh::~CSkinnedMesh() } } -f32 CSkinnedMesh::getMaxFrameNumber() const +f32 SkinnedMesh::getMaxFrameNumber() const { return EndFrame; } //! Gets the default animation speed of the animated mesh. /** \return Amount of frames per second. If the amount is 0, it is a static, non animated mesh. */ -f32 CSkinnedMesh::getAnimationSpeed() const +f32 SkinnedMesh::getAnimationSpeed() const { return FramesPerSecond; } @@ -126,13 +126,13 @@ f32 CSkinnedMesh::getAnimationSpeed() const //! Gets the frame count of the animated mesh. /** \param fps Frames per second to play the animation with. If the amount is 0, it is not animated. The actual speed is set in the scene node the mesh is instantiated in.*/ -void CSkinnedMesh::setAnimationSpeed(f32 fps) +void SkinnedMesh::setAnimationSpeed(f32 fps) { FramesPerSecond = fps; } //! returns the animated mesh based -IMesh *CSkinnedMesh::getMesh(f32 frame) +IMesh *SkinnedMesh::getMesh(f32 frame) { // animate(frame,startFrameLoop, endFrameLoop); if (frame == -1) @@ -149,7 +149,7 @@ IMesh *CSkinnedMesh::getMesh(f32 frame) //! Animates this mesh's joints based on frame input //! blend: {0-old position, 1-New position} -void CSkinnedMesh::animateMesh(f32 frame, f32 blend) +void SkinnedMesh::animateMesh(f32 frame, f32 blend) { if (!HasAnimation || LastAnimatedFrame == frame) return; @@ -205,7 +205,7 @@ void CSkinnedMesh::animateMesh(f32 frame, f32 blend) updateBoundingBox(); } -void CSkinnedMesh::buildAllLocalAnimatedMatrices() +void SkinnedMesh::buildAllLocalAnimatedMatrices() { for (u32 i = 0; i < AllJoints.size(); ++i) { SJoint *joint = AllJoints[i]; @@ -270,7 +270,7 @@ void CSkinnedMesh::buildAllLocalAnimatedMatrices() SkinnedLastFrame = false; } -void CSkinnedMesh::buildAllGlobalAnimatedMatrices(SJoint *joint, SJoint *parentJoint) +void SkinnedMesh::buildAllGlobalAnimatedMatrices(SJoint *joint, SJoint *parentJoint) { if (!joint) { for (u32 i = 0; i < RootJoints.size(); ++i) @@ -288,7 +288,7 @@ void CSkinnedMesh::buildAllGlobalAnimatedMatrices(SJoint *joint, SJoint *parentJ buildAllGlobalAnimatedMatrices(joint->Children[j], joint); } -void CSkinnedMesh::getFrameData(f32 frame, SJoint *joint, +void SkinnedMesh::getFrameData(f32 frame, SJoint *joint, core::vector3df &position, s32 &positionHint, core::vector3df &scale, s32 &scaleHint, core::quaternion &rotation, s32 &rotationHint) @@ -453,7 +453,7 @@ void CSkinnedMesh::getFrameData(f32 frame, SJoint *joint, //-------------------------------------------------------------------------- //! Preforms a software skin on this mesh based of joint positions -void CSkinnedMesh::skinMesh() +void SkinnedMesh::skinMesh() { if (!HasAnimation || SkinnedLastFrame) return; @@ -491,7 +491,7 @@ void CSkinnedMesh::skinMesh() updateBoundingBox(); } -void CSkinnedMesh::skinJoint(SJoint *joint, SJoint *parentJoint) +void SkinnedMesh::skinJoint(SJoint *joint, SJoint *parentJoint) { if (joint->Weights.size()) { // Find this joints pull on vertices... @@ -541,19 +541,19 @@ void CSkinnedMesh::skinJoint(SJoint *joint, SJoint *parentJoint) skinJoint(joint->Children[j], joint); } -E_ANIMATED_MESH_TYPE CSkinnedMesh::getMeshType() const +E_ANIMATED_MESH_TYPE SkinnedMesh::getMeshType() const { return EAMT_SKINNED; } //! Gets joint count. -u32 CSkinnedMesh::getJointCount() const +u32 SkinnedMesh::getJointCount() const { return AllJoints.size(); } //! Gets the name of a joint. -const std::optional &CSkinnedMesh::getJointName(u32 number) const +const std::optional &SkinnedMesh::getJointName(u32 number) const { if (number >= getJointCount()) { static const std::optional nullopt; @@ -563,7 +563,7 @@ const std::optional &CSkinnedMesh::getJointName(u32 number) const } //! Gets a joint number from its name -std::optional CSkinnedMesh::getJointNumber(const std::string &name) const +std::optional SkinnedMesh::getJointNumber(const std::string &name) const { for (u32 i = 0; i < AllJoints.size(); ++i) { if (AllJoints[i]->Name == name) @@ -574,13 +574,13 @@ std::optional CSkinnedMesh::getJointNumber(const std::string &name) const } //! returns amount of mesh buffers. -u32 CSkinnedMesh::getMeshBufferCount() const +u32 SkinnedMesh::getMeshBufferCount() const { return LocalBuffers.size(); } //! returns pointer to a mesh buffer -IMeshBuffer *CSkinnedMesh::getMeshBuffer(u32 nr) const +IMeshBuffer *SkinnedMesh::getMeshBuffer(u32 nr) const { if (nr < LocalBuffers.size()) return LocalBuffers[nr]; @@ -589,7 +589,7 @@ IMeshBuffer *CSkinnedMesh::getMeshBuffer(u32 nr) const } //! Returns pointer to a mesh buffer which fits a material -IMeshBuffer *CSkinnedMesh::getMeshBuffer(const video::SMaterial &material) const +IMeshBuffer *SkinnedMesh::getMeshBuffer(const video::SMaterial &material) const { for (u32 i = 0; i < LocalBuffers.size(); ++i) { if (LocalBuffers[i]->getMaterial() == material) @@ -598,29 +598,29 @@ IMeshBuffer *CSkinnedMesh::getMeshBuffer(const video::SMaterial &material) const return 0; } -u32 CSkinnedMesh::getTextureSlot(u32 meshbufNr) const +u32 SkinnedMesh::getTextureSlot(u32 meshbufNr) const { return TextureSlots.at(meshbufNr); } -void CSkinnedMesh::setTextureSlot(u32 meshbufNr, u32 textureSlot) { +void SkinnedMesh::setTextureSlot(u32 meshbufNr, u32 textureSlot) { TextureSlots.at(meshbufNr) = textureSlot; } //! returns an axis aligned bounding box -const core::aabbox3d &CSkinnedMesh::getBoundingBox() const +const core::aabbox3d &SkinnedMesh::getBoundingBox() const { return BoundingBox; } //! set user axis aligned bounding box -void CSkinnedMesh::setBoundingBox(const core::aabbox3df &box) +void SkinnedMesh::setBoundingBox(const core::aabbox3df &box) { BoundingBox = box; } //! set the hardware mapping hint, for driver -void CSkinnedMesh::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, +void SkinnedMesh::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer) { for (u32 i = 0; i < LocalBuffers.size(); ++i) @@ -628,71 +628,43 @@ void CSkinnedMesh::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, } //! flags the meshbuffer as changed, reloads hardware buffers -void CSkinnedMesh::setDirty(E_BUFFER_TYPE buffer) +void SkinnedMesh::setDirty(E_BUFFER_TYPE buffer) { for (u32 i = 0; i < LocalBuffers.size(); ++i) LocalBuffers[i]->setDirty(buffer); } -//! uses animation from another mesh -bool CSkinnedMesh::useAnimationFrom(const ISkinnedMesh *mesh) -{ - bool unmatched = false; - - for (u32 i = 0; i < AllJoints.size(); ++i) { - SJoint *joint = AllJoints[i]; - joint->UseAnimationFrom = 0; - - if (joint->Name == "") - unmatched = true; - else { - for (u32 j = 0; j < mesh->getAllJoints().size(); ++j) { - SJoint *otherJoint = mesh->getAllJoints()[j]; - if (joint->Name == otherJoint->Name) { - joint->UseAnimationFrom = otherJoint; - } - } - if (!joint->UseAnimationFrom) - unmatched = true; - } - } - - checkForAnimation(); - - return !unmatched; -} - //! Update Normals when Animating //! False= Don't animate them, faster //! True= Update normals (default) -void CSkinnedMesh::updateNormalsWhenAnimating(bool on) +void SkinnedMesh::updateNormalsWhenAnimating(bool on) { AnimateNormals = on; } //! Sets Interpolation Mode -void CSkinnedMesh::setInterpolationMode(E_INTERPOLATION_MODE mode) +void SkinnedMesh::setInterpolationMode(E_INTERPOLATION_MODE mode) { InterpolationMode = mode; } -core::array &CSkinnedMesh::getMeshBuffers() +core::array &SkinnedMesh::getMeshBuffers() { return LocalBuffers; } -core::array &CSkinnedMesh::getAllJoints() +core::array &SkinnedMesh::getAllJoints() { return AllJoints; } -const core::array &CSkinnedMesh::getAllJoints() const +const core::array &SkinnedMesh::getAllJoints() const { return AllJoints; } //! (This feature is not implemented in irrlicht yet) -bool CSkinnedMesh::setHardwareSkinning(bool on) +bool SkinnedMesh::setHardwareSkinning(bool on) { if (HardwareSkinning != on) { if (on) { @@ -715,7 +687,7 @@ bool CSkinnedMesh::setHardwareSkinning(bool on) return HardwareSkinning; } -void CSkinnedMesh::refreshJointCache() +void SkinnedMesh::refreshJointCache() { // copy cache from the mesh... for (u32 i = 0; i < AllJoints.size(); ++i) { @@ -729,7 +701,7 @@ void CSkinnedMesh::refreshJointCache() } } -void CSkinnedMesh::resetAnimation() +void SkinnedMesh::resetAnimation() { // copy from the cache to the mesh... for (u32 i = 0; i < AllJoints.size(); ++i) { @@ -745,7 +717,7 @@ void CSkinnedMesh::resetAnimation() LastAnimatedFrame = -1; } -void CSkinnedMesh::calculateGlobalMatrices(SJoint *joint, SJoint *parentJoint) +void SkinnedMesh::calculateGlobalMatrices(SJoint *joint, SJoint *parentJoint) { if (!joint && parentJoint) // bit of protection from endless loops return; @@ -775,7 +747,7 @@ void CSkinnedMesh::calculateGlobalMatrices(SJoint *joint, SJoint *parentJoint) SkinnedLastFrame = false; } -void CSkinnedMesh::checkForAnimation() +void SkinnedMesh::checkForAnimation() { u32 i, j; // Check for animation... @@ -868,7 +840,7 @@ void CSkinnedMesh::checkForAnimation() } //! called by loader after populating with mesh and bone data -void CSkinnedMesh::finalize() +void SkinnedMesh::finalize() { os::Printer::log("Skinned Mesh - finalize", ELL_DEBUG); u32 i; @@ -1046,7 +1018,7 @@ void CSkinnedMesh::finalize() } } -void CSkinnedMesh::updateBoundingBox(void) +void SkinnedMesh::updateBoundingBox(void) { if (!SkinningBuffers) return; @@ -1065,7 +1037,7 @@ void CSkinnedMesh::updateBoundingBox(void) } } -scene::SSkinMeshBuffer *CSkinnedMesh::addMeshBuffer() +scene::SSkinMeshBuffer *SkinnedMesh::addMeshBuffer() { scene::SSkinMeshBuffer *buffer = new scene::SSkinMeshBuffer(); TextureSlots.push_back(LocalBuffers.size()); @@ -1073,13 +1045,13 @@ scene::SSkinMeshBuffer *CSkinnedMesh::addMeshBuffer() return buffer; } -void CSkinnedMesh::addMeshBuffer(SSkinMeshBuffer *meshbuf) +void SkinnedMesh::addMeshBuffer(SSkinMeshBuffer *meshbuf) { TextureSlots.push_back(LocalBuffers.size()); LocalBuffers.push_back(meshbuf); } -CSkinnedMesh::SJoint *CSkinnedMesh::addJoint(SJoint *parent) +SkinnedMesh::SJoint *SkinnedMesh::addJoint(SJoint *parent) { SJoint *joint = new SJoint; @@ -1094,7 +1066,7 @@ CSkinnedMesh::SJoint *CSkinnedMesh::addJoint(SJoint *parent) return joint; } -CSkinnedMesh::SPositionKey *CSkinnedMesh::addPositionKey(SJoint *joint) +SkinnedMesh::SPositionKey *SkinnedMesh::addPositionKey(SJoint *joint) { if (!joint) return 0; @@ -1103,7 +1075,7 @@ CSkinnedMesh::SPositionKey *CSkinnedMesh::addPositionKey(SJoint *joint) return &joint->PositionKeys.getLast(); } -CSkinnedMesh::SScaleKey *CSkinnedMesh::addScaleKey(SJoint *joint) +SkinnedMesh::SScaleKey *SkinnedMesh::addScaleKey(SJoint *joint) { if (!joint) return 0; @@ -1112,7 +1084,7 @@ CSkinnedMesh::SScaleKey *CSkinnedMesh::addScaleKey(SJoint *joint) return &joint->ScaleKeys.getLast(); } -CSkinnedMesh::SRotationKey *CSkinnedMesh::addRotationKey(SJoint *joint) +SkinnedMesh::SRotationKey *SkinnedMesh::addRotationKey(SJoint *joint) { if (!joint) return 0; @@ -1121,7 +1093,7 @@ CSkinnedMesh::SRotationKey *CSkinnedMesh::addRotationKey(SJoint *joint) return &joint->RotationKeys.getLast(); } -CSkinnedMesh::SWeight *CSkinnedMesh::addWeight(SJoint *joint) +SkinnedMesh::SWeight *SkinnedMesh::addWeight(SJoint *joint) { if (!joint) return 0; @@ -1130,12 +1102,12 @@ CSkinnedMesh::SWeight *CSkinnedMesh::addWeight(SJoint *joint) return &joint->Weights.getLast(); } -bool CSkinnedMesh::isStatic() +bool SkinnedMesh::isStatic() const { return !HasAnimation; } -void CSkinnedMesh::normalizeWeights() +void SkinnedMesh::normalizeWeights() { // note: unsure if weights ids are going to be used. @@ -1176,7 +1148,7 @@ void CSkinnedMesh::normalizeWeights() } } -void CSkinnedMesh::recoverJointsFromMesh(core::array &jointChildSceneNodes) +void SkinnedMesh::recoverJointsFromMesh(core::array &jointChildSceneNodes) { for (u32 i = 0; i < AllJoints.size(); ++i) { IBoneSceneNode *node = jointChildSceneNodes[i]; @@ -1193,7 +1165,7 @@ void CSkinnedMesh::recoverJointsFromMesh(core::array &jointChi } } -void CSkinnedMesh::transferJointsToMesh(const core::array &jointChildSceneNodes) +void SkinnedMesh::transferJointsToMesh(const core::array &jointChildSceneNodes) { for (u32 i = 0; i < AllJoints.size(); ++i) { const IBoneSceneNode *const node = jointChildSceneNodes[i]; @@ -1214,7 +1186,7 @@ void CSkinnedMesh::transferJointsToMesh(const core::array &joi SkinnedLastFrame = false; } -void CSkinnedMesh::transferOnlyJointsHintsToMesh(const core::array &jointChildSceneNodes) +void SkinnedMesh::transferOnlyJointsHintsToMesh(const core::array &jointChildSceneNodes) { for (u32 i = 0; i < AllJoints.size(); ++i) { const IBoneSceneNode *const node = jointChildSceneNodes[i]; @@ -1227,7 +1199,7 @@ void CSkinnedMesh::transferOnlyJointsHintsToMesh(const core::array &jointChildSceneNodes, +void SkinnedMesh::addJoints(core::array &jointChildSceneNodes, IAnimatedMeshSceneNode *node, ISceneManager *smgr) { // Create new joints @@ -1264,7 +1236,7 @@ void CSkinnedMesh::addJoints(core::array &jointChildSceneNodes SkinnedLastFrame = false; } -void CSkinnedMesh::convertMeshToTangents() +void SkinnedMesh::convertMeshToTangents() { // now calculate tangents for (u32 b = 0; b < LocalBuffers.size(); ++b) { @@ -1315,7 +1287,7 @@ void CSkinnedMesh::convertMeshToTangents() } } -void CSkinnedMesh::calculateTangents( +void SkinnedMesh::calculateTangents( core::vector3df &normal, core::vector3df &tangent, core::vector3df &binormal, diff --git a/src/unittest/test_irr_gltf_mesh_loader.cpp b/src/unittest/test_irr_gltf_mesh_loader.cpp index 2d87db4e3..b1b0d99a1 100644 --- a/src/unittest/test_irr_gltf_mesh_loader.cpp +++ b/src/unittest/test_irr_gltf_mesh_loader.cpp @@ -12,7 +12,7 @@ #include "IFileSystem.h" #include "IReadFile.h" #include "ISceneManager.h" -#include "ISkinnedMesh.h" +#include "SkinnedMesh.h" #include "irrlicht.h" #include "catch.h" @@ -379,14 +379,14 @@ SECTION("simple sparse accessor") // https://github.com/KhronosGroup/glTF-Sample-Models/tree/main/2.0/SimpleSkin SECTION("simple skin") { - using ISkinnedMesh = irr::scene::ISkinnedMesh; + using SkinnedMesh = irr::scene::SkinnedMesh; const auto mesh = loadMesh(model_stem + "simple_skin.gltf"); REQUIRE(mesh != nullptr); - auto csm = dynamic_cast(mesh); + auto csm = dynamic_cast(mesh); const auto joints = csm->getAllJoints(); REQUIRE(joints.size() == 3); - const auto findJoint = [&](const std::function &predicate) { + const auto findJoint = [&](const std::function &predicate) { for (std::size_t i = 0; i < joints.size(); ++i) { if (predicate(joints[i])) { return joints[i]; @@ -420,7 +420,7 @@ SECTION("simple skin") SECTION("weights are correct") { - const auto weights = [&](const ISkinnedMesh::SJoint *joint) { + const auto weights = [&](const SkinnedMesh::SJoint *joint) { std::unordered_map weights; for (std::size_t i = 0; i < joint->Weights.size(); ++i) { const auto weight = joint->Weights[i]; From 05d31222f713cd152b86b589ecb7dec1bc986ad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Fri, 6 Dec 2024 18:05:03 +0100 Subject: [PATCH 101/136] Allow non-normalized weights in glTF models (#15310) We are being lax here, but the glTF specification just requires that "when the weights are stored using float component type, their linear sum SHOULD be as close as reasonably possible to 1.0 for a given vertex" In particular weights > 1 and weight sums well below or above 1 can be observed in models exported by Blender if they aren't manually normalized. These fail the glTF validator but Irrlicht normalizes weights itself so we can support them just fine. The docs have been updated to recommend normalizing weights (as well as documenting the status of interpolation support). Weights < 0, most of them close to 0, also occur. Consistent with Irrlicht, we ignore them, but we also raise a warning. --- doc/lua_api.md | 11 +++++++++-- irr/src/CGLTFMeshFileLoader.cpp | 31 ++++++++++++++++++++----------- irr/src/CGLTFMeshFileLoader.h | 8 ++++---- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index 2d5405090..449309493 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -309,17 +309,24 @@ it unlocks no special rendering features. Binary glTF (`.glb`) files are supported and recommended over `.gltf` files due to their space savings. -This means that many glTF features are not supported *yet*, including: +Bone weights should be normalized, e.g. using ["normalize all" in Blender](https://docs.blender.org/manual/en/4.2/grease_pencil/modes/weight_paint/weights_menu.html#normalize-all). + +You can use the [Khronos glTF validator](https://github.com/KhronosGroup/glTF-Validator) +to check whether a model is a valid glTF file. + +Many glTF features are not supported *yet*, including: * Animations * Only a single animation is supported, use frame ranges within this animation. + * Only linear interpolation is supported. * Cameras * Materials * Only base color textures are supported * Backface culling is overridden * Double-sided materials don't work * Alternative means of supplying data - * Embedded images + * Embedded images. You can use `gltfutil.py` from the + [modding tools](https://github.com/minetest/modtools) to strip or extract embedded images. * References to files via URIs Textures are supplied solely via the same means as for the other model file formats: diff --git a/irr/src/CGLTFMeshFileLoader.cpp b/irr/src/CGLTFMeshFileLoader.cpp index 9045569a6..139b4f670 100644 --- a/irr/src/CGLTFMeshFileLoader.cpp +++ b/irr/src/CGLTFMeshFileLoader.cpp @@ -305,7 +305,7 @@ SelfType::createNormalizedValuesAccessor( } } -template +template std::array SelfType::getNormalizedValues( const NormalizedValuesAccessor &accessor, const std::size_t i) @@ -313,17 +313,19 @@ std::array SelfType::getNormalizedValues( std::array values; if (std::holds_alternative>>(accessor)) { const auto u8s = std::get>>(accessor).get(i); - for (u8 i = 0; i < N; ++i) - values[i] = static_cast(u8s[i]) / std::numeric_limits::max(); + for (std::size_t j = 0; j < N; ++j) + values[j] = static_cast(u8s[j]) / std::numeric_limits::max(); } else if (std::holds_alternative>>(accessor)) { const auto u16s = std::get>>(accessor).get(i); - for (u8 i = 0; i < N; ++i) - values[i] = static_cast(u16s[i]) / std::numeric_limits::max(); + for (std::size_t j = 0; j < N; ++j) + values[j] = static_cast(u16s[j]) / std::numeric_limits::max(); } else { values = std::get>>(accessor).get(i); - for (u8 i = 0; i < N; ++i) { - if (values[i] < 0 || values[i] > 1) - throw std::runtime_error("invalid normalized value"); + if constexpr (validate) { + for (std::size_t j = 0; j < N; ++j) { + if (values[j] < 0 || values[j] > 1) + throw std::runtime_error("invalid normalized value"); + } } } return values; @@ -493,6 +495,7 @@ void SelfType::MeshExtractor::addPrimitive( const auto weightAccessor = createNormalizedValuesAccessor<4>(m_gltf_model, weights->at(set)); + bool negative_weights = false; for (std::size_t v = 0; v < n_vertices; ++v) { std::array jointIdxs; if (std::holds_alternative>>(jointAccessor)) { @@ -501,14 +504,18 @@ void SelfType::MeshExtractor::addPrimitive( } else if (std::holds_alternative>>(jointAccessor)) { jointIdxs = std::get>>(jointAccessor).get(v); } - std::array strengths = getNormalizedValues(weightAccessor, v); + + // Be lax: We can allow weights that aren't normalized. Irrlicht already normalizes them. + // The glTF spec only requires that these be "as close to 1 as reasonably possible". + auto strengths = getNormalizedValues<4, false>(weightAccessor, v); // 4 joints per set for (std::size_t in_set = 0; in_set < 4; ++in_set) { u16 jointIdx = jointIdxs[in_set]; f32 strength = strengths[in_set]; - if (strength == 0) - continue; + negative_weights = negative_weights || (strength < 0); + if (strength <= 0) + continue; // note: also ignores negative weights SkinnedMesh::SWeight *weight = m_irr_model->addWeight(m_loaded_nodes.at(skin.joints.at(jointIdx))); weight->buffer_id = meshbufNr; @@ -516,6 +523,8 @@ void SelfType::MeshExtractor::addPrimitive( weight->strength = strength; } } + if (negative_weights) + warn("negative weights"); } } diff --git a/irr/src/CGLTFMeshFileLoader.h b/irr/src/CGLTFMeshFileLoader.h index 35ee85726..1671d2903 100644 --- a/irr/src/CGLTFMeshFileLoader.h +++ b/irr/src/CGLTFMeshFileLoader.h @@ -91,7 +91,7 @@ private: const tiniergltf::GlTF &model, const std::size_t accessorIdx); - template + template static std::array getNormalizedValues( const NormalizedValuesAccessor &accessor, const std::size_t i); @@ -118,7 +118,7 @@ private: std::size_t getPrimitiveCount(const std::size_t meshIdx) const; void load(); - const std::vector &getWarnings() { + const std::unordered_set &getWarnings() { return warnings; } @@ -129,9 +129,9 @@ private: std::vector> m_mesh_loaders; std::vector m_loaded_nodes; - std::vector warnings; + std::unordered_set warnings; void warn(const std::string &warning) { - warnings.push_back(warning); + warnings.insert(warning); } void copyPositions(const std::size_t accessorIdx, From 88c845166cc364bdc34341620071db9cecaf7f16 Mon Sep 17 00:00:00 2001 From: cx384 Date: Fri, 6 Dec 2024 18:06:27 +0100 Subject: [PATCH 102/136] Fix L-System trees fruit node regression (#15513) --- src/mapgen/treegen.cpp | 3 +-- src/script/common/c_content.cpp | 7 +++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/mapgen/treegen.cpp b/src/mapgen/treegen.cpp index 483ec4797..e03f41482 100644 --- a/src/mapgen/treegen.cpp +++ b/src/mapgen/treegen.cpp @@ -23,8 +23,7 @@ void TreeDef::resolveNodeNames() getIdFromNrBacklog(&leavesnode.param0, "", CONTENT_IGNORE); if (leaves2_chance) getIdFromNrBacklog(&leaves2node.param0, "", CONTENT_IGNORE); - if (fruit_chance) - getIdFromNrBacklog(&fruitnode.param0, "", CONTENT_IGNORE); + getIdFromNrBacklog(&fruitnode.param0, "", CONTENT_IGNORE); } /* diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 6367e53f3..5f000acd8 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -2032,12 +2032,11 @@ bool read_tree_def(lua_State *L, int idx, const NodeDefManager *ndef, getstringfield(L, idx, "trunk_type", tree_def.trunk_type); getboolfield(L, idx, "thin_branches", tree_def.thin_branches); tree_def.fruit_chance = 0; + fruit = "air"; getstringfield(L, idx, "fruit", fruit); - if (!fruit.empty()) { + if (!fruit.empty()) getintfield(L, idx, "fruit_chance", tree_def.fruit_chance); - if (tree_def.fruit_chance) - tree_def.m_nodenames.push_back(fruit); - } + tree_def.m_nodenames.push_back(fruit); tree_def.explicit_seed = getintfield(L, idx, "seed", tree_def.seed); // Resolves the node IDs for trunk, leaves, leaves2 and fruit at runtime, From 5a8412dd23d1632b4ea7ff90635f3f2ec84f30b0 Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Fri, 6 Dec 2024 21:59:51 +0100 Subject: [PATCH 103/136] Formspec: Move tooltip above cursor when lacking space (#15470) --- src/gui/guiFormSpecMenu.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp index 2330f7c32..8a69f0429 100644 --- a/src/gui/guiFormSpecMenu.cpp +++ b/src/gui/guiFormSpecMenu.cpp @@ -3610,10 +3610,25 @@ void GUIFormSpecMenu::showTooltip(const std::wstring &text, // Calculate and set the tooltip position s32 tooltip_x = m_pointer.X + tooltip_offset_x; s32 tooltip_y = m_pointer.Y + tooltip_offset_y; - if (tooltip_x + tooltip_width > (s32)screenSize.X) - tooltip_x = (s32)screenSize.X - tooltip_width - m_btn_height; - if (tooltip_y + tooltip_height > (s32)screenSize.Y) - tooltip_y = (s32)screenSize.Y - tooltip_height - m_btn_height; + // Bottom/Left limited positions (if the tooltip is too far out) + s32 tooltip_x_alt = (s32)screenSize.X - tooltip_width - m_btn_height; + s32 tooltip_y_alt = (s32)screenSize.Y - tooltip_height - m_btn_height; + + int collision = (tooltip_x_alt < tooltip_x) + 2 * (tooltip_y_alt < tooltip_y); + switch (collision) { + case 1: // x + tooltip_x = tooltip_x_alt; + break; + case 2: // y + tooltip_y = tooltip_y_alt; + break; + case 3: // both + tooltip_x = tooltip_x_alt; + tooltip_y = (s32)screenSize.Y - 2 * tooltip_height - m_btn_height; + break; + default: // OK + break; + } m_tooltip_element->setRelativePosition( core::rect( From b8577988484649c2a9f73dedd4a85677343db463 Mon Sep 17 00:00:00 2001 From: veprogames <75524847+veprogames@users.noreply.github.com> Date: Fri, 6 Dec 2024 22:00:06 +0100 Subject: [PATCH 104/136] Fix distorted Sun, Moon and Star visuals based on Orbit Tilt (#15459) --- src/client/sky.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/client/sky.cpp b/src/client/sky.cpp index 8da7fc68e..f0cb560d7 100644 --- a/src/client/sky.cpp +++ b/src/client/sky.cpp @@ -661,7 +661,9 @@ void Sky::draw_stars(video::IVideoDriver * driver, float wicked_time_of_day) return; m_materials[0].ColorParam = color.toSColor(); - auto sky_rotation = core::matrix4().setRotationAxisRadians(2.0f * M_PI * (wicked_time_of_day - 0.25f), v3f(0.0f, 0.0f, 1.0f)); + auto day_rotation = core::matrix4().setRotationAxisRadians(2.0f * M_PI * (wicked_time_of_day - 0.25f), v3f(0.0f, 0.0f, 1.0f)); + auto orbit_rotation = core::matrix4().setRotationAxisRadians(m_sky_params.body_orbit_tilt * M_PI / 180.0, v3f(1.0f, 0.0f, 0.0f)); + auto sky_rotation = orbit_rotation * day_rotation; auto world_matrix = driver->getTransform(video::ETS_WORLD); driver->setTransform(video::ETS_WORLD, world_matrix * sky_rotation); driver->setMaterial(m_materials[0]); @@ -695,13 +697,11 @@ void Sky::place_sky_body( * day_position: turn the body around the Z axis, to place it depending of the time of the day */ { - v3f centrum = getSkyBodyPosition(horizon_position, day_position, m_sky_params.body_orbit_tilt); - v3f untilted_centrum = getSkyBodyPosition(horizon_position, day_position, 0.f); for (video::S3DVertex &vertex : vertices) { // Body is directed to -Z (south) by default vertex.Pos.rotateXZBy(horizon_position); vertex.Pos.rotateXYBy(day_position); - vertex.Pos += centrum - untilted_centrum; + vertex.Pos.rotateYZBy(m_sky_params.body_orbit_tilt); } } From ae96a8d4fa9ade70672fe8d2152013c547edfb47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Fri, 6 Dec 2024 22:01:31 +0100 Subject: [PATCH 105/136] Fix mainmenu crash if no servers match search fixes a regression caused by 6c324cb --- builtin/mainmenu/tab_online.lua | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua index 6545569b2..422e9ba23 100644 --- a/builtin/mainmenu/tab_online.lua +++ b/builtin/mainmenu/tab_online.lua @@ -57,6 +57,11 @@ end -- Persists the selected server in the "address" and "remote_port" settings local function set_selected_server(server) + if server == nil then -- reset selection + core.settings:remove("address") + core.settings:remove("remote_port") + return + end local address = server.address local port = server.port gamedata.serverdescription = server.description @@ -360,6 +365,7 @@ local function main_button_handler(tabview, fields, name, tabdata) tabdata.search_for = fields.te_search search_server_list(fields.te_search:lower()) if menudata.search_result then + -- Note: This clears the selection if there are no results set_selected_server(menudata.search_result[1]) end From 8d43ad252275999d66a47ba40219c8e014fe4917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Sun, 8 Dec 2024 19:48:52 +0100 Subject: [PATCH 106/136] Migrate rendered Lua API docs CNAME to `api.luanti.org` --- CNAME | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CNAME b/CNAME index c8f58d469..cd4ccafcc 100644 --- a/CNAME +++ b/CNAME @@ -1 +1 @@ -api.minetest.net +api.luanti.org From c7fe2ee5c9c84284d54c8dda20c57c759f63f821 Mon Sep 17 00:00:00 2001 From: cx384 Date: Sun, 8 Dec 2024 20:27:22 +0100 Subject: [PATCH 107/136] Add `core.spawn_tree_on_vmanip` (#15415) This function works like `core.spawn_tree`, but spawns an L-system tree onto a VoxelManip object instead on the map. --- doc/lua_api.md | 3 + games/devtest/mods/testitems/init.lua | 65 ++++++++++++++++++ .../textures/testitems_tree_spawner.png | Bin 0 -> 120 bytes .../testitems_tree_spawner_vmanip.png | Bin 0 -> 150 bytes src/mapgen/treegen.cpp | 11 +++ src/mapgen/treegen.h | 3 + src/script/lua_api/l_env.cpp | 12 +--- src/script/lua_api/l_mapgen.cpp | 23 +++++++ src/script/lua_api/l_mapgen.h | 3 + 9 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 games/devtest/mods/testitems/textures/testitems_tree_spawner.png create mode 100644 games/devtest/mods/testitems/textures/testitems_tree_spawner_vmanip.png diff --git a/doc/lua_api.md b/doc/lua_api.md index 449309493..c4c74d884 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -6588,6 +6588,9 @@ Environment access on-the-fly * `core.spawn_tree (pos, {treedef})` * spawns L-system tree at given `pos` with definition in `treedef` table +* `core.spawn_tree_on_vmanip(vmanip, pos, treedef)` + * analogous to `core.spawn_tree`, but spawns a L-system tree onto the specified + VoxelManip object `vmanip` instead of the map. * `core.transforming_liquid_add(pos)` * add node to liquid flow update queue * `core.get_node_max_level(pos)` diff --git a/games/devtest/mods/testitems/init.lua b/games/devtest/mods/testitems/init.lua index 12da2ad1c..71a85ef6d 100644 --- a/games/devtest/mods/testitems/init.lua +++ b/games/devtest/mods/testitems/init.lua @@ -105,3 +105,68 @@ core.register_craftitem("testitems:telescope_stick", { return itemstack end, }) + + +-- Tree spawners + +local tree_def={ + axiom="Af", + rules_a="TT[&GB][&+GB][&++GB][&+++GB]A", + rules_b="[+GB]fB", + trunk="basenodes:tree", + leaves="basenodes:leaves", + angle=90, + iterations=4, + trunk_type="single", + thin_branches=true, +} + +core.register_craftitem("testitems:tree_spawner", { + description = S("Tree Spawner"), + inventory_image = "testitems_tree_spawner.png", + on_place = function(itemstack, placer, pointed_thing) + if (not pointed_thing or pointed_thing.type ~= "node") then + return + end + core.spawn_tree(pointed_thing.above, tree_def) + end, +}) + +local vmanip_for_trees = {} -- per player +core.register_craftitem("testitems:tree_spawner_vmanip", { + description = S("Tree Spawner using VoxelManip"), + inventory_image = "testitems_tree_spawner_vmanip.png", + on_place = function(itemstack, placer, pointed_thing) + if (not pointed_thing or pointed_thing.type ~= "node" or + not core.is_player(placer)) then + return + end + local name = placer:get_player_name() + local vm = vmanip_for_trees[name] + if not vm then + vm = VoxelManip(vector.add(pointed_thing.above, 20), + vector.subtract(pointed_thing.above, 20)) + vmanip_for_trees[name] = vm + core.chat_send_player(name, + "Tree in new VoxelManip spawned, left click to apply to map, ".. + "or right click to add more trees.") + end + core.spawn_tree_on_vmanip(vm, pointed_thing.above, tree_def) + end, + on_use = function(itemstack, user, pointed_thing) + if not core.is_player(user) then + return + end + local name = user:get_player_name() + local vm = vmanip_for_trees[name] + if vm then + vm:write_to_map() + vmanip_for_trees[name] = nil + core.chat_send_player(name, "VoxelManip written to map.") + end + end, +}) + +core.register_on_leaveplayer(function(player, timed_out) + vmanip_for_trees[player:get_player_name()] = nil +end) diff --git a/games/devtest/mods/testitems/textures/testitems_tree_spawner.png b/games/devtest/mods/testitems/textures/testitems_tree_spawner.png new file mode 100644 index 0000000000000000000000000000000000000000..aa743067735eb222486e5ca17a3d1b7a13bd1dec GIT binary patch literal 120 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`_MR?|Ar`&K2@+Qhm`s0b&oMc- zVez&j^#aTGGa4*E%%gByoB1*8jN*-zjVbvTu5+I_cjP(iq&-FjoSj*00?Z7&wjPU5 Tw9R}8G>XB~)z4*}Q$iB}CYvYN literal 0 HcmV?d00001 diff --git a/games/devtest/mods/testitems/textures/testitems_tree_spawner_vmanip.png b/games/devtest/mods/testitems/textures/testitems_tree_spawner_vmanip.png new file mode 100644 index 0000000000000000000000000000000000000000..2d8e0311fa9bf3557f77da69f34bd92fe1d128cd GIT binary patch literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`v7RoDAr`&K2@+Qhm`s0b&oMc- zVez&j^#aTGGa4*E%%gByoB1*8jN*-zjVbvPo;EFiAM;SkVOC;|KyPpF!;%Rso5T}p ya!ee<8!~2yPdIuZ)~l9zg6U%E2HiCpObn^k?WY#Zyy6G6h{4m<&t;ucLK6TG4K+ak literal 0 HcmV?d00001 diff --git a/src/mapgen/treegen.cpp b/src/mapgen/treegen.cpp index e03f41482..688833fa2 100644 --- a/src/mapgen/treegen.cpp +++ b/src/mapgen/treegen.cpp @@ -875,4 +875,15 @@ void make_pine_tree(MMVManip &vmanip, v3s16 p0, const NodeDefManager *ndef, } } +std::string error_to_string(error e) +{ + switch (e) { + case SUCCESS: + return "success"; + case UNBALANCED_BRACKETS: + return "closing ']' has no matching opening bracket"; + } + return "unknown error"; +} + }; // namespace treegen diff --git a/src/mapgen/treegen.h b/src/mapgen/treegen.h index 159063eb3..dba7ea047 100644 --- a/src/mapgen/treegen.h +++ b/src/mapgen/treegen.h @@ -68,4 +68,7 @@ namespace treegen { treegen::error make_ltree(MMVManip &vmanip, v3s16 p0, const TreeDef &def); // Helper to spawn it directly on map treegen::error spawn_ltree(ServerMap *map, v3s16 p0, const TreeDef &def); + + // Helper to get a string from the error message + std::string error_to_string(error e); }; // namespace treegen diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 666dee712..5ebb2c3e4 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -1307,11 +1307,7 @@ int ModApiEnv::l_spawn_tree(lua_State *L) ServerMap *map = &env->getServerMap(); treegen::error e; if ((e = treegen::spawn_ltree (map, p0, tree_def)) != treegen::SUCCESS) { - if (e == treegen::UNBALANCED_BRACKETS) { - luaL_error(L, "spawn_tree(): closing ']' has no matching opening bracket"); - } else { - luaL_error(L, "spawn_tree(): unknown error"); - } + throw LuaError("spawn_tree(): " + treegen::error_to_string(e)); } lua_pushboolean(L, true); @@ -1614,11 +1610,7 @@ int ModApiEnvVM::l_spawn_tree(lua_State *L) treegen::error e; if ((e = treegen::make_ltree(*vm, p0, tree_def)) != treegen::SUCCESS) { - if (e == treegen::UNBALANCED_BRACKETS) { - throw LuaError("spawn_tree(): closing ']' has no matching opening bracket"); - } else { - throw LuaError("spawn_tree(): unknown error"); - } + throw LuaError("spawn_tree(): " + treegen::error_to_string(e)); } lua_pushboolean(L, true); diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index 89323b2f6..d102b357f 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -1773,6 +1773,27 @@ int ModApiMapgen::l_place_schematic_on_vmanip(lua_State *L) return 1; } +// spawn_tree_on_vmanip(vmanip, pos, treedef) +int ModApiMapgen::l_spawn_tree_on_vmanip(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + MMVManip *vm = checkObject(L, 1)->vm; + v3s16 p0 = read_v3s16(L, 2); + treegen::TreeDef tree_def; + const NodeDefManager *ndef = getGameDef(L)->ndef(); + if (!read_tree_def(L, 3, ndef, tree_def)) + return 0; + + treegen::error e = treegen::make_ltree(*vm, p0, tree_def); + if (e != treegen::SUCCESS) { + throw LuaError("spawn_tree_on_vmanip(): " + treegen::error_to_string(e)); + } + + lua_pushboolean(L, true); + return 1; +} + // serialize_schematic(schematic, format, options={...}) int ModApiMapgen::l_serialize_schematic(lua_State *L) @@ -2023,6 +2044,7 @@ void ModApiMapgen::Initialize(lua_State *L, int top) API_FCT(create_schematic); API_FCT(place_schematic); API_FCT(place_schematic_on_vmanip); + API_FCT(spawn_tree_on_vmanip); API_FCT(serialize_schematic); API_FCT(read_schematic); } @@ -2049,6 +2071,7 @@ void ModApiMapgen::InitializeEmerge(lua_State *L, int top) API_FCT(generate_ores); API_FCT(generate_decorations); API_FCT(place_schematic_on_vmanip); + API_FCT(spawn_tree_on_vmanip); API_FCT(serialize_schematic); API_FCT(read_schematic); } diff --git a/src/script/lua_api/l_mapgen.h b/src/script/lua_api/l_mapgen.h index d72cbcbad..860daa7e8 100644 --- a/src/script/lua_api/l_mapgen.h +++ b/src/script/lua_api/l_mapgen.h @@ -131,6 +131,9 @@ private: // replacements, force_placement, flagstring) static int l_place_schematic_on_vmanip(lua_State *L); + // spawn_tree_on_vmanip(vmanip, pos, treedef) + static int l_spawn_tree_on_vmanip(lua_State *L); + // serialize_schematic(schematic, format, options={...}) static int l_serialize_schematic(lua_State *L); From 50928b97593ba6381ec776e0408aad92761c0840 Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Thu, 28 Nov 2024 19:16:07 +0100 Subject: [PATCH 108/136] Mapgen: Add rudimentary unittests --- src/mapgen/mg_biome.cpp | 28 ++------ src/mapgen/mg_biome.h | 52 ++++++++------- src/script/lua_api/l_mapgen.cpp | 25 +++---- src/unittest/CMakeLists.txt | 1 + src/unittest/test_mapgen.cpp | 114 ++++++++++++++++++++++++++++++++ 5 files changed, 162 insertions(+), 58 deletions(-) create mode 100644 src/unittest/test_mapgen.cpp diff --git a/src/mapgen/mg_biome.cpp b/src/mapgen/mg_biome.cpp index a1c4f5810..788bacede 100644 --- a/src/mapgen/mg_biome.cpp +++ b/src/mapgen/mg_biome.cpp @@ -25,21 +25,7 @@ BiomeManager::BiomeManager(Server *server) : // Create default biome to be used in case none exist Biome *b = new Biome; - b->name = "default"; - b->flags = 0; - b->depth_top = 0; - b->depth_filler = -MAX_MAP_GENERATION_LIMIT; - b->depth_water_top = 0; - b->depth_riverbed = 0; - b->min_pos = v3s16(-MAX_MAP_GENERATION_LIMIT, - -MAX_MAP_GENERATION_LIMIT, -MAX_MAP_GENERATION_LIMIT); - b->max_pos = v3s16(MAX_MAP_GENERATION_LIMIT, - MAX_MAP_GENERATION_LIMIT, MAX_MAP_GENERATION_LIMIT); - b->heat_point = 0.0; - b->humidity_point = 0.0; - b->vertical_blend = 0; - b->weight = 1.0f; b->m_nodenames.emplace_back("mapgen_stone"); b->m_nodenames.emplace_back("mapgen_stone"); @@ -64,11 +50,13 @@ void BiomeManager::clear() { EmergeManager *emerge = m_server->getEmergeManager(); - // Remove all dangling references in Decorations - DecorationManager *decomgr = emerge->getWritableDecorationManager(); - for (size_t i = 0; i != decomgr->getNumObjects(); i++) { - Decoration *deco = (Decoration *)decomgr->getRaw(i); - deco->biomes.clear(); + if (emerge) { + // Remove all dangling references in Decorations + DecorationManager *decomgr = emerge->getWritableDecorationManager(); + for (size_t i = 0; i != decomgr->getNumObjects(); i++) { + Decoration *deco = (Decoration *)decomgr->getRaw(i); + deco->biomes.clear(); + } } // Don't delete the first biome @@ -299,8 +287,6 @@ ObjDef *Biome::clone() const ObjDef::cloneTo(obj); NodeResolver::cloneTo(obj); - obj->flags = flags; - obj->c_top = c_top; obj->c_filler = c_filler; obj->c_stone = c_stone; diff --git a/src/mapgen/mg_biome.h b/src/mapgen/mg_biome.h index 3e9de89d9..637ec14b1 100644 --- a/src/mapgen/mg_biome.h +++ b/src/mapgen/mg_biome.h @@ -19,6 +19,12 @@ class BiomeManager; typedef u16 biome_t; +constexpr v3s16 MAX_MAP_GENERATION_LIMIT_V3( + MAX_MAP_GENERATION_LIMIT, + MAX_MAP_GENERATION_LIMIT, + MAX_MAP_GENERATION_LIMIT +); + #define BIOME_NONE ((biome_t)0) enum BiomeType { @@ -29,32 +35,32 @@ class Biome : public ObjDef, public NodeResolver { public: ObjDef *clone() const; - u32 flags; - - content_t c_top; - content_t c_filler; - content_t c_stone; - content_t c_water_top; - content_t c_water; - content_t c_river_water; - content_t c_riverbed; - content_t c_dust; + content_t + c_top = CONTENT_IGNORE, + c_filler = CONTENT_IGNORE, + c_stone = CONTENT_IGNORE, + c_water_top = CONTENT_IGNORE, + c_water = CONTENT_IGNORE, + c_river_water = CONTENT_IGNORE, + c_riverbed = CONTENT_IGNORE, + c_dust = CONTENT_IGNORE; std::vector c_cave_liquid; - content_t c_dungeon; - content_t c_dungeon_alt; - content_t c_dungeon_stair; + content_t + c_dungeon = CONTENT_IGNORE, + c_dungeon_alt = CONTENT_IGNORE, + c_dungeon_stair = CONTENT_IGNORE; - s16 depth_top; - s16 depth_filler; - s16 depth_water_top; - s16 depth_riverbed; + s16 depth_top = 0; + s16 depth_filler = -MAX_MAP_GENERATION_LIMIT; + s16 depth_water_top = 0; + s16 depth_riverbed = 0; - v3s16 min_pos; - v3s16 max_pos; - float heat_point; - float humidity_point; - s16 vertical_blend; - float weight; + v3s16 min_pos = -MAX_MAP_GENERATION_LIMIT_V3; + v3s16 max_pos = MAX_MAP_GENERATION_LIMIT_V3; + float heat_point = 0.0f; + float humidity_point = 0.0f; + s16 vertical_blend = 0; + float weight = 1.0f; virtual void resolveNodeNames(); }; diff --git a/src/script/lua_api/l_mapgen.cpp b/src/script/lua_api/l_mapgen.cpp index d102b357f..a7101ee92 100644 --- a/src/script/lua_api/l_mapgen.cpp +++ b/src/script/lua_api/l_mapgen.cpp @@ -366,22 +366,19 @@ Biome *read_biome_def(lua_State *L, int index, const NodeDefManager *ndef) ModApiMapgen::es_BiomeTerrainType, BIOMETYPE_NORMAL); Biome *b = BiomeManager::create(biometype); - b->name = getstringfield_default(L, index, "name", ""); - b->depth_top = getintfield_default(L, index, "depth_top", 0); - b->depth_filler = getintfield_default(L, index, "depth_filler", -31000); - b->depth_water_top = getintfield_default(L, index, "depth_water_top", 0); - b->depth_riverbed = getintfield_default(L, index, "depth_riverbed", 0); - b->heat_point = getfloatfield_default(L, index, "heat_point", 0.f); - b->humidity_point = getfloatfield_default(L, index, "humidity_point", 0.f); - b->vertical_blend = getintfield_default(L, index, "vertical_blend", 0); - b->weight = getfloatfield_default(L, index, "weight", 1.f); - b->flags = 0; // reserved + getstringfield(L, index, "name", b->name); + getintfield(L, index, "depth_top", b->depth_top); + getintfield(L, index, "depth_filler", b->depth_filler); + getintfield(L, index, "depth_water_top", b->depth_water_top); + getintfield(L, index, "depth_riverbed", b->depth_riverbed); + getfloatfield(L, index, "heat_point", b->heat_point); + getfloatfield(L, index, "humidity_point", b->humidity_point); + getintfield(L, index, "vertical_blend", b->vertical_blend); + getfloatfield(L, index, "weight", b->weight); - b->min_pos = getv3s16field_default( - L, index, "min_pos", v3s16(-31000, -31000, -31000)); + b->min_pos = getv3s16field_default(L, index, "min_pos", b->min_pos); getintfield(L, index, "y_min", b->min_pos.Y); - b->max_pos = getv3s16field_default( - L, index, "max_pos", v3s16(31000, 31000, 31000)); + b->max_pos = getv3s16field_default(L, index, "max_pos", b->max_pos); getintfield(L, index, "y_max", b->max_pos.Y); std::vector &nn = b->m_nodenames; diff --git a/src/unittest/CMakeLists.txt b/src/unittest/CMakeLists.txt index 46e4f9a18..2b70a6918 100644 --- a/src/unittest/CMakeLists.txt +++ b/src/unittest/CMakeLists.txt @@ -17,6 +17,7 @@ set (UNITTEST_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/test_lua.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_map.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_mapblock.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test_mapgen.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_map_settings_manager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_mapnode.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_modchannels.cpp diff --git a/src/unittest/test_mapgen.cpp b/src/unittest/test_mapgen.cpp new file mode 100644 index 000000000..f72e85ba3 --- /dev/null +++ b/src/unittest/test_mapgen.cpp @@ -0,0 +1,114 @@ +// Luanti +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright (C) 2024 Minetest core developers & community + +#include "test.h" + +#include "emerge.h" +#include "mapgen/mapgen.h" +#include "mapgen/mg_biome.h" +#include "mock_server.h" + +class TestMapgen : public TestBase +{ +public: + TestMapgen() { TestManager::registerTestModule(this); } + const char *getName() { return "TestMapgen"; } + + void runTests(IGameDef *gamedef); + + void testBiomeGen(IGameDef *gamedef); +}; + +static TestMapgen g_test_instance; + +namespace { + class MockBiomeManager : public BiomeManager { + public: + MockBiomeManager(Server *server) : BiomeManager(server) {} + + void setNodeDefManager(const NodeDefManager *ndef) + { + m_ndef = ndef; + } + }; +} + +void TestMapgen::runTests(IGameDef *gamedef) +{ + TEST(testBiomeGen, gamedef); +} + +void TestMapgen::testBiomeGen(IGameDef *gamedef) +{ + MockServer server(getTestTempDirectory()); + MockBiomeManager bmgr(&server); + bmgr.setNodeDefManager(gamedef->getNodeDefManager()); + + { + // Add some biomes (equivalent to l_register_biome) + // Taken from minetest_game/mods/default/mapgen.lua + size_t bmgr_count = bmgr.getNumObjects(); // this is 1 ? + + Biome *b = BiomeManager::create(BIOMETYPE_NORMAL); + b->name = "deciduous_forest"; + b->c_top = t_CONTENT_GRASS; + b->depth_top = 1; + b->c_filler = t_CONTENT_BRICK; // dirt + b->depth_filler = 3; + b->c_stone = t_CONTENT_STONE; + b->min_pos.Y = 1; + b->heat_point = 60.0f; + b->humidity_point = 68.0f; + UASSERT(bmgr.add(b) != OBJDEF_INVALID_HANDLE); + + b = BiomeManager::create(BIOMETYPE_NORMAL); + b->name = "deciduous_forest_shore"; + b->c_top = t_CONTENT_BRICK; // dirt + b->depth_top = 1; + b->c_filler = t_CONTENT_BRICK; // dirt + b->depth_filler = 3; + b->c_stone = t_CONTENT_STONE; + b->max_pos.Y = 0; + b->heat_point = 60.0f; + b->humidity_point = 68.0f; + UASSERT(bmgr.add(b) != OBJDEF_INVALID_HANDLE); + UASSERT(bmgr.getNumObjects() - bmgr_count == 2); + } + + + std::unique_ptr params(BiomeManager::createBiomeParams(BIOMEGEN_ORIGINAL)); + + constexpr v3s16 CSIZE(16, 16, 16); // misleading name. measured in nodes. + std::unique_ptr biomegen( + bmgr.createBiomeGen(BIOMEGEN_ORIGINAL, params.get(), CSIZE) + ); + + { + // Test biome transitions + // getBiomeAtIndex (Y only) + // getNextTransitionY + const struct { + s16 check_y; + const char *name; + s16 next_y; + } expected_biomes[] = { + { MAX_MAP_GENERATION_LIMIT, "deciduous_forest", 1 }, + // ^ FIXME: next_y should be 0 (min_pos.Y - 1) + { 1, "deciduous_forest", 0 }, + { 0, "deciduous_forest_shore", -MAX_MAP_GENERATION_LIMIT }, + { -100, "deciduous_forest_shore", -MAX_MAP_GENERATION_LIMIT }, + }; + for (const auto expected : expected_biomes) { + Biome *biome = biomegen->getBiomeAtIndex( + (1 * CSIZE.X) + 1, // index in CSIZE 2D noise map + v3s16(2000, expected.check_y, -1000) // absolute coordinates + ); + s16 next_y = biomegen->getNextTransitionY(expected.check_y); + + UASSERTEQ(auto, biome->name, expected.name); + UASSERTEQ(auto, next_y, expected.next_y); + } + } +} + From 480eb7d816db5b1a8073d188f46e4d1e0b36bc53 Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Thu, 28 Nov 2024 22:12:24 +0100 Subject: [PATCH 109/136] Mapgen: Fix biome Y calculation regression BiomeGen::getNextTransitionY(y) did not guarantee the condition (y < biome_y_min) of the next loop because the function may return the value (biome_y_min - 1). Hence, the biome was not updated until one Y coordinate after. --- src/mapgen/cavegen.cpp | 8 ++++---- src/mapgen/mapgen.cpp | 16 +++++++++++----- src/mapgen/mg_biome.cpp | 5 ++++- src/mapgen/mg_biome.h | 3 ++- src/unittest/test_mapgen.cpp | 7 +++---- 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/mapgen/cavegen.cpp b/src/mapgen/cavegen.cpp index f422db67d..6bb841ab5 100644 --- a/src/mapgen/cavegen.cpp +++ b/src/mapgen/cavegen.cpp @@ -84,7 +84,7 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm, u16 depth_riverbed = biome->depth_riverbed; u16 nplaced = 0; - s16 biome_y_min = m_bmgn->getNextTransitionY(nmax.Y); + s16 biome_y_next = m_bmgn->getNextTransitionY(nmax.Y); // Don't excavate the overgenerated stone at nmax.Y + 1, // this creates a 'roof' over the tunnel, preventing light in @@ -94,13 +94,13 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm, index3d -= m_ystride, VoxelArea::add_y(em, vi, -1)) { // We need this check to make sure that biomes don't generate too far down - if (y < biome_y_min) { + if (y <= biome_y_next) { biome = m_bmgn->getBiomeAtIndex(index2d, v3s16(x, y, z)); - biome_y_min = m_bmgn->getNextTransitionY(y); + biome_y_next = m_bmgn->getNextTransitionY(y); if (x == nmin.X && z == nmin.Z && false) { dstream << "cavegen: biome at " << y << " is " << biome->name - << ", next at " << biome_y_min << std::endl; + << ", next at " << biome_y_next << std::endl; } } diff --git a/src/mapgen/mapgen.cpp b/src/mapgen/mapgen.cpp index dd416a3e4..d236132df 100644 --- a/src/mapgen/mapgen.cpp +++ b/src/mapgen/mapgen.cpp @@ -644,7 +644,7 @@ void MapgenBasic::generateBiomes() u16 depth_riverbed = 0; u32 vi = vm->m_area.index(x, node_max.Y, z); - s16 biome_y_min = biomegen->getNextTransitionY(node_max.Y); + s16 biome_y_next = biomegen->getNextTransitionY(node_max.Y); // Check node at base of mapchunk above, either a node of a previously // generated mapchunk or if not, a node of overgenerated base terrain. @@ -661,23 +661,29 @@ void MapgenBasic::generateBiomes() for (s16 y = node_max.Y; y >= node_min.Y; y--) { content_t c = vm->m_data[vi].getContent(); + const bool biome_outdated = !biome || y <= biome_y_next; // Biome is (re)calculated: // 1. At the surface of stone below air or water. // 2. At the surface of water below air. // 3. When stone or water is detected but biome has not yet been calculated. // 4. When stone or water is detected just below a biome's lower limit. bool is_stone_surface = (c == c_stone) && - (air_above || water_above || !biome || y < biome_y_min); // 1, 3, 4 + (air_above || water_above || biome_outdated); // 1, 3, 4 bool is_water_surface = (c == c_water_source || c == c_river_water_source) && - (air_above || !biome || y < biome_y_min); // 2, 3, 4 + (air_above || biome_outdated); // 2, 3, 4 if (is_stone_surface || is_water_surface) { - if (!biome || y < biome_y_min) { + if (biome_outdated) { // (Re)calculate biome biome = biomegen->getBiomeAtIndex(index, v3s16(x, y, z)); - biome_y_min = biomegen->getNextTransitionY(y); + biome_y_next = biomegen->getNextTransitionY(y); + + if (x == node_min.X && z == node_min.Z && false) { + dstream << "biomegen: biome at " << y << " is " << biome->name + << ", next at " << biome_y_next << std::endl; + } } // Add biome to biomemap at first stone surface detected diff --git a/src/mapgen/mg_biome.cpp b/src/mapgen/mg_biome.cpp index 788bacede..a0bb6dee2 100644 --- a/src/mapgen/mg_biome.cpp +++ b/src/mapgen/mg_biome.cpp @@ -129,7 +129,10 @@ BiomeGenOriginal::BiomeGenOriginal(BiomeManager *biomemgr, for (size_t i = 0; i < m_bmgr->getNumObjects(); i++) { Biome *b = (Biome *)m_bmgr->getRaw(i); values.push_back(b->max_pos.Y); - values.push_back(b->min_pos.Y); + // We scan for biomes from high Y to low Y (top to bottom). Hence, + // biomes effectively transition at (min_pos.Y - 1). + if (b->min_pos.Y > -MAX_MAP_GENERATION_LIMIT) + values.push_back(b->min_pos.Y - 1); } std::sort(values.begin(), values.end(), std::greater<>()); diff --git a/src/mapgen/mg_biome.h b/src/mapgen/mg_biome.h index 637ec14b1..8adce5db6 100644 --- a/src/mapgen/mg_biome.h +++ b/src/mapgen/mg_biome.h @@ -197,7 +197,8 @@ private: Noise *noise_heat_blend; Noise *noise_humidity_blend; - // ordered descending + /// Y values at which biomes may transition. + /// This array may only be used for downwards scanning! std::vector m_transitions_y; }; diff --git a/src/unittest/test_mapgen.cpp b/src/unittest/test_mapgen.cpp index f72e85ba3..62bd7e54f 100644 --- a/src/unittest/test_mapgen.cpp +++ b/src/unittest/test_mapgen.cpp @@ -93,11 +93,10 @@ void TestMapgen::testBiomeGen(IGameDef *gamedef) const char *name; s16 next_y; } expected_biomes[] = { - { MAX_MAP_GENERATION_LIMIT, "deciduous_forest", 1 }, - // ^ FIXME: next_y should be 0 (min_pos.Y - 1) + { MAX_MAP_GENERATION_LIMIT, "deciduous_forest", 0 }, { 1, "deciduous_forest", 0 }, - { 0, "deciduous_forest_shore", -MAX_MAP_GENERATION_LIMIT }, - { -100, "deciduous_forest_shore", -MAX_MAP_GENERATION_LIMIT }, + { 0, "deciduous_forest_shore", S16_MIN }, + { -100, "deciduous_forest_shore", S16_MIN }, }; for (const auto expected : expected_biomes) { Biome *biome = biomegen->getBiomeAtIndex( From eb6731bdc698fcef9f97061ed9d90d92324393a5 Mon Sep 17 00:00:00 2001 From: siliconsniffer <97843108+siliconsniffer@users.noreply.github.com> Date: Sun, 8 Dec 2024 20:28:37 +0100 Subject: [PATCH 110/136] Main menu: Add server favorite button (#15486) This adopts PR 13446. --- builtin/mainmenu/tab_online.lua | 37 +++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua index 422e9ba23..112c17457 100644 --- a/builtin/mainmenu/tab_online.lua +++ b/builtin/mainmenu/tab_online.lua @@ -55,7 +55,20 @@ local function get_sorted_servers() return servers end +local function is_selected_fav(server) + local address = core.settings:get("address") + local port = tonumber(core.settings:get("remote_port")) + + for _, fav in ipairs(serverlistmgr.get_favorites()) do + if address == fav.address and port == fav.port then + return true + end + end + return false +end + -- Persists the selected server in the "address" and "remote_port" settings + local function set_selected_server(server) if server == nil then -- reset selection core.settings:remove("address") @@ -66,14 +79,6 @@ local function set_selected_server(server) local port = server.port gamedata.serverdescription = server.description - gamedata.fav = false - for _, fav in ipairs(serverlistmgr.get_favorites()) do - if address == fav.address and port == fav.port then - gamedata.fav = true - break - end - end - if address and port then core.settings:set("address", address) core.settings:set("remote_port", port) @@ -165,15 +170,20 @@ local function get_formspec(tabview, name, tabdata) fgettext("Clients:\n$1", table.concat(clients_list, "\n")) .. "]" end retval = retval .. "style[btn_view_clients;padding=6]" - retval = retval .. "image_button[5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir .. + retval = retval .. "image_button[4.5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir .. "server_view_clients.png") .. ";btn_view_clients;]" end - if gamedata.fav then + if is_selected_fav() then retval = retval .. "tooltip[btn_delete_favorite;" .. fgettext("Remove favorite") .. "]" retval = retval .. "style[btn_delete_favorite;padding=6]" - retval = retval .. "image_button[" .. (can_view_clients_list and "4.5" or "5") .. ",1.3;0.5,0.5;" .. + retval = retval .. "image_button[5,1.3;0.5,0.5;" .. core.formspec_escape(defaulttexturedir .. "server_favorite_delete.png") .. ";btn_delete_favorite;]" + else + retval = retval .. "tooltip[btn_add_favorite;" .. fgettext("Add favorite") .. "]" + retval = retval .. "style[btn_add_favorite;padding=6]" + retval = retval .. "image_button[5,1.3;0.5,0.5;" .. + core.formspec_escape(defaulttexturedir .. "server_favorite.png") .. ";btn_add_favorite;]" end end @@ -336,6 +346,11 @@ local function main_button_handler(tabview, fields, name, tabdata) end end + if fields.btn_add_favorite then + serverlistmgr.add_favorite(find_selected_server()) + return true + end + if fields.btn_delete_favorite then local idx = core.get_table_index("servers") if not idx then return end From 21437090b80275f7967b7f5927ae0ead7f49d2e1 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 7 Dec 2024 12:59:40 +0100 Subject: [PATCH 111/136] Don't recalculate meshnode normals unnecessarily --- src/client/content_mapblock.cpp | 28 +++++++++++++++------------- src/client/mesh.cpp | 4 ++-- src/client/mesh.h | 2 +- src/nodedef.cpp | 7 +++++-- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index 2d294953a..25d303156 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -1644,7 +1644,6 @@ void MapblockMeshGenerator::drawMeshNode() { u8 facedir = 0; scene::IMesh* mesh; - bool private_mesh; // as a grab/drop pair is not thread-safe int degrotate = 0; if (cur_node.f->param_type_2 == CPT2_FACEDIR || @@ -1664,32 +1663,37 @@ void MapblockMeshGenerator::drawMeshNode() if (cur_node.f->mesh_ptr) { // clone and rotate mesh - private_mesh = true; mesh = cloneMesh(cur_node.f->mesh_ptr); + bool modified = true; if (facedir) rotateMeshBy6dFacedir(mesh, facedir); else if (degrotate) rotateMeshXZby(mesh, 1.5f * degrotate); - recalculateBoundingBox(mesh); - meshmanip->recalculateNormals(mesh, true, false); + else + modified = false; + if (modified) { + recalculateBoundingBox(mesh); + // FIXME: we should rotate the normals too, instead of recalculating + meshmanip->recalculateNormals(mesh, true, false); + } } else { warningstream << "drawMeshNode(): missing mesh" << std::endl; return; } - int mesh_buffer_count = mesh->getMeshBufferCount(); - for (int j = 0; j < mesh_buffer_count; j++) { + for (u32 j = 0; j < mesh->getMeshBufferCount(); j++) { // Only up to 6 tiles are supported - const auto tile = mesh->getTextureSlot(j); + const u32 tile = mesh->getTextureSlot(j); useTile(MYMIN(tile, 5)); + scene::IMeshBuffer *buf = mesh->getMeshBuffer(j); video::S3DVertex *vertices = (video::S3DVertex *)buf->getVertices(); - int vertex_count = buf->getVertexCount(); + u32 vertex_count = buf->getVertexCount(); if (data->m_smooth_lighting) { // Mesh is always private here. So the lighting is applied to each // vertex right here. - for (int k = 0; k < vertex_count; k++) { + 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; @@ -1697,15 +1701,13 @@ void MapblockMeshGenerator::drawMeshNode() collector->append(cur_node.tile, vertices, vertex_count, buf->getIndices(), buf->getIndexCount()); } else { - // Don't modify the mesh, it may not be private here. - // Instead, let the collector process colors, etc. + // 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); } } - if (private_mesh) - mesh->drop(); + mesh->drop(); } // also called when the drawtype is known but should have been pre-converted diff --git a/src/client/mesh.cpp b/src/client/mesh.cpp index 3f947ae50..012b9a45a 100644 --- a/src/client/mesh.cpp +++ b/src/client/mesh.cpp @@ -272,9 +272,9 @@ void rotateMeshYZby(scene::IMesh *mesh, f64 degrees) rotateMesh<&v3f::Y, &v3f::Z>(mesh, degrees); } -void rotateMeshBy6dFacedir(scene::IMesh *mesh, int facedir) +void rotateMeshBy6dFacedir(scene::IMesh *mesh, u8 facedir) { - int axisdir = facedir >> 2; + u8 axisdir = facedir >> 2; facedir &= 0x03; switch (facedir) { case 1: rotateMeshXZby(mesh, -90); break; diff --git a/src/client/mesh.h b/src/client/mesh.h index 5fd0ebb0e..3345e24f7 100644 --- a/src/client/mesh.h +++ b/src/client/mesh.h @@ -68,7 +68,7 @@ void setMeshColorByNormal(scene::IMesh *mesh, const v3f &normal, Rotate the mesh by 6d facedir value. Method only for meshnodes, not suitable for entities. */ -void rotateMeshBy6dFacedir(scene::IMesh *mesh, int facedir); +void rotateMeshBy6dFacedir(scene::IMesh *mesh, u8 facedir); /* Rotate the mesh around the axis and given angle in degrees. diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 2301b179f..81348cf23 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -943,14 +943,17 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc palette = tsrc->getPalette(palette_name); if (drawtype == NDT_MESH && !mesh.empty()) { - // Meshnode drawtype // Read the mesh and apply scale mesh_ptr = client->getMesh(mesh); if (mesh_ptr) { v3f scale = v3f(BS) * visual_scale; scaleMesh(mesh_ptr, scale); recalculateBoundingBox(mesh_ptr); - meshmanip->recalculateNormals(mesh_ptr, true, false); + if (!checkMeshNormals(mesh_ptr)) { + infostream << "ContentFeatures: recalculating normals for mesh " + << mesh << std::endl; + meshmanip->recalculateNormals(mesh_ptr, true, false); + } } } } From 3c5e0d10fc169ecdd062f7afa20a2b0faeaf3a7f Mon Sep 17 00:00:00 2001 From: Lars Mueller Date: Mon, 9 Dec 2024 00:45:37 +0100 Subject: [PATCH 112/136] Rotate meshnode normals correctly instead of recalculating --- src/client/content_mapblock.cpp | 2 -- src/client/mesh.cpp | 12 ++++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index 25d303156..49abbd4fa 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -1673,8 +1673,6 @@ void MapblockMeshGenerator::drawMeshNode() modified = false; if (modified) { recalculateBoundingBox(mesh); - // FIXME: we should rotate the normals too, instead of recalculating - meshmanip->recalculateNormals(mesh, true, false); } } else { warningstream << "drawMeshNode(): missing mesh" << std::endl; diff --git a/src/client/mesh.cpp b/src/client/mesh.cpp index 012b9a45a..eb56d3580 100644 --- a/src/client/mesh.cpp +++ b/src/client/mesh.cpp @@ -249,10 +249,14 @@ static void rotateMesh(scene::IMesh *mesh, float degrees) float c = std::cos(degrees); float s = std::sin(degrees); auto rotator = [c, s] (video::S3DVertex *vertex) { - float u = vertex->Pos.*U; - float v = vertex->Pos.*V; - vertex->Pos.*U = c * u - s * v; - vertex->Pos.*V = s * u + c * v; + auto rotate_vec = [c, s] (v3f &vec) { + float u = vec.*U; + float v = vec.*V; + vec.*U = c * u - s * v; + vec.*V = s * u + c * v; + }; + rotate_vec(vertex->Pos); + rotate_vec(vertex->Normal); }; applyToMesh(mesh, rotator); } From 8957739cdfa7010795bf8344c114702ff51b9857 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 6 Dec 2024 21:00:47 +0100 Subject: [PATCH 113/136] Use appropriate sized type for VoxelArea extent --- src/map.h | 2 +- src/mapgen/cavegen.cpp | 4 ++-- src/mapgen/dungeongen.cpp | 2 +- src/mapgen/mapgen.cpp | 16 ++++++++-------- src/mapgen/mapgen.h | 2 +- src/mapgen/mapgen_carpathian.cpp | 2 +- src/mapgen/mapgen_flat.cpp | 2 +- src/mapgen/mapgen_v6.cpp | 14 +++++++------- src/mapgen/mapgen_v6.h | 2 +- src/mapgen/mapgen_v7.cpp | 2 +- src/mapgen/mapgen_valleys.cpp | 2 +- src/mapgen/mg_decoration.cpp | 2 +- src/unittest/test_voxelarea.cpp | 20 +++++++++++++------ src/voxel.cpp | 2 +- src/voxel.h | 33 +++++++++++++++++++------------- src/voxelalgorithms.cpp | 2 +- 16 files changed, 62 insertions(+), 47 deletions(-) diff --git a/src/map.h b/src/map.h index bbe91f5d6..37d1a713d 100644 --- a/src/map.h +++ b/src/map.h @@ -79,7 +79,7 @@ struct MapEditEvent VoxelArea a; for (v3s16 p : modified_blocks) { v3s16 np1 = p*MAP_BLOCKSIZE; - v3s16 np2 = np1 + v3s16(1,1,1)*MAP_BLOCKSIZE - v3s16(1,1,1); + v3s16 np2 = np1 + v3s16(MAP_BLOCKSIZE-1); a.addPoint(np1); a.addPoint(np2); } diff --git a/src/mapgen/cavegen.cpp b/src/mapgen/cavegen.cpp index 6bb841ab5..0c3ec1f81 100644 --- a/src/mapgen/cavegen.cpp +++ b/src/mapgen/cavegen.cpp @@ -64,7 +64,7 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm, noise_cave1->perlinMap3D(nmin.X, nmin.Y - 1, nmin.Z); noise_cave2->perlinMap3D(nmin.X, nmin.Y - 1, nmin.Z); - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); u32 index2d = 0; // Biomemap index for (s16 z = nmin.Z; z <= nmax.Z; z++) @@ -230,7 +230,7 @@ bool CavernsNoise::generateCaverns(MMVManip *vm, v3s16 nmin, v3s16 nmax) //// Place nodes bool near_cavern = false; - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); u32 index2d = 0; for (s16 z = nmin.Z; z <= nmax.Z; z++) diff --git a/src/mapgen/dungeongen.cpp b/src/mapgen/dungeongen.cpp index 948cc62b1..249c462ba 100644 --- a/src/mapgen/dungeongen.cpp +++ b/src/mapgen/dungeongen.cpp @@ -127,7 +127,7 @@ void DungeonGen::generate(MMVManip *vm, u32 bseed, v3s16 nmin, v3s16 nmax) void DungeonGen::makeDungeon(v3s16 start_padding) { - const v3s16 &areasize = vm->m_area.getExtent(); + const v3s32 &areasize = vm->m_area.getExtent(); v3s16 roomsize; v3s16 roomplace; diff --git a/src/mapgen/mapgen.cpp b/src/mapgen/mapgen.cpp index d236132df..3778c3807 100644 --- a/src/mapgen/mapgen.cpp +++ b/src/mapgen/mapgen.cpp @@ -240,7 +240,7 @@ u32 Mapgen::getBlockSeed2(v3s16 p, s32 seed) // Returns -MAX_MAP_GENERATION_LIMIT if not found s16 Mapgen::findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax) { - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y); s16 y; @@ -258,7 +258,7 @@ s16 Mapgen::findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax) // Returns -MAX_MAP_GENERATION_LIMIT if not found or if ground is found first s16 Mapgen::findLiquidSurface(v2s16 p2d, s16 ymin, s16 ymax) { - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y); s16 y; @@ -296,7 +296,7 @@ void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax) void Mapgen::getSurfaces(v2s16 p2d, s16 ymin, s16 ymax, std::vector &floors, std::vector &ceilings) { - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); bool is_walkable = false; u32 vi = vm->m_area.index(p2d.X, ymax, p2d.Y); @@ -320,7 +320,7 @@ void Mapgen::getSurfaces(v2s16 p2d, s16 ymin, s16 ymax, } -inline bool Mapgen::isLiquidHorizontallyFlowable(u32 vi, v3s16 em) +inline bool Mapgen::isLiquidHorizontallyFlowable(u32 vi, v3s32 em) { u32 vi_neg_x = vi; VoxelArea::add_x(em, vi_neg_x, -1); @@ -357,7 +357,7 @@ void Mapgen::updateLiquid(UniqueQueue *trans_liquid, v3s16 nmin, v3s16 nm { bool isignored, isliquid, wasignored, wasliquid, waschecked, waspushed; content_t was_n; - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); isignored = true; isliquid = false; @@ -481,7 +481,7 @@ void Mapgen::propagateSunlight(v3s16 nmin, v3s16 nmax, bool propagate_shadow) //TimeTaker t("propagateSunlight"); VoxelArea a(nmin, nmax); bool block_is_underground = (water_level >= nmax.Y); - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); // NOTE: Direct access to the low 4 bits of param1 is okay here because, // by definition, sunlight will never be in the night lightbank. @@ -629,7 +629,7 @@ void MapgenBasic::generateBiomes() assert(biomegen); assert(biomemap); - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); u32 index = 0; noise_filler_depth->perlinMap2D(node_min.X, node_min.Z); @@ -774,7 +774,7 @@ void MapgenBasic::dustTopNodes() if (node_max.Y < water_level) return; - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); u32 index = 0; for (s16 z = node_min.Z; z <= node_max.Z; z++) diff --git a/src/mapgen/mapgen.h b/src/mapgen/mapgen.h index 5e5ff9f3c..a81b9a361 100644 --- a/src/mapgen/mapgen.h +++ b/src/mapgen/mapgen.h @@ -261,7 +261,7 @@ private: // isLiquidHorizontallyFlowable() is a helper function for updateLiquid() // that checks whether there are floodable nodes without liquid beneath // the node at index vi. - inline bool isLiquidHorizontallyFlowable(u32 vi, v3s16 em); + inline bool isLiquidHorizontallyFlowable(u32 vi, v3s32 em); }; /* diff --git a/src/mapgen/mapgen_carpathian.cpp b/src/mapgen/mapgen_carpathian.cpp index ba54a3672..46048b51f 100644 --- a/src/mapgen/mapgen_carpathian.cpp +++ b/src/mapgen/mapgen_carpathian.cpp @@ -445,7 +445,7 @@ int MapgenCarpathian::generateTerrain() noise_rivers->perlinMap2D(node_min.X, node_min.Z); //// Place nodes - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); s16 stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT; u32 index2d = 0; diff --git a/src/mapgen/mapgen_flat.cpp b/src/mapgen/mapgen_flat.cpp index f0e7984d5..e96e4e45a 100644 --- a/src/mapgen/mapgen_flat.cpp +++ b/src/mapgen/mapgen_flat.cpp @@ -278,7 +278,7 @@ s16 MapgenFlat::generateTerrain() MapNode n_stone(c_stone); MapNode n_water(c_water_source); - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); s16 stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT; u32 ni2d = 0; diff --git a/src/mapgen/mapgen_v6.cpp b/src/mapgen/mapgen_v6.cpp index 2f5a3cf7a..44243618e 100644 --- a/src/mapgen/mapgen_v6.cpp +++ b/src/mapgen/mapgen_v6.cpp @@ -222,7 +222,7 @@ void MapgenV6Params::setDefaultSettings(Settings *settings) // Returns Y one under area minimum if not found s16 MapgenV6::find_stone_level(v2s16 p2d) { - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); s16 y_nodes_max = vm->m_area.MaxEdge.Y; s16 y_nodes_min = vm->m_area.MinEdge.Y; u32 i = vm->m_area.index(p2d.X, y_nodes_max, p2d.Y); @@ -670,7 +670,7 @@ int MapgenV6::generateGround() BiomeV6Type bt = getBiome(v2s16(x, z)); // Fill ground with stone - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); u32 i = vm->m_area.index(x, node_min.Y, z); for (s16 y = node_min.Y; y <= node_max.Y; y++) { if (vm->m_data[i].getContent() == CONTENT_IGNORE) { @@ -739,7 +739,7 @@ void MapgenV6::addMud() // Add mud on ground s16 mudcount = 0; - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); s16 y_start = surface_y + 1; u32 i = vm->m_area.index(x, y_start, z); for (s16 y = y_start; y <= node_max.Y; y++) { @@ -757,7 +757,7 @@ void MapgenV6::addMud() void MapgenV6::flowMud(s16 &mudflow_minpos, s16 &mudflow_maxpos) { - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); static const v3s16 dirs4[4] = { v3s16(0, 0, 1), // Back v3s16(1, 0, 0), // Right @@ -870,7 +870,7 @@ void MapgenV6::flowMud(s16 &mudflow_minpos, s16 &mudflow_maxpos) void MapgenV6::moveMud(u32 remove_index, u32 place_index, - u32 above_remove_index, v2s16 pos, v3s16 em) + u32 above_remove_index, v2s16 pos, v3s32 em) { MapNode n_air(CONTENT_AIR); // Copy mud from old place to new place @@ -920,7 +920,7 @@ void MapgenV6::placeTreesAndJungleGrass() if (c_junglegrass == CONTENT_IGNORE) c_junglegrass = CONTENT_AIR; MapNode n_junglegrass(c_junglegrass); - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); // Divide area into parts s16 div = 8; @@ -1027,7 +1027,7 @@ void MapgenV6::growGrass() // Add surface nodes MapNode n_dirt_with_grass(c_dirt_with_grass); MapNode n_dirt_with_snow(c_dirt_with_snow); MapNode n_snowblock(c_snowblock); - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); u32 index = 0; for (s16 z = full_node_min.Z; z <= full_node_max.Z; z++) diff --git a/src/mapgen/mapgen_v6.h b/src/mapgen/mapgen_v6.h index 30b31f84a..6d776665a 100644 --- a/src/mapgen/mapgen_v6.h +++ b/src/mapgen/mapgen_v6.h @@ -150,7 +150,7 @@ public: void addMud(); void flowMud(s16 &mudflow_minpos, s16 &mudflow_maxpos); void moveMud(u32 remove_index, u32 place_index, - u32 above_remove_index, v2s16 pos, v3s16 em); + u32 above_remove_index, v2s16 pos, v3s32 em); void growGrass(); void placeTreesAndJungleGrass(); virtual void generateCaves(int max_stone_y); diff --git a/src/mapgen/mapgen_v7.cpp b/src/mapgen/mapgen_v7.cpp index 491a1514a..fe052f3b7 100644 --- a/src/mapgen/mapgen_v7.cpp +++ b/src/mapgen/mapgen_v7.cpp @@ -523,7 +523,7 @@ int MapgenV7::generateTerrain() } //// Place nodes - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); s16 stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT; u32 index2d = 0; diff --git a/src/mapgen/mapgen_valleys.cpp b/src/mapgen/mapgen_valleys.cpp index 196454642..55185c445 100644 --- a/src/mapgen/mapgen_valleys.cpp +++ b/src/mapgen/mapgen_valleys.cpp @@ -344,7 +344,7 @@ int MapgenValleys::generateTerrain() noise_inter_valley_fill->perlinMap3D(node_min.X, node_min.Y - 1, node_min.Z); - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT; u32 index_2d = 0; diff --git a/src/mapgen/mg_decoration.cpp b/src/mapgen/mg_decoration.cpp index 60183d4e4..e8f381ec6 100644 --- a/src/mapgen/mg_decoration.cpp +++ b/src/mapgen/mg_decoration.cpp @@ -346,7 +346,7 @@ size_t DecoSimple::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling) pr->range(deco_param2, deco_param2_max) : deco_param2; bool force_placement = (flags & DECO_FORCE_PLACEMENT); - const v3s16 &em = vm->m_area.getExtent(); + const v3s32 &em = vm->m_area.getExtent(); u32 vi = vm->m_area.index(p); if (ceiling) { diff --git a/src/unittest/test_voxelarea.cpp b/src/unittest/test_voxelarea.cpp index 384fda0d1..4bdd9af5b 100644 --- a/src/unittest/test_voxelarea.cpp +++ b/src/unittest/test_voxelarea.cpp @@ -107,11 +107,16 @@ void TestVoxelArea::test_pad() void TestVoxelArea::test_extent() { VoxelArea v1(v3s16(-1337, -547, -789), v3s16(-147, 447, 669)); - UASSERT(v1.getExtent() == v3s16(1191, 995, 1459)); + UASSERT(v1.getExtent() == v3s32(1191, 995, 1459)); VoxelArea v2(v3s16(32493, -32507, 32752), v3s16(32508, -32492, 32767)); - UASSERT(v2.getExtent() == v3s16(16, 16, 16)); + UASSERT(v2.getExtent() == v3s32(16, 16, 16)); + // side length bigger than S16_MAX + VoxelArea v3({-20000, 12, 34}, {20000, 12, 34}); + UASSERT(v3.getExtent() == v3s32(40001, 1, 1)); + + UASSERT(VoxelArea().hasEmptyExtent()); UASSERT(VoxelArea({2,3,4}, {1,2,3}).hasEmptyExtent()); UASSERT(VoxelArea({2,3,4}, {2,2,3}).hasEmptyExtent() == false); } @@ -124,6 +129,9 @@ void TestVoxelArea::test_volume() VoxelArea v2(v3s16(32493, -32507, 32752), v3s16(32508, -32492, 32767)); UASSERTEQ(s32, v2.getVolume(), 4096); + VoxelArea v3({-20000, 12, 34}, {20000, 12, 34}); + UASSERTEQ(s32, v3.getVolume(), 40000); + UASSERTEQ(s32, VoxelArea({2,3,4}, {1,2,3}).getVolume(), 0); UASSERTEQ(s32, VoxelArea({2,3,4}, {2,2,3}).getVolume(), 0); } @@ -388,7 +396,7 @@ void TestVoxelArea::test_index_v3s16_all_neg() void TestVoxelArea::test_add_x() { - v3s16 extent; + v3s32 extent; u32 i = 4; VoxelArea::add_x(extent, i, 8); UASSERTEQ(u32, i, 12) @@ -396,7 +404,7 @@ void TestVoxelArea::test_add_x() void TestVoxelArea::test_add_y() { - v3s16 extent(740, 16, 87); + v3s32 extent(740, 16, 87); u32 i = 8; VoxelArea::add_y(extent, i, 88); UASSERTEQ(u32, i, 65128) @@ -404,7 +412,7 @@ void TestVoxelArea::test_add_y() void TestVoxelArea::test_add_z() { - v3s16 extent(114, 80, 256); + v3s32 extent(114, 80, 256); u32 i = 4; VoxelArea::add_z(extent, i, 8); UASSERTEQ(u32, i, 72964) @@ -412,7 +420,7 @@ void TestVoxelArea::test_add_z() void TestVoxelArea::test_add_p() { - v3s16 extent(33, 14, 742); + v3s32 extent(33, 14, 742); v3s16 a(15, 12, 369); u32 i = 4; VoxelArea::add_p(extent, i, a); diff --git a/src/voxel.cpp b/src/voxel.cpp index b0a63b4f0..d9fceb2b9 100644 --- a/src/voxel.cpp +++ b/src/voxel.cpp @@ -38,7 +38,7 @@ void VoxelManipulator::clear() void VoxelManipulator::print(std::ostream &o, const NodeDefManager *ndef, VoxelPrintMode mode) const { - const v3s16 &em = m_area.getExtent(); + auto &em = m_area.getExtent(); v3s16 of = m_area.MinEdge; o<<"size: "<= 0); - assert(m_cache_extent.Y >= 0); - assert(m_cache_extent.Z >= 0); + assert(m_cache_extent.X >= 0 && m_cache_extent.X <= MAX_EXTENT); + assert(m_cache_extent.Y >= 0 && m_cache_extent.Y <= MAX_EXTENT); + assert(m_cache_extent.Z >= 0 && m_cache_extent.Z <= MAX_EXTENT); } - v3s16 m_cache_extent = v3s16(0,0,0); + static constexpr s32 MAX_EXTENT = S16_MAX - S16_MIN + 1; + v3s32 m_cache_extent; }; enum : u8 { diff --git a/src/voxelalgorithms.cpp b/src/voxelalgorithms.cpp index cd2664938..5da39d6ed 100644 --- a/src/voxelalgorithms.cpp +++ b/src/voxelalgorithms.cpp @@ -767,7 +767,7 @@ void fill_with_sunlight(MMVManip *vm, const NodeDefManager *ndef, v2s16 offset, bool light[MAP_BLOCKSIZE][MAP_BLOCKSIZE]) { // Distance in array between two nodes on top of each other. - s16 ystride = vm->m_area.getExtent().X; + s32 ystride = vm->m_area.getExtent().X; // Cache the ignore node. MapNode ignore = MapNode(CONTENT_IGNORE); // For each column of nodes: From 67126cbd1bab16e5860de6510b8af15fb9f7c9e7 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 6 Dec 2024 21:03:52 +0100 Subject: [PATCH 114/136] Fix meaning of VoxelArea::hasEmptyExtent() --- src/emerge_internal.h | 4 ++-- src/unittest/test_voxelarea.cpp | 2 +- src/voxel.h | 8 +++----- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/emerge_internal.h b/src/emerge_internal.h index 6dd438603..6a71c7523 100644 --- a/src/emerge_internal.h +++ b/src/emerge_internal.h @@ -93,7 +93,7 @@ public: MapEditEventAreaIgnorer(VoxelArea *ignorevariable, const VoxelArea &a): m_ignorevariable(ignorevariable) { - if (m_ignorevariable->getVolume() == 0) + if (m_ignorevariable->hasEmptyExtent()) *m_ignorevariable = a; else m_ignorevariable = nullptr; @@ -102,7 +102,7 @@ public: ~MapEditEventAreaIgnorer() { if (m_ignorevariable) { - assert(m_ignorevariable->getVolume() != 0); + assert(!m_ignorevariable->hasEmptyExtent()); *m_ignorevariable = VoxelArea(); } } diff --git a/src/unittest/test_voxelarea.cpp b/src/unittest/test_voxelarea.cpp index 4bdd9af5b..321420a52 100644 --- a/src/unittest/test_voxelarea.cpp +++ b/src/unittest/test_voxelarea.cpp @@ -118,7 +118,7 @@ void TestVoxelArea::test_extent() UASSERT(VoxelArea().hasEmptyExtent()); UASSERT(VoxelArea({2,3,4}, {1,2,3}).hasEmptyExtent()); - UASSERT(VoxelArea({2,3,4}, {2,2,3}).hasEmptyExtent() == false); + UASSERT(VoxelArea({2,3,4}, {2,2,3}).hasEmptyExtent()); } void TestVoxelArea::test_volume() diff --git a/src/voxel.h b/src/voxel.h index 2a0970aad..a5ffc7ce6 100644 --- a/src/voxel.h +++ b/src/voxel.h @@ -114,11 +114,9 @@ public: return m_cache_extent; } - /// @note `getVolume() == 0` and `getEmptyExtent()` are not equivalent. bool hasEmptyExtent() const { - // FIXME: shouldn't this actually be a component-wise check? - return m_cache_extent == v3s32(0,0,0); + return !m_cache_extent.X || !m_cache_extent.Y || !m_cache_extent.Z; } s32 getVolume() const @@ -207,7 +205,7 @@ public: if(a.hasEmptyExtent()) { VoxelArea b = *this; - if (b.getVolume() != 0) + if (!b.hasEmptyExtent()) result.push_back(b); return; } @@ -216,7 +214,7 @@ public: const auto &take = [&result] (v3s16 min, v3s16 max) { VoxelArea b(min, max); - if (b.getVolume() != 0) + if (!b.hasEmptyExtent()) result.push_back(b); }; From 4f800dd2b4bd61bb248f93f0a3146847350e4318 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 6 Dec 2024 21:17:59 +0100 Subject: [PATCH 115/136] Change VoxelArea volume to be u32 --- src/map.cpp | 4 ++-- src/mapgen/treegen.cpp | 7 +++---- src/unittest/test_voxelalgorithms.cpp | 4 ++-- src/unittest/test_voxelarea.cpp | 13 +++++++------ src/voxel.cpp | 4 ++-- src/voxel.h | 7 ++++--- 6 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 1af8684e1..240788944 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -766,7 +766,7 @@ void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max, VoxelArea block_area_nodes (p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1)); - u32 size_MB = block_area_nodes.getVolume()*4/1000000; + u32 size_MB = block_area_nodes.getVolume() * sizeof(MapNode) / 1000000U; if(size_MB >= 1) { infostream<<"initialEmerge: area: "; @@ -855,7 +855,7 @@ MMVManip *MMVManip::clone() const { MMVManip *ret = new MMVManip(); - const s32 size = m_area.getVolume(); + const u32 size = m_area.getVolume(); ret->m_area = m_area; if (m_data) { ret->m_data = new MapNode[size]; diff --git a/src/mapgen/treegen.cpp b/src/mapgen/treegen.cpp index 688833fa2..8198cf266 100644 --- a/src/mapgen/treegen.cpp +++ b/src/mapgen/treegen.cpp @@ -77,7 +77,7 @@ void make_tree(MMVManip &vmanip, v3s16 p0, bool is_apple_tree, VoxelArea leaves_a(v3s16(-2, -1, -2), v3s16(2, 2, 2)); Buffer leaves_d(leaves_a.getVolume()); - for (s32 i = 0; i < leaves_a.getVolume(); i++) + for (u32 i = 0; i < leaves_d.getSize(); i++) leaves_d[i] = 0; // Force leaves at near the end of the trunk @@ -697,9 +697,8 @@ void make_jungletree(MMVManip &vmanip, v3s16 p0, const NodeDefManager *ndef, p1.Y -= 1; VoxelArea leaves_a(v3s16(-3, -2, -3), v3s16(3, 2, 3)); - //SharedPtr leaves_d(new u8[leaves_a.getVolume()]); Buffer leaves_d(leaves_a.getVolume()); - for (s32 i = 0; i < leaves_a.getVolume(); i++) + for (u32 i = 0; i < leaves_d.getSize(); i++) leaves_d[i] = 0; // Force leaves at near the end of the trunk @@ -788,7 +787,7 @@ void make_pine_tree(MMVManip &vmanip, v3s16 p0, const NodeDefManager *ndef, VoxelArea leaves_a(v3s16(-3, -6, -3), v3s16(3, 3, 3)); Buffer leaves_d(leaves_a.getVolume()); - for (s32 i = 0; i < leaves_a.getVolume(); i++) + for (u32 i = 0; i < leaves_d.getSize(); i++) leaves_d[i] = 0; // Upper branches diff --git a/src/unittest/test_voxelalgorithms.cpp b/src/unittest/test_voxelalgorithms.cpp index 2a98412b4..b8ba11248 100644 --- a/src/unittest/test_voxelalgorithms.cpp +++ b/src/unittest/test_voxelalgorithms.cpp @@ -98,8 +98,8 @@ void TestVoxelAlgorithms::testLighting(IGameDef *gamedef) std::map modified_blocks; MMVManip vm(&map); vm.initialEmerge(bpmin, bpmax, false); - s32 volume = vm.m_area.getVolume(); - for (s32 i = 0; i < volume; i++) + u32 volume = vm.m_area.getVolume(); + for (u32 i = 0; i < volume; i++) vm.m_data[i] = MapNode(CONTENT_AIR); for (s16 z = -10; z <= 10; z++) for (s16 y = -10; y <= 10; y++) diff --git a/src/unittest/test_voxelarea.cpp b/src/unittest/test_voxelarea.cpp index 321420a52..f594a9be7 100644 --- a/src/unittest/test_voxelarea.cpp +++ b/src/unittest/test_voxelarea.cpp @@ -124,16 +124,17 @@ void TestVoxelArea::test_extent() void TestVoxelArea::test_volume() { VoxelArea v1(v3s16(-1337, -547, -789), v3s16(-147, 447, 669)); - UASSERTEQ(s32, v1.getVolume(), 1728980655); + UASSERTEQ(u32, v1.getVolume(), 1728980655); VoxelArea v2(v3s16(32493, -32507, 32752), v3s16(32508, -32492, 32767)); - UASSERTEQ(s32, v2.getVolume(), 4096); + UASSERTEQ(u32, v2.getVolume(), 4096); - VoxelArea v3({-20000, 12, 34}, {20000, 12, 34}); - UASSERTEQ(s32, v3.getVolume(), 40000); + // volume bigger than S32_MAX + VoxelArea v3({1, 1, 1}, {1337, 1337, 1337}); + UASSERTEQ(u32, v3.getVolume(), 2389979753U); - UASSERTEQ(s32, VoxelArea({2,3,4}, {1,2,3}).getVolume(), 0); - UASSERTEQ(s32, VoxelArea({2,3,4}, {2,2,3}).getVolume(), 0); + UASSERTEQ(u32, VoxelArea({2,3,4}, {1,2,3}).getVolume(), 0); + UASSERTEQ(u32, VoxelArea({2,3,4}, {2,2,3}).getVolume(), 0); } void TestVoxelArea::test_contains_voxelarea() diff --git a/src/voxel.cpp b/src/voxel.cpp index d9fceb2b9..8f3858a1f 100644 --- a/src/voxel.cpp +++ b/src/voxel.cpp @@ -137,7 +137,7 @@ void VoxelManipulator::addArea(const VoxelArea &area) new_area.addArea(area); } - s32 new_size = new_area.getVolume(); + u32 new_size = new_area.getVolume(); // Allocate new data and clear flags MapNode *new_data = new MapNode[new_size]; @@ -147,7 +147,7 @@ void VoxelManipulator::addArea(const VoxelArea &area) memset(new_flags, VOXELFLAG_NO_DATA, new_size); // Copy old data - s32 old_x_width = m_area.MaxEdge.X - m_area.MinEdge.X + 1; + u32 old_x_width = m_area.getExtent().X; for(s32 z=m_area.MinEdge.Z; z<=m_area.MaxEdge.Z; z++) for(s32 y=m_area.MinEdge.Y; y<=m_area.MaxEdge.Y; y++) { diff --git a/src/voxel.h b/src/voxel.h index a5ffc7ce6..a35be3e19 100644 --- a/src/voxel.h +++ b/src/voxel.h @@ -119,10 +119,10 @@ public: return !m_cache_extent.X || !m_cache_extent.Y || !m_cache_extent.Z; } - s32 getVolume() const + u32 getVolume() const { // FIXME: possible integer overflow here - return m_cache_extent.X * m_cache_extent.Y * m_cache_extent.Z; + return (u32)m_cache_extent.X * (u32)m_cache_extent.Y * (u32)m_cache_extent.Z; } bool contains(const VoxelArea &a) const @@ -148,8 +148,9 @@ public: } bool contains(s32 i) const { - return (i >= 0 && i < getVolume()); + return i >= 0 && static_cast(i) < getVolume(); } + bool operator==(const VoxelArea &other) const { return (MinEdge == other.MinEdge From bcbee873e8e9a44f558aba61bb2a54dfc6bab8ed Mon Sep 17 00:00:00 2001 From: DS Date: Tue, 10 Dec 2024 22:00:43 +0100 Subject: [PATCH 116/136] Use openssl's sha1 and sha256, optionally (#15472) --- .github/workflows/linux.yml | 2 + doc/compiling/README.md | 1 + doc/compiling/linux.md | 1 + src/CMakeLists.txt | 22 ++++++++++ src/benchmark/CMakeLists.txt | 1 + src/benchmark/benchmark_sha.cpp | 23 ++++++++++ src/client/clientmedia.cpp | 9 +--- src/cmake_config.h.in | 1 + src/network/clientpackethandler.cpp | 9 +--- src/script/lua_api/l_util.cpp | 15 ++----- src/server.cpp | 13 +++--- src/unittest/test_map_settings_manager.cpp | 6 +-- src/util/CMakeLists.txt | 3 +- src/util/auth.cpp | 6 +-- src/util/hashing.cpp | 50 ++++++++++++++++++++++ src/util/hashing.h | 21 +++++++++ util/ci/common.sh | 1 + 17 files changed, 141 insertions(+), 43 deletions(-) create mode 100644 src/benchmark/benchmark_sha.cpp create mode 100644 src/util/hashing.cpp create mode 100644 src/util/hashing.h diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index fe0c97324..0fb780464 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -49,6 +49,8 @@ jobs: env: CC: gcc-7 CXX: g++-7 + # Test fallback SHA implementations + CMAKE_FLAGS: '-DENABLE_OPENSSL=0' - name: Test run: | diff --git a/doc/compiling/README.md b/doc/compiling/README.md index 55357adf6..16167977b 100644 --- a/doc/compiling/README.md +++ b/doc/compiling/README.md @@ -30,6 +30,7 @@ General options and their default values: ENABLE_POSTGRESQL=ON - Build with libpq; Enables use of PostgreSQL map backend (PostgreSQL 9.5 or greater recommended) ENABLE_REDIS=ON - Build with libhiredis; Enables use of Redis map backend ENABLE_SPATIAL=ON - Build with LibSpatial; Speeds up AreaStores + ENABLE_OPENSSL=ON - Build with OpenSSL; Speeds up SHA1 and SHA2 hashing ENABLE_SOUND=ON - Build with OpenAL, libogg & libvorbis; in-game sounds ENABLE_LTO= - Build with IPO/LTO optimizations (smaller and more efficient than regular build) ENABLE_LUAJIT=ON - Build with LuaJIT (much faster than non-JIT Lua) diff --git a/doc/compiling/linux.md b/doc/compiling/linux.md index 54f7de2a0..54a44d501 100644 --- a/doc/compiling/linux.md +++ b/doc/compiling/linux.md @@ -18,6 +18,7 @@ | JsonCPP | 1.0.0+ | Bundled JsonCPP is used if not present | | Curl | 7.56.0+ | Optional | | gettext | - | Optional | +| OpenSSL | 3.0+ | Optional (only libcrypto used) | For Debian/Ubuntu users: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d764e186e..692651049 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -249,6 +249,19 @@ if(ENABLE_SPATIAL) endif(SPATIAL_LIBRARY AND SPATIAL_INCLUDE_DIR) endif(ENABLE_SPATIAL) +option(ENABLE_OPENSSL "Use OpenSSL's libcrypto for faster SHA implementations" TRUE) +set(USE_OPENSSL FALSE) + +if(ENABLE_OPENSSL) + find_package(OpenSSL 3.0) + if(OPENSSL_FOUND) + set(USE_OPENSSL TRUE) + message(STATUS "OpenSSL's libcrypto SHA enabled.") + else() + message(STATUS "OpenSSL not found!") + endif() +endif(ENABLE_OPENSSL) + find_package(ZLIB REQUIRED) find_package(Zstd REQUIRED) @@ -593,6 +606,9 @@ add_dependencies(EngineCommon GenerateVersion) target_link_libraries(EngineCommon sha256 ) +if(USE_OPENSSL) + target_link_libraries(EngineCommon OpenSSL::Crypto) +endif() get_target_property( IRRLICHT_INCLUDES IrrlichtMt::IrrlichtMt INTERFACE_INCLUDE_DIRECTORIES) target_include_directories(EngineCommon PRIVATE ${IRRLICHT_INCLUDES}) @@ -726,6 +742,9 @@ if(BUILD_CLIENT) if (USE_SPATIAL) target_link_libraries(${PROJECT_NAME} ${SPATIAL_LIBRARY}) endif() + if (USE_OPENSSL) + target_link_libraries(${PROJECT_NAME} OpenSSL::Crypto) + endif() if(BUILD_UNITTESTS OR BUILD_BENCHMARKS) target_link_libraries(${PROJECT_NAME} Catch2::Catch2) endif() @@ -795,6 +814,9 @@ if(BUILD_SERVER) if (USE_SPATIAL) target_link_libraries(${PROJECT_NAME}server ${SPATIAL_LIBRARY}) endif() + if (USE_OPENSSL) + target_link_libraries(${PROJECT_NAME}server OpenSSL::Crypto) + endif() if(USE_CURL) target_link_libraries( ${PROJECT_NAME}server diff --git a/src/benchmark/CMakeLists.txt b/src/benchmark/CMakeLists.txt index f79fcf1ef..e8150848a 100644 --- a/src/benchmark/CMakeLists.txt +++ b/src/benchmark/CMakeLists.txt @@ -5,6 +5,7 @@ set (BENCHMARK_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/benchmark_serialize.cpp ${CMAKE_CURRENT_SOURCE_DIR}/benchmark_mapblock.cpp ${CMAKE_CURRENT_SOURCE_DIR}/benchmark_mapmodify.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/benchmark_sha.cpp PARENT_SCOPE) set (BENCHMARK_CLIENT_SRCS diff --git a/src/benchmark/benchmark_sha.cpp b/src/benchmark/benchmark_sha.cpp new file mode 100644 index 000000000..616606f55 --- /dev/null +++ b/src/benchmark/benchmark_sha.cpp @@ -0,0 +1,23 @@ +// SPDX-FileCopyrightText: 2024 Luanti Contributors +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "catch.h" +#include "util/hashing.h" +#include + +TEST_CASE("benchmark_sha") +{ + std::string input; + input.resize(100000); + + BENCHMARK("sha1_input100000", i) { + input[0] = (char)i; + return hashing::sha1(input); + }; + + BENCHMARK("sha256_input100000", i) { + input[0] = (char)i; + return hashing::sha256(input); + }; +} diff --git a/src/client/clientmedia.cpp b/src/client/clientmedia.cpp index 2c6cb69b3..2ee0d747b 100644 --- a/src/client/clientmedia.cpp +++ b/src/client/clientmedia.cpp @@ -13,7 +13,7 @@ #include "settings.h" #include "util/hex.h" #include "util/serialize.h" -#include "util/sha1.h" +#include "util/hashing.h" #include "util/string.h" #include @@ -537,12 +537,7 @@ bool IClientMediaDownloader::checkAndLoad( std::string sha1_hex = hex_encode(sha1); // Compute actual checksum of data - std::string data_sha1; - { - SHA1 ctx; - ctx.addBytes(data); - data_sha1 = ctx.getDigest(); - } + std::string data_sha1 = hashing::sha1(data); // Check that received file matches announced checksum if (data_sha1 != sha1) { diff --git a/src/cmake_config.h.in b/src/cmake_config.h.in index 5dc6e4b74..2ec91dfd1 100644 --- a/src/cmake_config.h.in +++ b/src/cmake_config.h.in @@ -29,6 +29,7 @@ #cmakedefine01 USE_SYSTEM_GMP #cmakedefine01 USE_SYSTEM_JSONCPP #cmakedefine01 USE_REDIS +#cmakedefine01 USE_OPENSSL #cmakedefine01 HAVE_ENDIAN_H #cmakedefine01 HAVE_STRLCPY #cmakedefine01 HAVE_MALLOC_TRIM diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 4b899e598..1024988bd 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -28,7 +28,7 @@ #include "script/scripting_client.h" #include "util/serialize.h" #include "util/srp.h" -#include "util/sha1.h" +#include "util/hashing.h" #include "tileanimation.h" #include "gettext.h" #include "skyparams.h" @@ -1645,12 +1645,7 @@ void Client::handleCommand_MediaPush(NetworkPacket *pkt) if (!filedata.empty()) { // LEGACY CODEPATH // Compute and check checksum of data - std::string computed_hash; - { - SHA1 ctx; - ctx.addBytes(filedata); - computed_hash = ctx.getDigest(); - } + std::string computed_hash = hashing::sha1(filedata); if (raw_hash != computed_hash) { verbosestream << "Hash of file data mismatches, ignoring." << std::endl; return; diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index cfea974b3..f84835e8b 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -27,8 +27,7 @@ #include "config.h" #include "version.h" #include "util/hex.h" -#include "util/sha1.h" -#include "my_sha256.h" +#include "util/hashing.h" #include "util/png.h" #include "player.h" #include "daynightratio.h" @@ -540,12 +539,7 @@ int ModApiUtil::l_sha1(lua_State *L) bool hex = !lua_isboolean(L, 2) || !readParam(L, 2); // Compute actual checksum of data - std::string data_sha1; - { - SHA1 ctx; - ctx.addBytes(data); - data_sha1 = ctx.getDigest(); - } + std::string data_sha1 = hashing::sha1(data); if (hex) { std::string sha1_hex = hex_encode(data_sha1); @@ -564,10 +558,7 @@ int ModApiUtil::l_sha256(lua_State *L) auto data = readParam(L, 1); bool hex = !lua_isboolean(L, 2) || !readParam(L, 2); - std::string data_sha256; - data_sha256.resize(SHA256_DIGEST_LENGTH); - SHA256(reinterpret_cast(data.data()), data.size(), - reinterpret_cast(data_sha256.data())); + std::string data_sha256 = hashing::sha256(data); if (hex) { lua_pushstring(L, hex_encode(data_sha256).c_str()); diff --git a/src/server.cpp b/src/server.cpp index b21955170..0a5300f5f 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -44,7 +44,7 @@ #include "defaultsettings.h" #include "server/mods.h" #include "util/base64.h" -#include "util/sha1.h" +#include "util/hashing.h" #include "util/hex.h" #include "database/database.h" #include "chatmessage.h" @@ -2548,14 +2548,11 @@ bool Server::addMediaFile(const std::string &filename, return false; } - SHA1 sha1; - sha1.addBytes(filedata); - - std::string digest = sha1.getDigest(); - std::string sha1_base64 = base64_encode(digest); - std::string sha1_hex = hex_encode(digest); + std::string sha1 = hashing::sha1(filedata); + std::string sha1_base64 = base64_encode(sha1); + std::string sha1_hex = hex_encode(sha1); if (digest_to) - *digest_to = digest; + *digest_to = sha1; // Put in list m_media[filename] = MediaInfo(filepath, sha1_base64); diff --git a/src/unittest/test_map_settings_manager.cpp b/src/unittest/test_map_settings_manager.cpp index 234b40cda..8fb074e17 100644 --- a/src/unittest/test_map_settings_manager.cpp +++ b/src/unittest/test_map_settings_manager.cpp @@ -7,7 +7,7 @@ #include "noise.h" #include "settings.h" #include "mapgen/mapgen_v5.h" -#include "util/sha1.h" +#include "util/hashing.h" #include "map_settings_manager.h" class TestMapSettingsManager : public TestBase { @@ -171,11 +171,9 @@ void TestMapSettingsManager::testMapSettingsManager() 0x78, 0x56, 0x95, 0x2d, 0xdc, 0x6a, 0xf7, 0x61, 0x36, 0x5f }; - SHA1 ctx; std::string metafile_contents; UASSERT(fs::ReadFile(test_mapmeta_path, metafile_contents)); - ctx.addBytes(metafile_contents); - std::string sha1_result = ctx.getDigest(); + std::string sha1_result = hashing::sha1(metafile_contents); int resultdiff = memcmp(sha1_result.data(), expected_contents_hash, 20); UASSERT(!resultdiff); diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index 761e51a4a..ec88a33c2 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -1,10 +1,11 @@ set(util_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/areastore.cpp ${CMAKE_CURRENT_SOURCE_DIR}/auth.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/colorize.cpp ${CMAKE_CURRENT_SOURCE_DIR}/base64.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/colorize.cpp ${CMAKE_CURRENT_SOURCE_DIR}/directiontables.cpp ${CMAKE_CURRENT_SOURCE_DIR}/enriched_string.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/hashing.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ieee_float.cpp ${CMAKE_CURRENT_SOURCE_DIR}/metricsbackend.cpp ${CMAKE_CURRENT_SOURCE_DIR}/numeric.cpp diff --git a/src/util/auth.cpp b/src/util/auth.cpp index 3c8e5763a..040d15bf9 100644 --- a/src/util/auth.cpp +++ b/src/util/auth.cpp @@ -6,7 +6,7 @@ #include #include "auth.h" #include "base64.h" -#include "sha1.h" +#include "util/hashing.h" #include "srp.h" #include "util/string.h" #include "debug.h" @@ -23,9 +23,7 @@ std::string translate_password(const std::string &name, return ""; std::string slt = name + password; - SHA1 sha1; - sha1.addBytes(slt); - std::string digest = sha1.getDigest(); + std::string digest = hashing::sha1(slt); std::string pwd = base64_encode(digest); return pwd; } diff --git a/src/util/hashing.cpp b/src/util/hashing.cpp new file mode 100644 index 000000000..452cd6818 --- /dev/null +++ b/src/util/hashing.cpp @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2024 Luanti Contributors +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "hashing.h" + +#include "debug.h" +#include "config.h" +#if USE_OPENSSL +#include +#include +#else +#include "util/sha1.h" +#include "my_sha256.h" +#endif + +namespace hashing +{ + +std::string sha1(std::string_view data) +{ +#if USE_OPENSSL + std::string digest(SHA1_DIGEST_SIZE, '\000'); + auto src = reinterpret_cast(data.data()); + auto dst = reinterpret_cast(digest.data()); + SHA1(src, data.size(), dst); + return digest; +#else + SHA1 sha1; + sha1.addBytes(data); + return sha1.getDigest(); +#endif +} + +std::string sha256(std::string_view data) +{ + std::string digest(SHA256_DIGEST_SIZE, '\000'); + auto src = reinterpret_cast(data.data()); + auto dst = reinterpret_cast(digest.data()); +#if USE_OPENSSL + // can't call SHA256(), because it's defined by our sha256.c fallback + auto success = EVP_Digest(src, data.size(), dst, nullptr, EVP_sha256(), nullptr) == 1; + FATAL_ERROR_IF(!success, "sha256 failed"); +#else + SHA256(src, data.size(), dst); +#endif + return digest; +} + +} diff --git a/src/util/hashing.h b/src/util/hashing.h new file mode 100644 index 000000000..3e9a0fee7 --- /dev/null +++ b/src/util/hashing.h @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2024 Luanti Contributors +// +// SPDX-License-Identifier: LGPL-2.1-or-later + +#pragma once + +#include +#include + +namespace hashing +{ + +// Size of raw digest in bytes +constexpr size_t SHA1_DIGEST_SIZE = 20; +constexpr size_t SHA256_DIGEST_SIZE = 32; + +// Returns the digest of data +std::string sha1(std::string_view data); +std::string sha256(std::string_view data); + +} diff --git a/util/ci/common.sh b/util/ci/common.sh index 201b182f2..4d4fe1195 100644 --- a/util/ci/common.sh +++ b/util/ci/common.sh @@ -7,6 +7,7 @@ install_linux_deps() { libpng-dev libjpeg-dev libgl1-mesa-dev libsdl2-dev libfreetype-dev libsqlite3-dev libhiredis-dev libogg-dev libgmp-dev libvorbis-dev libopenal-dev libpq-dev libleveldb-dev libcurl4-openssl-dev libzstd-dev + libssl-dev ) sudo apt-get update From 9f71e741580e5340d400561c146b39d26dfe06a4 Mon Sep 17 00:00:00 2001 From: Timur1324 <46261539+Timur13240@users.noreply.github.com> Date: Thu, 12 Dec 2024 14:31:12 +0000 Subject: [PATCH 117/136] Get server list over https (#15538) --- builtin/settingtypes.txt | 4 ++-- src/defaultsettings.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index b10f776ac..e4a7c120a 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -772,7 +772,7 @@ contentdb_max_concurrent_downloads (ContentDB Max Concurrent Downloads) int 3 1 enable_local_map_saving (Saving map received from server) bool false # URL to the server list displayed in the Multiplayer Tab. -serverlist_url (Serverlist URL) string servers.luanti.org +serverlist_url (Serverlist URL) string https://servers.luanti.org # If enabled, account registration is separate from login in the UI. # If disabled, new accounts will be registered automatically when logging in. @@ -810,7 +810,7 @@ server_announce (Announce server) bool false server_announce_send_players (Send player names to the server list) bool true # Announce to this serverlist. -serverlist_url (Serverlist URL) string servers.luanti.org +serverlist_url (Serverlist URL) string https://servers.luanti.org # Message of the day displayed to players connecting. motd (Message of the day) string diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 600058b5c..674442469 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -78,7 +78,7 @@ void set_default_settings() settings->setDefault("language", ""); settings->setDefault("name", ""); settings->setDefault("bind_address", ""); - settings->setDefault("serverlist_url", "servers.luanti.org"); + settings->setDefault("serverlist_url", "https://servers.luanti.org"); // Client settings->setDefault("address", ""); From d123bc095134f1cb00ccb80f820be3a4c4fddf88 Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Thu, 12 Dec 2024 15:31:48 +0100 Subject: [PATCH 118/136] Main menu: show favorite removal button for offline servers (#15530) This fixes a regression from 6c324cb871d. --- builtin/mainmenu/tab_online.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua index 112c17457..b8257b90a 100644 --- a/builtin/mainmenu/tab_online.lua +++ b/builtin/mainmenu/tab_online.lua @@ -93,6 +93,11 @@ local function find_selected_server() return server end end + for _, server in ipairs(serverlistmgr.get_favorites()) do + if server.address == address and server.port == port then + return server + end + end end local function get_formspec(tabview, name, tabdata) From 1e59b9a75651130aa7061c2c67dd588d74bb6cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:33:08 +0100 Subject: [PATCH 119/136] Refactor `SkinnedMesh` (#15522) --- irr/include/SkinnedMesh.h | 308 +++++++----- irr/src/CAnimatedMeshSceneNode.cpp | 13 +- irr/src/CAnimatedMeshSceneNode.h | 2 +- irr/src/CB3DMeshFileLoader.cpp | 99 +--- irr/src/CB3DMeshFileLoader.h | 2 +- irr/src/CGLTFMeshFileLoader.cpp | 24 +- irr/src/CGLTFMeshFileLoader.h | 4 +- irr/src/CXMeshFileLoader.cpp | 51 +- irr/src/CXMeshFileLoader.h | 2 +- irr/src/SkinnedMesh.cpp | 778 ++++++----------------------- 10 files changed, 387 insertions(+), 896 deletions(-) diff --git a/irr/include/SkinnedMesh.h b/irr/include/SkinnedMesh.h index 54ce8ed2c..4cf5905c9 100644 --- a/irr/include/SkinnedMesh.h +++ b/irr/include/SkinnedMesh.h @@ -9,6 +9,7 @@ #include "SMeshBuffer.h" #include "SSkinMeshBuffer.h" #include "quaternion.h" +#include "vector3d.h" #include #include @@ -18,18 +19,6 @@ namespace irr namespace scene { -enum E_INTERPOLATION_MODE -{ - // constant does use the current key-values without interpolation - EIM_CONSTANT = 0, - - // linear interpolation - EIM_LINEAR, - - //! count of all available interpolation modes - EIM_COUNT -}; - class IAnimatedMeshSceneNode; class IBoneSceneNode; class ISceneManager; @@ -38,7 +27,14 @@ class SkinnedMesh : public IAnimatedMesh { public: //! constructor - SkinnedMesh(); + SkinnedMesh() : + EndFrame(0.f), FramesPerSecond(25.f), + LastAnimatedFrame(-1), SkinnedLastFrame(false), + HasAnimation(false), PreparedForSkinning(false), + AnimateNormals(true), HardwareSkinning(false) + { + SkinningBuffers = &LocalBuffers; + } //! destructor virtual ~SkinnedMesh(); @@ -58,9 +54,8 @@ public: //! returns the animated mesh for the given frame IMesh *getMesh(f32) override; - //! Animates this mesh's joints based on frame input - //! blend: {0-old position, 1-New position} - void animateMesh(f32 frame, f32 blend); + //! Animates joints based on frame input + void animateMesh(f32 frame); //! Performs a software skin on this mesh based of joint positions void skinMesh(); @@ -82,10 +77,14 @@ public: void setTextureSlot(u32 meshbufNr, u32 textureSlot); //! returns an axis aligned bounding box - const core::aabbox3d &getBoundingBox() const override; + const core::aabbox3d &getBoundingBox() const override { + return BoundingBox; + } //! set user axis aligned bounding box - void setBoundingBox(const core::aabbox3df &box) override; + void setBoundingBox(const core::aabbox3df &box) override { + BoundingBox = box; + } //! set the hardware mapping hint, for driver void setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer = EBT_VERTEX_AND_INDEX) override; @@ -94,7 +93,9 @@ public: void setDirty(E_BUFFER_TYPE buffer = EBT_VERTEX_AND_INDEX) override; //! Returns the type of the animated mesh. - E_ANIMATED_MESH_TYPE getMeshType() const override; + E_ANIMATED_MESH_TYPE getMeshType() const override { + return EAMT_SKINNED; + } //! Gets joint count. u32 getJointCount() const; @@ -112,18 +113,19 @@ public: //! Update Normals when Animating /** \param on If false don't animate, which is faster. Else update normals, which allows for proper lighting of - animated meshes. */ - void updateNormalsWhenAnimating(bool on); - - //! Sets Interpolation Mode - void setInterpolationMode(E_INTERPOLATION_MODE mode); + animated meshes (default). */ + void updateNormalsWhenAnimating(bool on) { + AnimateNormals = on; + } //! converts the vertex type of all meshbuffers to tangents. /** E.g. used for bump mapping. */ void convertMeshToTangents(); //! Does the mesh have no animation - bool isStatic() const; + bool isStatic() const { + return !HasAnimation; + } //! Allows to enable hardware skinning. /* This feature is not implemented in Irrlicht yet */ @@ -138,16 +140,13 @@ public: virtual void updateBoundingBox(); //! Recovers the joints from the mesh - void recoverJointsFromMesh(core::array &jointChildSceneNodes); + void recoverJointsFromMesh(std::vector &jointChildSceneNodes); //! Transfers the joint data to the mesh - void transferJointsToMesh(const core::array &jointChildSceneNodes); - - //! Transfers the joint hints to the mesh - void transferOnlyJointsHintsToMesh(const core::array &jointChildSceneNodes); + void transferJointsToMesh(const std::vector &jointChildSceneNodes); //! Creates an array of joints from this mesh as children of node - void addJoints(core::array &jointChildSceneNodes, + void addJoints(std::vector &jointChildSceneNodes, IAnimatedMeshSceneNode *node, ISceneManager *smgr); @@ -171,35 +170,133 @@ public: core::vector3df StaticNormal; }; - //! Animation keyframe which describes a new position - struct SPositionKey - { - f32 frame; - core::vector3df position; + template + struct Channel { + struct Frame { + f32 time; + T value; + }; + std::vector frames; + bool interpolate = true; + + bool empty() const { + return frames.empty(); + } + + f32 getEndFrame() const { + return frames.empty() ? 0 : frames.back().time; + } + + void pushBack(f32 time, const T &value) { + frames.push_back({time, value}); + } + + void append(const Channel &other) { + frames.insert(frames.end(), other.frames.begin(), other.frames.end()); + } + + void cleanup() { + if (frames.empty()) + return; + + std::vector ordered; + ordered.push_back(frames.front()); + // Drop out-of-order frames + for (auto it = frames.begin() + 1; it != frames.end(); ++it) { + if (it->time > ordered.back().time) { + ordered.push_back(*it); + } + } + frames.clear(); + // Drop redundant middle keys + frames.push_back(ordered.front()); + for (u32 i = 1; i < ordered.size() - 1; ++i) { + if (ordered[i - 1].value != ordered[i].value + || ordered[i + 1].value != ordered[i].value) { + frames.push_back(ordered[i]); + } + } + if (ordered.size() > 1) + frames.push_back(ordered.back()); + frames.shrink_to_fit(); + } + + static core::quaternion interpolateValue(core::quaternion from, core::quaternion to, f32 time) { + core::quaternion result; + result.slerp(from, to, time, 0.001f); + return result; + } + + static core::vector3df interpolateValue(core::vector3df from, core::vector3df to, f32 time) { + // Note: `from` and `to` are swapped here compared to quaternion slerp + return to.getInterpolated(from, time); + } + + std::optional get(f32 time) const { + if (frames.empty()) + return std::nullopt; + + const auto next = std::lower_bound(frames.begin(), frames.end(), time, [](const auto& frame, f32 time) { + return frame.time < time; + }); + if (next == frames.begin()) + return next->value; + if (next == frames.end()) + return frames.back().value; + + const auto prev = next - 1; + if (!interpolate) + return prev->value; + + return interpolateValue(prev->value, next->value, (time - prev->time) / (next->time - prev->time)); + } }; - //! Animation keyframe which describes a new scale - struct SScaleKey - { - f32 frame; - core::vector3df scale; - }; + struct Keys { + Channel position; + Channel rotation; + Channel scale; - //! Animation keyframe which describes a new rotation - struct SRotationKey - { - f32 frame; - core::quaternion rotation; + bool empty() const { + return position.empty() && rotation.empty() && scale.empty(); + } + + void append(const Keys &other) { + position.append(other.position); + rotation.append(other.rotation); + scale.append(other.scale); + } + + f32 getEndFrame() const { + return std::max({ + position.getEndFrame(), + rotation.getEndFrame(), + scale.getEndFrame() + }); + } + + void updateTransform(f32 frame, + core::vector3df &t, core::quaternion &r, core::vector3df &s) const + { + if (auto pos = position.get(frame)) + t = *pos; + if (auto rot = rotation.get(frame)) + r = *rot; + if (auto scl = scale.get(frame)) + s = *scl; + } + + void cleanup() { + position.cleanup(); + rotation.cleanup(); + scale.cleanup(); + } }; //! Joints struct SJoint { - SJoint() : - UseAnimationFrom(0), GlobalSkinningSpace(false), - positionHint(-1), scaleHint(-1), rotationHint(-1) - { - } + SJoint() : GlobalSkinningSpace(false) {} //! The name of this joint std::optional Name; @@ -208,22 +305,16 @@ public: core::matrix4 LocalMatrix; //! List of child joints - core::array Children; + std::vector Children; //! List of attached meshes - core::array AttachedMeshes; + std::vector AttachedMeshes; - //! Animation keys causing translation change - core::array PositionKeys; - - //! Animation keys causing scale change - core::array ScaleKeys; - - //! Animation keys causing rotation change - core::array RotationKeys; + // Animation keyframes for translation, rotation, scale + Keys keys; //! Skin weights - core::array Weights; + std::vector Weights; //! Unnecessary for loaders, will be overwritten on finalize core::matrix4 GlobalMatrix; // loaders may still choose to set this (temporarily) to calculate absolute vertex data. @@ -241,49 +332,14 @@ public: //! Internal members used by SkinnedMesh friend class SkinnedMesh; - SJoint *UseAnimationFrom; bool GlobalSkinningSpace; - - s32 positionHint; - s32 scaleHint; - s32 rotationHint; }; - // Interface for the mesh loaders (finalize should lock these functions, and they should have some prefix like loader_ - // these functions will use the needed arrays, set values, etc to help the loaders + const std::vector &getAllJoints() const { + return AllJoints; + } - //! exposed for loaders to add mesh buffers - core::array &getMeshBuffers(); - - //! alternative method for adding joints - core::array &getAllJoints(); - - //! alternative method for reading joints - const core::array &getAllJoints() const; - - //! loaders should call this after populating the mesh - void finalize(); - - //! Adds a new meshbuffer to the mesh, access it as last one - SSkinMeshBuffer *addMeshBuffer(); - - //! Adds a new meshbuffer to the mesh, access it as last one - void addMeshBuffer(SSkinMeshBuffer *meshbuf); - - //! Adds a new joint to the mesh, access it as last one - SJoint *addJoint(SJoint *parent = 0); - - //! Adds a new position key to the mesh, access it as last one - SPositionKey *addPositionKey(SJoint *joint); - //! Adds a new rotation key to the mesh, access it as last one - SRotationKey *addRotationKey(SJoint *joint); - //! Adds a new scale key to the mesh, access it as last one - SScaleKey *addScaleKey(SJoint *joint); - - //! Adds a new weight to the mesh, access it as last one - SWeight *addWeight(SJoint *joint); - -private: +protected: void checkForAnimation(); void normalizeWeights(); @@ -292,11 +348,6 @@ private: void buildAllGlobalAnimatedMatrices(SJoint *Joint = 0, SJoint *ParentJoint = 0); - void getFrameData(f32 frame, SJoint *Node, - core::vector3df &position, s32 &positionHint, - core::vector3df &scale, s32 &scaleHint, - core::quaternion &rotation, s32 &rotationHint); - void calculateGlobalMatrices(SJoint *Joint, SJoint *ParentJoint); void skinJoint(SJoint *Joint, SJoint *ParentJoint); @@ -306,18 +357,18 @@ private: const core::vector3df &vt1, const core::vector3df &vt2, const core::vector3df &vt3, const core::vector2df &tc1, const core::vector2df &tc2, const core::vector2df &tc3); - core::array *SkinningBuffers; // Meshbuffer to skin, default is to skin localBuffers + std::vector *SkinningBuffers; // Meshbuffer to skin, default is to skin localBuffers - core::array LocalBuffers; + std::vector LocalBuffers; //! Mapping from meshbuffer number to bindable texture slot std::vector TextureSlots; - core::array AllJoints; - core::array RootJoints; + std::vector AllJoints; + std::vector RootJoints; // bool can't be used here because std::vector // doesn't allow taking a reference to individual elements. - core::array> Vertices_Moved; + std::vector> Vertices_Moved; core::aabbox3d BoundingBox; @@ -327,13 +378,42 @@ private: f32 LastAnimatedFrame; bool SkinnedLastFrame; - E_INTERPOLATION_MODE InterpolationMode : 8; - bool HasAnimation; bool PreparedForSkinning; bool AnimateNormals; bool HardwareSkinning; }; +// Interface for mesh loaders +class SkinnedMeshBuilder : public SkinnedMesh { +public: + SkinnedMeshBuilder() : SkinnedMesh() {} + + //! loaders should call this after populating the mesh + // returns *this, so do not try to drop the mesh builder instance + SkinnedMesh *finalize(); + + //! alternative method for adding joints + std::vector &getAllJoints() { + return AllJoints; + } + + //! Adds a new meshbuffer to the mesh, access it as last one + SSkinMeshBuffer *addMeshBuffer(); + + //! Adds a new meshbuffer to the mesh, access it as last one + void addMeshBuffer(SSkinMeshBuffer *meshbuf); + + //! Adds a new joint to the mesh, access it as last one + SJoint *addJoint(SJoint *parent = nullptr); + + void addPositionKey(SJoint *joint, f32 frame, core::vector3df pos); + void addRotationKey(SJoint *joint, f32 frame, core::quaternion rotation); + void addScaleKey(SJoint *joint, f32 frame, core::vector3df scale); + + //! Adds a new weight to the mesh, access it as last one + SWeight *addWeight(SJoint *joint); +}; + } // end namespace scene } // end namespace irr diff --git a/irr/src/CAnimatedMeshSceneNode.cpp b/irr/src/CAnimatedMeshSceneNode.cpp index 5250fe889..d249e37c5 100644 --- a/irr/src/CAnimatedMeshSceneNode.cpp +++ b/irr/src/CAnimatedMeshSceneNode.cpp @@ -170,7 +170,7 @@ IMesh *CAnimatedMeshSceneNode::getMeshForCurrentFrame() if (JointMode == EJUOR_CONTROL) // write to mesh skinnedMesh->transferJointsToMesh(JointChildSceneNodes); else - skinnedMesh->animateMesh(getFrameNr(), 1.0f); + skinnedMesh->animateMesh(getFrameNr()); // Update the skinned mesh for the current joint transforms. skinnedMesh->skinMesh(); @@ -299,12 +299,10 @@ void CAnimatedMeshSceneNode::render() if (Mesh->getMeshType() == EAMT_SKINNED) { // draw skeleton - for (u32 g = 0; g < ((SkinnedMesh *)Mesh)->getAllJoints().size(); ++g) { - auto *joint = ((SkinnedMesh *)Mesh)->getAllJoints()[g]; - - for (u32 n = 0; n < joint->Children.size(); ++n) { + for (auto *joint : ((SkinnedMesh *)Mesh)->getAllJoints()) { + for (const auto *childJoint : joint->Children) { driver->draw3DLine(joint->GlobalAnimatedMatrix.getTranslation(), - joint->Children[n]->GlobalAnimatedMatrix.getTranslation(), + childJoint->GlobalAnimatedMatrix.getTranslation(), video::SColor(255, 51, 66, 255)); } } @@ -598,8 +596,7 @@ void CAnimatedMeshSceneNode::animateJoints(bool CalculateAbsolutePositions) SkinnedMesh *skinnedMesh = static_cast(Mesh); - skinnedMesh->transferOnlyJointsHintsToMesh(JointChildSceneNodes); - skinnedMesh->animateMesh(frame, 1.0f); + skinnedMesh->animateMesh(frame); skinnedMesh->recoverJointsFromMesh(JointChildSceneNodes); //----------------------------------------- diff --git a/irr/src/CAnimatedMeshSceneNode.h b/irr/src/CAnimatedMeshSceneNode.h index e45edca86..047a4030f 100644 --- a/irr/src/CAnimatedMeshSceneNode.h +++ b/irr/src/CAnimatedMeshSceneNode.h @@ -169,7 +169,7 @@ private: IAnimationEndCallBack *LoopCallBack; s32 PassCount; - core::array JointChildSceneNodes; + std::vector JointChildSceneNodes; core::array PretransitingSave; }; diff --git a/irr/src/CB3DMeshFileLoader.cpp b/irr/src/CB3DMeshFileLoader.cpp index 6923cde04..3bcc4b85f 100644 --- a/irr/src/CB3DMeshFileLoader.cpp +++ b/irr/src/CB3DMeshFileLoader.cpp @@ -10,6 +10,7 @@ #include "IVideoDriver.h" #include "IFileSystem.h" +#include "SkinnedMesh.h" #include "coreutil.h" #include "os.h" @@ -51,12 +52,12 @@ IAnimatedMesh *CB3DMeshFileLoader::createMesh(io::IReadFile *file) return 0; B3DFile = file; - AnimatedMesh = new scene::SkinnedMesh(); + AnimatedMesh = new scene::SkinnedMeshBuilder(); ShowWarning = true; // If true a warning is issued if too many textures are used VerticesStart = 0; if (load()) { - AnimatedMesh->finalize(); + return AnimatedMesh->finalize(); } else { AnimatedMesh->drop(); AnimatedMesh = 0; @@ -254,7 +255,7 @@ bool CB3DMeshFileLoader::readChunkMESH(SkinnedMesh::SJoint *inJoint) meshBuffer->Material = Materials[brushID].Material; } - if (readChunkTRIS(meshBuffer, AnimatedMesh->getMeshBuffers().size() - 1, VerticesStart) == false) + if (readChunkTRIS(meshBuffer, AnimatedMesh->getMeshBufferCount() - 1, VerticesStart) == false) return false; if (!NormalsInFile) { @@ -569,7 +570,7 @@ bool CB3DMeshFileLoader::readChunkKEYS(SkinnedMesh::SJoint *inJoint) { #ifdef _B3D_READER_DEBUG // Only print first, that's just too much output otherwise - if (!inJoint || (inJoint->PositionKeys.empty() && inJoint->ScaleKeys.empty() && inJoint->RotationKeys.empty())) { + if (!inJoint || inJoint->keys.empty()) { core::stringc logStr; for (u32 i = 1; i < B3dStack.size(); ++i) logStr += "-"; @@ -584,13 +585,6 @@ bool CB3DMeshFileLoader::readChunkKEYS(SkinnedMesh::SJoint *inJoint) flags = os::Byteswap::byteswap(flags); #endif - SkinnedMesh::SPositionKey *oldPosKey = 0; - core::vector3df oldPos[2]; - SkinnedMesh::SScaleKey *oldScaleKey = 0; - core::vector3df oldScale[2]; - SkinnedMesh::SRotationKey *oldRotKey = 0; - core::quaternion oldRot[2]; - bool isFirst[3] = {true, true, true}; while ((B3dStack.getLast().startposition + B3dStack.getLast().length) > B3DFile->getPos()) // this chunk repeats { s32 frame; @@ -600,91 +594,24 @@ bool CB3DMeshFileLoader::readChunkKEYS(SkinnedMesh::SJoint *inJoint) frame = os::Byteswap::byteswap(frame); #endif + if (frame < 1) { + os::Printer::log("Illegal frame number found", B3DFile->getFileName(), ELL_ERROR); + frame = 1; + } + // Add key frames, frames in Irrlicht are zero-based f32 data[4]; if (flags & 1) { readFloats(data, 3); - if ((oldPosKey != 0) && (oldPos[0] == oldPos[1])) { - const core::vector3df pos(data[0], data[1], data[2]); - if (oldPos[1] == pos) - oldPosKey->frame = (f32)frame - 1; - else { - oldPos[0] = oldPos[1]; - oldPosKey = AnimatedMesh->addPositionKey(inJoint); - oldPosKey->frame = (f32)frame - 1; - oldPos[1].set(oldPosKey->position.set(pos)); - } - } else if (oldPosKey == 0 && isFirst[0]) { - oldPosKey = AnimatedMesh->addPositionKey(inJoint); - oldPosKey->frame = (f32)frame - 1; - oldPos[0].set(oldPosKey->position.set(data[0], data[1], data[2])); - oldPosKey = 0; - isFirst[0] = false; - } else { - if (oldPosKey != 0) - oldPos[0] = oldPos[1]; - oldPosKey = AnimatedMesh->addPositionKey(inJoint); - oldPosKey->frame = (f32)frame - 1; - oldPos[1].set(oldPosKey->position.set(data[0], data[1], data[2])); - } + AnimatedMesh->addPositionKey(inJoint, frame - 1, {data[0], data[1], data[2]}); } if (flags & 2) { readFloats(data, 3); - if ((oldScaleKey != 0) && (oldScale[0] == oldScale[1])) { - const core::vector3df scale(data[0], data[1], data[2]); - if (oldScale[1] == scale) - oldScaleKey->frame = (f32)frame - 1; - else { - oldScale[0] = oldScale[1]; - oldScaleKey = AnimatedMesh->addScaleKey(inJoint); - oldScaleKey->frame = (f32)frame - 1; - oldScale[1].set(oldScaleKey->scale.set(scale)); - } - } else if (oldScaleKey == 0 && isFirst[1]) { - oldScaleKey = AnimatedMesh->addScaleKey(inJoint); - oldScaleKey->frame = (f32)frame - 1; - oldScale[0].set(oldScaleKey->scale.set(data[0], data[1], data[2])); - oldScaleKey = 0; - isFirst[1] = false; - } else { - if (oldScaleKey != 0) - oldScale[0] = oldScale[1]; - oldScaleKey = AnimatedMesh->addScaleKey(inJoint); - oldScaleKey->frame = (f32)frame - 1; - oldScale[1].set(oldScaleKey->scale.set(data[0], data[1], data[2])); - } + AnimatedMesh->addScaleKey(inJoint, frame - 1, {data[0], data[1], data[2]}); } if (flags & 4) { readFloats(data, 4); - if ((oldRotKey != 0) && (oldRot[0] == oldRot[1])) { - // meant to be in this order since b3d stores W first - const core::quaternion rot(data[1], data[2], data[3], data[0]); - if (oldRot[1] == rot) - oldRotKey->frame = (f32)frame - 1; - else { - oldRot[0] = oldRot[1]; - oldRotKey = AnimatedMesh->addRotationKey(inJoint); - oldRotKey->frame = (f32)frame - 1; - oldRot[1].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0])); - oldRot[1].normalize(); - } - } else if (oldRotKey == 0 && isFirst[2]) { - oldRotKey = AnimatedMesh->addRotationKey(inJoint); - oldRotKey->frame = (f32)frame - 1; - // meant to be in this order since b3d stores W first - oldRot[0].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0])); - oldRot[0].normalize(); - oldRotKey = 0; - isFirst[2] = false; - } else { - if (oldRotKey != 0) - oldRot[0] = oldRot[1]; - oldRotKey = AnimatedMesh->addRotationKey(inJoint); - oldRotKey->frame = (f32)frame - 1; - // meant to be in this order since b3d stores W first - oldRot[1].set(oldRotKey->rotation.set(data[1], data[2], data[3], data[0])); - oldRot[1].normalize(); - } + AnimatedMesh->addRotationKey(inJoint, frame - 1, core::quaternion(data[1], data[2], data[3], data[0])); } } diff --git a/irr/src/CB3DMeshFileLoader.h b/irr/src/CB3DMeshFileLoader.h index 711f2737f..55978d743 100644 --- a/irr/src/CB3DMeshFileLoader.h +++ b/irr/src/CB3DMeshFileLoader.h @@ -63,7 +63,7 @@ private: core::array BaseVertices; - SkinnedMesh *AnimatedMesh; + SkinnedMeshBuilder *AnimatedMesh; io::IReadFile *B3DFile; // B3Ds have Vertex ID's local within the mesh I don't want this diff --git a/irr/src/CGLTFMeshFileLoader.cpp b/irr/src/CGLTFMeshFileLoader.cpp index 139b4f670..79c68355b 100644 --- a/irr/src/CGLTFMeshFileLoader.cpp +++ b/irr/src/CGLTFMeshFileLoader.cpp @@ -346,14 +346,14 @@ IAnimatedMesh* SelfType::createMesh(io::IReadFile* file) const char *filename = file->getFileName().c_str(); try { tiniergltf::GlTF model = parseGLTF(file); - irr_ptr mesh(new SkinnedMesh()); + irr_ptr mesh(new SkinnedMeshBuilder()); MeshExtractor extractor(std::move(model), mesh.get()); try { extractor.load(); for (const auto &warning : extractor.getWarnings()) { os::Printer::log(filename, warning.c_str(), ELL_WARNING); } - return mesh.release(); + return mesh.release()->finalize(); } catch (const std::runtime_error &e) { os::Printer::log("error converting gltf to irrlicht mesh", e.what(), ELL_ERROR); } @@ -691,27 +691,27 @@ void SelfType::MeshExtractor::loadAnimation(const std::size_t animIdx) case tiniergltf::AnimationChannelTarget::Path::TRANSLATION: { const auto outputAccessor = Accessor::make(m_gltf_model, sampler.output); for (std::size_t i = 0; i < n_frames; ++i) { - auto *key = m_irr_model->addPositionKey(joint); - key->frame = inputAccessor.get(i); - key->position = convertHandedness(outputAccessor.get(i)); + f32 frame = inputAccessor.get(i); + core::vector3df position = outputAccessor.get(i); + m_irr_model->addPositionKey(joint, frame, convertHandedness(position)); } break; } case tiniergltf::AnimationChannelTarget::Path::ROTATION: { const auto outputAccessor = Accessor::make(m_gltf_model, sampler.output); for (std::size_t i = 0; i < n_frames; ++i) { - auto *key = m_irr_model->addRotationKey(joint); - key->frame = inputAccessor.get(i); - key->rotation = convertHandedness(outputAccessor.get(i)); + f32 frame = inputAccessor.get(i); + core::quaternion rotation = outputAccessor.get(i); + m_irr_model->addRotationKey(joint, frame, convertHandedness(rotation)); } break; } case tiniergltf::AnimationChannelTarget::Path::SCALE: { const auto outputAccessor = Accessor::make(m_gltf_model, sampler.output); for (std::size_t i = 0; i < n_frames; ++i) { - auto *key = m_irr_model->addScaleKey(joint); - key->frame = inputAccessor.get(i); - key->scale = outputAccessor.get(i); + f32 frame = inputAccessor.get(i); + core::vector3df scale = outputAccessor.get(i); + m_irr_model->addScaleKey(joint, frame, scale); } break; } @@ -756,8 +756,6 @@ void SelfType::MeshExtractor::load() } catch (const std::bad_optional_access &e) { throw std::runtime_error(e.what()); } - - m_irr_model->finalize(); } /** diff --git a/irr/src/CGLTFMeshFileLoader.h b/irr/src/CGLTFMeshFileLoader.h index 1671d2903..a4eac8baa 100644 --- a/irr/src/CGLTFMeshFileLoader.h +++ b/irr/src/CGLTFMeshFileLoader.h @@ -100,7 +100,7 @@ private: { public: MeshExtractor(tiniergltf::GlTF &&model, - SkinnedMesh *mesh) noexcept + SkinnedMeshBuilder *mesh) noexcept : m_gltf_model(std::move(model)), m_irr_model(mesh) {}; /* Gets indices for the given mesh/primitive. @@ -124,7 +124,7 @@ private: private: const tiniergltf::GlTF m_gltf_model; - SkinnedMesh *m_irr_model; + SkinnedMeshBuilder *m_irr_model; std::vector> m_mesh_loaders; std::vector m_loaded_nodes; diff --git a/irr/src/CXMeshFileLoader.cpp b/irr/src/CXMeshFileLoader.cpp index 19d4e5b01..cb02298eb 100644 --- a/irr/src/CXMeshFileLoader.cpp +++ b/irr/src/CXMeshFileLoader.cpp @@ -3,6 +3,7 @@ // For conditions of distribution and use, see copyright notice in irrlicht.h #include "CXMeshFileLoader.h" +#include "SkinnedMesh.h" #include "os.h" #include "fast_atof.h" @@ -57,7 +58,7 @@ IAnimatedMesh *CXMeshFileLoader::createMesh(io::IReadFile *file) u32 time = os::Timer::getRealTime(); #endif - AnimatedMesh = new SkinnedMesh(); + AnimatedMesh = new SkinnedMeshBuilder(); if (load(file)) { AnimatedMesh->finalize(); @@ -92,7 +93,7 @@ IAnimatedMesh *CXMeshFileLoader::createMesh(io::IReadFile *file) delete Meshes[i]; Meshes.clear(); - return AnimatedMesh; + return AnimatedMesh->finalize(); } bool CXMeshFileLoader::load(io::IReadFile *file) @@ -124,7 +125,7 @@ bool CXMeshFileLoader::load(io::IReadFile *file) if (!mesh->HasSkinning) { // Set up rigid animation if (mesh->AttachedJointID != -1) { - AnimatedMesh->getAllJoints()[mesh->AttachedJointID]->AttachedMeshes.push_back(AnimatedMesh->getMeshBuffers().size() - 1); + AnimatedMesh->getAllJoints()[mesh->AttachedJointID]->AttachedMeshes.push_back(AnimatedMesh->getMeshBufferCount() - 1); } } } @@ -965,7 +966,7 @@ bool CXMeshFileLoader::parseDataObjectSkinWeights(SXMesh &mesh) u32 i; const u32 jointStart = joint->Weights.size(); - joint->Weights.reallocate(jointStart + nWeights); + joint->Weights.resize(jointStart + nWeights); mesh.WeightJoint.reallocate(mesh.WeightJoint.size() + nWeights); mesh.WeightNum.reallocate(mesh.WeightNum.size() + nWeights); @@ -1411,20 +1412,7 @@ bool CXMeshFileLoader::parseDataObjectAnimation() joint->Name = FrameName.c_str(); } - joint->PositionKeys.reallocate(joint->PositionKeys.size() + animationDump.PositionKeys.size()); - for (u32 n = 0; n < animationDump.PositionKeys.size(); ++n) { - joint->PositionKeys.push_back(animationDump.PositionKeys[n]); - } - - joint->ScaleKeys.reallocate(joint->ScaleKeys.size() + animationDump.ScaleKeys.size()); - for (u32 n = 0; n < animationDump.ScaleKeys.size(); ++n) { - joint->ScaleKeys.push_back(animationDump.ScaleKeys[n]); - } - - joint->RotationKeys.reallocate(joint->RotationKeys.size() + animationDump.RotationKeys.size()); - for (u32 n = 0; n < animationDump.RotationKeys.size(); ++n) { - joint->RotationKeys.push_back(animationDump.RotationKeys[n]); - } + joint->keys.append(animationDump.keys); } else os::Printer::log("joint name was never given", ELL_WARNING); @@ -1488,10 +1476,9 @@ bool CXMeshFileLoader::parseDataObjectAnimationKey(SkinnedMesh::SJoint *joint) os::Printer::log("Line", core::stringc(Line).c_str(), ELL_WARNING); } - SkinnedMesh::SRotationKey *key = AnimatedMesh->addRotationKey(joint); - key->frame = time; - key->rotation.set(X, Y, Z, W); - key->rotation.normalize(); + core::quaternion rotation(X, Y, Z, W); + rotation.normalize(); + AnimatedMesh->addRotationKey(joint, time, rotation); } break; case 1: // scale case 2: // position @@ -1514,13 +1501,9 @@ bool CXMeshFileLoader::parseDataObjectAnimationKey(SkinnedMesh::SJoint *joint) } if (keyType == 2) { - SkinnedMesh::SPositionKey *key = AnimatedMesh->addPositionKey(joint); - key->frame = time; - key->position = vector; + AnimatedMesh->addPositionKey(joint, time, vector); } else { - SkinnedMesh::SScaleKey *key = AnimatedMesh->addScaleKey(joint); - key->frame = time; - key->scale = vector; + AnimatedMesh->addScaleKey(joint, time, vector); } } break; case 3: @@ -1547,16 +1530,8 @@ bool CXMeshFileLoader::parseDataObjectAnimationKey(SkinnedMesh::SJoint *joint) // core::vector3df rotation = mat.getRotationDegrees(); - SkinnedMesh::SRotationKey *keyR = AnimatedMesh->addRotationKey(joint); - keyR->frame = time; - - // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched from mat to mat.getTransposed() for downward compatibility. - // Not tested so far if this was correct or wrong before quaternion fix! - keyR->rotation = core::quaternion(mat.getTransposed()); - - SkinnedMesh::SPositionKey *keyP = AnimatedMesh->addPositionKey(joint); - keyP->frame = time; - keyP->position = mat.getTranslation(); + AnimatedMesh->addRotationKey(joint, time, core::quaternion(mat.getTransposed())); + AnimatedMesh->addPositionKey(joint, time, mat.getTranslation()); /* core::vector3df scale=mat.getScale(); diff --git a/irr/src/CXMeshFileLoader.h b/irr/src/CXMeshFileLoader.h index 0902651a9..36610d3b3 100644 --- a/irr/src/CXMeshFileLoader.h +++ b/irr/src/CXMeshFileLoader.h @@ -155,7 +155,7 @@ private: bool readRGB(video::SColor &color); bool readRGBA(video::SColor &color); - SkinnedMesh *AnimatedMesh; + SkinnedMeshBuilder *AnimatedMesh; c8 *Buffer; const c8 *P; diff --git a/irr/src/SkinnedMesh.cpp b/irr/src/SkinnedMesh.cpp index 76bce0b87..64b25205e 100644 --- a/irr/src/SkinnedMesh.cpp +++ b/irr/src/SkinnedMesh.cpp @@ -8,106 +8,22 @@ #include "IAnimatedMeshSceneNode.h" #include "SSkinMeshBuffer.h" #include "os.h" - -namespace -{ -// Frames must always be increasing, so we remove objects where this isn't the case -// return number of kicked keys -template // T = objects containing a "frame" variable -irr::u32 dropBadKeys(irr::core::array &array) -{ - if (array.size() < 2) - return 0; - - irr::u32 n = 1; // new index - for (irr::u32 j = 1; j < array.size(); ++j) { - if (array[j].frame < array[n - 1].frame) - continue; // bad frame, unneeded and may cause problems - if (n != j) - array[n] = array[j]; - ++n; - } - irr::u32 d = array.size() - n; // remove already copied keys - if (d > 0) { - array.erase(n, d); - } - return d; -} - -// drop identical middle keys - we only need the first and last -// return number of kicked keys -template // Cmp = comparison for keys of type T -irr::u32 dropMiddleKeys(irr::core::array &array, Cmp &cmp) -{ - if (array.size() < 3) - return 0; - - irr::u32 s = 0; // old index for current key - irr::u32 n = 1; // new index for next key - for (irr::u32 j = 1; j < array.size(); ++j) { - if (cmp(array[j], array[s])) - continue; // same key, handle later - - if (j > s + 1) // had there been identical keys? - array[n++] = array[j - 1]; // keep the last - array[n++] = array[j]; // keep the new one - s = j; - } - if (array.size() > s + 1) // identical keys at the array end? - array[n++] = array[array.size() - 1]; // keep the last - - irr::u32 d = array.size() - n; // remove already copied keys - if (d > 0) { - array.erase(n, d); - } - return d; -} - -bool identicalPos(const irr::scene::SkinnedMesh::SPositionKey &a, const irr::scene::SkinnedMesh::SPositionKey &b) -{ - return a.position == b.position; -} - -bool identicalScale(const irr::scene::SkinnedMesh::SScaleKey &a, const irr::scene::SkinnedMesh::SScaleKey &b) -{ - return a.scale == b.scale; -} - -bool identicalRotation(const irr::scene::SkinnedMesh::SRotationKey &a, const irr::scene::SkinnedMesh::SRotationKey &b) -{ - return a.rotation == b.rotation; -} -} +#include namespace irr { namespace scene { -//! constructor -SkinnedMesh::SkinnedMesh() : - SkinningBuffers(0), EndFrame(0.f), FramesPerSecond(25.f), - LastAnimatedFrame(-1), SkinnedLastFrame(false), - InterpolationMode(EIM_LINEAR), - HasAnimation(false), PreparedForSkinning(false), - AnimateNormals(true), HardwareSkinning(false) -{ -#ifdef _DEBUG - setDebugName("SkinnedMesh"); -#endif - - SkinningBuffers = &LocalBuffers; -} - //! destructor SkinnedMesh::~SkinnedMesh() { - for (u32 i = 0; i < AllJoints.size(); ++i) - delete AllJoints[i]; + for (auto *joint : AllJoints) + delete joint; - for (u32 j = 0; j < LocalBuffers.size(); ++j) { - if (LocalBuffers[j]) - LocalBuffers[j]->drop(); + for (auto *buffer : LocalBuffers) { + if (buffer) + buffer->drop(); } } @@ -138,7 +54,7 @@ IMesh *SkinnedMesh::getMesh(f32 frame) if (frame == -1) return this; - animateMesh(frame, 1.0f); + animateMesh(frame); skinMesh(); return this; } @@ -147,9 +63,8 @@ IMesh *SkinnedMesh::getMesh(f32 frame) // Keyframe Animation //-------------------------------------------------------------------------- -//! Animates this mesh's joints based on frame input -//! blend: {0-old position, 1-New position} -void SkinnedMesh::animateMesh(f32 frame, f32 blend) +//! Animates joints based on frame input +void SkinnedMesh::animateMesh(f32 frame) { if (!HasAnimation || LastAnimatedFrame == frame) return; @@ -157,39 +72,14 @@ void SkinnedMesh::animateMesh(f32 frame, f32 blend) LastAnimatedFrame = frame; SkinnedLastFrame = false; - if (blend <= 0.f) - return; // No need to animate - - for (u32 i = 0; i < AllJoints.size(); ++i) { + for (auto *joint : AllJoints) { // The joints can be animated here with no input from their // parents, but for setAnimationMode extra checks are needed // to their parents - SJoint *joint = AllJoints[i]; - - const core::vector3df oldPosition = joint->Animatedposition; - const core::vector3df oldScale = joint->Animatedscale; - const core::quaternion oldRotation = joint->Animatedrotation; - - core::vector3df position = oldPosition; - core::vector3df scale = oldScale; - core::quaternion rotation = oldRotation; - - getFrameData(frame, joint, - position, joint->positionHint, - scale, joint->scaleHint, - rotation, joint->rotationHint); - - if (blend == 1.0f) { - // No blending needed - joint->Animatedposition = position; - joint->Animatedscale = scale; - joint->Animatedrotation = rotation; - } else { - // Blend animation - joint->Animatedposition = core::lerp(oldPosition, position, blend); - joint->Animatedscale = core::lerp(oldScale, scale, blend); - joint->Animatedrotation.slerp(oldRotation, rotation, blend); - } + joint->keys.updateTransform(frame, + joint->Animatedposition, + joint->Animatedrotation, + joint->Animatedscale); } // Note: @@ -207,15 +97,10 @@ void SkinnedMesh::animateMesh(f32 frame, f32 blend) void SkinnedMesh::buildAllLocalAnimatedMatrices() { - for (u32 i = 0; i < AllJoints.size(); ++i) { - SJoint *joint = AllJoints[i]; - + for (auto *joint : AllJoints) { // Could be faster: - if (joint->UseAnimationFrom && - (joint->UseAnimationFrom->PositionKeys.size() || - joint->UseAnimationFrom->ScaleKeys.size() || - joint->UseAnimationFrom->RotationKeys.size())) { + if (!joint->keys.empty()) { joint->GlobalSkinningSpace = false; // IRR_TEST_BROKEN_QUATERNION_USE: TODO - switched to getMatrix_transposed instead of getMatrix for downward compatibility. @@ -240,7 +125,7 @@ void SkinnedMesh::buildAllLocalAnimatedMatrices() m1[14] += Pos.Z * m1[15]; // ----------------------------------- - if (joint->ScaleKeys.size()) { + if (!joint->keys.scale.empty()) { /* core::matrix4 scaleMatrix; scaleMatrix.setScale(joint->Animatedscale); @@ -273,8 +158,8 @@ void SkinnedMesh::buildAllLocalAnimatedMatrices() void SkinnedMesh::buildAllGlobalAnimatedMatrices(SJoint *joint, SJoint *parentJoint) { if (!joint) { - for (u32 i = 0; i < RootJoints.size(); ++i) - buildAllGlobalAnimatedMatrices(RootJoints[i], 0); + for (auto *rootJoint : RootJoints) + buildAllGlobalAnimatedMatrices(rootJoint, 0); return; } else { // Find global matrix... @@ -284,168 +169,8 @@ void SkinnedMesh::buildAllGlobalAnimatedMatrices(SJoint *joint, SJoint *parentJo joint->GlobalAnimatedMatrix = parentJoint->GlobalAnimatedMatrix * joint->LocalAnimatedMatrix; } - for (u32 j = 0; j < joint->Children.size(); ++j) - buildAllGlobalAnimatedMatrices(joint->Children[j], joint); -} - -void SkinnedMesh::getFrameData(f32 frame, SJoint *joint, - core::vector3df &position, s32 &positionHint, - core::vector3df &scale, s32 &scaleHint, - core::quaternion &rotation, s32 &rotationHint) -{ - s32 foundPositionIndex = -1; - s32 foundScaleIndex = -1; - s32 foundRotationIndex = -1; - - if (joint->UseAnimationFrom) { - const core::array &PositionKeys = joint->UseAnimationFrom->PositionKeys; - const core::array &ScaleKeys = joint->UseAnimationFrom->ScaleKeys; - const core::array &RotationKeys = joint->UseAnimationFrom->RotationKeys; - - if (PositionKeys.size()) { - foundPositionIndex = -1; - - // Test the Hints... - if (positionHint >= 0 && (u32)positionHint < PositionKeys.size()) { - // check this hint - if (positionHint > 0 && PositionKeys[positionHint].frame >= frame && PositionKeys[positionHint - 1].frame < frame) - foundPositionIndex = positionHint; - else if (positionHint + 1 < (s32)PositionKeys.size()) { - // check the next index - if (PositionKeys[positionHint + 1].frame >= frame && - PositionKeys[positionHint + 0].frame < frame) { - positionHint++; - foundPositionIndex = positionHint; - } - } - } - - // The hint test failed, do a full scan... - if (foundPositionIndex == -1) { - for (u32 i = 0; i < PositionKeys.size(); ++i) { - if (PositionKeys[i].frame >= frame) { // Keys should to be sorted by frame - foundPositionIndex = i; - positionHint = i; - break; - } - } - } - - // Do interpolation... - if (foundPositionIndex != -1) { - if (InterpolationMode == EIM_CONSTANT || foundPositionIndex == 0) { - position = PositionKeys[foundPositionIndex].position; - } else if (InterpolationMode == EIM_LINEAR) { - const SPositionKey &KeyA = PositionKeys[foundPositionIndex]; - const SPositionKey &KeyB = PositionKeys[foundPositionIndex - 1]; - - const f32 fd1 = frame - KeyA.frame; - const f32 fd2 = KeyB.frame - frame; - position = ((KeyB.position - KeyA.position) / (fd1 + fd2)) * fd1 + KeyA.position; - } - } - } - - //------------------------------------------------------------ - - if (ScaleKeys.size()) { - foundScaleIndex = -1; - - // Test the Hints... - if (scaleHint >= 0 && (u32)scaleHint < ScaleKeys.size()) { - // check this hint - if (scaleHint > 0 && ScaleKeys[scaleHint].frame >= frame && ScaleKeys[scaleHint - 1].frame < frame) - foundScaleIndex = scaleHint; - else if (scaleHint + 1 < (s32)ScaleKeys.size()) { - // check the next index - if (ScaleKeys[scaleHint + 1].frame >= frame && - ScaleKeys[scaleHint + 0].frame < frame) { - scaleHint++; - foundScaleIndex = scaleHint; - } - } - } - - // The hint test failed, do a full scan... - if (foundScaleIndex == -1) { - for (u32 i = 0; i < ScaleKeys.size(); ++i) { - if (ScaleKeys[i].frame >= frame) { // Keys should to be sorted by frame - foundScaleIndex = i; - scaleHint = i; - break; - } - } - } - - // Do interpolation... - if (foundScaleIndex != -1) { - if (InterpolationMode == EIM_CONSTANT || foundScaleIndex == 0) { - scale = ScaleKeys[foundScaleIndex].scale; - } else if (InterpolationMode == EIM_LINEAR) { - const SScaleKey &KeyA = ScaleKeys[foundScaleIndex]; - const SScaleKey &KeyB = ScaleKeys[foundScaleIndex - 1]; - - const f32 fd1 = frame - KeyA.frame; - const f32 fd2 = KeyB.frame - frame; - scale = ((KeyB.scale - KeyA.scale) / (fd1 + fd2)) * fd1 + KeyA.scale; - } - } - } - - //------------------------------------------------------------- - - if (RotationKeys.size()) { - foundRotationIndex = -1; - - // Test the Hints... - if (rotationHint >= 0 && (u32)rotationHint < RotationKeys.size()) { - // check this hint - if (rotationHint > 0 && RotationKeys[rotationHint].frame >= frame && RotationKeys[rotationHint - 1].frame < frame) - foundRotationIndex = rotationHint; - else if (rotationHint + 1 < (s32)RotationKeys.size()) { - // check the next index - if (RotationKeys[rotationHint + 1].frame >= frame && - RotationKeys[rotationHint + 0].frame < frame) { - rotationHint++; - foundRotationIndex = rotationHint; - } - } - } - - // The hint test failed, do a full scan... - if (foundRotationIndex == -1) { - for (u32 i = 0; i < RotationKeys.size(); ++i) { - if (RotationKeys[i].frame >= frame) { // Keys should be sorted by frame - foundRotationIndex = i; - rotationHint = i; - break; - } - } - } - - // Do interpolation... - if (foundRotationIndex != -1) { - if (InterpolationMode == EIM_CONSTANT || foundRotationIndex == 0) { - rotation = RotationKeys[foundRotationIndex].rotation; - } else if (InterpolationMode == EIM_LINEAR) { - const SRotationKey &KeyA = RotationKeys[foundRotationIndex]; - const SRotationKey &KeyB = RotationKeys[foundRotationIndex - 1]; - - const f32 fd1 = frame - KeyA.frame; - const f32 fd2 = KeyB.frame - frame; - const f32 t = fd1 / (fd1 + fd2); - - /* - f32 t = 0; - if (KeyA.frame!=KeyB.frame) - t = (frame-KeyA.frame) / (KeyB.frame - KeyA.frame); - */ - - rotation.slerp(KeyA.rotation, KeyB.rotation, t); - } - } - } - } + for (auto *childJoint : joint->Children) + buildAllGlobalAnimatedMatrices(childJoint, joint); } //-------------------------------------------------------------------------- @@ -465,28 +190,24 @@ void SkinnedMesh::skinMesh() SkinnedLastFrame = true; if (!HardwareSkinning) { - // Software skin.... - u32 i; - // rigid animation - for (i = 0; i < AllJoints.size(); ++i) { - for (u32 j = 0; j < AllJoints[i]->AttachedMeshes.size(); ++j) { - SSkinMeshBuffer *Buffer = (*SkinningBuffers)[AllJoints[i]->AttachedMeshes[j]]; - Buffer->Transformation = AllJoints[i]->GlobalAnimatedMatrix; + for (auto *joint : AllJoints) { + for (u32 attachedMeshIdx : joint->AttachedMeshes) { + SSkinMeshBuffer *Buffer = (*SkinningBuffers)[attachedMeshIdx]; + Buffer->Transformation = joint->GlobalAnimatedMatrix; } } // clear skinning helper array - for (i = 0; i < Vertices_Moved.size(); ++i) - for (u32 j = 0; j < Vertices_Moved[i].size(); ++j) - Vertices_Moved[i][j] = false; + for (std::vector &buf : Vertices_Moved) + std::fill(buf.begin(), buf.end(), false); // skin starting with the root joints - for (i = 0; i < RootJoints.size(); ++i) - skinJoint(RootJoints[i], 0); + for (auto *rootJoint : RootJoints) + skinJoint(rootJoint, 0); - for (i = 0; i < SkinningBuffers->size(); ++i) - (*SkinningBuffers)[i]->setDirty(EBT_VERTEX); + for (auto *buffer : *SkinningBuffers) + buffer->setDirty(EBT_VERTEX); } updateBoundingBox(); } @@ -500,12 +221,10 @@ void SkinnedMesh::skinJoint(SJoint *joint, SJoint *parentJoint) core::vector3df thisVertexMove, thisNormalMove; - core::array &buffersUsed = *SkinningBuffers; + auto &buffersUsed = *SkinningBuffers; // Skin Vertices Positions and Normals... - for (u32 i = 0; i < joint->Weights.size(); ++i) { - SWeight &weight = joint->Weights[i]; - + for (const auto &weight : joint->Weights) { // Pull this vertex... jointVertexPull.transformVect(thisVertexMove, weight.StaticPos); @@ -537,13 +256,8 @@ void SkinnedMesh::skinJoint(SJoint *joint, SJoint *parentJoint) } // Skin all children - for (u32 j = 0; j < joint->Children.size(); ++j) - skinJoint(joint->Children[j], joint); -} - -E_ANIMATED_MESH_TYPE SkinnedMesh::getMeshType() const -{ - return EAMT_SKINNED; + for (auto *childJoint : joint->Children) + skinJoint(childJoint, joint); } //! Gets joint count. @@ -607,18 +321,6 @@ void SkinnedMesh::setTextureSlot(u32 meshbufNr, u32 textureSlot) { TextureSlots.at(meshbufNr) = textureSlot; } -//! returns an axis aligned bounding box -const core::aabbox3d &SkinnedMesh::getBoundingBox() const -{ - return BoundingBox; -} - -//! set user axis aligned bounding box -void SkinnedMesh::setBoundingBox(const core::aabbox3df &box) -{ - BoundingBox = box; -} - //! set the hardware mapping hint, for driver void SkinnedMesh::setHardwareMappingHint(E_HARDWARE_MAPPING newMappingHint, E_BUFFER_TYPE buffer) @@ -634,35 +336,6 @@ void SkinnedMesh::setDirty(E_BUFFER_TYPE buffer) LocalBuffers[i]->setDirty(buffer); } -//! Update Normals when Animating -//! False= Don't animate them, faster -//! True= Update normals (default) -void SkinnedMesh::updateNormalsWhenAnimating(bool on) -{ - AnimateNormals = on; -} - -//! Sets Interpolation Mode -void SkinnedMesh::setInterpolationMode(E_INTERPOLATION_MODE mode) -{ - InterpolationMode = mode; -} - -core::array &SkinnedMesh::getMeshBuffers() -{ - return LocalBuffers; -} - -core::array &SkinnedMesh::getAllJoints() -{ - return AllJoints; -} - -const core::array &SkinnedMesh::getAllJoints() const -{ - return AllJoints; -} - //! (This feature is not implemented in irrlicht yet) bool SkinnedMesh::setHardwareSkinning(bool on) { @@ -670,13 +343,12 @@ bool SkinnedMesh::setHardwareSkinning(bool on) if (on) { // set mesh to static pose... - for (u32 i = 0; i < AllJoints.size(); ++i) { - SJoint *joint = AllJoints[i]; - for (u32 j = 0; j < joint->Weights.size(); ++j) { - const u16 buffer_id = joint->Weights[j].buffer_id; - const u32 vertex_id = joint->Weights[j].vertex_id; - LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = joint->Weights[j].StaticPos; - LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = joint->Weights[j].StaticNormal; + for (auto *joint : AllJoints) { + for (const auto &weight : joint->Weights) { + const u16 buffer_id = weight.buffer_id; + const u32 vertex_id = weight.vertex_id; + LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = weight.StaticPos; + LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = weight.StaticNormal; LocalBuffers[buffer_id]->boundingBoxNeedsRecalculated(); } } @@ -690,13 +362,12 @@ bool SkinnedMesh::setHardwareSkinning(bool on) void SkinnedMesh::refreshJointCache() { // copy cache from the mesh... - for (u32 i = 0; i < AllJoints.size(); ++i) { - SJoint *joint = AllJoints[i]; - for (u32 j = 0; j < joint->Weights.size(); ++j) { - const u16 buffer_id = joint->Weights[j].buffer_id; - const u32 vertex_id = joint->Weights[j].vertex_id; - joint->Weights[j].StaticPos = LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos; - joint->Weights[j].StaticNormal = LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal; + for (auto *joint : AllJoints) { + for (auto &weight : joint->Weights) { + const u16 buffer_id = weight.buffer_id; + const u32 vertex_id = weight.vertex_id; + weight.StaticPos = LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos; + weight.StaticNormal = LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal; } } } @@ -704,13 +375,12 @@ void SkinnedMesh::refreshJointCache() void SkinnedMesh::resetAnimation() { // copy from the cache to the mesh... - for (u32 i = 0; i < AllJoints.size(); ++i) { - SJoint *joint = AllJoints[i]; - for (u32 j = 0; j < joint->Weights.size(); ++j) { - const u16 buffer_id = joint->Weights[j].buffer_id; - const u32 vertex_id = joint->Weights[j].vertex_id; - LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = joint->Weights[j].StaticPos; - LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = joint->Weights[j].StaticNormal; + for (auto *joint : AllJoints) { + for (const auto &weight : joint->Weights) { + const u16 buffer_id = weight.buffer_id; + const u32 vertex_id = weight.vertex_id; + LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos = weight.StaticPos; + LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal = weight.StaticNormal; } } SkinnedLastFrame = false; @@ -724,8 +394,8 @@ void SkinnedMesh::calculateGlobalMatrices(SJoint *joint, SJoint *parentJoint) // Go through the root bones if (!joint) { - for (u32 i = 0; i < RootJoints.size(); ++i) - calculateGlobalMatrices(RootJoints[i], 0); + for (auto *rootJoint : RootJoints) + calculateGlobalMatrices(rootJoint, nullptr); return; } @@ -742,51 +412,36 @@ void SkinnedMesh::calculateGlobalMatrices(SJoint *joint, SJoint *parentJoint) joint->GlobalInversedMatrix->makeInverse(); // slow } - for (u32 j = 0; j < joint->Children.size(); ++j) - calculateGlobalMatrices(joint->Children[j], joint); + for (auto *childJoint : joint->Children) + calculateGlobalMatrices(childJoint, joint); SkinnedLastFrame = false; } void SkinnedMesh::checkForAnimation() { - u32 i, j; // Check for animation... HasAnimation = false; - for (i = 0; i < AllJoints.size(); ++i) { - if (AllJoints[i]->UseAnimationFrom) { - if (AllJoints[i]->UseAnimationFrom->PositionKeys.size() || - AllJoints[i]->UseAnimationFrom->ScaleKeys.size() || - AllJoints[i]->UseAnimationFrom->RotationKeys.size()) { - HasAnimation = true; - } + for (auto *joint : AllJoints) { + if (!joint->keys.empty()) { + HasAnimation = true; + break; } } // meshes with weights, are still counted as animated for ragdolls, etc if (!HasAnimation) { - for (i = 0; i < AllJoints.size(); ++i) { - if (AllJoints[i]->Weights.size()) + for (auto *joint : AllJoints) { + if (joint->Weights.size()) { HasAnimation = true; + break; + } } } if (HasAnimation) { - //--- Find the length of the animation --- - EndFrame = 0; - for (i = 0; i < AllJoints.size(); ++i) { - if (AllJoints[i]->UseAnimationFrom) { - if (AllJoints[i]->UseAnimationFrom->PositionKeys.size()) - if (AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame > EndFrame) - EndFrame = AllJoints[i]->UseAnimationFrom->PositionKeys.getLast().frame; - - if (AllJoints[i]->UseAnimationFrom->ScaleKeys.size()) - if (AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame > EndFrame) - EndFrame = AllJoints[i]->UseAnimationFrom->ScaleKeys.getLast().frame; - - if (AllJoints[i]->UseAnimationFrom->RotationKeys.size()) - if (AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame > EndFrame) - EndFrame = AllJoints[i]->UseAnimationFrom->RotationKeys.getLast().frame; - } + EndFrame = 0.0f; + for (const auto *joint : AllJoints) { + EndFrame = std::max(EndFrame, joint->keys.getEndFrame()); } } @@ -794,42 +449,40 @@ void SkinnedMesh::checkForAnimation() PreparedForSkinning = true; // check for bugs: - for (i = 0; i < AllJoints.size(); ++i) { - SJoint *joint = AllJoints[i]; - for (j = 0; j < joint->Weights.size(); ++j) { - const u16 buffer_id = joint->Weights[j].buffer_id; - const u32 vertex_id = joint->Weights[j].vertex_id; + for (auto *joint : AllJoints) { + for (auto &weight : joint->Weights) { + const u16 buffer_id = weight.buffer_id; + const u32 vertex_id = weight.vertex_id; // check for invalid ids if (buffer_id >= LocalBuffers.size()) { os::Printer::log("Skinned Mesh: Weight buffer id too large", ELL_WARNING); - joint->Weights[j].buffer_id = joint->Weights[j].vertex_id = 0; + weight.buffer_id = weight.vertex_id = 0; } else if (vertex_id >= LocalBuffers[buffer_id]->getVertexCount()) { os::Printer::log("Skinned Mesh: Weight vertex id too large", ELL_WARNING); - joint->Weights[j].buffer_id = joint->Weights[j].vertex_id = 0; + weight.buffer_id = weight.vertex_id = 0; } } } // An array used in skinning - for (i = 0; i < Vertices_Moved.size(); ++i) - for (j = 0; j < Vertices_Moved[i].size(); ++j) + for (u32 i = 0; i < Vertices_Moved.size(); ++i) + for (u32 j = 0; j < Vertices_Moved[i].size(); ++j) Vertices_Moved[i][j] = false; // For skinning: cache weight values for speed - for (i = 0; i < AllJoints.size(); ++i) { - SJoint *joint = AllJoints[i]; - for (j = 0; j < joint->Weights.size(); ++j) { - const u16 buffer_id = joint->Weights[j].buffer_id; - const u32 vertex_id = joint->Weights[j].vertex_id; + for (auto *joint : AllJoints) { + for (auto &weight : joint->Weights) { + const u16 buffer_id = weight.buffer_id; + const u32 vertex_id = weight.vertex_id; - joint->Weights[j].Moved = &Vertices_Moved[buffer_id][vertex_id]; - joint->Weights[j].StaticPos = LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos; - joint->Weights[j].StaticNormal = LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal; + weight.Moved = &Vertices_Moved[buffer_id][vertex_id]; + weight.StaticPos = LocalBuffers[buffer_id]->getVertex(vertex_id)->Pos; + weight.StaticNormal = LocalBuffers[buffer_id]->getVertex(vertex_id)->Normal; - // joint->Weights[j]._Pos=&Buffers[buffer_id]->getVertex(vertex_id)->Pos; + // weight._Pos=&Buffers[buffer_id]->getVertex(vertex_id)->Pos; } } @@ -840,148 +493,52 @@ void SkinnedMesh::checkForAnimation() } //! called by loader after populating with mesh and bone data -void SkinnedMesh::finalize() +SkinnedMesh *SkinnedMeshBuilder::finalize() { os::Printer::log("Skinned Mesh - finalize", ELL_DEBUG); - u32 i; // Make sure we recalc the next frame LastAnimatedFrame = -1; SkinnedLastFrame = false; // calculate bounding box - for (i = 0; i < LocalBuffers.size(); ++i) { - LocalBuffers[i]->recalculateBoundingBox(); + for (auto *buffer : LocalBuffers) { + buffer->recalculateBoundingBox(); } if (AllJoints.size() || RootJoints.size()) { // populate AllJoints or RootJoints, depending on which is empty - if (!RootJoints.size()) { + if (RootJoints.empty()) { - for (u32 CheckingIdx = 0; CheckingIdx < AllJoints.size(); ++CheckingIdx) { + for (auto *joint : AllJoints) { bool foundParent = false; - for (i = 0; i < AllJoints.size(); ++i) { - for (u32 n = 0; n < AllJoints[i]->Children.size(); ++n) { - if (AllJoints[i]->Children[n] == AllJoints[CheckingIdx]) + for (const auto *parentJoint : AllJoints) { + for (const auto *childJoint : parentJoint->Children) { + if (childJoint == joint) foundParent = true; } } if (!foundParent) - RootJoints.push_back(AllJoints[CheckingIdx]); + RootJoints.push_back(joint); } } else { AllJoints = RootJoints; } } - for (i = 0; i < AllJoints.size(); ++i) { - AllJoints[i]->UseAnimationFrom = AllJoints[i]; - } - // Set array sizes... - for (i = 0; i < LocalBuffers.size(); ++i) { - Vertices_Moved.push_back(core::array()); - Vertices_Moved[i].set_used(LocalBuffers[i]->getVertexCount()); + for (u32 i = 0; i < LocalBuffers.size(); ++i) { + Vertices_Moved.emplace_back(LocalBuffers[i]->getVertexCount()); } checkForAnimation(); if (HasAnimation) { - irr::u32 redundantPosKeys = 0; - irr::u32 unorderedPosKeys = 0; - irr::u32 redundantScaleKeys = 0; - irr::u32 unorderedScaleKeys = 0; - irr::u32 redundantRotationKeys = 0; - irr::u32 unorderedRotationKeys = 0; - - //--- optimize and check keyframes --- - for (i = 0; i < AllJoints.size(); ++i) { - core::array &PositionKeys = AllJoints[i]->PositionKeys; - core::array &ScaleKeys = AllJoints[i]->ScaleKeys; - core::array &RotationKeys = AllJoints[i]->RotationKeys; - - // redundant = identical middle keys - we only need the first and last frame - // unordered = frames which are out of order - we can't handle those - redundantPosKeys += dropMiddleKeys(PositionKeys, identicalPos); - unorderedPosKeys += dropBadKeys(PositionKeys); - redundantScaleKeys += dropMiddleKeys(ScaleKeys, identicalScale); - unorderedScaleKeys += dropBadKeys(ScaleKeys); - redundantRotationKeys += dropMiddleKeys(RotationKeys, identicalRotation); - unorderedRotationKeys += dropBadKeys(RotationKeys); - - // Fill empty keyframe areas - if (PositionKeys.size()) { - SPositionKey *Key; - Key = &PositionKeys[0]; // getFirst - if (Key->frame != 0) { - PositionKeys.push_front(*Key); - Key = &PositionKeys[0]; // getFirst - Key->frame = 0; - } - - Key = &PositionKeys.getLast(); - if (Key->frame != EndFrame) { - PositionKeys.push_back(*Key); - Key = &PositionKeys.getLast(); - Key->frame = EndFrame; - } - } - - if (ScaleKeys.size()) { - SScaleKey *Key; - Key = &ScaleKeys[0]; // getFirst - if (Key->frame != 0) { - ScaleKeys.push_front(*Key); - Key = &ScaleKeys[0]; // getFirst - Key->frame = 0; - } - - Key = &ScaleKeys.getLast(); - if (Key->frame != EndFrame) { - ScaleKeys.push_back(*Key); - Key = &ScaleKeys.getLast(); - Key->frame = EndFrame; - } - } - - if (RotationKeys.size()) { - SRotationKey *Key; - Key = &RotationKeys[0]; // getFirst - if (Key->frame != 0) { - RotationKeys.push_front(*Key); - Key = &RotationKeys[0]; // getFirst - Key->frame = 0; - } - - Key = &RotationKeys.getLast(); - if (Key->frame != EndFrame) { - RotationKeys.push_back(*Key); - Key = &RotationKeys.getLast(); - Key->frame = EndFrame; - } - } - } - - if (redundantPosKeys > 0) { - os::Printer::log("Skinned Mesh - redundant position frames kicked", core::stringc(redundantPosKeys).c_str(), ELL_DEBUG); - } - if (unorderedPosKeys > 0) { - irr::os::Printer::log("Skinned Mesh - unsorted position frames kicked", irr::core::stringc(unorderedPosKeys).c_str(), irr::ELL_DEBUG); - } - if (redundantScaleKeys > 0) { - os::Printer::log("Skinned Mesh - redundant scale frames kicked", core::stringc(redundantScaleKeys).c_str(), ELL_DEBUG); - } - if (unorderedScaleKeys > 0) { - irr::os::Printer::log("Skinned Mesh - unsorted scale frames kicked", irr::core::stringc(unorderedScaleKeys).c_str(), irr::ELL_DEBUG); - } - if (redundantRotationKeys > 0) { - os::Printer::log("Skinned Mesh - redundant rotation frames kicked", core::stringc(redundantRotationKeys).c_str(), ELL_DEBUG); - } - if (unorderedRotationKeys > 0) { - irr::os::Printer::log("Skinned Mesh - unsorted rotation frames kicked", irr::core::stringc(unorderedRotationKeys).c_str(), irr::ELL_DEBUG); + for (auto *joint : AllJoints) { + joint->keys.cleanup(); } } @@ -989,15 +546,11 @@ void SkinnedMesh::finalize() calculateGlobalMatrices(0, 0); - // animateMesh(0, 1); - // buildAllLocalAnimatedMatrices(); - // buildAllGlobalAnimatedMatrices(); - // rigid animation for non animated meshes - for (i = 0; i < AllJoints.size(); ++i) { - for (u32 j = 0; j < AllJoints[i]->AttachedMeshes.size(); ++j) { - SSkinMeshBuffer *Buffer = (*SkinningBuffers)[AllJoints[i]->AttachedMeshes[j]]; - Buffer->Transformation = AllJoints[i]->GlobalAnimatedMatrix; + for (auto *joint : AllJoints) { + for (u32 attachedMeshIdx : joint->AttachedMeshes) { + SSkinMeshBuffer *Buffer = (*SkinningBuffers)[attachedMeshIdx]; + Buffer->Transformation = joint->GlobalAnimatedMatrix; } } @@ -1016,6 +569,8 @@ void SkinnedMesh::finalize() BoundingBox.addInternalBox(bb); } } + + return this; } void SkinnedMesh::updateBoundingBox(void) @@ -1023,21 +578,18 @@ void SkinnedMesh::updateBoundingBox(void) if (!SkinningBuffers) return; - core::array &buffer = *SkinningBuffers; BoundingBox.reset(0, 0, 0); - if (!buffer.empty()) { - for (u32 j = 0; j < buffer.size(); ++j) { - buffer[j]->recalculateBoundingBox(); - core::aabbox3df bb = buffer[j]->BoundingBox; - buffer[j]->Transformation.transformBoxEx(bb); + for (auto *buffer : *SkinningBuffers) { + buffer->recalculateBoundingBox(); + core::aabbox3df bb = buffer->BoundingBox; + buffer->Transformation.transformBoxEx(bb); - BoundingBox.addInternalBox(bb); - } + BoundingBox.addInternalBox(bb); } } -scene::SSkinMeshBuffer *SkinnedMesh::addMeshBuffer() +scene::SSkinMeshBuffer *SkinnedMeshBuilder::addMeshBuffer() { scene::SSkinMeshBuffer *buffer = new scene::SSkinMeshBuffer(); TextureSlots.push_back(LocalBuffers.size()); @@ -1045,13 +597,13 @@ scene::SSkinMeshBuffer *SkinnedMesh::addMeshBuffer() return buffer; } -void SkinnedMesh::addMeshBuffer(SSkinMeshBuffer *meshbuf) +void SkinnedMeshBuilder::addMeshBuffer(SSkinMeshBuffer *meshbuf) { TextureSlots.push_back(LocalBuffers.size()); LocalBuffers.push_back(meshbuf); } -SkinnedMesh::SJoint *SkinnedMesh::addJoint(SJoint *parent) +SkinnedMesh::SJoint *SkinnedMeshBuilder::addJoint(SJoint *parent) { SJoint *joint = new SJoint; @@ -1066,45 +618,31 @@ SkinnedMesh::SJoint *SkinnedMesh::addJoint(SJoint *parent) return joint; } -SkinnedMesh::SPositionKey *SkinnedMesh::addPositionKey(SJoint *joint) +void SkinnedMeshBuilder::addPositionKey(SJoint *joint, f32 frame, core::vector3df pos) { - if (!joint) - return 0; - - joint->PositionKeys.push_back(SPositionKey()); - return &joint->PositionKeys.getLast(); + _IRR_DEBUG_BREAK_IF(!joint); + joint->keys.position.pushBack(frame, pos); } -SkinnedMesh::SScaleKey *SkinnedMesh::addScaleKey(SJoint *joint) +void SkinnedMeshBuilder::addScaleKey(SJoint *joint, f32 frame, core::vector3df scale) { - if (!joint) - return 0; - - joint->ScaleKeys.push_back(SScaleKey()); - return &joint->ScaleKeys.getLast(); + _IRR_DEBUG_BREAK_IF(!joint); + joint->keys.scale.pushBack(frame, scale); } -SkinnedMesh::SRotationKey *SkinnedMesh::addRotationKey(SJoint *joint) +void SkinnedMeshBuilder::addRotationKey(SJoint *joint, f32 frame, core::quaternion rot) { - if (!joint) - return 0; - - joint->RotationKeys.push_back(SRotationKey()); - return &joint->RotationKeys.getLast(); + _IRR_DEBUG_BREAK_IF(!joint); + joint->keys.rotation.pushBack(frame, rot); } -SkinnedMesh::SWeight *SkinnedMesh::addWeight(SJoint *joint) +SkinnedMesh::SWeight *SkinnedMeshBuilder::addWeight(SJoint *joint) { if (!joint) - return 0; + return nullptr; - joint->Weights.push_back(SWeight()); - return &joint->Weights.getLast(); -} - -bool SkinnedMesh::isStatic() const -{ - return !HasAnimation; + joint->Weights.emplace_back(); + return &joint->Weights.back(); } void SkinnedMesh::normalizeWeights() @@ -1113,42 +651,39 @@ void SkinnedMesh::normalizeWeights() // Normalise the weights on bones.... - u32 i, j; - core::array> verticesTotalWeight; + std::vector> verticesTotalWeight; - verticesTotalWeight.reallocate(LocalBuffers.size()); - for (i = 0; i < LocalBuffers.size(); ++i) { - verticesTotalWeight.push_back(core::array()); - verticesTotalWeight[i].set_used(LocalBuffers[i]->getVertexCount()); + verticesTotalWeight.reserve(LocalBuffers.size()); + for (u32 i = 0; i < LocalBuffers.size(); ++i) { + verticesTotalWeight.emplace_back(LocalBuffers[i]->getVertexCount()); } - for (i = 0; i < verticesTotalWeight.size(); ++i) - for (j = 0; j < verticesTotalWeight[i].size(); ++j) + for (u32 i = 0; i < verticesTotalWeight.size(); ++i) + for (u32 j = 0; j < verticesTotalWeight[i].size(); ++j) verticesTotalWeight[i][j] = 0; - for (i = 0; i < AllJoints.size(); ++i) { - SJoint *joint = AllJoints[i]; - for (j = 0; j < joint->Weights.size(); ++j) { - if (joint->Weights[j].strength <= 0) { // Check for invalid weights - joint->Weights.erase(j); - --j; - } else { - verticesTotalWeight[joint->Weights[j].buffer_id][joint->Weights[j].vertex_id] += joint->Weights[j].strength; - } + for (auto *joint : AllJoints) { + auto &weights = joint->Weights; + + weights.erase(std::remove_if(weights.begin(), weights.end(), [](const auto &weight) { + return weight.strength <= 0; + }), weights.end()); + + for (const auto &weight : weights) { + verticesTotalWeight[weight.buffer_id][weight.vertex_id] += weight.strength; } } - for (i = 0; i < AllJoints.size(); ++i) { - SJoint *joint = AllJoints[i]; - for (j = 0; j < joint->Weights.size(); ++j) { - const f32 total = verticesTotalWeight[joint->Weights[j].buffer_id][joint->Weights[j].vertex_id]; + for (auto *joint : AllJoints) { + for (auto &weight : joint->Weights) { + const f32 total = verticesTotalWeight[weight.buffer_id][weight.vertex_id]; if (total != 0 && total != 1) - joint->Weights[j].strength /= total; + weight.strength /= total; } } } -void SkinnedMesh::recoverJointsFromMesh(core::array &jointChildSceneNodes) +void SkinnedMesh::recoverJointsFromMesh(std::vector &jointChildSceneNodes) { for (u32 i = 0; i < AllJoints.size(); ++i) { IBoneSceneNode *node = jointChildSceneNodes[i]; @@ -1157,15 +692,11 @@ void SkinnedMesh::recoverJointsFromMesh(core::array &jointChil node->setRotation(joint->LocalAnimatedMatrix.getRotationDegrees()); node->setScale(joint->LocalAnimatedMatrix.getScale()); - node->positionHint = joint->positionHint; - node->scaleHint = joint->scaleHint; - node->rotationHint = joint->rotationHint; - node->updateAbsolutePosition(); } } -void SkinnedMesh::transferJointsToMesh(const core::array &jointChildSceneNodes) +void SkinnedMesh::transferJointsToMesh(const std::vector &jointChildSceneNodes) { for (u32 i = 0; i < AllJoints.size(); ++i) { const IBoneSceneNode *const node = jointChildSceneNodes[i]; @@ -1175,10 +706,6 @@ void SkinnedMesh::transferJointsToMesh(const core::array &join joint->LocalAnimatedMatrix.setTranslation(node->getPosition()); joint->LocalAnimatedMatrix *= core::matrix4().setScale(node->getScale()); - joint->positionHint = node->positionHint; - joint->scaleHint = node->scaleHint; - joint->rotationHint = node->rotationHint; - joint->GlobalSkinningSpace = (node->getSkinningSpace() == EBSS_GLOBAL); } // Make sure we recalc the next frame @@ -1186,20 +713,7 @@ void SkinnedMesh::transferJointsToMesh(const core::array &join SkinnedLastFrame = false; } -void SkinnedMesh::transferOnlyJointsHintsToMesh(const core::array &jointChildSceneNodes) -{ - for (u32 i = 0; i < AllJoints.size(); ++i) { - const IBoneSceneNode *const node = jointChildSceneNodes[i]; - SJoint *joint = AllJoints[i]; - - joint->positionHint = node->positionHint; - joint->scaleHint = node->scaleHint; - joint->rotationHint = node->rotationHint; - } - SkinnedLastFrame = false; -} - -void SkinnedMesh::addJoints(core::array &jointChildSceneNodes, +void SkinnedMesh::addJoints(std::vector &jointChildSceneNodes, IAnimatedMeshSceneNode *node, ISceneManager *smgr) { // Create new joints From ac7406c8a1013ea8bfc94c48dbc5dc97532c0cbd Mon Sep 17 00:00:00 2001 From: y5nw <37980625+y5nw@users.noreply.github.com> Date: Thu, 12 Dec 2024 15:33:34 +0100 Subject: [PATCH 120/136] Fixup parsing for `Plural-Forms` (#15519) --- src/gettext_plural_form.cpp | 34 ++++++++++++++--------------- src/gettext_plural_form.h | 4 ++-- src/unittest/test_translations.cpp | 35 +++++++++++++++++++++++++++--- 3 files changed, 51 insertions(+), 22 deletions(-) diff --git a/src/gettext_plural_form.cpp b/src/gettext_plural_form.cpp index 6a5322421..89dd721a4 100644 --- a/src/gettext_plural_form.cpp +++ b/src/gettext_plural_form.cpp @@ -90,16 +90,16 @@ class TernaryOperation: public GettextPluralForm }; typedef std::pair ParserResult; -typedef ParserResult (*Parser)(const size_t, const std::wstring_view &); +typedef ParserResult (*Parser)(const size_t, std::wstring_view); -static ParserResult parse_expr(const size_t nplurals, const std::wstring_view &str); +static ParserResult parse_expr(const size_t nplurals, std::wstring_view str); template typename Operator> static ParserResult reduce_ltr(const size_t nplurals, const ParserResult &res, const wchar_t* pattern) { if (!str_starts_with(res.second, pattern)) return ParserResult(nullptr, res.second); - auto next = Parser(nplurals, res.second.substr(std::char_traits::length(pattern))); + auto next = Parser(nplurals, trim(res.second.substr(std::char_traits::length(pattern)))); if (!next.first) return next; next.first = GettextPluralForm::Ptr(new BinaryOperation(res.first, next.first)); @@ -123,7 +123,7 @@ static ParserResult reduce_ltr(const size_t nplurals, const ParserResult &res, c } template typename Operator, template typename... Operators> -static ParserResult parse_ltr(const size_t nplurals, const std::wstring_view &str, const wchar_t** patterns) +static ParserResult parse_ltr(const size_t nplurals, std::wstring_view str, const wchar_t** patterns) { auto &&pres = Parser(nplurals, str); if (!pres.first) @@ -139,7 +139,7 @@ static ParserResult parse_ltr(const size_t nplurals, const std::wstring_view &st return pres; } -static ParserResult parse_atomic(const size_t nplurals, const std::wstring_view &str) +static ParserResult parse_atomic(const size_t nplurals, std::wstring_view str) { if (str.empty()) return ParserResult(nullptr, str); @@ -151,7 +151,7 @@ static ParserResult parse_atomic(const size_t nplurals, const std::wstring_view return ParserResult(new ConstValue(nplurals, val), trim(str.substr(endp-str.data()))); } -static ParserResult parse_parenthesized(const size_t nplurals, const std::wstring_view &str) +static ParserResult parse_parenthesized(const size_t nplurals, std::wstring_view str) { if (str.empty()) return ParserResult(nullptr, str); @@ -167,7 +167,7 @@ static ParserResult parse_parenthesized(const size_t nplurals, const std::wstrin return result; } -static ParserResult parse_negation(const size_t nplurals, const std::wstring_view &str) +static ParserResult parse_negation(const size_t nplurals, std::wstring_view str) { if (str.empty()) return ParserResult(nullptr, str); @@ -179,43 +179,43 @@ static ParserResult parse_negation(const size_t nplurals, const std::wstring_vie return result; } -static ParserResult parse_multiplicative(const size_t nplurals, const std::wstring_view &str) +static ParserResult parse_multiplicative(const size_t nplurals, std::wstring_view str) { static const wchar_t *patterns[] = { L"*", L"/", L"%" }; return parse_ltr(nplurals, str, patterns); } -static ParserResult parse_additive(const size_t nplurals, const std::wstring_view &str) +static ParserResult parse_additive(const size_t nplurals, std::wstring_view str) { static const wchar_t *patterns[] = { L"+", L"-" }; return parse_ltr(nplurals, str, patterns); } -static ParserResult parse_comparison(const size_t nplurals, const std::wstring_view &str) +static ParserResult parse_comparison(const size_t nplurals, std::wstring_view str) { static const wchar_t *patterns[] = { L"<=", L">=", L"<", L">" }; return parse_ltr(nplurals, str, patterns); } -static ParserResult parse_equality(const size_t nplurals, const std::wstring_view &str) +static ParserResult parse_equality(const size_t nplurals, std::wstring_view str) { static const wchar_t *patterns[] = { L"==", L"!=" }; return parse_ltr(nplurals, str, patterns); } -static ParserResult parse_conjunction(const size_t nplurals, const std::wstring_view &str) +static ParserResult parse_conjunction(const size_t nplurals, std::wstring_view str) { static const wchar_t *and_pattern[] = { L"&&" }; return parse_ltr(nplurals, str, and_pattern); } -static ParserResult parse_disjunction(const size_t nplurals, const std::wstring_view &str) +static ParserResult parse_disjunction(const size_t nplurals, std::wstring_view str) { static const wchar_t *or_pattern[] = { L"||" }; return parse_ltr(nplurals, str, or_pattern); } -static ParserResult parse_ternary(const size_t nplurals, const std::wstring_view &str) +static ParserResult parse_ternary(const size_t nplurals, std::wstring_view str) { auto pres = parse_disjunction(nplurals, str); if (pres.second.empty() || pres.second[0] != '?') // no ? : @@ -229,12 +229,12 @@ static ParserResult parse_ternary(const size_t nplurals, const std::wstring_view return ParserResult(new TernaryOperation(cond, val, pres.first), pres.second); } -static ParserResult parse_expr(const size_t nplurals, const std::wstring_view &str) +static ParserResult parse_expr(const size_t nplurals, std::wstring_view str) { return parse_ternary(nplurals, trim(str)); } -GettextPluralForm::Ptr GettextPluralForm::parse(const size_t nplurals, const std::wstring_view &str) +GettextPluralForm::Ptr GettextPluralForm::parse(const size_t nplurals, std::wstring_view str) { if (nplurals == 0) return nullptr; @@ -244,7 +244,7 @@ GettextPluralForm::Ptr GettextPluralForm::parse(const size_t nplurals, const std return result.first; } -GettextPluralForm::Ptr GettextPluralForm::parseHeaderLine(const std::wstring_view &str) +GettextPluralForm::Ptr GettextPluralForm::parseHeaderLine(std::wstring_view str) { if (!str_starts_with(str, L"Plural-Forms: nplurals=") || !str_ends_with(str, L";")) return nullptr; diff --git a/src/gettext_plural_form.h b/src/gettext_plural_form.h index d73718965..1d3195e9a 100644 --- a/src/gettext_plural_form.h +++ b/src/gettext_plural_form.h @@ -24,8 +24,8 @@ public: } virtual ~GettextPluralForm() {}; - static GettextPluralForm::Ptr parse(const size_t nplurals, const std::wstring_view &str); - static GettextPluralForm::Ptr parseHeaderLine(const std::wstring_view &str); + static GettextPluralForm::Ptr parse(const size_t nplurals, std::wstring_view str); + static GettextPluralForm::Ptr parseHeaderLine(std::wstring_view str); protected: GettextPluralForm(size_t nplurals): nplurals(nplurals) {}; private: diff --git a/src/unittest/test_translations.cpp b/src/unittest/test_translations.cpp index 37fc78ee4..5bab3e15c 100644 --- a/src/unittest/test_translations.cpp +++ b/src/unittest/test_translations.cpp @@ -25,12 +25,41 @@ TEST_CASE("test translations") { SECTION("Plural-Forms function for translations") { - auto form = GettextPluralForm::parseHeaderLine(L"Plural-Forms: nplurals=3; plural= (n-1+1)<=1 ? n||1?0:1 : 1?(!!2):2;"); - REQUIRE(form); - REQUIRE(form->size() == 3); +#define REQUIRE_FORM_SIZE(x) {REQUIRE(form); REQUIRE(form->size() == (x));} + // Test cases from https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html + auto form = GettextPluralForm::parseHeaderLine(L"Plural-Forms: nplurals=2; plural=n != 1;"); + REQUIRE_FORM_SIZE(2); + CHECK((*form)(0) == 1); + CHECK((*form)(1) == 0); + CHECK((*form)(2) == 1); + + form = GettextPluralForm::parseHeaderLine(L"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;"); + REQUIRE_FORM_SIZE(3); + CHECK((*form)(0) == 2); + CHECK((*form)(1) == 0); + CHECK((*form)(102) == 1); + CHECK((*form)(111) == 1); + + form = GettextPluralForm::parseHeaderLine(L"Plural-Forms: nplurals=3; " + "plural=n%10==1 && n%100!=11 ? 0 : " + "n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;"); + REQUIRE_FORM_SIZE(3); + CHECK((*form)(0) == 2); + CHECK((*form)(1) == 0); + CHECK((*form)(102) == 1); + CHECK((*form)(104) == 1); + CHECK((*form)(111) == 2); + CHECK((*form)(112) == 2); + CHECK((*form)(121) == 0); + CHECK((*form)(122) == 1); + + // Edge cases + form = GettextPluralForm::parseHeaderLine(L"Plural-Forms: nplurals=3; plural= (n-1+1)<=1 ? n||1?0:1 : 1?(!!2):2;"); + REQUIRE_FORM_SIZE(3); CHECK((*form)(0) == 0); CHECK((*form)(1) == 0); CHECK((*form)(2) == 1); +#undef REQUIRE_FORM_SIZE } SECTION("PO file parser") From ba63c1505ad4cda3d959ed0402c9c4c9771ba7f9 Mon Sep 17 00:00:00 2001 From: Wuzzy Date: Sat, 14 Dec 2024 16:59:29 +0100 Subject: [PATCH 121/136] Docs: Change translation example from `NS` to `PS` (#15476) The currently established convention uses `NS` for "translation no-ops", i.e., it will be collected by a string-collecting utility but not be translated by Luanti at this place. We don't want to mislead modders with this example into using `NS` for plural forms instead, breaking with the established convention and making use of automated tools harder. See also: https://github.com/minetest/modtools/pull/11 --- doc/lua_api.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index c4c74d884..7fe464a30 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -4190,14 +4190,14 @@ Two functions are provided to translate strings: `core.translate` and * `core.get_translator(textdomain)` is a simple wrapper around `core.translate` and `core.translate_n`. - After `local S, NS = core.get_translator(textdomain)`, we have + After `local S, PS = core.get_translator(textdomain)`, we have `S(str, ...)` equivalent to `core.translate(textdomain, str, ...)`, and - `NS(str, str_plural, n, ...)` to `core.translate_n(textdomain, str, str_plural, n, ...)`. + `PS(str, str_plural, n, ...)` to `core.translate_n(textdomain, str, str_plural, n, ...)`. It is intended to be used in the following way, so that it avoids verbose repetitions of `core.translate`: ```lua - local S, NS = core.get_translator(textdomain) + local S, PS = core.get_translator(textdomain) S(str, ...) ``` @@ -4231,7 +4231,7 @@ command that shows the amount of time since the player joined. We can do the following: ```lua -local S, NS = core.get_translator("hello") +local S, PS = core.get_translator("hello") core.register_on_joinplayer(function(player) local name = player:get_player_name() core.chat_send_player(name, S("Hello @1, how are you today?", name)) @@ -4240,7 +4240,7 @@ core.register_chatcommand("playtime", { func = function(name) local last_login = core.get_auth_handler().get_auth(name).last_login local playtime = math.floor((last_login-os.time())/60) - return true, NS( + return true, PS( "You have been playing for @1 minute.", "You have been playing for @1 minutes.", minutes, tostring(minutes)) @@ -4287,7 +4287,7 @@ After creating the `locale` directory, a translation template for the above example using the following command: ```sh -xgettext -L lua -kS -kNS:1,2 -kcore.translate:1c,2 -kcore.translate_n:1c,2,3 \ +xgettext -L lua -kS -kPS:1,2 -kcore.translate:1c,2 -kcore.translate_n:1c,2,3 \ -d hello -o locale/hello.pot *.lua ``` From f7a695c212bea96887b32b859645f621fd8f1b48 Mon Sep 17 00:00:00 2001 From: sfence Date: Sat, 14 Dec 2024 17:01:06 +0100 Subject: [PATCH 122/136] Optimize raycast performance (#15233) by skipping nodes not on the ray with selection boxes smaller than 1x1x1 early on --- doc/lua_api.md | 2 ++ src/environment.cpp | 6 ++++++ src/nodedef.cpp | 12 ++++++++++++ src/nodedef.h | 5 +++++ 4 files changed, 25 insertions(+) diff --git a/doc/lua_api.md b/doc/lua_api.md index 7fe464a30..d753b6b53 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -9948,6 +9948,8 @@ Used by `core.register_node`. selection_box = { -- see [Node boxes] for possibilities + -- Selection boxes that oversize node size can cause + -- significant performance drop of Raycasts. }, -- Custom selection box definition. Multiple boxes can be defined. -- If "nodebox" drawtype is used and selection_box is nil, then node_box diff --git a/src/environment.cpp b/src/environment.cpp index fe582afd4..e66c7e2de 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -163,6 +163,8 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result_p) break; // About to go out of bounds } + const v3s16 pos_on_ray = state->m_iterator.m_current_node_pos; + // For each untested node for (s16 z = new_nodes.MinEdge.Z; z <= new_nodes.MaxEdge.Z; z++) for (s16 y = new_nodes.MinEdge.Y; y <= new_nodes.MaxEdge.Y; y++) @@ -175,6 +177,10 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result_p) if (!is_valid_position) continue; + // Optimization: Skip non-oversized selection boxes for other positions. + if ((pos_on_ray != np) && !nodedef->get(n).has_big_selection_box) + continue; + PointabilityType pointable = isPointableNode(n, nodedef, state->m_liquids_pointable, state->m_pointabilities); diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 81348cf23..0fde1b68e 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -1257,6 +1257,15 @@ inline void NodeDefManager::fixSelectionBoxIntUnion() m_selection_box_union.MaxEdge.Z / BS - 0.5f); } +inline void NodeDefManager::calcBigSelectionBox(content_t id, const ContentFeatures &def) +{ + aabb3f box_union; + getNodeBoxUnion(def.selection_box, def, &box_union); + m_content_features[id].has_big_selection_box = + (box_union.MinEdge.X < -BS/2) || (box_union.MaxEdge.X > BS/2) || + (box_union.MinEdge.Y < -BS/2) || (box_union.MaxEdge.Y > BS/2) || + (box_union.MinEdge.Z < -BS/2) || (box_union.MaxEdge.Z > BS/2); +} void NodeDefManager::eraseIdFromGroups(content_t id) { @@ -1312,6 +1321,7 @@ content_t NodeDefManager::set(const std::string &name, const ContentFeatures &de getNodeBoxUnion(def.selection_box, def, &m_selection_box_union); fixSelectionBoxIntUnion(); + calcBigSelectionBox(id, def); // Add this content to the list of all groups it belongs to for (const auto &group : def.groups) { const std::string &group_name = group.first; @@ -1525,6 +1535,8 @@ void NodeDefManager::deSerialize(std::istream &is, u16 protocol_version) getNodeBoxUnion(f.selection_box, f, &m_selection_box_union); fixSelectionBoxIntUnion(); + + calcBigSelectionBox(i, f); } // Since liquid_alternative_flowing_id and liquid_alternative_source_id diff --git a/src/nodedef.h b/src/nodedef.h index c3f88ce83..e33f42699 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -425,6 +425,8 @@ struct ContentFeatures NodeBox node_box; NodeBox selection_box; NodeBox collision_box; + //! Whether any selection box extent is > BS/2. + bool has_big_selection_box; // --- SOUND PROPERTIES --- @@ -774,6 +776,9 @@ private: */ void fixSelectionBoxIntUnion(); + //! Calculates ContentFeatures::&has_big_selection_box + void calcBigSelectionBox(content_t id, const ContentFeatures &def); + //! Features indexed by ID. std::vector m_content_features; From 23e502fa0efc4db4052ed26ed12e9666fbf51279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Sat, 14 Dec 2024 17:02:16 +0100 Subject: [PATCH 123/136] Test & document conventions used by `matrix4::setRotation*` (#15542) Also includes a minor `matrix4::transformVect` refactor to make testing easier. --- irr/include/matrix4.h | 47 ++++++++++----------- src/unittest/CMakeLists.txt | 1 + src/unittest/test_irr_matrix4.cpp | 69 +++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 23 deletions(-) create mode 100644 src/unittest/test_irr_matrix4.cpp diff --git a/irr/include/matrix4.h b/irr/include/matrix4.h index 7897b9acb..ed74dc9d2 100644 --- a/irr/include/matrix4.h +++ b/irr/include/matrix4.h @@ -178,9 +178,13 @@ public: CMatrix4 &setInverseTranslation(const vector3d &translation); //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified. + //! NOTE: Rotation order is ZYX. This means that vectors are + //! first rotated around the X, then the Y, and finally the Z axis. + //! NOTE: The rotation is done as per the right-hand rule. + //! See test_irr_matrix4.cpp if you're still unsure about the conventions used here. inline CMatrix4 &setRotationRadians(const vector3d &rotation); - //! Make a rotation matrix from Euler angles. The 4th row and column are unmodified. + //! Same as `setRotationRadians`, but uses degrees. CMatrix4 &setRotationDegrees(const vector3d &rotation); //! Get the rotation, as set by setRotation() when you already know the scale used to create the matrix @@ -236,12 +240,21 @@ public: [[nodiscard]] vector3d rotateAndScaleVect(const vector3d &vect) const; //! Transforms the vector by this matrix - /** This operation is performed as if the vector was 4d with the 4th component =1 */ - void transformVect(vector3df &vect) const; + /** This operation is performed as if the vector was 4d with the 4th component = 1 */ + [[nodiscard]] vector3d transformVect(const vector3d &v) const; + + //! Transforms the vector by this matrix + /** This operation is performed as if the vector was 4d with the 4th component = 1 */ + void transformVect(vector3d &vect) const { + const vector3d &v = vect; + vect = transformVect(v); + } //! Transforms input vector by this matrix and stores result in output vector - /** This operation is performed as if the vector was 4d with the 4th component =1 */ - void transformVect(vector3df &out, const vector3df &in) const; + /** This operation is performed as if the vector was 4d with the 4th component = 1 */ + void transformVect(vector3d &out, const vector3d &in) const { + out = transformVect(in); + } //! An alternate transform vector method, writing into an array of 4 floats /** This operation is performed as if the vector was 4d with the 4th component =1. @@ -1099,25 +1112,13 @@ inline vector3d CMatrix4::scaleThenInvRotVect(const vector3d &v) const } template -inline void CMatrix4::transformVect(vector3df &vect) const +inline vector3d CMatrix4::transformVect(const vector3d &v) const { - T vector[3]; - - vector[0] = vect.X * M[0] + vect.Y * M[4] + vect.Z * M[8] + M[12]; - vector[1] = vect.X * M[1] + vect.Y * M[5] + vect.Z * M[9] + M[13]; - vector[2] = vect.X * M[2] + vect.Y * M[6] + vect.Z * M[10] + M[14]; - - vect.X = static_cast(vector[0]); - vect.Y = static_cast(vector[1]); - vect.Z = static_cast(vector[2]); -} - -template -inline void CMatrix4::transformVect(vector3df &out, const vector3df &in) const -{ - out.X = in.X * M[0] + in.Y * M[4] + in.Z * M[8] + M[12]; - out.Y = in.X * M[1] + in.Y * M[5] + in.Z * M[9] + M[13]; - out.Z = in.X * M[2] + in.Y * M[6] + in.Z * M[10] + M[14]; + return { + v.X * M[0] + v.Y * M[4] + v.Z * M[8] + M[12], + v.X * M[1] + v.Y * M[5] + v.Z * M[9] + M[13], + v.X * M[2] + v.Y * M[6] + v.Z * M[10] + M[14], + }; } template diff --git a/src/unittest/CMakeLists.txt b/src/unittest/CMakeLists.txt index 2b70a6918..b7ca17199 100644 --- a/src/unittest/CMakeLists.txt +++ b/src/unittest/CMakeLists.txt @@ -53,6 +53,7 @@ set (UNITTEST_CLIENT_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/test_eventmanager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_gameui.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_irr_gltf_mesh_loader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test_irr_matrix4.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_mesh_compare.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test_keycode.cpp PARENT_SCOPE) diff --git a/src/unittest/test_irr_matrix4.cpp b/src/unittest/test_irr_matrix4.cpp new file mode 100644 index 000000000..6272c8c26 --- /dev/null +++ b/src/unittest/test_irr_matrix4.cpp @@ -0,0 +1,69 @@ +// Luanti +// SPDX-License-Identifier: LGPL-2.1-or-later + +#include "catch.h" +#include "irrMath.h" +#include "matrix4.h" +#include "irr_v3d.h" + +using matrix4 = core::matrix4; + +static bool matrix_equals(const matrix4 &a, const matrix4 &b) { + return a.equals(b, 0.00001f); +} + +constexpr v3f x{1, 0, 0}; +constexpr v3f y{0, 1, 0}; +constexpr v3f z{0, 0, 1}; + +TEST_CASE("matrix4") { + +SECTION("setRotationRadians") { + SECTION("rotation order is ZYX (matrix notation)") { + v3f rot{1, 2, 3}; + matrix4 X, Y, Z, ZYX; + X.setRotationRadians({rot.X, 0, 0}); + Y.setRotationRadians({0, rot.Y, 0}); + Z.setRotationRadians({0, 0, rot.Z}); + ZYX.setRotationRadians(rot); + CHECK(!matrix_equals(X * Y * Z, ZYX)); + CHECK(!matrix_equals(X * Z * Y, ZYX)); + CHECK(!matrix_equals(Y * X * Z, ZYX)); + CHECK(!matrix_equals(Y * Z * X, ZYX)); + CHECK(!matrix_equals(Z * X * Y, ZYX)); + CHECK(matrix_equals(Z * Y * X, ZYX)); + } + + const f32 quarter_turn = core::PI / 2; + + // See https://en.wikipedia.org/wiki/Right-hand_rule#/media/File:Cartesian_coordinate_system_handedness.svg + // for a visualization of what handedness means for rotations + + SECTION("rotation is right-handed") { + SECTION("rotation around the X-axis is Z-up, counter-clockwise") { + matrix4 X; + X.setRotationRadians({quarter_turn, 0, 0}); + CHECK(X.transformVect(x).equals(x)); + CHECK(X.transformVect(y).equals(z)); + CHECK(X.transformVect(z).equals(-y)); + } + + SECTION("rotation around the Y-axis is Z-up, clockwise") { + matrix4 Y; + Y.setRotationRadians({0, quarter_turn, 0}); + CHECK(Y.transformVect(y).equals(y)); + CHECK(Y.transformVect(x).equals(-z)); + CHECK(Y.transformVect(z).equals(x)); + } + + SECTION("rotation around the Z-axis is Y-up, counter-clockwise") { + matrix4 Z; + Z.setRotationRadians({0, 0, quarter_turn}); + CHECK(Z.transformVect(z).equals(z)); + CHECK(Z.transformVect(x).equals(y)); + CHECK(Z.transformVect(y).equals(-x)); + } + } +} + +} From fef28aced9236d80fc16ba928fb9661feac94207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Sat, 14 Dec 2024 17:03:08 +0100 Subject: [PATCH 124/136] Irrlicht: Get rid of obsolete `setDebugName` (#15541) Co-authored-by: sfan5 --- irr/include/CIndexBuffer.h | 7 +------ irr/include/CMeshBuffer.h | 3 --- irr/include/CVertexBuffer.h | 7 +------ irr/include/IGUIElement.h | 4 ---- irr/include/IReferenceCounted.h | 25 ----------------------- irr/include/SAnimatedMesh.h | 3 --- irr/include/SMesh.h | 7 +------ irr/include/SSkinMeshBuffer.h | 3 --- irr/src/CAnimatedMeshSceneNode.cpp | 6 +----- irr/src/CAttributes.cpp | 7 +------ irr/src/CB3DMeshFileLoader.cpp | 6 +----- irr/src/CBillboardSceneNode.cpp | 4 ---- irr/src/CBoneSceneNode.cpp | 3 --- irr/src/CCameraSceneNode.cpp | 4 ---- irr/src/CDummyTransformationSceneNode.cpp | 4 ---- irr/src/CEGLManager.cpp | 6 +----- irr/src/CEmptySceneNode.cpp | 4 ---- irr/src/CFileList.cpp | 4 ---- irr/src/CFileSystem.cpp | 4 ---- irr/src/CGLXManager.cpp | 4 ---- irr/src/CGUIButton.cpp | 3 --- irr/src/CGUICheckBox.cpp | 4 ---- irr/src/CGUIComboBox.cpp | 4 ---- irr/src/CGUIEditBox.cpp | 4 ---- irr/src/CGUIEnvironment.cpp | 4 ---- irr/src/CGUIFileOpenDialog.cpp | 4 ---- irr/src/CGUIFont.cpp | 4 ---- irr/src/CGUIImage.cpp | 6 +----- irr/src/CGUIImageList.cpp | 4 ---- irr/src/CGUIListBox.cpp | 4 ---- irr/src/CGUIScrollBar.cpp | 4 ---- irr/src/CGUISkin.cpp | 4 ---- irr/src/CGUISpriteBank.cpp | 4 ---- irr/src/CGUIStaticText.cpp | 4 ---- irr/src/CGUITabControl.cpp | 8 -------- irr/src/CImageLoaderJPG.cpp | 3 --- irr/src/CImageWriterJPG.cpp | 6 +----- irr/src/CImageWriterPNG.cpp | 6 +----- irr/src/CIrrDeviceLinux.cpp | 4 ---- irr/src/CIrrDeviceOSX.mm | 4 ---- irr/src/CIrrDeviceSDL.cpp | 4 ---- irr/src/CIrrDeviceWin32.cpp | 4 ---- irr/src/CLimitReadFile.cpp | 4 ---- irr/src/CLogger.cpp | 6 +----- irr/src/CMemoryFile.cpp | 12 ++--------- irr/src/CMeshSceneNode.cpp | 4 ---- irr/src/CNSOGLManager.mm | 6 +----- irr/src/CNullDriver.cpp | 4 ---- irr/src/COBJMeshFileLoader.cpp | 6 +----- irr/src/COSOperator.cpp | 6 +----- irr/src/COpenGLCoreRenderTarget.h | 4 ---- irr/src/COpenGLDriver.cpp | 6 +----- irr/src/COpenGLSLMaterialRenderer.cpp | 4 ---- irr/src/CReadFile.cpp | 4 ---- irr/src/CSDLManager.cpp | 6 +----- irr/src/CSceneCollisionManager.cpp | 4 ---- irr/src/CSceneManager.cpp | 5 ----- irr/src/CWGLManager.cpp | 3 --- irr/src/CWriteFile.cpp | 4 ---- irr/src/CXMeshFileLoader.cpp | 6 +----- irr/src/CZipReader.cpp | 10 +-------- irr/src/OpenGL/Driver.cpp | 4 ---- irr/src/OpenGL/MaterialRenderer.cpp | 4 ---- irr/src/OpenGL/Renderer2D.cpp | 4 ---- src/gui/guiEditBoxWithScrollbar.cpp | 4 ---- src/gui/guiHyperText.cpp | 4 ---- src/irrlicht_changes/CGUITTFont.cpp | 3 --- src/irrlicht_changes/static_text.cpp | 4 ---- 68 files changed, 20 insertions(+), 322 deletions(-) diff --git a/irr/include/CIndexBuffer.h b/irr/include/CIndexBuffer.h index 904b0ab9a..ba85d49e6 100644 --- a/irr/include/CIndexBuffer.h +++ b/irr/include/CIndexBuffer.h @@ -24,12 +24,7 @@ class CIndexBuffer final : public IIndexBuffer { public: //! Default constructor for empty buffer - CIndexBuffer() - { -#ifdef _DEBUG - setDebugName("CIndexBuffer"); -#endif - } + CIndexBuffer() {} video::E_INDEX_TYPE getType() const override { diff --git a/irr/include/CMeshBuffer.h b/irr/include/CMeshBuffer.h index 9a6d4426f..d0c41ccfa 100644 --- a/irr/include/CMeshBuffer.h +++ b/irr/include/CMeshBuffer.h @@ -22,9 +22,6 @@ public: CMeshBuffer() : PrimitiveType(EPT_TRIANGLES) { -#ifdef _DEBUG - setDebugName("CMeshBuffer"); -#endif Vertices = new CVertexBuffer(); Indices = new SIndexBuffer(); } diff --git a/irr/include/CVertexBuffer.h b/irr/include/CVertexBuffer.h index 4b3f33688..1bface16c 100644 --- a/irr/include/CVertexBuffer.h +++ b/irr/include/CVertexBuffer.h @@ -24,12 +24,7 @@ class CVertexBuffer final : public IVertexBuffer { public: //! Default constructor for empty buffer - CVertexBuffer() - { -#ifdef _DEBUG - setDebugName("CVertexBuffer"); -#endif - } + CVertexBuffer() {} const void *getData() const override { diff --git a/irr/include/IGUIElement.h b/irr/include/IGUIElement.h index cffac10d1..429bc06b3 100644 --- a/irr/include/IGUIElement.h +++ b/irr/include/IGUIElement.h @@ -34,10 +34,6 @@ public: AlignLeft(EGUIA_UPPERLEFT), AlignRight(EGUIA_UPPERLEFT), AlignTop(EGUIA_UPPERLEFT), AlignBottom(EGUIA_UPPERLEFT), Environment(environment), Type(type) { -#ifdef _DEBUG - setDebugName("IGUIElement"); -#endif - // if we were given a parent to attach to if (parent) { parent->addChildToEnd(this); diff --git a/irr/include/IReferenceCounted.h b/irr/include/IReferenceCounted.h index 68aa20fb6..65c991db2 100644 --- a/irr/include/IReferenceCounted.h +++ b/irr/include/IReferenceCounted.h @@ -136,31 +136,6 @@ public: return ReferenceCounter; } -#ifdef _DEBUG - //! Returns the debug name of the object. - /** The Debugname may only be set and changed by the object - itself. This method should only be used in Debug mode. - \return Returns a string, previously set by setDebugName(); */ - const c8 *getDebugName() const - { - return DebugName; - } - -protected: - //! Sets the debug name of the object. - /** The Debugname may only be set and changed by the object - itself. This method should only be used in Debug mode. - \param newName: New debug name to set. */ - void setDebugName(const c8 *newName) - { - DebugName = newName; - } - -private: - //! The debug name. - const c8 *DebugName = nullptr; -#endif - private: //! The reference counter. Mutable to do reference counting on const objects. diff --git a/irr/include/SAnimatedMesh.h b/irr/include/SAnimatedMesh.h index dd7306633..8f7156236 100644 --- a/irr/include/SAnimatedMesh.h +++ b/irr/include/SAnimatedMesh.h @@ -21,9 +21,6 @@ struct SAnimatedMesh final : public IAnimatedMesh SAnimatedMesh(scene::IMesh *mesh = 0, scene::E_ANIMATED_MESH_TYPE type = scene::EAMT_UNKNOWN) : IAnimatedMesh(), FramesPerSecond(25.f), Type(type) { -#ifdef _DEBUG - setDebugName("SAnimatedMesh"); -#endif addMesh(mesh); recalculateBoundingBox(); } diff --git a/irr/include/SMesh.h b/irr/include/SMesh.h index 15fa65115..c9a76b051 100644 --- a/irr/include/SMesh.h +++ b/irr/include/SMesh.h @@ -17,12 +17,7 @@ namespace scene struct SMesh final : public IMesh { //! constructor - SMesh() - { -#ifdef _DEBUG - setDebugName("SMesh"); -#endif - } + SMesh() {} //! destructor virtual ~SMesh() diff --git a/irr/include/SSkinMeshBuffer.h b/irr/include/SSkinMeshBuffer.h index b0b6658b3..82c0d9f37 100644 --- a/irr/include/SSkinMeshBuffer.h +++ b/irr/include/SSkinMeshBuffer.h @@ -22,9 +22,6 @@ struct SSkinMeshBuffer final : public IMeshBuffer VertexType(vt), PrimitiveType(EPT_TRIANGLES), BoundingBoxNeedsRecalculated(true) { -#ifdef _DEBUG - setDebugName("SSkinMeshBuffer"); -#endif Vertices_Tangents = new SVertexBufferTangents(); Vertices_2TCoords = new SVertexBufferLightMap(); Vertices_Standard = new SVertexBuffer(); diff --git a/irr/src/CAnimatedMeshSceneNode.cpp b/irr/src/CAnimatedMeshSceneNode.cpp index d249e37c5..3871d52a3 100644 --- a/irr/src/CAnimatedMeshSceneNode.cpp +++ b/irr/src/CAnimatedMeshSceneNode.cpp @@ -38,10 +38,6 @@ CAnimatedMeshSceneNode::CAnimatedMeshSceneNode(IAnimatedMesh *mesh, Looping(true), ReadOnlyMaterials(false), RenderFromIdentity(false), LoopCallBack(0), PassCount(0) { -#ifdef _DEBUG - setDebugName("CAnimatedMeshSceneNode"); -#endif - setMesh(mesh); } @@ -227,7 +223,7 @@ void CAnimatedMeshSceneNode::render() Box = m->getBoundingBox(); } else { #ifdef _DEBUG - os::Printer::log("Animated Mesh returned no mesh to render.", Mesh->getDebugName(), ELL_WARNING); + os::Printer::log("Animated Mesh returned no mesh to render.", ELL_WARNING); #endif return; } diff --git a/irr/src/CAttributes.cpp b/irr/src/CAttributes.cpp index b1509e455..924bd1a45 100644 --- a/irr/src/CAttributes.cpp +++ b/irr/src/CAttributes.cpp @@ -12,12 +12,7 @@ namespace irr namespace io { -CAttributes::CAttributes() -{ -#ifdef _DEBUG - setDebugName("CAttributes"); -#endif -} +CAttributes::CAttributes() {} CAttributes::~CAttributes() { diff --git a/irr/src/CB3DMeshFileLoader.cpp b/irr/src/CB3DMeshFileLoader.cpp index 3bcc4b85f..e99bd2eed 100644 --- a/irr/src/CB3DMeshFileLoader.cpp +++ b/irr/src/CB3DMeshFileLoader.cpp @@ -29,11 +29,7 @@ namespace scene CB3DMeshFileLoader::CB3DMeshFileLoader(scene::ISceneManager *smgr) : AnimatedMesh(0), B3DFile(0), VerticesStart(0), NormalsInFile(false), HasVertexColors(false), ShowWarning(true) -{ -#ifdef _DEBUG - setDebugName("CB3DMeshFileLoader"); -#endif -} +{} //! returns true if the file maybe is able to be loaded by this class //! based on the file extension (e.g. ".bsp") diff --git a/irr/src/CBillboardSceneNode.cpp b/irr/src/CBillboardSceneNode.cpp index 1c6d88dae..6769e8f04 100644 --- a/irr/src/CBillboardSceneNode.cpp +++ b/irr/src/CBillboardSceneNode.cpp @@ -20,10 +20,6 @@ CBillboardSceneNode::CBillboardSceneNode(ISceneNode *parent, ISceneManager *mgr, IBillboardSceneNode(parent, mgr, id, position), Buffer(new SMeshBuffer()) { -#ifdef _DEBUG - setDebugName("CBillboardSceneNode"); -#endif - setSize(size); auto &Vertices = Buffer->Vertices->Data; diff --git a/irr/src/CBoneSceneNode.cpp b/irr/src/CBoneSceneNode.cpp index b9eb8892e..7aa637094 100644 --- a/irr/src/CBoneSceneNode.cpp +++ b/irr/src/CBoneSceneNode.cpp @@ -18,9 +18,6 @@ CBoneSceneNode::CBoneSceneNode(ISceneNode *parent, ISceneManager *mgr, s32 id, BoneIndex(boneIndex), AnimationMode(EBAM_AUTOMATIC), SkinningSpace(EBSS_LOCAL) { -#ifdef _DEBUG - setDebugName("CBoneSceneNode"); -#endif setName(boneName); } diff --git a/irr/src/CCameraSceneNode.cpp b/irr/src/CCameraSceneNode.cpp index f8899e5ff..e1c3c96f6 100644 --- a/irr/src/CCameraSceneNode.cpp +++ b/irr/src/CCameraSceneNode.cpp @@ -20,10 +20,6 @@ CCameraSceneNode::CCameraSceneNode(ISceneNode *parent, ISceneManager *mgr, s32 i Target(lookat), UpVector(0.0f, 1.0f, 0.0f), ZNear(1.0f), ZFar(3000.0f), InputReceiverEnabled(true), TargetAndRotationAreBound(false) { -#ifdef _DEBUG - setDebugName("CCameraSceneNode"); -#endif - // set default projection Fovy = core::PI / 2.5f; // Field of view, in radians. Aspect = 4.0f / 3.0f; // Aspect ratio. diff --git a/irr/src/CDummyTransformationSceneNode.cpp b/irr/src/CDummyTransformationSceneNode.cpp index 73953dd38..e354038df 100644 --- a/irr/src/CDummyTransformationSceneNode.cpp +++ b/irr/src/CDummyTransformationSceneNode.cpp @@ -15,10 +15,6 @@ CDummyTransformationSceneNode::CDummyTransformationSceneNode( ISceneNode *parent, ISceneManager *mgr, s32 id) : IDummyTransformationSceneNode(parent, mgr, id) { -#ifdef _DEBUG - setDebugName("CDummyTransformationSceneNode"); -#endif - setAutomaticCulling(scene::EAC_OFF); } diff --git a/irr/src/CEGLManager.cpp b/irr/src/CEGLManager.cpp index 6c39c5c74..b70a0c091 100644 --- a/irr/src/CEGLManager.cpp +++ b/irr/src/CEGLManager.cpp @@ -18,11 +18,7 @@ namespace video CEGLManager::CEGLManager() : IContextManager(), EglWindow(0), EglDisplay(EGL_NO_DISPLAY), EglSurface(EGL_NO_SURFACE), EglContext(EGL_NO_CONTEXT), EglConfig(0), MajorVersion(0), MinorVersion(0) -{ -#ifdef _DEBUG - setDebugName("CEGLManager"); -#endif -} +{} CEGLManager::~CEGLManager() { diff --git a/irr/src/CEmptySceneNode.cpp b/irr/src/CEmptySceneNode.cpp index 2b965a198..70a2ca21d 100644 --- a/irr/src/CEmptySceneNode.cpp +++ b/irr/src/CEmptySceneNode.cpp @@ -14,10 +14,6 @@ namespace scene CEmptySceneNode::CEmptySceneNode(ISceneNode *parent, ISceneManager *mgr, s32 id) : ISceneNode(parent, mgr, id) { -#ifdef _DEBUG - setDebugName("CEmptySceneNode"); -#endif - setAutomaticCulling(scene::EAC_OFF); } diff --git a/irr/src/CFileList.cpp b/irr/src/CFileList.cpp index cd6c85df4..9294f3f46 100644 --- a/irr/src/CFileList.cpp +++ b/irr/src/CFileList.cpp @@ -18,10 +18,6 @@ static const io::path emptyFileListEntry; CFileList::CFileList(const io::path &path, bool ignoreCase, bool ignorePaths) : IgnorePaths(ignorePaths), IgnoreCase(ignoreCase), Path(path) { -#ifdef _DEBUG - setDebugName("CFileList"); -#endif - Path.replace('\\', '/'); } diff --git a/irr/src/CFileSystem.cpp b/irr/src/CFileSystem.cpp index 4b938c4c5..d8f04eb1d 100644 --- a/irr/src/CFileSystem.cpp +++ b/irr/src/CFileSystem.cpp @@ -43,10 +43,6 @@ namespace io //! constructor CFileSystem::CFileSystem() { -#ifdef _DEBUG - setDebugName("CFileSystem"); -#endif - setFileListSystem(FILESYSTEM_NATIVE); //! reset current working directory getWorkingDirectory(); diff --git a/irr/src/CGLXManager.cpp b/irr/src/CGLXManager.cpp index 8593621b7..89a5cac20 100644 --- a/irr/src/CGLXManager.cpp +++ b/irr/src/CGLXManager.cpp @@ -23,10 +23,6 @@ namespace video CGLXManager::CGLXManager(const SIrrlichtCreationParameters ¶ms, const SExposedVideoData &videodata, int screennr) : Params(params), PrimaryContext(videodata), VisualInfo(0), glxFBConfig(0), GlxWin(0) { -#ifdef _DEBUG - setDebugName("CGLXManager"); -#endif - CurrentContext.OpenGLLinux.X11Display = PrimaryContext.OpenGLLinux.X11Display; int major, minor; diff --git a/irr/src/CGUIButton.cpp b/irr/src/CGUIButton.cpp index 60bab5f83..ea685be94 100644 --- a/irr/src/CGUIButton.cpp +++ b/irr/src/CGUIButton.cpp @@ -26,9 +26,6 @@ CGUIButton::CGUIButton(IGUIEnvironment *environment, IGUIElement *parent, IsPushButton(false), Pressed(false), UseAlphaChannel(false), DrawBorder(true), ScaleImage(false) { -#ifdef _DEBUG - setDebugName("CGUIButton"); -#endif setNotClipped(noclip); // This element can be tabbed. diff --git a/irr/src/CGUICheckBox.cpp b/irr/src/CGUICheckBox.cpp index 18dd6856a..4d407e676 100644 --- a/irr/src/CGUICheckBox.cpp +++ b/irr/src/CGUICheckBox.cpp @@ -19,10 +19,6 @@ namespace gui CGUICheckBox::CGUICheckBox(bool checked, IGUIEnvironment *environment, IGUIElement *parent, s32 id, core::rect rectangle) : IGUICheckBox(environment, parent, id, rectangle), CheckTime(0), Pressed(false), Checked(checked), Border(false), Background(false) { -#ifdef _DEBUG - setDebugName("CGUICheckBox"); -#endif - // this element can be tabbed into setTabStop(true); setTabOrder(-1); diff --git a/irr/src/CGUIComboBox.cpp b/irr/src/CGUIComboBox.cpp index 0088641b5..b55602b0c 100644 --- a/irr/src/CGUIComboBox.cpp +++ b/irr/src/CGUIComboBox.cpp @@ -26,10 +26,6 @@ CGUIComboBox::CGUIComboBox(IGUIEnvironment *environment, IGUIElement *parent, Selected(-1), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER), MaxSelectionRows(5), HasFocus(false), ActiveFont(nullptr) { -#ifdef _DEBUG - setDebugName("CGUIComboBox"); -#endif - IGUISkin *skin = Environment->getSkin(); ListButton = Environment->addButton(core::recti(0, 0, 1, 1), this, -1, L""); diff --git a/irr/src/CGUIEditBox.cpp b/irr/src/CGUIEditBox.cpp index 8d03caf4a..7d1571606 100644 --- a/irr/src/CGUIEditBox.cpp +++ b/irr/src/CGUIEditBox.cpp @@ -39,10 +39,6 @@ CGUIEditBox::CGUIEditBox(const wchar_t *text, bool border, PasswordChar(L'*'), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER), CurrentTextRect(0, 0, 1, 1), FrameRect(rectangle) { -#ifdef _DEBUG - setDebugName("CGUIEditBox"); -#endif - Text = text; if (Environment) diff --git a/irr/src/CGUIEnvironment.cpp b/irr/src/CGUIEnvironment.cpp index 80115ab11..b40896327 100644 --- a/irr/src/CGUIEnvironment.cpp +++ b/irr/src/CGUIEnvironment.cpp @@ -50,10 +50,6 @@ CGUIEnvironment::CGUIEnvironment(io::IFileSystem *fs, video::IVideoDriver *drive if (Operator) Operator->grab(); -#ifdef _DEBUG - IGUIEnvironment::setDebugName("CGUIEnvironment"); -#endif - loadBuiltInFont(); IGUISkin *skin = createSkin(gui::EGST_WINDOWS_METALLIC); diff --git a/irr/src/CGUIFileOpenDialog.cpp b/irr/src/CGUIFileOpenDialog.cpp index 1e669b255..7add9d8e1 100644 --- a/irr/src/CGUIFileOpenDialog.cpp +++ b/irr/src/CGUIFileOpenDialog.cpp @@ -33,10 +33,6 @@ CGUIFileOpenDialog::CGUIFileOpenDialog(const wchar_t *title, (parent->getAbsolutePosition().getHeight() - FOD_HEIGHT) / 2 + FOD_HEIGHT)), FileNameText(0), FileList(0), Dragging(false) { -#ifdef _DEBUG - IGUIElement::setDebugName("CGUIFileOpenDialog"); -#endif - Text = title; FileSystem = Environment ? Environment->getFileSystem() : 0; diff --git a/irr/src/CGUIFont.cpp b/irr/src/CGUIFont.cpp index 4d85702f5..c00b40395 100644 --- a/irr/src/CGUIFont.cpp +++ b/irr/src/CGUIFont.cpp @@ -21,10 +21,6 @@ CGUIFont::CGUIFont(IGUIEnvironment *env, const io::path &filename) : Driver(0), SpriteBank(0), Environment(env), WrongCharacter(0), MaxHeight(0), GlobalKerningWidth(0), GlobalKerningHeight(0) { -#ifdef _DEBUG - setDebugName("CGUIFont"); -#endif - if (Environment) { // don't grab environment, to avoid circular references Driver = Environment->getVideoDriver(); diff --git a/irr/src/CGUIImage.cpp b/irr/src/CGUIImage.cpp index 5f7bb8e26..a17e8f2d0 100644 --- a/irr/src/CGUIImage.cpp +++ b/irr/src/CGUIImage.cpp @@ -17,11 +17,7 @@ namespace gui CGUIImage::CGUIImage(IGUIEnvironment *environment, IGUIElement *parent, s32 id, core::rect rectangle) : IGUIImage(environment, parent, id, rectangle), Texture(0), Color(255, 255, 255, 255), UseAlphaChannel(false), ScaleImage(false), DrawBounds(0.f, 0.f, 1.f, 1.f), DrawBackground(true) -{ -#ifdef _DEBUG - setDebugName("CGUIImage"); -#endif -} +{} //! destructor CGUIImage::~CGUIImage() diff --git a/irr/src/CGUIImageList.cpp b/irr/src/CGUIImageList.cpp index 3bd30d913..b11f10b0c 100644 --- a/irr/src/CGUIImageList.cpp +++ b/irr/src/CGUIImageList.cpp @@ -18,10 +18,6 @@ CGUIImageList::CGUIImageList(video::IVideoDriver *driver) : ImagesPerRow(0), UseAlphaChannel(false) { -#ifdef _DEBUG - setDebugName("CGUIImageList"); -#endif - if (Driver) { Driver->grab(); } diff --git a/irr/src/CGUIListBox.cpp b/irr/src/CGUIListBox.cpp index 78cb96ecf..f8db2cf80 100644 --- a/irr/src/CGUIListBox.cpp +++ b/irr/src/CGUIListBox.cpp @@ -29,10 +29,6 @@ CGUIListBox::CGUIListBox(IGUIEnvironment *environment, IGUIElement *parent, ScrollBar(0), selectTime(0), LastKeyTime(0), Selecting(false), DrawBack(drawBack), MoveOverSelect(moveOverSelect), AutoScroll(true), HighlightWhenNotFocused(true) { -#ifdef _DEBUG - setDebugName("CGUIListBox"); -#endif - IGUISkin *skin = Environment->getSkin(); ScrollBar = new CGUIScrollBar(false, Environment, this, -1, diff --git a/irr/src/CGUIScrollBar.cpp b/irr/src/CGUIScrollBar.cpp index f9ebad09e..5e7737bc1 100644 --- a/irr/src/CGUIScrollBar.cpp +++ b/irr/src/CGUIScrollBar.cpp @@ -28,10 +28,6 @@ CGUIScrollBar::CGUIScrollBar(bool horizontal, IGUIEnvironment *environment, DrawHeight(0), Min(0), Max(100), SmallStep(10), LargeStep(50), DesiredPos(0), LastChange(0) { -#ifdef _DEBUG - setDebugName("CGUIScrollBar"); -#endif - refreshControls(); setNotClipped(noclip); diff --git a/irr/src/CGUISkin.cpp b/irr/src/CGUISkin.cpp index e9721a5fa..3c130f7a1 100644 --- a/irr/src/CGUISkin.cpp +++ b/irr/src/CGUISkin.cpp @@ -20,10 +20,6 @@ namespace gui CGUISkin::CGUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver) : SpriteBank(0), Driver(driver), Type(type) { - #ifdef _DEBUG - setDebugName("CGUISkin"); - #endif - if ((Type == EGST_WINDOWS_CLASSIC) || (Type == EGST_WINDOWS_METALLIC)) { Colors[EGDC_3D_DARK_SHADOW] = video::SColor(101,50,50,50); diff --git a/irr/src/CGUISpriteBank.cpp b/irr/src/CGUISpriteBank.cpp index fe0c087b8..ea3fe8788 100644 --- a/irr/src/CGUISpriteBank.cpp +++ b/irr/src/CGUISpriteBank.cpp @@ -16,10 +16,6 @@ namespace gui CGUISpriteBank::CGUISpriteBank(IGUIEnvironment *env) : Environment(env), Driver(0) { -#ifdef _DEBUG - setDebugName("CGUISpriteBank"); -#endif - if (Environment) { Driver = Environment->getVideoDriver(); if (Driver) diff --git a/irr/src/CGUIStaticText.cpp b/irr/src/CGUIStaticText.cpp index 035847583..871589447 100644 --- a/irr/src/CGUIStaticText.cpp +++ b/irr/src/CGUIStaticText.cpp @@ -27,10 +27,6 @@ CGUIStaticText::CGUIStaticText(const wchar_t *text, bool border, OverrideColor(video::SColor(101, 255, 255, 255)), BGColor(video::SColor(101, 210, 210, 210)), OverrideFont(0), LastBreakFont(0) { -#ifdef _DEBUG - setDebugName("CGUIStaticText"); -#endif - Text = text; if (environment && environment->getSkin()) { BGColor = environment->getSkin()->getColor(gui::EGDC_3D_FACE); diff --git a/irr/src/CGUITabControl.cpp b/irr/src/CGUITabControl.cpp index 3e02773db..bca7f0f21 100644 --- a/irr/src/CGUITabControl.cpp +++ b/irr/src/CGUITabControl.cpp @@ -29,10 +29,6 @@ CGUITab::CGUITab(IGUIEnvironment *environment, BackColor(0, 0, 0, 0), OverrideTextColorEnabled(false), TextColor(255, 0, 0, 0), DrawBackground(false) { -#ifdef _DEBUG - setDebugName("CGUITab"); -#endif - const IGUISkin *const skin = environment->getSkin(); if (skin) TextColor = skin->getColor(EGDC_BUTTON_TEXT); @@ -104,10 +100,6 @@ CGUITabControl::CGUITabControl(IGUIEnvironment *environment, Border(border), FillBackground(fillbackground), ScrollControl(false), TabHeight(0), VerticalAlignment(EGUIA_UPPERLEFT), UpButton(0), DownButton(0), TabMaxWidth(0), CurrentScrollTabIndex(0), TabExtraWidth(20) { -#ifdef _DEBUG - setDebugName("CGUITabControl"); -#endif - IGUISkin *skin = Environment->getSkin(); IGUISpriteBank *sprites = 0; diff --git a/irr/src/CImageLoaderJPG.cpp b/irr/src/CImageLoaderJPG.cpp index 5b7978a4b..ec1a998b9 100644 --- a/irr/src/CImageLoaderJPG.cpp +++ b/irr/src/CImageLoaderJPG.cpp @@ -19,9 +19,6 @@ namespace video //! constructor CImageLoaderJPG::CImageLoaderJPG() { -#ifdef _DEBUG - setDebugName("CImageLoaderJPG"); -#endif } //! destructor diff --git a/irr/src/CImageWriterJPG.cpp b/irr/src/CImageWriterJPG.cpp index 1220c47e6..778d1fb74 100644 --- a/irr/src/CImageWriterJPG.cpp +++ b/irr/src/CImageWriterJPG.cpp @@ -169,11 +169,7 @@ IImageWriter *createImageWriterJPG() } CImageWriterJPG::CImageWriterJPG() -{ -#ifdef _DEBUG - setDebugName("CImageWriterJPG"); -#endif -} +{} bool CImageWriterJPG::isAWriteableFileExtension(const io::path &filename) const { diff --git a/irr/src/CImageWriterPNG.cpp b/irr/src/CImageWriterPNG.cpp index 35e33c3d5..51332d285 100644 --- a/irr/src/CImageWriterPNG.cpp +++ b/irr/src/CImageWriterPNG.cpp @@ -54,11 +54,7 @@ void PNGAPI user_write_data_fcn(png_structp png_ptr, png_bytep data, png_size_t } CImageWriterPNG::CImageWriterPNG() -{ -#ifdef _DEBUG - setDebugName("CImageWriterPNG"); -#endif -} +{} bool CImageWriterPNG::isAWriteableFileExtension(const io::path &filename) const { diff --git a/irr/src/CIrrDeviceLinux.cpp b/irr/src/CIrrDeviceLinux.cpp index 0b9ef5b71..7c5d9cf0b 100644 --- a/irr/src/CIrrDeviceLinux.cpp +++ b/irr/src/CIrrDeviceLinux.cpp @@ -105,10 +105,6 @@ CIrrDeviceLinux::CIrrDeviceLinux(const SIrrlichtCreationParameters ¶m) : WindowHasFocus(false), WindowMinimized(false), WindowMaximized(param.WindowMaximized), ExternalWindow(false), AutorepeatSupport(0) { -#ifdef _DEBUG - setDebugName("CIrrDeviceLinux"); -#endif - // print version, distribution etc. // thx to LynxLuna for pointing me to the uname function core::stringc linuxversion; diff --git a/irr/src/CIrrDeviceOSX.mm b/irr/src/CIrrDeviceOSX.mm index 4b46e5e29..859d9b752 100644 --- a/irr/src/CIrrDeviceOSX.mm +++ b/irr/src/CIrrDeviceOSX.mm @@ -524,10 +524,6 @@ CIrrDeviceMacOSX::CIrrDeviceMacOSX(const SIrrlichtCreationParameters ¶m) : { struct utsname name; -#ifdef _DEBUG - setDebugName("CIrrDeviceMacOSX"); -#endif - if (firstLaunch) { firstLaunch = false; diff --git a/irr/src/CIrrDeviceSDL.cpp b/irr/src/CIrrDeviceSDL.cpp index 543bea63e..f7974202f 100644 --- a/irr/src/CIrrDeviceSDL.cpp +++ b/irr/src/CIrrDeviceSDL.cpp @@ -253,10 +253,6 @@ CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters ¶m) : Resizable(param.WindowResizable == 1 ? true : false), CurrentTouchCount(0), IsInBackground(false) { -#ifdef _DEBUG - setDebugName("CIrrDeviceSDL"); -#endif - if (++SDLDeviceInstances == 1) { #ifdef __ANDROID__ // Blocking on pause causes problems with multiplayer. diff --git a/irr/src/CIrrDeviceWin32.cpp b/irr/src/CIrrDeviceWin32.cpp index 417694517..f0947163d 100644 --- a/irr/src/CIrrDeviceWin32.cpp +++ b/irr/src/CIrrDeviceWin32.cpp @@ -713,10 +713,6 @@ CIrrDeviceWin32::CIrrDeviceWin32(const SIrrlichtCreationParameters ¶ms) : ExternalWindow(false), Win32CursorControl(0), JoyControl(0), WindowMaximized(params.WindowMaximized) { -#ifdef _DEBUG - setDebugName("CIrrDeviceWin32"); -#endif - // get windows version and create OS operator core::stringc winversion; getWindowsVersion(winversion); diff --git a/irr/src/CLimitReadFile.cpp b/irr/src/CLimitReadFile.cpp index de9bf9ec3..b13120194 100644 --- a/irr/src/CLimitReadFile.cpp +++ b/irr/src/CLimitReadFile.cpp @@ -17,10 +17,6 @@ CLimitReadFile::CLimitReadFile(IReadFile *alreadyOpenedFile, long pos, AreaStart(0), AreaEnd(0), Pos(0), File(alreadyOpenedFile) { -#ifdef _DEBUG - setDebugName("CLimitReadFile"); -#endif - if (File) { File->grab(); AreaStart = pos; diff --git a/irr/src/CLogger.cpp b/irr/src/CLogger.cpp index 70d06b36a..2bb589a99 100644 --- a/irr/src/CLogger.cpp +++ b/irr/src/CLogger.cpp @@ -9,11 +9,7 @@ namespace irr CLogger::CLogger(IEventReceiver *r) : LogLevel(ELL_INFORMATION), Receiver(r) -{ -#ifdef _DEBUG - setDebugName("CLogger"); -#endif -} +{} //! Returns the current set log level. ELOG_LEVEL CLogger::getLogLevel() const diff --git a/irr/src/CMemoryFile.cpp b/irr/src/CMemoryFile.cpp index 6d7906b91..4e6baa99c 100644 --- a/irr/src/CMemoryFile.cpp +++ b/irr/src/CMemoryFile.cpp @@ -12,11 +12,7 @@ namespace io CMemoryReadFile::CMemoryReadFile(const void *memory, long len, const io::path &fileName, bool d) : Buffer(memory), Len(len), Pos(0), Filename(fileName), deleteMemoryWhenDropped(d) -{ -#ifdef _DEBUG - setDebugName("CMemoryReadFile"); -#endif -} +{} CMemoryReadFile::~CMemoryReadFile() { @@ -82,11 +78,7 @@ const io::path &CMemoryReadFile::getFileName() const CMemoryWriteFile::CMemoryWriteFile(void *memory, long len, const io::path &fileName, bool d) : Buffer(memory), Len(len), Pos(0), Filename(fileName), deleteMemoryWhenDropped(d) -{ -#ifdef _DEBUG - setDebugName("CMemoryWriteFile"); -#endif -} +{} CMemoryWriteFile::~CMemoryWriteFile() { diff --git a/irr/src/CMeshSceneNode.cpp b/irr/src/CMeshSceneNode.cpp index 6d02eada5..2d9e400e9 100644 --- a/irr/src/CMeshSceneNode.cpp +++ b/irr/src/CMeshSceneNode.cpp @@ -23,10 +23,6 @@ CMeshSceneNode::CMeshSceneNode(IMesh *mesh, ISceneNode *parent, ISceneManager *m Mesh(0), PassCount(0), ReadOnlyMaterials(false) { -#ifdef _DEBUG - setDebugName("CMeshSceneNode"); -#endif - setMesh(mesh); } diff --git a/irr/src/CNSOGLManager.mm b/irr/src/CNSOGLManager.mm index c1e543e53..b550df20e 100644 --- a/irr/src/CNSOGLManager.mm +++ b/irr/src/CNSOGLManager.mm @@ -16,11 +16,7 @@ namespace video CNSOGLManager::CNSOGLManager() : PrimaryContext(SExposedVideoData(0)), PixelFormat(nil) -{ -#ifdef _DEBUG - setDebugName("CNSOGLManager"); -#endif -} +{} CNSOGLManager::~CNSOGLManager() { diff --git a/irr/src/CNullDriver.cpp b/irr/src/CNullDriver.cpp index efbad7598..80aacb042 100644 --- a/irr/src/CNullDriver.cpp +++ b/irr/src/CNullDriver.cpp @@ -53,10 +53,6 @@ CNullDriver::CNullDriver(io::IFileSystem *io, const core::dimension2d &scre ViewPort(0, 0, 0, 0), ScreenSize(screenSize), MinVertexCountForVBO(500), TextureCreationFlags(0), OverrideMaterial2DEnabled(false), AllowZWriteOnTransparent(false) { -#ifdef _DEBUG - setDebugName("CNullDriver"); -#endif - DriverAttributes = new io::CAttributes(); DriverAttributes->addInt("MaxTextures", MATERIAL_MAX_TEXTURES); DriverAttributes->addInt("MaxSupportedTextures", MATERIAL_MAX_TEXTURES); diff --git a/irr/src/COBJMeshFileLoader.cpp b/irr/src/COBJMeshFileLoader.cpp index 97e90c322..fdbcbd1d0 100644 --- a/irr/src/COBJMeshFileLoader.cpp +++ b/irr/src/COBJMeshFileLoader.cpp @@ -26,11 +26,7 @@ namespace scene //! Constructor COBJMeshFileLoader::COBJMeshFileLoader(scene::ISceneManager *smgr) : SceneManager(smgr) -{ -#ifdef _DEBUG - setDebugName("COBJMeshFileLoader"); -#endif -} +{} //! destructor COBJMeshFileLoader::~COBJMeshFileLoader() diff --git a/irr/src/COSOperator.cpp b/irr/src/COSOperator.cpp index d53223916..518f26563 100644 --- a/irr/src/COSOperator.cpp +++ b/irr/src/COSOperator.cpp @@ -43,11 +43,7 @@ COSOperator::COSOperator(const core::stringc &osVersion, CIrrDeviceLinux *device // constructor COSOperator::COSOperator(const core::stringc &osVersion) : OperatingSystem(osVersion) -{ -#ifdef _DEBUG - setDebugName("COSOperator"); -#endif -} +{} COSOperator::~COSOperator() { diff --git a/irr/src/COpenGLCoreRenderTarget.h b/irr/src/COpenGLCoreRenderTarget.h index a174e926e..50656ce1f 100644 --- a/irr/src/COpenGLCoreRenderTarget.h +++ b/irr/src/COpenGLCoreRenderTarget.h @@ -28,10 +28,6 @@ public: AssignedDepth(false), AssignedStencil(false), RequestTextureUpdate(false), RequestDepthStencilUpdate(false), BufferID(0), ColorAttachment(0), MultipleRenderTarget(0), Driver(driver) { -#ifdef _DEBUG - setDebugName("COpenGLCoreRenderTarget"); -#endif - DriverType = Driver->getDriverType(); Size = Driver->getScreenSize(); diff --git a/irr/src/COpenGLDriver.cpp b/irr/src/COpenGLDriver.cpp index f7c0be7dd..7d98482e8 100644 --- a/irr/src/COpenGLDriver.cpp +++ b/irr/src/COpenGLDriver.cpp @@ -32,11 +32,7 @@ COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters ¶ms, io::IFil CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), CacheHandler(0), CurrentRenderMode(ERM_NONE), ResetRenderStates(true), Transformation3DChanged(true), AntiAlias(params.AntiAlias), ColorFormat(ECF_R8G8B8), FixedPipelineState(EOFPS_ENABLE), Params(params), ContextManager(contextManager) -{ -#ifdef _DEBUG - setDebugName("COpenGLDriver"); -#endif -} +{} bool COpenGLDriver::initDriver() { diff --git a/irr/src/COpenGLSLMaterialRenderer.cpp b/irr/src/COpenGLSLMaterialRenderer.cpp index 27393adeb..de0f090c3 100644 --- a/irr/src/COpenGLSLMaterialRenderer.cpp +++ b/irr/src/COpenGLSLMaterialRenderer.cpp @@ -50,10 +50,6 @@ COpenGLSLMaterialRenderer::COpenGLSLMaterialRenderer(video::COpenGLDriver *drive Driver(driver), CallBack(callback), Alpha(false), Blending(false), AlphaTest(false), Program(0), Program2(0), UserData(userData) { -#ifdef _DEBUG - setDebugName("COpenGLSLMaterialRenderer"); -#endif - switch (baseMaterial) { case EMT_TRANSPARENT_VERTEX_ALPHA: case EMT_TRANSPARENT_ALPHA_CHANNEL: diff --git a/irr/src/CReadFile.cpp b/irr/src/CReadFile.cpp index 6c6e49d55..3ef90e715 100644 --- a/irr/src/CReadFile.cpp +++ b/irr/src/CReadFile.cpp @@ -12,10 +12,6 @@ namespace io CReadFile::CReadFile(const io::path &fileName) : File(0), FileSize(0), Filename(fileName) { -#ifdef _DEBUG - setDebugName("CReadFile"); -#endif - openFile(); } diff --git a/irr/src/CSDLManager.cpp b/irr/src/CSDLManager.cpp index 855c8c9e4..56fe9e0d7 100644 --- a/irr/src/CSDLManager.cpp +++ b/irr/src/CSDLManager.cpp @@ -15,11 +15,7 @@ namespace video CSDLManager::CSDLManager(CIrrDeviceSDL *device) : IContextManager(), SDLDevice(device) -{ -#ifdef _DEBUG - setDebugName("CSDLManager"); -#endif -} +{} bool CSDLManager::initialize(const SIrrlichtCreationParameters ¶ms, const SExposedVideoData &data) { diff --git a/irr/src/CSceneCollisionManager.cpp b/irr/src/CSceneCollisionManager.cpp index 77549a7dc..3d8f1091f 100644 --- a/irr/src/CSceneCollisionManager.cpp +++ b/irr/src/CSceneCollisionManager.cpp @@ -17,10 +17,6 @@ namespace scene CSceneCollisionManager::CSceneCollisionManager(ISceneManager *smanager, video::IVideoDriver *driver) : SceneManager(smanager), Driver(driver) { -#ifdef _DEBUG - setDebugName("CSceneCollisionManager"); -#endif - if (Driver) Driver->grab(); } diff --git a/irr/src/CSceneManager.cpp b/irr/src/CSceneManager.cpp index a6716525a..94b6c24a7 100644 --- a/irr/src/CSceneManager.cpp +++ b/irr/src/CSceneManager.cpp @@ -44,11 +44,6 @@ CSceneManager::CSceneManager(video::IVideoDriver *driver, ActiveCamera(0), Parameters(0), MeshCache(cache), CurrentRenderPass(ESNRP_NONE) { -#ifdef _DEBUG - ISceneManager::setDebugName("CSceneManager ISceneManager"); - ISceneNode::setDebugName("CSceneManager ISceneNode"); -#endif - // root node's scene manager SceneManager = this; diff --git a/irr/src/CWGLManager.cpp b/irr/src/CWGLManager.cpp index 785524fbc..d0dc9bf6a 100644 --- a/irr/src/CWGLManager.cpp +++ b/irr/src/CWGLManager.cpp @@ -19,9 +19,6 @@ namespace video CWGLManager::CWGLManager() : PrimaryContext(SExposedVideoData(0)), PixelFormat(0), libHandle(NULL) { -#ifdef _DEBUG - setDebugName("CWGLManager"); -#endif memset(FunctionPointers, 0, sizeof(FunctionPointers)); } diff --git a/irr/src/CWriteFile.cpp b/irr/src/CWriteFile.cpp index 362b284ee..f6a7efd2b 100644 --- a/irr/src/CWriteFile.cpp +++ b/irr/src/CWriteFile.cpp @@ -13,10 +13,6 @@ namespace io CWriteFile::CWriteFile(const io::path &fileName, bool append) : Filename(fileName), FileSize(0) { -#ifdef _DEBUG - setDebugName("CWriteFile"); -#endif - openFile(append); } diff --git a/irr/src/CXMeshFileLoader.cpp b/irr/src/CXMeshFileLoader.cpp index cb02298eb..508b632c0 100644 --- a/irr/src/CXMeshFileLoader.cpp +++ b/irr/src/CXMeshFileLoader.cpp @@ -32,11 +32,7 @@ namespace scene CXMeshFileLoader::CXMeshFileLoader(scene::ISceneManager *smgr) : AnimatedMesh(0), Buffer(0), P(0), End(0), BinaryNumCount(0), Line(0), ErrorState(false), CurFrame(0), MajorVersion(0), MinorVersion(0), BinaryFormat(false), FloatSize(0) -{ -#ifdef _DEBUG - setDebugName("CXMeshFileLoader"); -#endif -} +{} //! returns true if the file maybe is able to be loaded by this class //! based on the file extension (e.g. ".bsp") diff --git a/irr/src/CZipReader.cpp b/irr/src/CZipReader.cpp index 036f6302a..dc5c0a4f0 100644 --- a/irr/src/CZipReader.cpp +++ b/irr/src/CZipReader.cpp @@ -24,11 +24,7 @@ namespace io //! Constructor CArchiveLoaderZIP::CArchiveLoaderZIP(io::IFileSystem *fs) : FileSystem(fs) -{ -#ifdef _DEBUG - setDebugName("CArchiveLoaderZIP"); -#endif -} +{} //! returns true if the file maybe is able to be loaded by this class bool CArchiveLoaderZIP::isALoadableFileFormat(const io::path &filename) const @@ -107,10 +103,6 @@ bool CArchiveLoaderZIP::isALoadableFileFormat(io::IReadFile *file) const CZipReader::CZipReader(IFileSystem *fs, IReadFile *file, bool ignoreCase, bool ignorePaths, bool isGZip) : CFileList((file ? file->getFileName() : io::path("")), ignoreCase, ignorePaths), FileSystem(fs), File(file), IsGZip(isGZip) { -#ifdef _DEBUG - setDebugName("CZipReader"); -#endif - if (File) { File->grab(); diff --git a/irr/src/OpenGL/Driver.cpp b/irr/src/OpenGL/Driver.cpp index da19b0bae..5df87861d 100644 --- a/irr/src/OpenGL/Driver.cpp +++ b/irr/src/OpenGL/Driver.cpp @@ -155,10 +155,6 @@ COpenGL3DriverBase::COpenGL3DriverBase(const SIrrlichtCreationParameters ¶ms OGLES2ShaderPath(params.OGLES2ShaderPath), ColorFormat(ECF_R8G8B8), ContextManager(contextManager), EnableErrorTest(params.DriverDebug) { -#ifdef _DEBUG - setDebugName("Driver"); -#endif - if (!ContextManager) return; diff --git a/irr/src/OpenGL/MaterialRenderer.cpp b/irr/src/OpenGL/MaterialRenderer.cpp index d5bf9004a..7439dba61 100644 --- a/irr/src/OpenGL/MaterialRenderer.cpp +++ b/irr/src/OpenGL/MaterialRenderer.cpp @@ -30,10 +30,6 @@ COpenGL3MaterialRenderer::COpenGL3MaterialRenderer(COpenGL3DriverBase *driver, Driver(driver), CallBack(callback), Alpha(false), Blending(false), Program(0), UserData(userData) { -#ifdef _DEBUG - setDebugName("MaterialRenderer"); -#endif - switch (baseMaterial) { case EMT_TRANSPARENT_VERTEX_ALPHA: case EMT_TRANSPARENT_ALPHA_CHANNEL: diff --git a/irr/src/OpenGL/Renderer2D.cpp b/irr/src/OpenGL/Renderer2D.cpp index b625feda4..1dd717aa8 100644 --- a/irr/src/OpenGL/Renderer2D.cpp +++ b/irr/src/OpenGL/Renderer2D.cpp @@ -22,10 +22,6 @@ COpenGL3Renderer2D::COpenGL3Renderer2D(const c8 *vertexShaderProgram, const c8 * COpenGL3MaterialRenderer(driver, 0, EMT_SOLID), WithTexture(withTexture) { -#ifdef _DEBUG - setDebugName("Renderer2D"); -#endif - int Temp = 0; init(Temp, vertexShaderProgram, pixelShaderProgram, false); diff --git a/src/gui/guiEditBoxWithScrollbar.cpp b/src/gui/guiEditBoxWithScrollbar.cpp index ed5db785b..bc594bba6 100644 --- a/src/gui/guiEditBoxWithScrollbar.cpp +++ b/src/gui/guiEditBoxWithScrollbar.cpp @@ -30,10 +30,6 @@ GUIEditBoxWithScrollBar::GUIEditBoxWithScrollBar(const wchar_t* text, bool borde : GUIEditBox(environment, parent, id, rectangle, border, writable), m_background(true), m_bg_color_used(false), m_tsrc(tsrc) { -#ifdef _DEBUG - setDebugName("GUIEditBoxWithScrollBar"); -#endif - Text = text; diff --git a/src/gui/guiHyperText.cpp b/src/gui/guiHyperText.cpp index e3900a1fd..8efd81d0f 100644 --- a/src/gui/guiHyperText.cpp +++ b/src/gui/guiHyperText.cpp @@ -1015,10 +1015,6 @@ GUIHyperText::GUIHyperText(const wchar_t *text, IGUIEnvironment *environment, m_drawer(text, client, environment, tsrc), m_text_scrollpos(0, 0) { -#ifdef _DEBUG - setDebugName("GUIHyperText"); -#endif - IGUISkin *skin = 0; if (Environment) skin = Environment->getSkin(); diff --git a/src/irrlicht_changes/CGUITTFont.cpp b/src/irrlicht_changes/CGUITTFont.cpp index 8337390c1..73962605d 100644 --- a/src/irrlicht_changes/CGUITTFont.cpp +++ b/src/irrlicht_changes/CGUITTFont.cpp @@ -254,9 +254,6 @@ CGUITTFont::CGUITTFont(IGUIEnvironment *env) batch_load_size(1), Device(0), Environment(env), Driver(0), GlobalKerningWidth(0), GlobalKerningHeight(0), shadow_offset(0), shadow_alpha(0), fallback(0) { - #ifdef _DEBUG - setDebugName("CGUITTFont"); - #endif if (Environment) { diff --git a/src/irrlicht_changes/static_text.cpp b/src/irrlicht_changes/static_text.cpp index eba397963..d06419e1f 100644 --- a/src/irrlicht_changes/static_text.cpp +++ b/src/irrlicht_changes/static_text.cpp @@ -30,10 +30,6 @@ StaticText::StaticText(const EnrichedString &text, bool border, RestrainTextInside(true), RightToLeft(false), OverrideFont(0), LastBreakFont(0) { - #ifdef _DEBUG - setDebugName("StaticText"); - #endif - setText(text); } From 52a6673dab08800df0ef8f6403d9c58489764722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Sat, 14 Dec 2024 17:04:12 +0100 Subject: [PATCH 125/136] Get rid of obsolete workaround for collision detection bugs (#15540) --- src/client/content_cao.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index b73b3602c..d90d4e8b0 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -1663,11 +1663,6 @@ void GenericCAO::processMessage(const std::string &data) bool is_end_position = readU8(is); float update_interval = readF32(is); - // Place us a bit higher if we're physical, to not sink into - // the ground due to sucky collision detection... - if(m_prop.physical) - m_position += v3f(0,0.002,0); - if(getParent() != NULL) // Just in case return; From f99a1a7c7c1a3d96332169978b63ffb10c56dbb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Sat, 14 Dec 2024 18:50:21 +0100 Subject: [PATCH 126/136] Revert "Optimize raycast performance (#15233)" This reverts commit f7a695c212bea96887b32b859645f621fd8f1b48. --- doc/lua_api.md | 2 -- src/environment.cpp | 6 ------ src/nodedef.cpp | 12 ------------ src/nodedef.h | 5 ----- 4 files changed, 25 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index d753b6b53..7fe464a30 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -9948,8 +9948,6 @@ Used by `core.register_node`. selection_box = { -- see [Node boxes] for possibilities - -- Selection boxes that oversize node size can cause - -- significant performance drop of Raycasts. }, -- Custom selection box definition. Multiple boxes can be defined. -- If "nodebox" drawtype is used and selection_box is nil, then node_box diff --git a/src/environment.cpp b/src/environment.cpp index e66c7e2de..fe582afd4 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -163,8 +163,6 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result_p) break; // About to go out of bounds } - const v3s16 pos_on_ray = state->m_iterator.m_current_node_pos; - // For each untested node for (s16 z = new_nodes.MinEdge.Z; z <= new_nodes.MaxEdge.Z; z++) for (s16 y = new_nodes.MinEdge.Y; y <= new_nodes.MaxEdge.Y; y++) @@ -177,10 +175,6 @@ void Environment::continueRaycast(RaycastState *state, PointedThing *result_p) if (!is_valid_position) continue; - // Optimization: Skip non-oversized selection boxes for other positions. - if ((pos_on_ray != np) && !nodedef->get(n).has_big_selection_box) - continue; - PointabilityType pointable = isPointableNode(n, nodedef, state->m_liquids_pointable, state->m_pointabilities); diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 0fde1b68e..81348cf23 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -1257,15 +1257,6 @@ inline void NodeDefManager::fixSelectionBoxIntUnion() m_selection_box_union.MaxEdge.Z / BS - 0.5f); } -inline void NodeDefManager::calcBigSelectionBox(content_t id, const ContentFeatures &def) -{ - aabb3f box_union; - getNodeBoxUnion(def.selection_box, def, &box_union); - m_content_features[id].has_big_selection_box = - (box_union.MinEdge.X < -BS/2) || (box_union.MaxEdge.X > BS/2) || - (box_union.MinEdge.Y < -BS/2) || (box_union.MaxEdge.Y > BS/2) || - (box_union.MinEdge.Z < -BS/2) || (box_union.MaxEdge.Z > BS/2); -} void NodeDefManager::eraseIdFromGroups(content_t id) { @@ -1321,7 +1312,6 @@ content_t NodeDefManager::set(const std::string &name, const ContentFeatures &de getNodeBoxUnion(def.selection_box, def, &m_selection_box_union); fixSelectionBoxIntUnion(); - calcBigSelectionBox(id, def); // Add this content to the list of all groups it belongs to for (const auto &group : def.groups) { const std::string &group_name = group.first; @@ -1535,8 +1525,6 @@ void NodeDefManager::deSerialize(std::istream &is, u16 protocol_version) getNodeBoxUnion(f.selection_box, f, &m_selection_box_union); fixSelectionBoxIntUnion(); - - calcBigSelectionBox(i, f); } // Since liquid_alternative_flowing_id and liquid_alternative_source_id diff --git a/src/nodedef.h b/src/nodedef.h index e33f42699..c3f88ce83 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -425,8 +425,6 @@ struct ContentFeatures NodeBox node_box; NodeBox selection_box; NodeBox collision_box; - //! Whether any selection box extent is > BS/2. - bool has_big_selection_box; // --- SOUND PROPERTIES --- @@ -776,9 +774,6 @@ private: */ void fixSelectionBoxIntUnion(); - //! Calculates ContentFeatures::&has_big_selection_box - void calcBigSelectionBox(content_t id, const ContentFeatures &def); - //! Features indexed by ID. std::vector m_content_features; From a37bdbf8b7778336c6740f994164097ebb4129e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20M=C3=BCller?= <34514239+appgurueu@users.noreply.github.com> Date: Wed, 18 Dec 2024 20:29:35 +0100 Subject: [PATCH 127/136] Restore `.x` models to working state (#15550) * Add "lava flan" (.x model) smoke test * Fix double finalize in `.x` mesh loader * Use reserve instead of resize again The weights are added indirectly via `AnimatedMesh->addWeight` --- .gitattributes | 1 + .../mods/testentities/models/LICENSE.txt | 8 + .../models/testentities_lava_flan.png | Bin 0 -> 1294 bytes .../models/testentities_lava_flan.x | 3506 +++++++++++++++++ games/devtest/mods/testentities/visuals.lua | 14 + irr/src/CXMeshFileLoader.cpp | 10 +- 6 files changed, 3535 insertions(+), 4 deletions(-) create mode 100644 games/devtest/mods/testentities/models/testentities_lava_flan.png create mode 100644 games/devtest/mods/testentities/models/testentities_lava_flan.x diff --git a/.gitattributes b/.gitattributes index ecd9a7a29..41a6c0979 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,3 +5,4 @@ *.h diff=cpp *.gltf binary +*.x binary diff --git a/games/devtest/mods/testentities/models/LICENSE.txt b/games/devtest/mods/testentities/models/LICENSE.txt index 4317d68d3..19ffffc5c 100644 --- a/games/devtest/mods/testentities/models/LICENSE.txt +++ b/games/devtest/mods/testentities/models/LICENSE.txt @@ -1,3 +1,5 @@ +"Minetest Sam": + Original model by MirceaKitsune (CC BY-SA 3.0). Various alterations and fixes by kilbith, sofar, xunto, Rogier-5, TeTpaAka, Desour, stujones11, An0n3m0us (CC BY-SA 3.0): @@ -5,3 +7,9 @@ stujones11, An0n3m0us (CC BY-SA 3.0): Jordach (CC BY-SA 3.0): testentities_sam.png + +"Lava Flan": + +Zeg9 (CC BY-SA 3.0): + testentities_lava_flan.x + testentities_lava_flan.png \ No newline at end of file diff --git a/games/devtest/mods/testentities/models/testentities_lava_flan.png b/games/devtest/mods/testentities/models/testentities_lava_flan.png new file mode 100644 index 0000000000000000000000000000000000000000..8cf37238fe1fdd8e11ffab67b1c1d8d2663a7ac3 GIT binary patch literal 1294 zcmV+p1@ZccP) zW!V?AB?2>w*~ZW;EXF7wmiRJ_$&7Kym>UTgVnkzrB_qq@InPU5D08hh=fmxDfB$>V zJ?Gq8=3cW#?&R~mVy0ZYEreVp@TX=~!Xrs&ZIX1zWZD-KgBC8&WWoOO@bM1OD8!pW zbf9LZUw~g)B*|MK8q>J@3HECm@qr_l4_rl_{qACoajb@Ow24CQrxgLl=n~?n!+};8 z%ciZwlOR5D6?yhc4I8ttO3uH_=X1{m(24-9UWi)7M$K#?i+F7dCB|T$J}LlC zkY_gzupNvXe7)I^e(EyB7(2-4yt15rxZB9WI+lfOe4UU8D*+`E(oqHlLRECnvvdGGV`k%Tpb$ zJgo^RYk`7hHr2wv+DuFPl9F7{@Y>k0c{UGh7t;ij`jLARh@N$`>sz?GRL=QGF0Wo6 zHqR=U)}~h^es}w#qWzGnZL}9xU*n?=5`@dMV#anVf^YHyu1qtf;tM4e6`Wtq<44nY zb#iiXRMfJ(+V#uwtcOu<}6V}sdTV={R%ctn93{G!aOOA))7ha|m zse)@KVWLcvg~IC&1`Ts1X>{H*Fn$&mE}_7NA4xD6DOY5EzlZ1}0H5!MN!>vxyyoEK zQ>*@QX0|Iiy;Vx#$RinA7onZs`16Y-s0FCW&PKrJ;Gw*Jf^*SxPFtYhL{^qO5TOcM z6B5RoNPxT7=fjPXWgI++*B#g+F>$H@4d?O&6ZNPX(O~4AQW6}<&PIE;aFK)m=5+^B zv|LFyKyACZa*!`ts3lavQ2d`SQDfBQ}15oE|B~wQk-2 zdQCswK>Mn@<6JFQKbv(JTddZ;LJ9{b?zlL5-@_dL0#E%Ivk87af&c&j07*qoM6N<$ Ef+HAvNdN!< literal 0 HcmV?d00001 diff --git a/games/devtest/mods/testentities/models/testentities_lava_flan.x b/games/devtest/mods/testentities/models/testentities_lava_flan.x new file mode 100644 index 000000000..be78ff97e --- /dev/null +++ b/games/devtest/mods/testentities/models/testentities_lava_flan.x @@ -0,0 +1,3506 @@ +xof 0303txt 0032 + +template XSkinMeshHeader { + <3cf169ce-ff7c-44ab-93c0-f78f62d172e2> + WORD nMaxSkinWeightsPerVertex; + WORD nMaxSkinWeightsPerFace; + WORD nBones; +} + +template SkinWeights { + <6f0d123b-bad2-4167-a0d0-80224f25fabb> + STRING transformNodeName; + DWORD nWeights; + array DWORD vertexIndices[nWeights]; + array float weights[nWeights]; + Matrix4x4 matrixOffset; +} + +Frame Root { + FrameTransformMatrix { + 1.000000, 0.000000, 0.000000, 0.000000, + 0.000000,-0.000000, 1.000000, 0.000000, + 0.000000, 1.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 1.000000;; + } + Frame Armature { + FrameTransformMatrix { + -5.000000, 0.000001, 0.000000, 0.000000, + -0.000001,-5.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 5.000000, 0.000000, + 0.000000, 0.000000,-5.000000, 1.000000;; + } + Frame Armature_Bone { + FrameTransformMatrix { + 1.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 1.000000, 0.000000, + 0.000000,-1.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 0.000000, 1.000000;; + } + Frame Armature_Bone_001 { + FrameTransformMatrix { + 1.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 1.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 1.000000, 0.000000, + 0.000000, 2.000000, 0.000000, 1.000000;; + } + Frame Armature_Bone_002 { + FrameTransformMatrix { + 1.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 1.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 1.000000, 0.000000, + 0.000000, 0.300000, 0.000000, 1.000000;; + } + Frame Armature_Bone_003 { + FrameTransformMatrix { + 1.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 1.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 1.000000, 0.000000, + 0.000000, 0.300000, 0.000000, 1.000000;; + } + Frame Armature_Bone_004 { + FrameTransformMatrix { + 1.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 1.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 1.000000, 0.000000, + 0.000000, 0.400000, 0.000000, 1.000000;; + } + } // End of Armature_Bone_004 + } // End of Armature_Bone_003 + } // End of Armature_Bone_002 + } // End of Armature_Bone_001 + } // End of Armature_Bone + Frame Cube { + FrameTransformMatrix { + 1.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 1.000000, 0.000000, 0.000000, + 0.000000, 0.000000, 1.000000, 0.000000, + 0.000000, 0.000000, 1.000000, 1.000000;; + } + Mesh { // Cube mesh + 264; + 1.000000; 1.000000;-1.000000;, + 1.000000;-1.000000;-1.000000;, + -1.000000;-1.000000;-1.000000;, + -1.000000; 1.000000;-1.000000;, + -1.000000; 1.000000; 1.000000;, + -1.000000;-1.000000; 1.000000;, + -0.800000;-0.800000; 1.000000;, + -0.800000; 0.800000; 1.000000;, + 1.000000; 1.000000;-1.000000;, + 1.000000; 0.999999; 1.000000;, + 0.999999;-1.000001; 1.000000;, + 1.000000;-1.000000;-1.000000;, + 1.000000;-1.000000;-1.000000;, + 0.999999;-1.000001; 1.000000;, + -1.000000;-1.000000; 1.000000;, + -1.000000;-1.000000;-1.000000;, + -1.000000;-1.000000;-1.000000;, + -1.000000;-1.000000; 1.000000;, + -1.000000; 1.000000; 1.000000;, + -1.000000; 1.000000;-1.000000;, + 1.000000; 0.999999; 1.000000;, + 1.000000; 1.000000;-1.000000;, + -1.000000; 1.000000;-1.000000;, + -1.000000; 1.000000; 1.000000;, + -0.800000; 0.800000; 1.666667;, + -0.800000;-0.800000; 1.666667;, + -0.800000;-0.800000; 2.000000;, + -0.800000; 0.800000; 2.000000;, + 0.999999;-1.000001; 1.000000;, + 1.000000; 0.999999; 1.000000;, + 0.800000; 0.800000; 1.000000;, + 0.799999;-0.800001; 1.000000;, + 1.000000; 0.999999; 1.000000;, + -1.000000; 1.000000; 1.000000;, + -0.800000; 0.800000; 1.000000;, + 0.800000; 0.800000; 1.000000;, + -1.000000;-1.000000; 1.000000;, + 0.999999;-1.000001; 1.000000;, + 0.799999;-0.800001; 1.000000;, + -0.800000;-0.800000; 1.000000;, + -0.800000;-0.800000; 2.000000;, + 0.799999;-0.800001; 2.000000;, + 0.640000;-0.640000; 2.000000;, + -0.640000;-0.640000; 2.000000;, + 0.799999;-0.800001; 1.666667;, + 0.800000; 0.800000; 1.666667;, + 0.800000; 0.800000; 2.000000;, + 0.799999;-0.800001; 2.000000;, + 0.800000; 0.800000; 1.666667;, + -0.800000; 0.800000; 1.666667;, + -0.800000; 0.800000; 2.000000;, + 0.800000; 0.800000; 2.000000;, + -0.800000;-0.800000; 1.666667;, + 0.799999;-0.800001; 1.666667;, + 0.799999;-0.800001; 2.000000;, + -0.800000;-0.800000; 2.000000;, + 0.640000; 0.640000; 2.000000;, + -0.640000; 0.640000; 2.000000;, + -0.640000; 0.640000; 2.500000;, + 0.640000; 0.640000; 2.500000;, + -0.800000; 0.800000; 2.000000;, + -0.800000;-0.800000; 2.000000;, + -0.640000;-0.640000; 2.000000;, + -0.640000; 0.640000; 2.000000;, + 0.799999;-0.800001; 2.000000;, + 0.800000; 0.800000; 2.000000;, + 0.640000; 0.640000; 2.000000;, + 0.640000;-0.640000; 2.000000;, + 0.800000; 0.800000; 2.000000;, + -0.800000; 0.800000; 2.000000;, + -0.640000; 0.640000; 2.000000;, + 0.640000; 0.640000; 2.000000;, + 0.640000; 0.640000; 2.500000;, + -0.640000; 0.640000; 2.500000;, + -0.640000;-0.640000; 2.500000;, + 0.640000;-0.640000; 2.500000;, + -0.640000;-0.640000; 2.000000;, + 0.640000;-0.640000; 2.000000;, + 0.640000;-0.640000; 2.500000;, + -0.640000;-0.640000; 2.500000;, + -0.640000; 0.640000; 2.000000;, + -0.640000;-0.640000; 2.000000;, + -0.640000;-0.640000; 2.500000;, + -0.640000; 0.640000; 2.500000;, + 0.640000;-0.640000; 2.000000;, + 0.640000; 0.640000; 2.000000;, + 0.640000; 0.640000; 2.500000;, + 0.640000;-0.640000; 2.500000;, + -0.800000; 0.800000; 1.000000;, + -0.800000;-0.800000; 1.000000;, + -0.800000;-0.800000; 1.333333;, + -0.800000; 0.800000; 1.333333;, + -0.800000; 0.800000; 1.333333;, + -0.800000;-0.800000; 1.333333;, + -0.800000;-0.800000; 1.666667;, + -0.800000; 0.800000; 1.666667;, + 0.799999;-0.800001; 1.000000;, + 0.800000; 0.800000; 1.000000;, + 0.800000; 0.800000; 1.333333;, + 0.799999;-0.800001; 1.333333;, + 0.799999;-0.800001; 1.333333;, + 0.800000; 0.800000; 1.333333;, + 0.800000; 0.800000; 1.666667;, + 0.799999;-0.800001; 1.666667;, + 0.800000; 0.800000; 1.000000;, + -0.800000; 0.800000; 1.000000;, + -0.800000; 0.800000; 1.333333;, + 0.800000; 0.800000; 1.333333;, + 0.800000; 0.800000; 1.333333;, + -0.800000; 0.800000; 1.333333;, + -0.800000; 0.800000; 1.666667;, + 0.800000; 0.800000; 1.666667;, + -0.800000;-0.800000; 1.000000;, + 0.799999;-0.800001; 1.000000;, + 0.799999;-0.800001; 1.333333;, + -0.800000;-0.800000; 1.333333;, + 0.799999;-0.800001; 1.333333;, + 0.799999;-0.800001; 1.666667;, + 0.560000;-0.000000; 1.616667;, + 0.560000;-0.000000; 1.383333;, + -0.560000; 0.000000; 1.383333;, + 0.560000;-0.000000; 1.383333;, + 0.560000;-0.000000; 1.616667;, + -0.560000; 0.000000; 1.616667;, + 0.799999;-0.800001; 1.666667;, + -0.800000;-0.800000; 1.666667;, + -0.560000; 0.000000; 1.616667;, + 0.560000;-0.000000; 1.616667;, + -0.800000;-0.800000; 1.666667;, + -0.800000;-0.800000; 1.333333;, + -0.560000; 0.000000; 1.383333;, + -0.560000; 0.000000; 1.616667;, + -0.800000;-0.800000; 1.333333;, + 0.799999;-0.800001; 1.333333;, + 0.560000;-0.000000; 1.383333;, + -0.560000; 0.000000; 1.383333;, + -0.000000;-0.790000; 1.340000;, + -0.000000;-0.690000; 1.540000;, + -0.100000;-0.690000; 1.340000;, + -0.000000;-0.590000; 1.340000;, + -0.000000;-0.690000; 1.540000;, + 0.100000;-0.690000; 1.340000;, + 0.400000;-0.590000; 1.340000;, + 0.500000;-0.690000; 1.340000;, + 0.400000;-0.790000; 1.340000;, + 0.300000;-0.690000; 1.340000;, + -0.100000;-0.690000; 1.340000;, + -0.000000;-0.690000; 1.540000;, + -0.000000;-0.590000; 1.340000;, + 0.100000;-0.690000; 1.340000;, + -0.000000;-0.690000; 1.540000;, + -0.000000;-0.790000; 1.340000;, + 0.200000;-0.590000; 1.340000;, + 0.300000;-0.690000; 1.340000;, + 0.200000;-0.790000; 1.340000;, + 0.100000;-0.690000; 1.340000;, + 0.300000;-0.690000; 1.340000;, + 0.200000;-0.690000; 1.540000;, + 0.200000;-0.790000; 1.340000;, + 0.100000;-0.690000; 1.340000;, + 0.200000;-0.690000; 1.540000;, + 0.200000;-0.590000; 1.340000;, + 0.200000;-0.590000; 1.340000;, + 0.200000;-0.690000; 1.540000;, + 0.300000;-0.690000; 1.340000;, + 0.500000;-0.690000; 1.340000;, + 0.400000;-0.690000; 1.540000;, + 0.400000;-0.790000; 1.340000;, + 0.200000;-0.790000; 1.340000;, + 0.200000;-0.690000; 1.540000;, + 0.100000;-0.690000; 1.340000;, + -0.000000;-0.590000; 1.340000;, + 0.100000;-0.690000; 1.340000;, + -0.000000;-0.790000; 1.340000;, + -0.100000;-0.690000; 1.340000;, + 0.300000;-0.690000; 1.340000;, + 0.400000;-0.690000; 1.540000;, + 0.400000;-0.590000; 1.340000;, + 0.400000;-0.590000; 1.340000;, + 0.400000;-0.690000; 1.540000;, + 0.500000;-0.690000; 1.340000;, + 0.400000;-0.790000; 1.340000;, + 0.400000;-0.690000; 1.540000;, + 0.300000;-0.690000; 1.340000;, + -0.200000;-0.590000; 1.340000;, + -0.100000;-0.690000; 1.340000;, + -0.200000;-0.790000; 1.340000;, + -0.300000;-0.690000; 1.340000;, + -0.100000;-0.690000; 1.340000;, + -0.200000;-0.690000; 1.540000;, + -0.200000;-0.790000; 1.340000;, + -0.300000;-0.690000; 1.340000;, + -0.200000;-0.690000; 1.540000;, + -0.200000;-0.590000; 1.340000;, + -0.200000;-0.590000; 1.340000;, + -0.200000;-0.690000; 1.540000;, + -0.100000;-0.690000; 1.340000;, + -0.200000;-0.790000; 1.340000;, + -0.200000;-0.690000; 1.540000;, + -0.300000;-0.690000; 1.340000;, + -0.400000;-0.590000; 1.340000;, + -0.300000;-0.690000; 1.340000;, + -0.400000;-0.790000; 1.340000;, + -0.500000;-0.690000; 1.340000;, + -0.300000;-0.690000; 1.340000;, + -0.400000;-0.690000; 1.540000;, + -0.400000;-0.790000; 1.340000;, + -0.500000;-0.690000; 1.340000;, + -0.400000;-0.690000; 1.540000;, + -0.400000;-0.590000; 1.340000;, + -0.400000;-0.590000; 1.340000;, + -0.400000;-0.690000; 1.540000;, + -0.300000;-0.690000; 1.340000;, + -0.400000;-0.790000; 1.340000;, + -0.400000;-0.690000; 1.540000;, + -0.500000;-0.690000; 1.340000;, + 0.200000;-0.700000; 2.400000;, + 0.200000;-0.500000; 2.400000;, + 0.200000;-0.500000; 2.200000;, + 0.200000;-0.700000; 2.200000;, + 0.200000;-0.500000; 2.400000;, + 0.400000;-0.500000; 2.400000;, + 0.400000;-0.500000; 2.200000;, + 0.200000;-0.500000; 2.200000;, + 0.400000;-0.500000; 2.400000;, + 0.400000;-0.700000; 2.400000;, + 0.400000;-0.700000; 2.200000;, + 0.400000;-0.500000; 2.200000;, + 0.400000;-0.700000; 2.400000;, + 0.200000;-0.700000; 2.400000;, + 0.200000;-0.700000; 2.200000;, + 0.400000;-0.700000; 2.200000;, + 0.200000;-0.700000; 2.200000;, + 0.200000;-0.500000; 2.200000;, + 0.400000;-0.500000; 2.200000;, + 0.400000;-0.700000; 2.200000;, + 0.400000;-0.700000; 2.400000;, + 0.400000;-0.500000; 2.400000;, + 0.200000;-0.500000; 2.400000;, + 0.200000;-0.700000; 2.400000;, + -0.400000;-0.700000; 2.400000;, + -0.400000;-0.500000; 2.400000;, + -0.400000;-0.500000; 2.200000;, + -0.400000;-0.700000; 2.200000;, + -0.400000;-0.500000; 2.400000;, + -0.200000;-0.500000; 2.400000;, + -0.200000;-0.500000; 2.200000;, + -0.400000;-0.500000; 2.200000;, + -0.200000;-0.500000; 2.400000;, + -0.200000;-0.700000; 2.400000;, + -0.200000;-0.700000; 2.200000;, + -0.200000;-0.500000; 2.200000;, + -0.200000;-0.700000; 2.400000;, + -0.400000;-0.700000; 2.400000;, + -0.400000;-0.700000; 2.200000;, + -0.200000;-0.700000; 2.200000;, + -0.400000;-0.700000; 2.200000;, + -0.400000;-0.500000; 2.200000;, + -0.200000;-0.500000; 2.200000;, + -0.200000;-0.700000; 2.200000;, + -0.200000;-0.700000; 2.400000;, + -0.200000;-0.500000; 2.400000;, + -0.400000;-0.500000; 2.400000;, + -0.400000;-0.700000; 2.400000;; + 71; + 4;3;2;1;0;, + 4;7;6;5;4;, + 4;11;10;9;8;, + 4;15;14;13;12;, + 4;19;18;17;16;, + 4;23;22;21;20;, + 4;27;26;25;24;, + 4;31;30;29;28;, + 4;35;34;33;32;, + 4;39;38;37;36;, + 4;43;42;41;40;, + 4;47;46;45;44;, + 4;51;50;49;48;, + 4;55;54;53;52;, + 4;59;58;57;56;, + 4;63;62;61;60;, + 4;67;66;65;64;, + 4;71;70;69;68;, + 4;75;74;73;72;, + 4;79;78;77;76;, + 4;83;82;81;80;, + 4;87;86;85;84;, + 4;91;90;89;88;, + 4;95;94;93;92;, + 4;99;98;97;96;, + 4;103;102;101;100;, + 4;107;106;105;104;, + 4;111;110;109;108;, + 4;115;114;113;112;, + 4;119;118;117;116;, + 4;123;122;121;120;, + 4;127;126;125;124;, + 4;131;130;129;128;, + 4;135;134;133;132;, + 3;138;137;136;, + 3;141;140;139;, + 4;145;144;143;142;, + 3;148;147;146;, + 3;151;150;149;, + 4;155;154;153;152;, + 3;158;157;156;, + 3;161;160;159;, + 3;164;163;162;, + 3;167;166;165;, + 3;170;169;168;, + 4;174;173;172;171;, + 3;177;176;175;, + 3;180;179;178;, + 3;183;182;181;, + 4;187;186;185;184;, + 3;190;189;188;, + 3;193;192;191;, + 3;196;195;194;, + 3;199;198;197;, + 4;203;202;201;200;, + 3;206;205;204;, + 3;209;208;207;, + 3;212;211;210;, + 3;215;214;213;, + 4;219;218;217;216;, + 4;223;222;221;220;, + 4;227;226;225;224;, + 4;231;230;229;228;, + 4;235;234;233;232;, + 4;239;238;237;236;, + 4;243;242;241;240;, + 4;247;246;245;244;, + 4;251;250;249;248;, + 4;255;254;253;252;, + 4;259;258;257;256;, + 4;263;262;261;260;; + MeshNormals { // Cube normals + 71; + 0.000000; 0.000000;-1.000000;, + 0.000000; 0.000000; 1.000000;, + 1.000000;-0.000000; 0.000000;, + -0.000000;-1.000000;-0.000000;, + -1.000000; 0.000000;-0.000000;, + 0.000000; 1.000000; 0.000000;, + -1.000000; 0.000000; 0.000000;, + -0.000000; 0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000; 0.000000; 1.000000;, + 0.000000; 0.000000; 1.000000;, + 1.000000;-0.000001; 0.000000;, + 0.000000; 1.000000; 0.000000;, + -0.000000;-1.000000; 0.000000;, + 0.000000; 1.000000; 0.000000;, + 0.000000; 0.000000; 1.000000;, + -0.000000; 0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + 0.000000;-0.000000; 1.000000;, + -0.000000;-1.000000; 0.000000;, + -1.000000; 0.000000; 0.000000;, + 1.000000;-0.000001; 0.000000;, + -1.000000; 0.000000; 0.000000;, + -1.000000; 0.000000; 0.000000;, + 1.000000;-0.000001; 0.000000;, + 1.000000;-0.000001; 0.000000;, + 0.000000; 1.000000; 0.000000;, + 0.000000; 1.000000; 0.000000;, + -0.000000;-1.000000; 0.000000;, + -0.957826;-0.287348; 0.000000;, + -0.000000;-1.000000; 0.000000;, + -0.000000;-0.062378;-0.998053;, + 0.957826;-0.287348; 0.000000;, + 0.000000;-0.062378; 0.998053;, + -0.666667;-0.666667; 0.333333;, + 0.666667; 0.666666; 0.333333;, + 0.000000; 0.000000;-1.000000;, + -0.666667; 0.666667; 0.333333;, + 0.666667;-0.666667; 0.333333;, + 0.000000; 0.000000;-1.000000;, + 0.666667;-0.666667; 0.333333;, + -0.666667; 0.666667; 0.333333;, + 0.666667; 0.666667; 0.333333;, + 0.666667;-0.666667; 0.333333;, + -0.666667;-0.666667; 0.333333;, + 0.000000; 0.000000;-1.000000;, + -0.666667; 0.666667; 0.333333;, + 0.666667; 0.666667; 0.333333;, + -0.666667;-0.666667; 0.333333;, + 0.000000; 0.000000;-1.000000;, + 0.666667;-0.666667; 0.333333;, + -0.666667; 0.666667; 0.333333;, + 0.666667; 0.666667; 0.333333;, + -0.666667;-0.666667; 0.333333;, + 0.000000; 0.000000;-1.000000;, + 0.666667;-0.666667; 0.333333;, + -0.666667; 0.666667; 0.333333;, + 0.666667; 0.666667; 0.333333;, + -0.666667;-0.666667; 0.333333;, + -1.000000; 0.000000; 0.000000;, + 0.000000; 1.000000;-0.000000;, + 1.000000; 0.000000;-0.000000;, + 0.000000;-1.000000; 0.000000;, + -0.000000; 0.000000;-1.000000;, + -0.000000; 0.000000; 1.000000;, + -1.000000; 0.000000; 0.000000;, + 0.000000; 1.000000;-0.000000;, + 1.000000; 0.000000;-0.000000;, + 0.000000;-1.000000; 0.000000;, + -0.000000; 0.000000;-1.000000;, + -0.000000; 0.000000; 1.000000;; + 71; + 4;0;0;0;0;, + 4;1;1;1;1;, + 4;2;2;2;2;, + 4;3;3;3;3;, + 4;4;4;4;4;, + 4;5;5;5;5;, + 4;6;6;6;6;, + 4;7;7;7;7;, + 4;8;8;8;8;, + 4;9;9;9;9;, + 4;10;10;10;10;, + 4;11;11;11;11;, + 4;12;12;12;12;, + 4;13;13;13;13;, + 4;14;14;14;14;, + 4;15;15;15;15;, + 4;16;16;16;16;, + 4;17;17;17;17;, + 4;18;18;18;18;, + 4;19;19;19;19;, + 4;20;20;20;20;, + 4;21;21;21;21;, + 4;22;22;22;22;, + 4;23;23;23;23;, + 4;24;24;24;24;, + 4;25;25;25;25;, + 4;26;26;26;26;, + 4;27;27;27;27;, + 4;28;28;28;28;, + 4;29;29;29;29;, + 4;30;30;30;30;, + 4;31;31;31;31;, + 4;32;32;32;32;, + 4;33;33;33;33;, + 3;34;34;34;, + 3;35;35;35;, + 4;36;36;36;36;, + 3;37;37;37;, + 3;38;38;38;, + 4;39;39;39;39;, + 3;40;40;40;, + 3;41;41;41;, + 3;42;42;42;, + 3;43;43;43;, + 3;44;44;44;, + 4;45;45;45;45;, + 3;46;46;46;, + 3;47;47;47;, + 3;48;48;48;, + 4;49;49;49;49;, + 3;50;50;50;, + 3;51;51;51;, + 3;52;52;52;, + 3;53;53;53;, + 4;54;54;54;54;, + 3;55;55;55;, + 3;56;56;56;, + 3;57;57;57;, + 3;58;58;58;, + 4;59;59;59;59;, + 4;60;60;60;60;, + 4;61;61;61;61;, + 4;62;62;62;62;, + 4;63;63;63;63;, + 4;64;64;64;64;, + 4;65;65;65;65;, + 4;66;66;66;66;, + 4;67;67;67;67;, + 4;68;68;68;68;, + 4;69;69;69;69;, + 4;70;70;70;70;; + } // End of Cube normals + MeshTextureCoords { // Cube UV coordinates + 264; + 0.000000; 0.500000;, + 0.500000; 0.500000;, + 0.500000; 0.000000;, + 0.000000; 0.000000;, + -0.000104; 0.000450;, + -0.000014; 0.499950;, + 0.058184; 0.442464;, + 0.057363; 0.058619;, + 0.000000; 0.500000;, + 0.500000; 0.500000;, + 0.500000; 0.000000;, + 0.000000; 0.000000;, + 0.000000; 0.500000;, + 0.500000; 0.500000;, + 0.500000; 0.000000;, + 0.000000; 0.000000;, + 0.000000; 0.500000;, + 0.500000; 0.500000;, + 0.500000; 0.000000;, + 0.000000; 0.000000;, + 0.000000; 0.500000;, + 0.500000; 0.500000;, + 0.500000; 0.000000;, + 0.000000; 0.000000;, + 0.499960; 0.416620;, + 0.000040; 0.416620;, + 0.000040; 0.624921;, + 0.499960; 0.624921;, + 0.499489; 0.499550;, + 0.499399; 0.000050;, + 0.441201; 0.057536;, + 0.442021; 0.441381;, + 0.499399; 0.000050;, + -0.000104; 0.000450;, + 0.057363; 0.058619;, + 0.441201; 0.057536;, + -0.000014; 0.499950;, + 0.499489; 0.499550;, + 0.442021; 0.441381;, + 0.058184; 0.442464;, + -0.000014; 0.499950;, + 0.499489; 0.499550;, + 0.442022; 0.441382;, + 0.058184; 0.442464;, + 0.000040; 0.208320;, + 0.499960; 0.208320;, + 0.499960; 0.000020;, + 0.000040; 0.000020;, + 0.499960; 0.416621;, + 0.000040; 0.416620;, + 0.000040; 0.624921;, + 0.499960; 0.624921;, + 0.000046; 0.499908;, + 0.499954; 0.499909;, + 0.499954; 0.291613;, + 0.000046; 0.291613;, + 0.499969;-0.015638;, + 0.000031;-0.015639;, + 0.000031; 0.374937;, + 0.499969; 0.374938;, + -0.000104; 0.000450;, + -0.000014; 0.499950;, + 0.058184; 0.442464;, + 0.057364; 0.058619;, + 0.499489; 0.499550;, + 0.499399; 0.000050;, + 0.441201; 0.057536;, + 0.442022; 0.441382;, + 0.499399; 0.000050;, + -0.000104; 0.000450;, + 0.057364; 0.058619;, + 0.441201; 0.057536;, + 0.499950; 0.000050;, + 0.000050; 0.000050;, + 0.000050; 0.499950;, + 0.499950; 0.499950;, + 0.000031; 0.374937;, + 0.499969; 0.374938;, + 0.499969;-0.015638;, + 0.000031;-0.015639;, + 0.499969;-0.015639;, + 0.000031;-0.015639;, + 0.000031; 0.374937;, + 0.499969; 0.374938;, + 0.000031; 0.374937;, + 0.499969; 0.374938;, + 0.499969;-0.015639;, + 0.000031;-0.015639;, + 0.499960; 0.000019;, + 0.000040; 0.000019;, + 0.000040; 0.208320;, + 0.499960; 0.208320;, + 0.499960; 0.208320;, + 0.000040; 0.208320;, + 0.000040; 0.416620;, + 0.499960; 0.416620;, + 0.000040; 0.624921;, + 0.499960; 0.624921;, + 0.499960; 0.416620;, + 0.000040; 0.416621;, + 0.000040; 0.416621;, + 0.499960; 0.416620;, + 0.499960; 0.208320;, + 0.000040; 0.208320;, + 0.499961; 0.000021;, + 0.000040; 0.000020;, + 0.000040; 0.208320;, + 0.499960; 0.208321;, + 0.499960; 0.208321;, + 0.000040; 0.208320;, + 0.000040; 0.416620;, + 0.499960; 0.416621;, + 0.000046; 0.291430;, + 0.499954; 0.291430;, + 0.499954; 0.083135;, + 0.000046; 0.083134;, + 0.482632; 0.297524;, + 0.499972; 0.143183;, + 0.275451; 0.201614;, + 0.279529; 0.217376;, + 0.000023; 0.249954;, + 0.499977; 0.249954;, + 0.499977; 0.041640;, + 0.000023; 0.041640;, + 0.499972; 0.143183;, + 0.017368; 0.143350;, + 0.220471; 0.223498;, + 0.275451; 0.201614;, + 0.017368; 0.143350;, + 0.000028; 0.297691;, + 0.224549; 0.239260;, + 0.220471; 0.223498;, + 0.000035; 0.499630;, + 0.499965; 0.499457;, + 0.424889; 0.249031;, + 0.074938; 0.249151;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.000000; 1.000000;, + 1.000000; 1.000000;, + 1.000000; 0.000000;, + 0.000000; 0.000000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.000000; 1.000000;, + 1.000000; 1.000000;, + 1.000000; 0.000000;, + 0.000000; 0.000000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.000000; 1.000000;, + 1.000000; 1.000000;, + 1.000000; 0.000000;, + 0.000000; 0.000000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.000000; 1.000000;, + 1.000000; 1.000000;, + 1.000000; 0.000000;, + 0.000000; 0.000000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.000000; 1.000000;, + 1.000000; 1.000000;, + 1.000000; 0.000000;, + 0.000000; 0.000000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.843750; 0.500000;, + 0.750000; 0.375000;, + 0.656250; 0.500000;, + 0.562500; 0.562500;, + 0.500000; 0.500000;, + 0.500000; 1.000000;, + 0.562500; 0.937500;, + 0.000000; 1.000000;, + 1.000000; 1.000000;, + 1.000000; 0.000000;, + 0.000000; 0.000000;, + 1.000000; 0.500000;, + 0.937500; 0.562500;, + 0.937500; 0.937500;, + 0.999902; 0.999901;, + 0.968750; 0.031250;, + 0.843750; 0.031250;, + 0.843750; 0.156250;, + 0.968750; 0.156250;, + 0.562500; 0.937500;, + 0.500000; 1.000000;, + 0.999902; 0.999901;, + 0.937500; 0.937500;, + 0.937500; 0.562500;, + 1.000000; 0.500000;, + 0.500000; 0.500000;, + 0.562500; 0.562500;, + 0.562500; 0.562500;, + 0.500000; 0.500000;, + 0.500000; 1.000000;, + 0.562500; 0.937500;, + 0.000000; 1.000000;, + 1.000000; 1.000000;, + 1.000000; 0.000000;, + 0.000000; 0.000000;, + 1.000000; 0.500000;, + 0.937500; 0.562500;, + 0.937559; 0.942680;, + 0.999902; 0.999901;, + 0.656250; 0.031250;, + 0.531250; 0.031250;, + 0.531250; 0.156250;, + 0.656250; 0.156250;, + 0.562500; 0.937500;, + 0.500000; 1.000000;, + 0.999902; 0.999901;, + 0.937559; 0.942680;, + 0.937500; 0.562500;, + 1.000000; 0.500000;, + 0.500000; 0.500000;, + 0.562500; 0.562500;; + } // End of Cube UV coordinates + MeshMaterialList { // Cube material list + 1; + 71; + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0;; + Material Material { + 0.640000; 0.640000; 0.640000; 1.000000;; + 96.078431; + 0.500000; 0.500000; 0.500000;; + 0.000000; 0.000000; 0.000000;; + } + } // End of Cube material list + XSkinMeshHeader { + 5; + 15; + 5; + } + SkinWeights { + "Armature_Bone_003"; + 249; + 4, + 5, + 6, + 7, + 9, + 10, + 13, + 14, + 17, + 18, + 20, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 76, + 77, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 145, + 146, + 147, + 148, + 149, + 150, + 151, + 152, + 153, + 154, + 155, + 156, + 157, + 158, + 159, + 160, + 161, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 171, + 172, + 173, + 174, + 175, + 176, + 177, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 209, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 219, + 220, + 221, + 222, + 223, + 224, + 225, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 239, + 240, + 241, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 251, + 252, + 253, + 254, + 255, + 256, + 257, + 258, + 259, + 260, + 261, + 262, + 263; + 0.097855, + 0.076266, + 0.083495, + 0.107234, + 0.089782, + 0.015282, + 0.015282, + 0.076266, + 0.076266, + 0.097855, + 0.089782, + 0.097855, + 0.297901, + 0.287737, + 0.176628, + 0.182485, + 0.015282, + 0.089782, + 0.098610, + 0.018636, + 0.089782, + 0.097855, + 0.107234, + 0.098610, + 0.076266, + 0.015282, + 0.018636, + 0.083495, + 0.176628, + 0.003327, + 0.018794, + 0.127925, + 0.020404, + 0.286977, + 0.174766, + 0.003327, + 0.286977, + 0.297901, + 0.182485, + 0.174766, + 0.287737, + 0.020404, + 0.003327, + 0.176628, + 0.126954, + 0.136859, + 0.062329, + 0.060353, + 0.182485, + 0.176628, + 0.127925, + 0.136859, + 0.003327, + 0.174766, + 0.126954, + 0.018794, + 0.174766, + 0.182485, + 0.136859, + 0.126954, + 0.060353, + 0.062329, + 0.059240, + 0.127925, + 0.018794, + 0.059240, + 0.136859, + 0.127925, + 0.059240, + 0.062329, + 0.018794, + 0.126954, + 0.060353, + 0.107234, + 0.083495, + 0.133455, + 0.171692, + 0.171692, + 0.133455, + 0.287737, + 0.297901, + 0.018636, + 0.098610, + 0.162048, + 0.016914, + 0.016914, + 0.162048, + 0.286977, + 0.020404, + 0.098610, + 0.107234, + 0.171692, + 0.162048, + 0.162048, + 0.171692, + 0.297901, + 0.286977, + 0.083495, + 0.018636, + 0.016914, + 0.133455, + 0.016914, + 0.020404, + 0.031793, + 0.024185, + 0.091978, + 0.024185, + 0.031793, + 0.098530, + 0.020404, + 0.287737, + 0.098530, + 0.031793, + 0.287737, + 0.133455, + 0.091978, + 0.098530, + 0.133455, + 0.016914, + 0.024185, + 0.091978, + 0.500298, + 0.488502, + 0.484399, + 0.484912, + 0.488502, + 0.484399, + 0.574901, + 0.567861, + 0.584345, + 0.581311, + 0.484399, + 0.488502, + 0.484912, + 0.484399, + 0.488502, + 0.500298, + 0.650639, + 0.642159, + 0.660270, + 0.658477, + 0.642159, + 0.652886, + 0.660270, + 0.658477, + 0.652886, + 0.650639, + 0.650639, + 0.652886, + 0.642159, + 0.567861, + 0.577104, + 0.584345, + 0.660270, + 0.652886, + 0.658477, + 0.484912, + 0.484399, + 0.500298, + 0.484399, + 0.581311, + 0.577104, + 0.574901, + 0.574901, + 0.577104, + 0.567861, + 0.584345, + 0.577104, + 0.581311, + 0.650637, + 0.658473, + 0.660266, + 0.642160, + 0.658473, + 0.652884, + 0.660266, + 0.642160, + 0.652884, + 0.650637, + 0.650637, + 0.652884, + 0.658473, + 0.660266, + 0.652884, + 0.642160, + 0.574890, + 0.581306, + 0.584343, + 0.567845, + 0.581306, + 0.577096, + 0.584343, + 0.567845, + 0.577096, + 0.574890, + 0.574890, + 0.577096, + 0.581306, + 0.584343, + 0.577096, + 0.567845, + 0.228406, + 0.235541, + 0.226562, + 0.226110, + 0.235541, + 0.218934, + 0.220409, + 0.226562, + 0.218934, + 0.223567, + 0.223362, + 0.220409, + 0.223567, + 0.228406, + 0.226110, + 0.223362, + 0.226110, + 0.226562, + 0.220409, + 0.223362, + 0.223567, + 0.218934, + 0.235541, + 0.228406, + 0.467092, + 0.474056, + 0.449203, + 0.459631, + 0.474056, + 0.473079, + 0.460570, + 0.449203, + 0.473079, + 0.467589, + 0.462597, + 0.460570, + 0.467589, + 0.467092, + 0.459631, + 0.462597, + 0.459631, + 0.449203, + 0.460570, + 0.462597, + 0.467589, + 0.473079, + 0.474056, + 0.467092; + 1.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000,-1.000000, 0.000000, + 0.000000, 1.000000, 0.000000, 0.000000, + 0.000000,-1.600000, 0.000000, 1.000000;; + } // End of Armature_Bone_003 skin weights + SkinWeights { + "Armature_Bone_002"; + 210; + 0, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 13, + 14, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 136, + 137, + 138, + 139, + 140, + 141, + 142, + 143, + 144, + 145, + 146, + 147, + 148, + 149, + 150, + 151, + 152, + 153, + 154, + 155, + 156, + 157, + 158, + 159, + 160, + 161, + 162, + 163, + 164, + 165, + 166, + 167, + 168, + 169, + 170, + 171, + 172, + 173, + 174, + 175, + 176, + 177, + 178, + 179, + 180, + 181, + 182, + 183, + 184, + 185, + 186, + 187, + 188, + 189, + 190, + 191, + 192, + 193, + 194, + 195, + 196, + 197, + 198, + 199, + 200, + 201, + 202, + 203, + 204, + 205, + 206, + 207, + 208, + 209, + 210, + 211, + 212, + 213, + 214, + 215; + 0.026699, + 0.019645, + 0.225152, + 0.090050, + 0.096422, + 0.247592, + 0.026699, + 0.225915, + 0.091110, + 0.091110, + 0.090050, + 0.090050, + 0.225152, + 0.019645, + 0.225915, + 0.026699, + 0.019645, + 0.225152, + 0.378267, + 0.217186, + 0.396865, + 0.489530, + 0.091110, + 0.225915, + 0.248358, + 0.097508, + 0.225915, + 0.225152, + 0.247592, + 0.248358, + 0.090050, + 0.091110, + 0.097508, + 0.096422, + 0.396865, + 0.398905, + 0.438519, + 0.443076, + 0.218141, + 0.380147, + 0.489880, + 0.398905, + 0.380147, + 0.378267, + 0.489530, + 0.489880, + 0.217186, + 0.218141, + 0.398905, + 0.396865, + 0.504112, + 0.502873, + 0.231972, + 0.249788, + 0.489530, + 0.396865, + 0.443076, + 0.502873, + 0.398905, + 0.489880, + 0.504112, + 0.438519, + 0.489880, + 0.489530, + 0.502873, + 0.504112, + 0.249788, + 0.231972, + 0.219728, + 0.214257, + 0.443076, + 0.438519, + 0.214257, + 0.219728, + 0.502873, + 0.443076, + 0.219728, + 0.231972, + 0.438519, + 0.504112, + 0.249788, + 0.214257, + 0.247592, + 0.096422, + 0.123030, + 0.409380, + 0.409380, + 0.123030, + 0.217186, + 0.378267, + 0.097508, + 0.248358, + 0.410435, + 0.124284, + 0.124284, + 0.410435, + 0.380147, + 0.218141, + 0.248358, + 0.247592, + 0.409380, + 0.410435, + 0.410435, + 0.409380, + 0.378267, + 0.380147, + 0.096422, + 0.097508, + 0.124284, + 0.123030, + 0.124284, + 0.218141, + 0.103633, + 0.087149, + 0.092557, + 0.087149, + 0.103633, + 0.094423, + 0.218141, + 0.217186, + 0.094423, + 0.103633, + 0.217186, + 0.123030, + 0.092557, + 0.094423, + 0.123030, + 0.124284, + 0.087149, + 0.092557, + 0.499702, + 0.511498, + 0.515601, + 0.515088, + 0.511498, + 0.515601, + 0.425099, + 0.432139, + 0.415655, + 0.418689, + 0.515601, + 0.511498, + 0.515088, + 0.515601, + 0.511498, + 0.499702, + 0.349361, + 0.357841, + 0.339730, + 0.341523, + 0.357841, + 0.347114, + 0.339730, + 0.341523, + 0.347114, + 0.349361, + 0.349361, + 0.347114, + 0.357841, + 0.432139, + 0.422896, + 0.415655, + 0.339730, + 0.347114, + 0.341523, + 0.515088, + 0.515601, + 0.499702, + 0.515601, + 0.418689, + 0.422896, + 0.425099, + 0.425099, + 0.422896, + 0.432139, + 0.415655, + 0.422896, + 0.418689, + 0.349363, + 0.341527, + 0.339734, + 0.357840, + 0.341527, + 0.347116, + 0.339734, + 0.357840, + 0.347116, + 0.349363, + 0.349363, + 0.347116, + 0.341527, + 0.339734, + 0.347116, + 0.357840, + 0.425110, + 0.418694, + 0.415657, + 0.432155, + 0.418694, + 0.422904, + 0.415657, + 0.432155, + 0.422904, + 0.425110, + 0.425110, + 0.422904, + 0.418694, + 0.415657, + 0.422904, + 0.432155; + 1.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000,-1.000000, 0.000000, + 0.000000, 1.000000, 0.000000, 0.000000, + 0.000000,-1.300000, 0.000000, 1.000000;; + } // End of Armature_Bone_002 skin weights + SkinWeights { + "Armature_Bone_001"; + 127; + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 75, + 76, + 77, + 78, + 80, + 81, + 84, + 85, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135; + 0.028090, + 0.044667, + 0.027228, + 0.014924, + 0.187604, + 0.200597, + 0.217670, + 0.204339, + 0.028090, + 0.204480, + 0.310430, + 0.044667, + 0.044667, + 0.310430, + 0.200597, + 0.027228, + 0.027228, + 0.200597, + 0.187604, + 0.014924, + 0.204480, + 0.028090, + 0.014924, + 0.187604, + 0.067482, + 0.064812, + 0.031709, + 0.033965, + 0.310430, + 0.204480, + 0.222012, + 0.341423, + 0.204480, + 0.187604, + 0.204339, + 0.222012, + 0.200597, + 0.310430, + 0.341423, + 0.217670, + 0.031709, + 0.101587, + 0.070428, + 0.017181, + 0.167670, + 0.078366, + 0.047455, + 0.101587, + 0.078366, + 0.067482, + 0.033965, + 0.047455, + 0.064812, + 0.167670, + 0.101587, + 0.031709, + 0.027631, + 0.014453, + 0.033965, + 0.031709, + 0.017181, + 0.014453, + 0.101587, + 0.047455, + 0.027631, + 0.070428, + 0.047455, + 0.033965, + 0.014453, + 0.027631, + 0.008199, + 0.017181, + 0.070428, + 0.008199, + 0.014453, + 0.017181, + 0.070428, + 0.027631, + 0.008199, + 0.204339, + 0.217670, + 0.123770, + 0.116219, + 0.116219, + 0.123770, + 0.064812, + 0.067482, + 0.341423, + 0.222012, + 0.131980, + 0.371812, + 0.371812, + 0.131980, + 0.078366, + 0.167670, + 0.222012, + 0.204339, + 0.116219, + 0.131980, + 0.131980, + 0.116219, + 0.067482, + 0.078366, + 0.217670, + 0.341423, + 0.371812, + 0.123770, + 0.371812, + 0.167670, + 0.122698, + 0.132035, + 0.078042, + 0.132035, + 0.122698, + 0.065986, + 0.167670, + 0.064812, + 0.065986, + 0.122698, + 0.064812, + 0.123770, + 0.078042, + 0.065986, + 0.123770, + 0.371812, + 0.132035, + 0.078042; + 1.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000,-1.000000, 0.000000, + 0.000000, 1.000000, 0.000000, 0.000000, + 0.000000,-1.000000, 0.000000, 1.000000;; + } // End of Armature_Bone_001 skin weights + SkinWeights { + "Armature_Bone"; + 136; + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135; + 0.945211, + 0.955333, + 0.972772, + 0.965432, + 0.441407, + 0.557541, + 0.520087, + 0.387790, + 0.945211, + 0.424328, + 0.470645, + 0.955333, + 0.955333, + 0.470645, + 0.557541, + 0.972772, + 0.972772, + 0.557541, + 0.441407, + 0.965432, + 0.424328, + 0.945211, + 0.965432, + 0.441407, + 0.133775, + 0.243816, + 0.149205, + 0.083512, + 0.470645, + 0.424328, + 0.371115, + 0.418447, + 0.424328, + 0.441407, + 0.387790, + 0.371115, + 0.557541, + 0.470645, + 0.418447, + 0.520087, + 0.149205, + 0.102630, + 0.077530, + 0.107912, + 0.165882, + 0.124352, + 0.077496, + 0.102630, + 0.124352, + 0.133775, + 0.083512, + 0.077496, + 0.243816, + 0.165882, + 0.102630, + 0.149205, + 0.060886, + 0.066205, + 0.013250, + 0.011723, + 0.083512, + 0.149205, + 0.107912, + 0.066205, + 0.102630, + 0.077496, + 0.060886, + 0.077530, + 0.077496, + 0.083512, + 0.066205, + 0.060886, + 0.011723, + 0.013250, + 0.048094, + 0.022321, + 0.107912, + 0.077530, + 0.022321, + 0.048094, + 0.066205, + 0.107912, + 0.048094, + 0.013250, + 0.077530, + 0.060886, + 0.011723, + 0.022321, + 0.387790, + 0.520087, + 0.494225, + 0.226848, + 0.226848, + 0.494225, + 0.243816, + 0.133775, + 0.418447, + 0.371115, + 0.212428, + 0.276984, + 0.276984, + 0.212428, + 0.124352, + 0.165882, + 0.371115, + 0.387790, + 0.226848, + 0.212428, + 0.212428, + 0.226848, + 0.133775, + 0.124352, + 0.520087, + 0.418447, + 0.276984, + 0.494225, + 0.276984, + 0.165882, + 0.382664, + 0.483353, + 0.390460, + 0.483353, + 0.382664, + 0.298215, + 0.165882, + 0.243816, + 0.298215, + 0.382664, + 0.243816, + 0.494225, + 0.390460, + 0.298215, + 0.494225, + 0.276984, + 0.483353, + 0.390460; + 1.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000,-1.000000, 0.000000, + 0.000000, 1.000000, 0.000000, 0.000000, + 0.000000, 1.000000, 0.000000, 1.000000;; + } // End of Armature_Bone skin weights + SkinWeights { + "Armature_Bone_004"; + 172; + 4, + 5, + 6, + 7, + 9, + 10, + 13, + 14, + 17, + 18, + 20, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127, + 128, + 129, + 130, + 131, + 132, + 133, + 134, + 135, + 216, + 217, + 218, + 219, + 220, + 221, + 222, + 223, + 224, + 225, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 239, + 240, + 241, + 242, + 243, + 244, + 245, + 246, + 247, + 248, + 249, + 250, + 251, + 252, + 253, + 254, + 255, + 256, + 257, + 258, + 259, + 260, + 261, + 262, + 263; + 0.047982, + 0.075546, + 0.082326, + 0.053045, + 0.055496, + 0.112532, + 0.112532, + 0.075546, + 0.075546, + 0.047982, + 0.055496, + 0.047982, + 0.122575, + 0.186448, + 0.245593, + 0.210507, + 0.112532, + 0.055496, + 0.059905, + 0.123986, + 0.055496, + 0.047982, + 0.053045, + 0.059905, + 0.075546, + 0.112532, + 0.123986, + 0.082326, + 0.245593, + 0.393551, + 0.394730, + 0.303906, + 0.427903, + 0.130157, + 0.210403, + 0.393551, + 0.130157, + 0.122575, + 0.210507, + 0.210403, + 0.186448, + 0.427903, + 0.393551, + 0.245593, + 0.280416, + 0.279610, + 0.692449, + 0.678135, + 0.210507, + 0.245593, + 0.303906, + 0.279610, + 0.393551, + 0.210403, + 0.280416, + 0.394730, + 0.210403, + 0.210507, + 0.279610, + 0.280416, + 0.678135, + 0.692449, + 0.672937, + 0.755223, + 0.303906, + 0.394730, + 0.755223, + 0.672937, + 0.279610, + 0.303906, + 0.672937, + 0.692449, + 0.394730, + 0.280416, + 0.678135, + 0.755223, + 0.053045, + 0.082326, + 0.125519, + 0.075862, + 0.075862, + 0.125519, + 0.186448, + 0.122575, + 0.123986, + 0.059905, + 0.083109, + 0.210006, + 0.210006, + 0.083109, + 0.130157, + 0.427903, + 0.059905, + 0.053045, + 0.075862, + 0.083109, + 0.083109, + 0.075862, + 0.122575, + 0.130157, + 0.082326, + 0.123986, + 0.210006, + 0.125519, + 0.210006, + 0.427903, + 0.359212, + 0.273279, + 0.346964, + 0.273279, + 0.359212, + 0.442846, + 0.427903, + 0.186448, + 0.442846, + 0.359212, + 0.186448, + 0.125519, + 0.346964, + 0.442846, + 0.125519, + 0.210006, + 0.273279, + 0.346964, + 0.771594, + 0.764459, + 0.773438, + 0.773890, + 0.764459, + 0.781066, + 0.779591, + 0.773438, + 0.781066, + 0.776433, + 0.776638, + 0.779591, + 0.776433, + 0.771594, + 0.773890, + 0.776638, + 0.773890, + 0.773438, + 0.779591, + 0.776638, + 0.776433, + 0.781066, + 0.764459, + 0.771594, + 0.532908, + 0.525944, + 0.550797, + 0.540369, + 0.525944, + 0.526921, + 0.539430, + 0.550797, + 0.526921, + 0.532411, + 0.537403, + 0.539430, + 0.532411, + 0.532908, + 0.540369, + 0.537403, + 0.540369, + 0.550797, + 0.539430, + 0.537403, + 0.532411, + 0.526921, + 0.525944, + 0.532908; + 1.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000,-1.000000, 0.000000, + 0.000000, 1.000000, 0.000000, 0.000000, + 0.000000,-2.000000, 0.000000, 1.000000;; + } // End of Armature_Bone_004 skin weights + } // End of Cube mesh + } // End of Cube + } // End of Armature +} // End of Root +AnimationSet Global { + Animation { + {Armature} + AnimationKey { // Rotation + 0; + 31; + 0;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 1;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 2;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 3;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 4;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 5;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 6;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 7;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 8;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 9;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 10;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 11;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 12;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 13;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 14;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 15;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 16;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 17;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 18;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 19;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 20;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 21;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 22;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 23;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 24;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 25;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 26;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 27;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 28;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 29;4;-0.000000, 0.000000, 0.000000, 1.000000;;, + 30;4;-0.000000, 0.000000, 0.000000, 1.000000;;; + } + AnimationKey { // Scale + 1; + 31; + 0;3; 5.000000, 5.000000, 5.000000;;, + 1;3; 5.000000, 5.000000, 5.000000;;, + 2;3; 5.000000, 5.000000, 5.000000;;, + 3;3; 5.000000, 5.000000, 5.000000;;, + 4;3; 5.000000, 5.000000, 5.000000;;, + 5;3; 5.000000, 5.000000, 5.000000;;, + 6;3; 5.000000, 5.000000, 5.000000;;, + 7;3; 5.000000, 5.000000, 5.000000;;, + 8;3; 5.000000, 5.000000, 5.000000;;, + 9;3; 5.000000, 5.000000, 5.000000;;, + 10;3; 5.000000, 5.000000, 5.000000;;, + 11;3; 5.000000, 5.000000, 5.000000;;, + 12;3; 5.000000, 5.000000, 5.000000;;, + 13;3; 5.000000, 5.000000, 5.000000;;, + 14;3; 5.000000, 5.000000, 5.000000;;, + 15;3; 5.000000, 5.000000, 5.000000;;, + 16;3; 5.000000, 5.000000, 5.000000;;, + 17;3; 5.000000, 5.000000, 5.000000;;, + 18;3; 5.000000, 5.000000, 5.000000;;, + 19;3; 5.000000, 5.000000, 5.000000;;, + 20;3; 5.000000, 5.000000, 5.000000;;, + 21;3; 5.000000, 5.000000, 5.000000;;, + 22;3; 5.000000, 5.000000, 5.000000;;, + 23;3; 5.000000, 5.000000, 5.000000;;, + 24;3; 5.000000, 5.000000, 5.000000;;, + 25;3; 5.000000, 5.000000, 5.000000;;, + 26;3; 5.000000, 5.000000, 5.000000;;, + 27;3; 5.000000, 5.000000, 5.000000;;, + 28;3; 5.000000, 5.000000, 5.000000;;, + 29;3; 5.000000, 5.000000, 5.000000;;, + 30;3; 5.000000, 5.000000, 5.000000;;; + } + AnimationKey { // Position + 2; + 31; + 0;3; 0.000000, 0.000000,-5.000000;;, + 1;3; 0.000000, 0.000000,-5.000000;;, + 2;3; 0.000000, 0.000000,-5.000000;;, + 3;3; 0.000000, 0.000000,-5.000000;;, + 4;3; 0.000000, 0.000000,-5.000000;;, + 5;3; 0.000000, 0.000000,-5.000000;;, + 6;3; 0.000000, 0.000000,-5.000000;;, + 7;3; 0.000000, 0.000000,-5.000000;;, + 8;3; 0.000000, 0.000000,-5.000000;;, + 9;3; 0.000000, 0.000000,-5.000000;;, + 10;3; 0.000000, 0.000000,-5.000000;;, + 11;3; 0.000000, 0.000000,-5.000000;;, + 12;3; 0.000000, 0.000000,-5.000000;;, + 13;3; 0.000000, 0.000000,-5.000000;;, + 14;3; 0.000000, 0.000000,-5.000000;;, + 15;3; 0.000000, 0.000000,-5.000000;;, + 16;3; 0.000000, 0.000000,-5.000000;;, + 17;3; 0.000000, 0.000000,-5.000000;;, + 18;3; 0.000000, 0.000000,-5.000000;;, + 19;3; 0.000000, 0.000000,-5.000000;;, + 20;3; 0.000000, 0.000000,-5.000000;;, + 21;3; 0.000000, 0.000000,-5.000000;;, + 22;3; 0.000000, 0.000000,-5.000000;;, + 23;3; 0.000000, 0.000000,-5.000000;;, + 24;3; 0.000000, 0.000000,-5.000000;;, + 25;3; 0.000000, 0.000000,-5.000000;;, + 26;3; 0.000000, 0.000000,-5.000000;;, + 27;3; 0.000000, 0.000000,-5.000000;;, + 28;3; 0.000000, 0.000000,-5.000000;;, + 29;3; 0.000000, 0.000000,-5.000000;;, + 30;3; 0.000000, 0.000000,-5.000000;;; + } + } + Animation { + {Armature_Bone} + AnimationKey { // Rotation + 0; + 31; + 0;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 1;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 2;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 3;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 4;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 5;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 6;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 7;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 8;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 9;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 10;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 11;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 12;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 13;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 14;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 15;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 16;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 17;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 18;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 19;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 20;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 21;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 22;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 23;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 24;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 25;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 26;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 27;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 28;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 29;4;-0.707107, 0.707107, 0.000000, 0.000000;;, + 30;4;-0.707107, 0.707107, 0.000000, 0.000000;;; + } + AnimationKey { // Scale + 1; + 31; + 0;3; 1.000000, 1.000000, 1.000000;;, + 1;3; 1.000000, 1.000000, 1.000000;;, + 2;3; 1.000000, 1.000000, 1.000000;;, + 3;3; 1.000000, 1.000000, 1.000000;;, + 4;3; 1.000000, 1.000000, 1.000000;;, + 5;3; 1.000000, 1.000000, 1.000000;;, + 6;3; 1.000000, 1.000000, 1.000000;;, + 7;3; 1.000000, 1.000000, 1.000000;;, + 8;3; 1.000000, 1.000000, 1.000000;;, + 9;3; 1.000000, 1.000000, 1.000000;;, + 10;3; 1.000000, 1.000000, 1.000000;;, + 11;3; 1.000000, 1.000000, 1.000000;;, + 12;3; 1.000000, 1.000000, 1.000000;;, + 13;3; 1.000000, 1.000000, 1.000000;;, + 14;3; 1.000000, 1.000000, 1.000000;;, + 15;3; 1.000000, 1.000000, 1.000000;;, + 16;3; 1.000000, 1.000000, 1.000000;;, + 17;3; 1.000000, 1.000000, 1.000000;;, + 18;3; 1.000000, 1.000000, 1.000000;;, + 19;3; 1.000000, 1.000000, 1.000000;;, + 20;3; 1.000000, 1.000000, 1.000000;;, + 21;3; 1.000000, 1.000000, 1.000000;;, + 22;3; 1.000000, 1.000000, 1.000000;;, + 23;3; 1.000000, 1.000000, 1.000000;;, + 24;3; 1.000000, 1.000000, 1.000000;;, + 25;3; 1.000000, 1.000000, 1.000000;;, + 26;3; 1.000000, 1.000000, 1.000000;;, + 27;3; 1.000000, 1.000000, 1.000000;;, + 28;3; 1.000000, 1.000000, 1.000000;;, + 29;3; 1.000000, 1.000000, 1.000000;;, + 30;3; 1.000000, 1.000000, 1.000000;;; + } + AnimationKey { // Position + 2; + 31; + 0;3; 0.000000, 0.000000, 0.000000;;, + 1;3; 0.000000, 0.000000, 0.000000;;, + 2;3; 0.000000, 0.000000, 0.000000;;, + 3;3; 0.000000, 0.000000, 0.000000;;, + 4;3; 0.000000, 0.000000, 0.000000;;, + 5;3; 0.000000, 0.000000, 0.000000;;, + 6;3; 0.000000, 0.000000, 0.000000;;, + 7;3; 0.000000, 0.000000, 0.000000;;, + 8;3; 0.000000, 0.000000, 0.000000;;, + 9;3; 0.000000, 0.000000, 0.000000;;, + 10;3; 0.000000, 0.000000, 0.000000;;, + 11;3; 0.000000, 0.000000, 0.000000;;, + 12;3; 0.000000, 0.000000, 0.000000;;, + 13;3; 0.000000, 0.000000, 0.000000;;, + 14;3; 0.000000, 0.000000, 0.000000;;, + 15;3; 0.000000, 0.000000, 0.000000;;, + 16;3; 0.000000, 0.000000, 0.000000;;, + 17;3; 0.000000, 0.000000, 0.000000;;, + 18;3; 0.000000, 0.000000, 0.000000;;, + 19;3; 0.000000, 0.000000, 0.000000;;, + 20;3; 0.000000, 0.000000, 0.000000;;, + 21;3; 0.000000, 0.000000, 0.000000;;, + 22;3; 0.000000, 0.000000, 0.000000;;, + 23;3; 0.000000, 0.000000, 0.000000;;, + 24;3; 0.000000, 0.000000, 0.000000;;, + 25;3; 0.000000, 0.000000, 0.000000;;, + 26;3; 0.000000, 0.000000, 0.000000;;, + 27;3; 0.000000, 0.000000, 0.000000;;, + 28;3; 0.000000, 0.000000, 0.000000;;, + 29;3; 0.000000, 0.000000, 0.000000;;, + 30;3; 0.000000, 0.000000, 0.000000;;; + } + } + Animation { + {Armature_Bone_001} + AnimationKey { // Rotation + 0; + 31; + 0;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 1;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 2;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 3;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 4;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 5;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 6;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 7;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 8;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 9;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 10;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 11;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 12;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 13;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 14;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 15;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 16;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 17;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 18;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 19;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 20;4;-0.998539, 0.054035, 0.000000,-0.000000;;, + 21;4;-0.996147, 0.053932, 0.002355, 0.043499;;, + 22;4;-0.998539, 0.054035, 0.000000, 0.000000;;, + 23;4;-0.997589, 0.053983,-0.002357,-0.043556;;, + 24;4;-0.998539, 0.054035, 0.000000, 0.000000;;, + 25;4;-0.996639, 0.053932, 0.003045, 0.056265;;, + 26;4;-0.994740, 0.053829, 0.004709, 0.087028;;, + 27;4;-0.996147, 0.053932, 0.002355, 0.043519;;, + 28;4;-0.998539, 0.054035, 0.000000, 0.000000;;, + 29;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 30;4;-1.000000, 0.000000, 0.000000, 0.000000;;; + } + AnimationKey { // Scale + 1; + 31; + 0;3; 1.000000, 1.000000, 1.000000;;, + 1;3; 1.000000, 1.000000, 1.000000;;, + 2;3; 1.000000, 1.000000, 1.000000;;, + 3;3; 1.000000, 1.000000, 1.000000;;, + 4;3; 1.000000, 1.000000, 1.000000;;, + 5;3; 1.000000, 1.000000, 1.000000;;, + 6;3; 1.000000, 1.000000, 1.000000;;, + 7;3; 1.000000, 1.000000, 1.000000;;, + 8;3; 1.000000, 1.000000, 1.000000;;, + 9;3; 1.000000, 1.000000, 1.000000;;, + 10;3; 1.000000, 1.000000, 1.000000;;, + 11;3; 1.000000, 1.000000, 1.000000;;, + 12;3; 1.000000, 1.000000, 1.000000;;, + 13;3; 1.000000, 1.000000, 1.000000;;, + 14;3; 1.000000, 1.000000, 1.000000;;, + 15;3; 1.000000, 1.000000, 1.000000;;, + 16;3; 1.000000, 1.000000, 1.000000;;, + 17;3; 1.000000, 1.000000, 1.000000;;, + 18;3; 1.000000, 1.000000, 1.000000;;, + 19;3; 1.000000, 1.000000, 1.000000;;, + 20;3; 1.000000, 1.000000, 1.000000;;, + 21;3; 1.000000, 1.000000, 1.000000;;, + 22;3; 1.000000, 1.000000, 1.000000;;, + 23;3; 1.000000, 1.000000, 1.000000;;, + 24;3; 1.000000, 1.000000, 1.000000;;, + 25;3; 1.000000, 1.000000, 1.000000;;, + 26;3; 1.000000, 1.000000, 1.000000;;, + 27;3; 1.000000, 1.000000, 1.000000;;, + 28;3; 1.000000, 1.000000, 1.000000;;, + 29;3; 1.000000, 1.000000, 1.000000;;, + 30;3; 1.000000, 1.000000, 1.000000;;; + } + AnimationKey { // Position + 2; + 31; + 0;3; 0.000000, 2.000000, 0.000000;;, + 1;3; 0.000000, 2.000000, 0.000000;;, + 2;3; 0.000000, 2.000000, 0.000000;;, + 3;3; 0.000000, 2.000000, 0.000000;;, + 4;3; 0.000000, 2.000000, 0.000000;;, + 5;3; 0.000000, 2.000000, 0.000000;;, + 6;3; 0.000000, 2.000000, 0.000000;;, + 7;3; 0.000000, 2.000000, 0.000000;;, + 8;3; 0.000000, 2.000000, 0.000000;;, + 9;3; 0.000000, 2.000000, 0.000000;;, + 10;3; 0.000000, 2.000000, 0.000000;;, + 11;3; 0.000000, 2.000000, 0.000000;;, + 12;3; 0.000000, 2.000000, 0.000000;;, + 13;3; 0.000000, 2.000000, 0.000000;;, + 14;3; 0.000000, 2.000000, 0.000000;;, + 15;3; 0.000000, 2.000000, 0.000000;;, + 16;3; 0.000000, 2.000000, 0.000000;;, + 17;3; 0.000000, 2.000000, 0.000000;;, + 18;3; 0.000000, 2.000000, 0.000000;;, + 19;3; 0.000000, 2.000000, 0.000000;;, + 20;3; 0.000000, 2.000000, 0.000000;;, + 21;3; 0.000000, 2.000000, 0.000000;;, + 22;3; 0.000000, 2.000000, 0.000000;;, + 23;3; 0.000000, 2.000000, 0.000000;;, + 24;3; 0.000000, 2.000000, 0.000000;;, + 25;3; 0.000000, 2.000000, 0.000000;;, + 26;3; 0.000000, 2.000000, 0.000000;;, + 27;3; 0.000000, 2.000000, 0.000000;;, + 28;3; 0.000000, 2.000000, 0.000000;;, + 29;3; 0.000000, 2.000000, 0.000000;;, + 30;3; 0.000000, 2.000000, 0.000000;;; + } + } + Animation { + {Armature_Bone_002} + AnimationKey { // Rotation + 0; + 31; + 0;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 1;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 2;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 3;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 4;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 5;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 6;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 7;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 8;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 9;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 10;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 11;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 12;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 13;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 14;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 15;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 16;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 17;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 18;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 19;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 20;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 21;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 22;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 23;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 24;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 25;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 26;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 27;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 28;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 29;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 30;4;-1.000000, 0.000000, 0.000000, 0.000000;;; + } + AnimationKey { // Scale + 1; + 31; + 0;3; 1.000000, 1.000000, 1.000000;;, + 1;3; 1.000000, 1.000000, 1.000000;;, + 2;3; 1.000000, 1.000000, 1.000000;;, + 3;3; 1.000000, 1.000000, 1.000000;;, + 4;3; 1.000000, 1.000000, 1.000000;;, + 5;3; 1.000000, 1.000000, 1.000000;;, + 6;3; 1.000000, 1.000000, 1.000000;;, + 7;3; 1.000000, 1.000000, 1.000000;;, + 8;3; 1.000000, 1.000000, 1.000000;;, + 9;3; 1.000000, 1.000000, 1.000000;;, + 10;3; 1.000000, 1.000000, 1.000000;;, + 11;3; 1.000000, 1.000000, 1.000000;;, + 12;3; 1.000000, 1.000000, 1.000000;;, + 13;3; 1.000000, 1.000000, 1.000000;;, + 14;3; 1.000000, 1.000000, 1.000000;;, + 15;3; 1.000000, 1.000000, 1.000000;;, + 16;3; 1.000000, 1.000000, 1.000000;;, + 17;3; 1.000000, 1.000000, 1.000000;;, + 18;3; 1.000000, 1.000000, 1.000000;;, + 19;3; 1.000000, 1.000000, 1.000000;;, + 20;3; 1.000000, 1.000000, 1.000000;;, + 21;3; 1.000000, 1.000000, 1.000000;;, + 22;3; 1.000000, 1.000000, 1.000000;;, + 23;3; 1.000000, 1.000000, 1.000000;;, + 24;3; 1.000000, 1.000000, 1.000000;;, + 25;3; 1.000000, 1.000000, 1.000000;;, + 26;3; 1.000000, 1.000000, 1.000000;;, + 27;3; 1.000000, 1.000000, 1.000000;;, + 28;3; 1.000000, 1.000000, 1.000000;;, + 29;3; 1.000000, 1.000000, 1.000000;;, + 30;3; 1.000000, 1.000000, 1.000000;;; + } + AnimationKey { // Position + 2; + 31; + 0;3; 0.000000, 0.300000, 0.000000;;, + 1;3; 0.000000, 0.300000, 0.000000;;, + 2;3; 0.000000, 0.300000, 0.000000;;, + 3;3; 0.000000, 0.300000, 0.000000;;, + 4;3; 0.000000, 0.300000, 0.000000;;, + 5;3; 0.000000, 0.300000, 0.000000;;, + 6;3; 0.000000, 0.300000, 0.000000;;, + 7;3; 0.000000, 0.300000, 0.000000;;, + 8;3; 0.000000, 0.300000, 0.000000;;, + 9;3; 0.000000, 0.300000, 0.000000;;, + 10;3; 0.000000, 0.300000, 0.000000;;, + 11;3; 0.000000, 0.300000, 0.000000;;, + 12;3; 0.000000, 0.300000, 0.000000;;, + 13;3; 0.000000, 0.300000, 0.000000;;, + 14;3; 0.000000, 0.300000, 0.000000;;, + 15;3; 0.000000, 0.300000, 0.000000;;, + 16;3; 0.000000, 0.300000, 0.000000;;, + 17;3; 0.000000, 0.300000, 0.000000;;, + 18;3; 0.000000, 0.300000, 0.000000;;, + 19;3; 0.000000, 0.300000, 0.000000;;, + 20;3; 0.000000, 0.300000, 0.000000;;, + 21;3;-0.000000, 0.300000,-0.000000;;, + 22;3;-0.000000, 0.300000, 0.000000;;, + 23;3;-0.000000, 0.300000, 0.000000;;, + 24;3;-0.000000, 0.300000, 0.000000;;, + 25;3;-0.000000, 0.300000,-0.000000;;, + 26;3;-0.000000, 0.300000, 0.000000;;, + 27;3;-0.000000, 0.300000,-0.000000;;, + 28;3; 0.000000, 0.300000, 0.000000;;, + 29;3; 0.000000, 0.300000, 0.000000;;, + 30;3; 0.000000, 0.300000, 0.000000;;; + } + } + Animation { + {Armature_Bone_003} + AnimationKey { // Rotation + 0; + 31; + 0;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 1;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 2;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 3;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 4;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 5;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 6;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 7;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 8;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 9;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 10;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 11;4;-0.998097,-0.000000, 0.000000,-0.043583;;, + 12;4;-0.996195,-0.000000, 0.000000,-0.087156;;, + 13;4;-0.998097,-0.000000, 0.000000,-0.056342;;, + 14;4;-1.000000,-0.000000,-0.000000, 0.000000;;, + 15;4;-0.998097,-0.000000,-0.000000, 0.056342;;, + 16;4;-0.996195,-0.000000,-0.000000, 0.087156;;, + 17;4;-0.998097,-0.000000,-0.000000, 0.043583;;, + 18;4;-1.000000,-0.000000, 0.000000, 0.000000;;, + 19;4;-1.000000,-0.000000, 0.000000, 0.000000;;, + 20;4;-0.996195, 0.087156, 0.000000, 0.000000;;, + 21;4;-0.996434, 0.081668, 0.000000, 0.000000;;, + 22;4;-0.996936, 0.070172, 0.000000, 0.000000;;, + 23;4;-0.997535, 0.056459, 0.000000, 0.000000;;, + 24;4;-0.998149, 0.042383, 0.000000, 0.000000;;, + 25;4;-0.998729, 0.029106, 0.000000, 0.000000;;, + 26;4;-0.999236, 0.017493, 0.000000, 0.000000;;, + 27;4;-0.999638, 0.008289, 0.000000, 0.000000;;, + 28;4;-0.999904, 0.002208, 0.000000, 0.000000;;, + 29;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 30;4;-1.000000, 0.000000, 0.000000, 0.000000;;; + } + AnimationKey { // Scale + 1; + 31; + 0;3; 1.000000, 1.000000, 1.000000;;, + 1;3; 1.000000, 1.000000, 1.000000;;, + 2;3; 1.000000, 1.000000, 1.000000;;, + 3;3; 1.000000, 1.000000, 1.000000;;, + 4;3; 1.000000, 1.000000, 1.000000;;, + 5;3; 1.000000, 1.000000, 1.000000;;, + 6;3; 1.000000, 1.000000, 1.000000;;, + 7;3; 1.000000, 1.000000, 1.000000;;, + 8;3; 1.000000, 1.000000, 1.000000;;, + 9;3; 1.000000, 1.000000, 1.000000;;, + 10;3; 1.000000, 1.000000, 1.000000;;, + 11;3; 1.000000, 1.000000, 1.000000;;, + 12;3; 1.000000, 1.000000, 1.000000;;, + 13;3; 1.000000, 1.000000, 1.000000;;, + 14;3; 1.000000, 1.000000, 1.000000;;, + 15;3; 1.000000, 1.000000, 1.000000;;, + 16;3; 1.000000, 1.000000, 1.000000;;, + 17;3; 1.000000, 1.000000, 1.000000;;, + 18;3; 1.000000, 1.000000, 1.000000;;, + 19;3; 1.000000, 1.000000, 1.000000;;, + 20;3; 1.000000, 1.000000, 1.000000;;, + 21;3; 1.000000, 1.000000, 1.000000;;, + 22;3; 1.000000, 1.000000, 1.000000;;, + 23;3; 1.000000, 1.000000, 1.000000;;, + 24;3; 1.000000, 1.000000, 1.000000;;, + 25;3; 1.000000, 1.000000, 1.000000;;, + 26;3; 1.000000, 1.000000, 1.000000;;, + 27;3; 1.000000, 1.000000, 1.000000;;, + 28;3; 1.000000, 1.000000, 1.000000;;, + 29;3; 1.000000, 1.000000, 1.000000;;, + 30;3; 1.000000, 1.000000, 1.000000;;; + } + AnimationKey { // Position + 2; + 31; + 0;3; 0.000000, 0.300000, 0.000000;;, + 1;3; 0.000000, 0.300000, 0.000000;;, + 2;3; 0.000000, 0.300000, 0.000000;;, + 3;3; 0.000000, 0.300000, 0.000000;;, + 4;3; 0.000000, 0.300000, 0.000000;;, + 5;3; 0.000000, 0.300000, 0.000000;;, + 6;3; 0.000000, 0.300000, 0.000000;;, + 7;3; 0.000000, 0.300000, 0.000000;;, + 8;3; 0.000000, 0.300000, 0.000000;;, + 9;3; 0.000000, 0.300000, 0.000000;;, + 10;3; 0.000000, 0.300000, 0.000000;;, + 11;3; 0.000000, 0.300000, 0.000000;;, + 12;3; 0.000000, 0.300000, 0.000000;;, + 13;3; 0.000000, 0.300000, 0.000000;;, + 14;3; 0.000000, 0.300000, 0.000000;;, + 15;3; 0.000000, 0.300000, 0.000000;;, + 16;3; 0.000000, 0.300000, 0.000000;;, + 17;3; 0.000000, 0.300000, 0.000000;;, + 18;3; 0.000000, 0.300000, 0.000000;;, + 19;3; 0.000000, 0.300000, 0.000000;;, + 20;3; 0.000000, 0.300000, 0.000000;;, + 21;3;-0.000000, 0.300000,-0.000000;;, + 22;3;-0.000000, 0.300000,-0.000000;;, + 23;3; 0.000000, 0.300000, 0.000000;;, + 24;3;-0.000000, 0.300000,-0.000000;;, + 25;3; 0.000000, 0.300000,-0.000000;;, + 26;3;-0.000000, 0.300000,-0.000000;;, + 27;3;-0.000000, 0.300000,-0.000000;;, + 28;3;-0.000000, 0.300000, 0.000000;;, + 29;3; 0.000000, 0.300000, 0.000000;;, + 30;3; 0.000000, 0.300000, 0.000000;;; + } + } + Animation { + {Armature_Bone_004} + AnimationKey { // Rotation + 0; + 31; + 0;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 1;4;-0.999524, 0.021812, 0.000000,-0.000000;;, + 2;4;-0.999048, 0.043619, 0.000000,-0.000000;;, + 3;4;-0.999524, 0.028196, 0.000000,-0.000000;;, + 4;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 5;4;-0.999524,-0.028196,-0.000000, 0.000000;;, + 6;4;-0.999048,-0.043619,-0.000000, 0.000000;;, + 7;4;-0.999524,-0.021810,-0.000000, 0.000000;;, + 8;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 9;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 10;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 11;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 12;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 13;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 14;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 15;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 16;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 17;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 18;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 19;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 20;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 21;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 22;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 23;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 24;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 25;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 26;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 27;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 28;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 29;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 30;4;-1.000000, 0.000000, 0.000000, 0.000000;;; + } + AnimationKey { // Scale + 1; + 31; + 0;3; 1.000000, 1.000000, 1.000000;;, + 1;3; 1.000000, 1.000000, 1.000000;;, + 2;3; 1.000000, 1.000000, 1.000000;;, + 3;3; 1.000000, 1.000000, 1.000000;;, + 4;3; 1.000000, 1.000000, 1.000000;;, + 5;3; 1.000000, 1.000000, 1.000000;;, + 6;3; 1.000000, 1.000000, 1.000000;;, + 7;3; 1.000000, 1.000000, 1.000000;;, + 8;3; 1.000000, 1.000000, 1.000000;;, + 9;3; 1.000000, 1.000000, 1.000000;;, + 10;3; 1.000000, 1.000000, 1.000000;;, + 11;3; 1.000000, 1.000000, 1.000000;;, + 12;3; 1.000000, 1.000000, 1.000000;;, + 13;3; 1.000000, 1.000000, 1.000000;;, + 14;3; 1.000000, 1.000000, 1.000000;;, + 15;3; 1.000000, 1.000000, 1.000000;;, + 16;3; 1.000000, 1.000000, 1.000000;;, + 17;3; 1.000000, 1.000000, 1.000000;;, + 18;3; 1.000000, 1.000000, 1.000000;;, + 19;3; 1.000000, 1.000000, 1.000000;;, + 20;3; 1.000000, 1.000000, 1.000000;;, + 21;3; 1.000000, 1.000000, 1.000000;;, + 22;3; 1.000000, 1.000000, 1.000000;;, + 23;3; 1.000000, 1.000000, 1.000000;;, + 24;3; 1.000000, 1.000000, 1.000000;;, + 25;3; 1.000000, 1.000000, 1.000000;;, + 26;3; 1.000000, 1.000000, 1.000000;;, + 27;3; 1.000000, 1.000000, 1.000000;;, + 28;3; 1.000000, 1.000000, 1.000000;;, + 29;3; 1.000000, 1.000000, 1.000000;;, + 30;3; 1.000000, 1.000000, 1.000000;;; + } + AnimationKey { // Position + 2; + 31; + 0;3; 0.000000, 0.400000, 0.000000;;, + 1;3; 0.000000, 0.400000, 0.000000;;, + 2;3; 0.000000, 0.400000, 0.000000;;, + 3;3; 0.000000, 0.400000, 0.000000;;, + 4;3; 0.000000, 0.400000, 0.000000;;, + 5;3; 0.000000, 0.400000, 0.000000;;, + 6;3; 0.000000, 0.400000, 0.000000;;, + 7;3; 0.000000, 0.400000, 0.000000;;, + 8;3; 0.000000, 0.400000, 0.000000;;, + 9;3; 0.000000, 0.400000, 0.000000;;, + 10;3; 0.000000, 0.400000, 0.000000;;, + 11;3; 0.000000, 0.400000,-0.000000;;, + 12;3;-0.000000, 0.400000, 0.000000;;, + 13;3; 0.000000, 0.400000, 0.000000;;, + 14;3;-0.000000, 0.400000, 0.000000;;, + 15;3;-0.000000, 0.400000, 0.000000;;, + 16;3; 0.000000, 0.400000, 0.000000;;, + 17;3;-0.000000, 0.400000,-0.000000;;, + 18;3;-0.000000, 0.400000,-0.000000;;, + 19;3;-0.000000, 0.400000,-0.000000;;, + 20;3; 0.000000, 0.400000,-0.000000;;, + 21;3; 0.000000, 0.400000, 0.000000;;, + 22;3;-0.000000, 0.400000,-0.000000;;, + 23;3;-0.000000, 0.400000,-0.000000;;, + 24;3;-0.000000, 0.400000,-0.000000;;, + 25;3; 0.000000, 0.400000, 0.000000;;, + 26;3;-0.000000, 0.400000, 0.000000;;, + 27;3;-0.000000, 0.400000, 0.000000;;, + 28;3; 0.000000, 0.400000, 0.000000;;, + 29;3; 0.000000, 0.400000, 0.000000;;, + 30;3; 0.000000, 0.400000, 0.000000;;; + } + } + Animation { + {Cube} + AnimationKey { // Rotation + 0; + 31; + 0;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 1;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 2;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 3;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 4;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 5;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 6;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 7;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 8;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 9;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 10;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 11;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 12;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 13;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 14;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 15;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 16;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 17;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 18;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 19;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 20;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 21;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 22;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 23;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 24;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 25;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 26;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 27;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 28;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 29;4;-1.000000, 0.000000, 0.000000, 0.000000;;, + 30;4;-1.000000, 0.000000, 0.000000, 0.000000;;; + } + AnimationKey { // Scale + 1; + 31; + 0;3; 1.000000, 1.000000, 1.000000;;, + 1;3; 1.000000, 1.000000, 1.000000;;, + 2;3; 1.000000, 1.000000, 1.000000;;, + 3;3; 1.000000, 1.000000, 1.000000;;, + 4;3; 1.000000, 1.000000, 1.000000;;, + 5;3; 1.000000, 1.000000, 1.000000;;, + 6;3; 1.000000, 1.000000, 1.000000;;, + 7;3; 1.000000, 1.000000, 1.000000;;, + 8;3; 1.000000, 1.000000, 1.000000;;, + 9;3; 1.000000, 1.000000, 1.000000;;, + 10;3; 1.000000, 1.000000, 1.000000;;, + 11;3; 1.000000, 1.000000, 1.000000;;, + 12;3; 1.000000, 1.000000, 1.000000;;, + 13;3; 1.000000, 1.000000, 1.000000;;, + 14;3; 1.000000, 1.000000, 1.000000;;, + 15;3; 1.000000, 1.000000, 1.000000;;, + 16;3; 1.000000, 1.000000, 1.000000;;, + 17;3; 1.000000, 1.000000, 1.000000;;, + 18;3; 1.000000, 1.000000, 1.000000;;, + 19;3; 1.000000, 1.000000, 1.000000;;, + 20;3; 1.000000, 1.000000, 1.000000;;, + 21;3; 1.000000, 1.000000, 1.000000;;, + 22;3; 1.000000, 1.000000, 1.000000;;, + 23;3; 1.000000, 1.000000, 1.000000;;, + 24;3; 1.000000, 1.000000, 1.000000;;, + 25;3; 1.000000, 1.000000, 1.000000;;, + 26;3; 1.000000, 1.000000, 1.000000;;, + 27;3; 1.000000, 1.000000, 1.000000;;, + 28;3; 1.000000, 1.000000, 1.000000;;, + 29;3; 1.000000, 1.000000, 1.000000;;, + 30;3; 1.000000, 1.000000, 1.000000;;; + } + AnimationKey { // Position + 2; + 31; + 0;3; 0.000000, 0.000000, 1.000000;;, + 1;3; 0.000000, 0.000000, 1.000000;;, + 2;3; 0.000000, 0.000000, 1.000000;;, + 3;3; 0.000000, 0.000000, 1.000000;;, + 4;3; 0.000000, 0.000000, 1.000000;;, + 5;3; 0.000000, 0.000000, 1.000000;;, + 6;3; 0.000000, 0.000000, 1.000000;;, + 7;3; 0.000000, 0.000000, 1.000000;;, + 8;3; 0.000000, 0.000000, 1.000000;;, + 9;3; 0.000000, 0.000000, 1.000000;;, + 10;3; 0.000000, 0.000000, 1.000000;;, + 11;3; 0.000000, 0.000000, 1.000000;;, + 12;3; 0.000000, 0.000000, 1.000000;;, + 13;3; 0.000000, 0.000000, 1.000000;;, + 14;3; 0.000000, 0.000000, 1.000000;;, + 15;3; 0.000000, 0.000000, 1.000000;;, + 16;3; 0.000000, 0.000000, 1.000000;;, + 17;3; 0.000000, 0.000000, 1.000000;;, + 18;3; 0.000000, 0.000000, 1.000000;;, + 19;3; 0.000000, 0.000000, 1.000000;;, + 20;3; 0.000000, 0.000000, 1.000000;;, + 21;3; 0.000000, 0.000000, 1.000000;;, + 22;3; 0.000000, 0.000000, 1.000000;;, + 23;3; 0.000000, 0.000000, 1.000000;;, + 24;3; 0.000000, 0.000000, 1.000000;;, + 25;3; 0.000000, 0.000000, 1.000000;;, + 26;3; 0.000000, 0.000000, 1.000000;;, + 27;3; 0.000000, 0.000000, 1.000000;;, + 28;3; 0.000000, 0.000000, 1.000000;;, + 29;3; 0.000000, 0.000000, 1.000000;;, + 30;3; 0.000000, 0.000000, 1.000000;;; + } + } +} // End of AnimationSet Global diff --git a/games/devtest/mods/testentities/visuals.lua b/games/devtest/mods/testentities/visuals.lua index b61b5e819..6bb1b8282 100644 --- a/games/devtest/mods/testentities/visuals.lua +++ b/games/devtest/mods/testentities/visuals.lua @@ -79,6 +79,20 @@ core.register_entity("testentities:sam", { end, }) +core.register_entity("testentities:lava_flan", { + initial_properties = { + infotext = "Lava Flan (smoke test .x)", + visual = "mesh", + mesh = "testentities_lava_flan.x", + textures = { + "testentities_lava_flan.png" + }, + }, + on_activate = function(self) + self.object:set_animation({x = 0, y = 28}, 15, 0, true) + end, +}) + -- Advanced visual tests -- An entity for testing animated and yaw-modulated sprites diff --git a/irr/src/CXMeshFileLoader.cpp b/irr/src/CXMeshFileLoader.cpp index 508b632c0..c09f2e481 100644 --- a/irr/src/CXMeshFileLoader.cpp +++ b/irr/src/CXMeshFileLoader.cpp @@ -56,8 +56,9 @@ IAnimatedMesh *CXMeshFileLoader::createMesh(io::IReadFile *file) AnimatedMesh = new SkinnedMeshBuilder(); + SkinnedMesh *res = nullptr; if (load(file)) { - AnimatedMesh->finalize(); + res = AnimatedMesh->finalize(); } else { AnimatedMesh->drop(); AnimatedMesh = 0; @@ -89,7 +90,7 @@ IAnimatedMesh *CXMeshFileLoader::createMesh(io::IReadFile *file) delete Meshes[i]; Meshes.clear(); - return AnimatedMesh->finalize(); + return res; } bool CXMeshFileLoader::load(io::IReadFile *file) @@ -962,15 +963,16 @@ bool CXMeshFileLoader::parseDataObjectSkinWeights(SXMesh &mesh) u32 i; const u32 jointStart = joint->Weights.size(); - joint->Weights.resize(jointStart + nWeights); + joint->Weights.reserve(jointStart + nWeights); mesh.WeightJoint.reallocate(mesh.WeightJoint.size() + nWeights); mesh.WeightNum.reallocate(mesh.WeightNum.size() + nWeights); for (i = 0; i < nWeights; ++i) { mesh.WeightJoint.push_back(*n); - mesh.WeightNum.push_back(joint->Weights.size()); + mesh.WeightNum.push_back(joint->Weights.size()); // id of weight + // Note: This adds a weight to joint->Weights SkinnedMesh::SWeight *weight = AnimatedMesh->addWeight(joint); weight->buffer_id = 0; From 10f1e142f693da1d8f1da7485b69957a24e31069 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 20 Dec 2024 15:03:30 +0100 Subject: [PATCH 128/136] Fix threshold value for imageCleanTransparent fixes #15401 --- src/client/imagesource.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/client/imagesource.cpp b/src/client/imagesource.cpp index a14dac290..4adc39834 100644 --- a/src/client/imagesource.cpp +++ b/src/client/imagesource.cpp @@ -1511,10 +1511,18 @@ bool ImageSource::generateImagePart(std::string_view part_of_name, CHECK_BASEIMG(); - // Apply the "clean transparent" filter, if needed + /* Apply the "clean transparent" filter, if necessary + * This is needed since filtering will sample parts of the image + * that are transparent and PNG optimizers often discard the color + * information in those parts. */ if (m_setting_mipmap || m_setting_bilinear_filter || - m_setting_trilinear_filter || m_setting_anisotropic_filter) - imageCleanTransparent(baseimg, 127); + m_setting_trilinear_filter || m_setting_anisotropic_filter) { + /* Note: in theory we should pass either 0 or 127 depending on + * if the texture is used with an ALPHA or ALPHA_REF material, + * however we don't have this information here. + * It doesn't matter in practice. */ + imageCleanTransparent(baseimg, 0); + } /* Upscale textures to user's requested minimum size. This is a trick to make * filters look as good on low-res textures as on high-res ones, by making From b172e672956225633188d60f51111b03ce8fa714 Mon Sep 17 00:00:00 2001 From: cx384 Date: Fri, 20 Dec 2024 15:03:45 +0100 Subject: [PATCH 129/136] Remove game_ui from Client class --- src/client/client.cpp | 3 --- src/client/client.h | 4 ---- src/client/game.cpp | 2 +- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/client/client.cpp b/src/client/client.cpp index f17d4debf..222c1a2ac 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -14,7 +14,6 @@ #include "network/networkpacket.h" #include "threading/mutex_auto_lock.h" #include "client/clientevent.h" -#include "client/gameui.h" #include "client/renderingengine.h" #include "client/sound.h" #include "client/texturepaths.h" @@ -94,7 +93,6 @@ Client::Client( ISoundManager *sound, MtEventManager *event, RenderingEngine *rendering_engine, - GameUI *game_ui, ELoginRegister allow_login_or_register ): m_tsrc(tsrc), @@ -117,7 +115,6 @@ Client::Client( m_chosen_auth_mech(AUTH_MECHANISM_NONE), m_media_downloader(new ClientMediaDownloader()), m_state(LC_Created), - m_game_ui(game_ui), m_modchannel_mgr(new ModChannelMgr()) { // Add local player diff --git a/src/client/client.h b/src/client/client.h index c6803cbe1..e4bb77ab2 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -99,7 +99,6 @@ private: }; class ClientScripting; -class GameUI; class Client : public con::PeerHandler, public InventoryManager, public IGameDef { @@ -119,7 +118,6 @@ public: ISoundManager *sound, MtEventManager *event, RenderingEngine *rendering_engine, - GameUI *game_ui, ELoginRegister allow_login_or_register ); @@ -572,8 +570,6 @@ private: // own state LocalClientState m_state; - GameUI *m_game_ui; - // Used for saving server map to disk client-side MapDatabase *m_localdb = nullptr; IntervalLimiter m_localdb_save_interval; diff --git a/src/client/game.cpp b/src/client/game.cpp index dc13095d1..8bd6f5f29 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -1614,7 +1614,7 @@ bool Game::connectToServer(const GameStartData &start_data, start_data.password, *draw_control, texture_src, shader_src, itemdef_manager, nodedef_manager, sound_manager.get(), eventmgr, - m_rendering_engine, m_game_ui.get(), + m_rendering_engine, start_data.allow_login_or_register); } catch (const BaseException &e) { *error_message = fmtgettext("Error creating client: %s", e.what()); From f06383f78c98fcb8dd10c7616a3a770a360a198d Mon Sep 17 00:00:00 2001 From: cx384 Date: Fri, 20 Dec 2024 15:03:55 +0100 Subject: [PATCH 130/136] Minor API reference fixes --- doc/lua_api.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index 7fe464a30..91d8f314a 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -6566,7 +6566,7 @@ Environment access * `pointabilities`: Allows overriding the `pointable` property of nodes and objects. Uses the same format as the `pointabilities` property of item definitions. Default is `nil`. -* `core.find_path(pos1,pos2,searchdistance,max_jump,max_drop,algorithm)` +* `core.find_path(pos1, pos2, searchdistance, max_jump, max_drop, algorithm)` * returns table containing path that can be walked on * returns a table of 3D points representing a path from `pos1` to `pos2` or `nil` on failure. @@ -6586,7 +6586,7 @@ Environment access Difference between `"A*"` and `"A*_noprefetch"` is that `"A*"` will pre-calculate the cost-data, the other will calculate it on-the-fly -* `core.spawn_tree (pos, {treedef})` +* `core.spawn_tree(pos, treedef)` * spawns L-system tree at given `pos` with definition in `treedef` table * `core.spawn_tree_on_vmanip(vmanip, pos, treedef)` * analogous to `core.spawn_tree`, but spawns a L-system tree onto the specified From 7354cbe4635a35aad2a6c1a77fac457084341714 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Wed, 11 Dec 2024 14:17:51 +0100 Subject: [PATCH 131/136] Fix core::array::reallocate when shrinking --- irr/include/irrArray.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/irr/include/irrArray.h b/irr/include/irrArray.h index 4a87382bc..834dc825c 100644 --- a/irr/include/irrArray.h +++ b/irr/include/irrArray.h @@ -59,8 +59,12 @@ public: { size_t allocated = m_data.capacity(); if (new_size < allocated) { - if (canShrink) - m_data.resize(new_size); + if (canShrink) { + // since capacity != size don't accidentally make it bigger + if (m_data.size() > new_size) + m_data.resize(new_size); + m_data.shrink_to_fit(); + } } else { m_data.reserve(new_size); } From eb8beb335e30ba6e3a35a56ace665ec59cd840dd Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 13 Dec 2024 13:49:49 +0100 Subject: [PATCH 132/136] Fix bloom with post_processing_texture_bits < 16 --- src/client/render/pipeline.cpp | 21 +++++++++++++++++---- src/client/render/secondstage.cpp | 13 ++++++++----- src/defaultsettings.cpp | 2 ++ 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/client/render/pipeline.cpp b/src/client/render/pipeline.cpp index d24aa3ce8..33b3e78e2 100644 --- a/src/client/render/pipeline.cpp +++ b/src/client/render/pipeline.cpp @@ -6,6 +6,7 @@ #include "client/client.h" #include "client/hud.h" #include "IRenderTarget.h" +#include "SColor.h" #include #include @@ -122,10 +123,19 @@ bool TextureBuffer::ensureTexture(video::ITexture **texture, const TextureDefini if (!modify) return false; - if (*texture) + if (*texture) { m_driver->removeTexture(*texture); + *texture = nullptr; + } if (definition.valid) { + if (!m_driver->queryTextureFormat(definition.format)) { + errorstream << "Failed to create texture \"" << definition.name + << "\": unsupported format " << video::ColorFormatNames[definition.format] + << std::endl; + return false; + } + if (definition.clear) { // We're not able to clear a render target texture // We're not able to create a normal texture with MSAA @@ -142,9 +152,12 @@ bool TextureBuffer::ensureTexture(video::ITexture **texture, const TextureDefini } else { *texture = m_driver->addRenderTargetTexture(size, definition.name.c_str(), definition.format); } - } - else { - *texture = nullptr; + + if (!*texture) { + errorstream << "Failed to create texture \"" << definition.name + << "\"" << std::endl; + return false; + } } return true; diff --git a/src/client/render/secondstage.cpp b/src/client/render/secondstage.cpp index f6a0cf78e..35ebe8110 100644 --- a/src/client/render/secondstage.cpp +++ b/src/client/render/secondstage.cpp @@ -165,6 +165,9 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep // Number of mipmap levels of the bloom downsampling texture const u8 MIPMAP_LEVELS = 4; + // color_format can be a normalized integer format, but bloom requires + // values outside of [0,1] so this needs to be a different one. + const auto bloom_format = video::ECF_A16B16G16R16F; // post-processing stage @@ -173,16 +176,16 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep // common downsampling step for bloom or autoexposure if (enable_bloom || enable_auto_exposure) { - v2f downscale = scale * 0.5; + v2f downscale = scale * 0.5f; for (u8 i = 0; i < MIPMAP_LEVELS; i++) { - buffer->setTexture(TEXTURE_SCALE_DOWN + i, downscale, std::string("downsample") + std::to_string(i), color_format); + buffer->setTexture(TEXTURE_SCALE_DOWN + i, downscale, std::string("downsample") + std::to_string(i), bloom_format); if (enable_bloom) - buffer->setTexture(TEXTURE_SCALE_UP + i, downscale, std::string("upsample") + std::to_string(i), color_format); - downscale *= 0.5; + buffer->setTexture(TEXTURE_SCALE_UP + i, downscale, std::string("upsample") + std::to_string(i), bloom_format); + downscale *= 0.5f; } if (enable_bloom) { - buffer->setTexture(TEXTURE_BLOOM, scale, "bloom", color_format); + buffer->setTexture(TEXTURE_BLOOM, scale, "bloom", bloom_format); // get bright spots u32 shader_id = client->getShaderSource()->getShader("extract_bloom", TILE_MATERIAL_PLAIN, NDT_MESH); diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 674442469..b1094be2d 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -571,7 +571,9 @@ void set_default_settings() // Note: OpenGL ES 2.0 is not guaranteed to provide depth textures, // which we would need for PP. settings->setDefault("enable_post_processing", "false"); + // still set these two settings in case someone wants to enable it settings->setDefault("debanding", "false"); + settings->setDefault("post_processing_texture_bits", "8"); settings->setDefault("curl_verify_cert", "false"); // Apply settings according to screen size From a6293b9861b7e9ab8bb6ce91663f363970ecc816 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Fri, 13 Dec 2024 16:11:21 +0100 Subject: [PATCH 133/136] Initial refactoring on shader usage and generation `IShaderSource` was designed with the idea that if you want a shader, you must want it for a node. So it depends heavily on being given a tile material and the node drawtype. But this doesn't make sense neither in theory nor in practice. This commit takes a small step towards removing the incorrect abstraction. --- .../default_shader/opengl_fragment.glsl | 6 --- .../shaders/default_shader/opengl_vertex.glsl | 7 ---- .../shaders/nodes_shader/opengl_fragment.glsl | 10 ++--- .../shaders/nodes_shader/opengl_vertex.glsl | 6 +-- src/client/clouds.cpp | 2 +- src/client/hud.cpp | 12 +++--- src/client/minimap.cpp | 2 +- src/client/render/interlaced.cpp | 4 +- src/client/render/secondstage.cpp | 14 +++---- src/client/shader.cpp | 42 ++++++++++++++++--- src/client/shader.h | 25 ++++++++--- src/client/sky.cpp | 2 +- src/client/tile.h | 1 + src/nodedef.h | 1 + 14 files changed, 81 insertions(+), 53 deletions(-) delete mode 100644 client/shaders/default_shader/opengl_fragment.glsl delete mode 100644 client/shaders/default_shader/opengl_vertex.glsl diff --git a/client/shaders/default_shader/opengl_fragment.glsl b/client/shaders/default_shader/opengl_fragment.glsl deleted file mode 100644 index 300c0c589..000000000 --- a/client/shaders/default_shader/opengl_fragment.glsl +++ /dev/null @@ -1,6 +0,0 @@ -varying lowp vec4 varColor; - -void main(void) -{ - gl_FragData[0] = varColor; -} diff --git a/client/shaders/default_shader/opengl_vertex.glsl b/client/shaders/default_shader/opengl_vertex.glsl deleted file mode 100644 index d95a3c2d3..000000000 --- a/client/shaders/default_shader/opengl_vertex.glsl +++ /dev/null @@ -1,7 +0,0 @@ -varying lowp vec4 varColor; - -void main(void) -{ - gl_Position = mWorldViewProj * inVertexPosition; - varColor = inVertexColor; -} diff --git a/client/shaders/nodes_shader/opengl_fragment.glsl b/client/shaders/nodes_shader/opengl_fragment.glsl index c560a8505..639b658a5 100644 --- a/client/shaders/nodes_shader/opengl_fragment.glsl +++ b/client/shaders/nodes_shader/opengl_fragment.glsl @@ -1,7 +1,3 @@ -#if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_OPAQUE || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_BASIC || MATERIAL_TYPE == TILE_MATERIAL_LIQUID_TRANSPARENT) -#define MATERIAL_WAVING_LIQUID 1 -#endif - uniform sampler2D baseTexture; uniform vec3 dayLight; @@ -53,7 +49,7 @@ varying highp vec3 eyeVec; varying float nightRatio; #ifdef ENABLE_DYNAMIC_SHADOWS -#if (defined(MATERIAL_WAVING_LIQUID) && defined(ENABLE_WATER_REFLECTIONS) && ENABLE_WAVING_WATER) +#if (defined(ENABLE_WATER_REFLECTIONS) && MATERIAL_WAVING_LIQUID && ENABLE_WAVING_WATER) vec4 perm(vec4 x) { return mod(((x * 34.0) + 1.0) * x, 289.0); @@ -504,7 +500,7 @@ void main(void) vec3 viewVec = normalize(worldPosition + cameraOffset - cameraPosition); // Water reflections -#if (defined(MATERIAL_WAVING_LIQUID) && defined(ENABLE_WATER_REFLECTIONS) && ENABLE_WAVING_WATER) +#if (defined(ENABLE_WATER_REFLECTIONS) && MATERIAL_WAVING_LIQUID && ENABLE_WAVING_WATER) vec3 wavePos = worldPosition * vec3(2.0, 0.0, 2.0); float off = animationTimer * WATER_WAVE_SPEED * 10.0; wavePos.x /= WATER_WAVE_LENGTH * 3.0; @@ -532,7 +528,7 @@ void main(void) col.rgb += water_reflect_color * f_adj_shadow_strength * brightness_factor; #endif -#if (defined(ENABLE_NODE_SPECULAR) && !defined(MATERIAL_WAVING_LIQUID)) +#if (defined(ENABLE_NODE_SPECULAR) && !MATERIAL_WAVING_LIQUID) // Apply specular to blocks. if (dot(v_LightDirection, vNormal) < 0.0) { float intensity = 2.0 * (1.0 - (base.r * varColor.r)); diff --git a/client/shaders/nodes_shader/opengl_vertex.glsl b/client/shaders/nodes_shader/opengl_vertex.glsl index d5d6dd59e..15a39565c 100644 --- a/client/shaders/nodes_shader/opengl_vertex.glsl +++ b/client/shaders/nodes_shader/opengl_vertex.glsl @@ -108,8 +108,7 @@ float smoothTriangleWave(float x) return smoothCurve(triangleWave(x)) * 2.0 - 1.0; } -// OpenGL < 4.3 does not support continued preprocessor lines -#if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_OPAQUE || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_BASIC) && ENABLE_WAVING_WATER +#if MATERIAL_WAVING_LIQUID && ENABLE_WAVING_WATER // // Simple, fast noise function. @@ -166,8 +165,7 @@ void main(void) #endif vec4 pos = inVertexPosition; -// OpenGL < 4.3 does not support continued preprocessor lines -#if (MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_OPAQUE || MATERIAL_TYPE == TILE_MATERIAL_WAVING_LIQUID_BASIC) && ENABLE_WAVING_WATER +#if MATERIAL_WAVING_LIQUID && ENABLE_WAVING_WATER // Generate waves with Perlin-type noise. // The constants are calibrated such that they roughly // correspond to the old sine waves. diff --git a/src/client/clouds.cpp b/src/client/clouds.cpp index 82a85d7b0..55e89410d 100644 --- a/src/client/clouds.cpp +++ b/src/client/clouds.cpp @@ -38,7 +38,7 @@ Clouds::Clouds(scene::ISceneManager* mgr, IShaderSource *ssrc, m_material.FogEnable = true; m_material.AntiAliasing = video::EAAM_SIMPLE; { - auto sid = ssrc->getShader("cloud_shader", TILE_MATERIAL_ALPHA); + auto sid = ssrc->getShaderRaw("cloud_shader", true); m_material.MaterialType = ssrc->getShaderInfo(sid).material; } diff --git a/src/client/hud.cpp b/src/client/hud.cpp index 4fbd8740f..0aa847cb7 100644 --- a/src/client/hud.cpp +++ b/src/client/hud.cpp @@ -86,10 +86,11 @@ Hud::Hud(Client *client, LocalPlayer *player, // Initialize m_selection_material IShaderSource *shdrsrc = client->getShaderSource(); - { - auto shader_id = shdrsrc->getShader( - m_mode == HIGHLIGHT_HALO ? "selection_shader" : "default_shader", TILE_MATERIAL_ALPHA); + if (m_mode == HIGHLIGHT_HALO) { + auto shader_id = shdrsrc->getShaderRaw("selection_shader", true); m_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material; + } else { + m_selection_material.MaterialType = video::EMT_SOLID; } if (m_mode == HIGHLIGHT_BOX) { @@ -103,10 +104,7 @@ Hud::Hud(Client *client, LocalPlayer *player, } // Initialize m_block_bounds_material - { - auto shader_id = shdrsrc->getShader("default_shader", TILE_MATERIAL_ALPHA); - m_block_bounds_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material; - } + m_block_bounds_material.MaterialType = video::EMT_SOLID; m_block_bounds_material.Thickness = rangelim(g_settings->getS16("selectionbox_width"), 1, 5); diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp index b11d8b345..a37790f71 100644 --- a/src/client/minimap.cpp +++ b/src/client/minimap.cpp @@ -599,7 +599,7 @@ void Minimap::drawMinimap(core::rect rect) material.TextureLayers[1].Texture = data->heightmap_texture; if (data->mode.type == MINIMAP_TYPE_SURFACE) { - auto sid = m_shdrsrc->getShader("minimap_shader", TILE_MATERIAL_ALPHA); + auto sid = m_shdrsrc->getShaderRaw("minimap_shader", true); material.MaterialType = m_shdrsrc->getShaderInfo(sid).material; } else { material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; diff --git a/src/client/render/interlaced.cpp b/src/client/render/interlaced.cpp index f56d8a3d9..c4014a74d 100644 --- a/src/client/render/interlaced.cpp +++ b/src/client/render/interlaced.cpp @@ -66,10 +66,12 @@ void populateInterlacedPipeline(RenderPipeline *pipeline, Client *client) } pipeline->addStep(0.0f); + IShaderSource *s = client->getShaderSource(); - u32 shader = s->getShader("3d_interlaced_merge", TILE_MATERIAL_BASIC); + auto shader = s->getShaderRaw("3d_interlaced_merge"); video::E_MATERIAL_TYPE material = s->getShaderInfo(shader).material; auto texture_map = { TEXTURE_LEFT, TEXTURE_RIGHT, TEXTURE_MASK }; + auto merge = pipeline->addStep(material, texture_map); merge->setRenderSource(buffer); merge->setRenderTarget(pipeline->createOwned()); diff --git a/src/client/render/secondstage.cpp b/src/client/render/secondstage.cpp index 35ebe8110..42858fa84 100644 --- a/src/client/render/secondstage.cpp +++ b/src/client/render/secondstage.cpp @@ -188,7 +188,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep buffer->setTexture(TEXTURE_BLOOM, scale, "bloom", bloom_format); // get bright spots - u32 shader_id = client->getShaderSource()->getShader("extract_bloom", TILE_MATERIAL_PLAIN, NDT_MESH); + u32 shader_id = client->getShaderSource()->getShaderRaw("extract_bloom"); RenderStep *extract_bloom = pipeline->addStep(shader_id, std::vector { source, TEXTURE_EXPOSURE_1 }); extract_bloom->setRenderSource(buffer); extract_bloom->setRenderTarget(pipeline->createOwned(buffer, TEXTURE_BLOOM)); @@ -198,7 +198,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep if (enable_volumetric_light) { buffer->setTexture(TEXTURE_VOLUME, scale, "volume", color_format); - shader_id = client->getShaderSource()->getShader("volumetric_light", TILE_MATERIAL_PLAIN, NDT_MESH); + shader_id = client->getShaderSource()->getShaderRaw("volumetric_light"); auto volume = pipeline->addStep(shader_id, std::vector { source, TEXTURE_DEPTH }); volume->setRenderSource(buffer); volume->setRenderTarget(pipeline->createOwned(buffer, TEXTURE_VOLUME)); @@ -206,7 +206,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep } // downsample - shader_id = client->getShaderSource()->getShader("bloom_downsample", TILE_MATERIAL_PLAIN, NDT_MESH); + shader_id = client->getShaderSource()->getShaderRaw("bloom_downsample"); for (u8 i = 0; i < MIPMAP_LEVELS; i++) { auto step = pipeline->addStep(shader_id, std::vector { source }); step->setRenderSource(buffer); @@ -219,7 +219,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep // Bloom pt 2 if (enable_bloom) { // upsample - shader_id = client->getShaderSource()->getShader("bloom_upsample", TILE_MATERIAL_PLAIN, NDT_MESH); + shader_id = client->getShaderSource()->getShaderRaw("bloom_upsample"); for (u8 i = MIPMAP_LEVELS - 1; i > 0; i--) { auto step = pipeline->addStep(shader_id, std::vector { u8(TEXTURE_SCALE_DOWN + i - 1), source }); step->setRenderSource(buffer); @@ -232,7 +232,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep // Dynamic Exposure pt2 if (enable_auto_exposure) { - shader_id = client->getShaderSource()->getShader("update_exposure", TILE_MATERIAL_PLAIN, NDT_MESH); + shader_id = client->getShaderSource()->getShaderRaw("update_exposure"); auto update_exposure = pipeline->addStep(shader_id, std::vector { TEXTURE_EXPOSURE_1, u8(TEXTURE_SCALE_DOWN + MIPMAP_LEVELS - 1) }); update_exposure->setBilinearFilter(1, true); update_exposure->setRenderSource(buffer); @@ -246,7 +246,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep final_stage_source = TEXTURE_FXAA; buffer->setTexture(TEXTURE_FXAA, scale, "fxaa", color_format); - shader_id = client->getShaderSource()->getShader("fxaa", TILE_MATERIAL_PLAIN); + shader_id = client->getShaderSource()->getShaderRaw("fxaa"); PostProcessingStep *effect = pipeline->createOwned(shader_id, std::vector { TEXTURE_COLOR }); pipeline->addStep(effect); effect->setBilinearFilter(0, true); @@ -255,7 +255,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep } // final merge - shader_id = client->getShaderSource()->getShader("second_stage", TILE_MATERIAL_PLAIN, NDT_MESH); + shader_id = client->getShaderSource()->getShaderRaw("second_stage"); PostProcessingStep *effect = pipeline->createOwned(shader_id, std::vector { final_stage_source, TEXTURE_SCALE_UP, TEXTURE_EXPOSURE_2 }); pipeline->addStep(effect); if (enable_ssaa) diff --git a/src/client/shader.cpp b/src/client/shader.cpp index 8d2d5744a..0b328014a 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -271,7 +271,7 @@ public: The id 0 points to a null shader. Its material is EMT_SOLID. */ u32 getShaderIdDirect(const std::string &name, - MaterialType material_type, NodeDrawType drawtype) override; + MaterialType material_type, NodeDrawType drawtype); /* If shader specified by the name pointed by the id doesn't @@ -281,10 +281,18 @@ public: and not found in cache, the call is queued to the main thread for processing. */ - u32 getShader(const std::string &name, MaterialType material_type, NodeDrawType drawtype) override; + u32 getShaderRaw(const std::string &name, bool blendAlpha) override + { + // TODO: the shader system should be refactored to be much more generic. + // Just let callers pass arbitrary constants, this would also deal with + // runtime changes cleanly. + return getShader(name, blendAlpha ? TILE_MATERIAL_ALPHA : TILE_MATERIAL_BASIC, + NodeDrawType_END); + } + ShaderInfo getShaderInfo(u32 id) override; // Processes queued shader requests from other threads. @@ -607,11 +615,17 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, #define textureFlags texture2 )"; + /* Define constants for node and object shaders */ + const bool node_shader = drawtype != NodeDrawType_END; + if (node_shader) { + bool use_discard = fully_programmable; - // For renderers that should use discard instead of GL_ALPHA_TEST - const char *renderer = reinterpret_cast(GL.GetString(GL.RENDERER)); - if (strstr(renderer, "GC7000")) - use_discard = true; + if (!use_discard) { + // workaround for a certain OpenGL implementation lacking GL_ALPHA_TEST + const char *renderer = reinterpret_cast(GL.GetString(GL.RENDERER)); + if (strstr(renderer, "GC7000")) + use_discard = true; + } if (use_discard) { if (shaderinfo.base_material == video::EMT_TRANSPARENT_ALPHA_CHANNEL) shaders_header << "#define USE_DISCARD 1\n"; @@ -664,9 +678,25 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, shaders_header << "#define WATER_WAVE_LENGTH " << g_settings->getFloat("water_wave_length") << "\n"; shaders_header << "#define WATER_WAVE_SPEED " << g_settings->getFloat("water_wave_speed") << "\n"; } + 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_WAVING_LIQUID 1\n"; + break; + default: + shaders_header << "#define MATERIAL_WAVING_LIQUID 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"; + + } + + /* Other constants */ + shaders_header << "#define ENABLE_TONE_MAPPING " << g_settings->getBool("tone_mapping") << "\n"; if (g_settings->getBool("enable_dynamic_shadows")) { diff --git a/src/client/shader.h b/src/client/shader.h index c1d02bf2c..c78b0078a 100644 --- a/src/client/shader.h +++ b/src/client/shader.h @@ -196,18 +196,33 @@ using CachedStructPixelShaderSetting = CachedStructShaderSettinggetShaderInfo(ssrc->getShader("stars_shader", TILE_MATERIAL_ALPHA)).material; + ssrc->getShaderInfo(ssrc->getShaderRaw("stars_shader", true)).material; m_materials[1] = baseMaterial(); m_materials[1].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; diff --git a/src/client/tile.h b/src/client/tile.h index df02d2244..a2c5bbdfb 100644 --- a/src/client/tile.h +++ b/src/client/tile.h @@ -20,6 +20,7 @@ enum MaterialType{ TILE_MATERIAL_WAVING_LIQUID_BASIC, TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT, TILE_MATERIAL_WAVING_LIQUID_OPAQUE, + // Note: PLAIN isn't a material actually used by tiles, rather just entities. TILE_MATERIAL_PLAIN, TILE_MATERIAL_PLAIN_ALPHA }; diff --git a/src/nodedef.h b/src/nodedef.h index c3f88ce83..ab3362872 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -222,6 +222,7 @@ enum NodeDrawType : u8 NDT_MESH, // Combined plantlike-on-solid NDT_PLANTLIKE_ROOTED, + // Dummy for validity check NodeDrawType_END }; From 7bf0b1fc7e7aea06988586544bd36b15948c63de Mon Sep 17 00:00:00 2001 From: siliconsniffer <97843108+siliconsniffer@users.noreply.github.com> Date: Fri, 20 Dec 2024 15:04:26 +0100 Subject: [PATCH 134/136] Add server url button to main menu (#15536) Co-authored-by: Zughy <63455151+Zughy@users.noreply.github.com> --- LICENSE.txt | 1 + builtin/mainmenu/tab_online.lua | 12 ++++++++++++ textures/base/pack/server_url.png | Bin 0 -> 356 bytes 3 files changed, 13 insertions(+) create mode 100644 textures/base/pack/server_url.png diff --git a/LICENSE.txt b/LICENSE.txt index fb055807b..f7930f528 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -63,6 +63,7 @@ Zughy: textures/base/pack/settings_btn.png textures/base/pack/settings_info.png textures/base/pack/settings_reset.png + textures/base/pack/server_url.png textures/base/pack/server_view_clients.png appgurueu: diff --git a/builtin/mainmenu/tab_online.lua b/builtin/mainmenu/tab_online.lua index b8257b90a..12192715f 100644 --- a/builtin/mainmenu/tab_online.lua +++ b/builtin/mainmenu/tab_online.lua @@ -179,6 +179,13 @@ local function get_formspec(tabview, name, tabdata) "server_view_clients.png") .. ";btn_view_clients;]" end + if selected_server.url then + retval = retval .. "tooltip[btn_server_url;" .. fgettext("Open server website") .. "]" + retval = retval .. "style[btn_server_url;padding=6]" + retval = retval .. "image_button[" .. (can_view_clients_list and "4" or "4.5") .. ",1.3;0.5,0.5;" .. + core.formspec_escape(defaulttexturedir .. "server_url.png") .. ";btn_server_url;]" + end + if is_selected_fav() then retval = retval .. "tooltip[btn_delete_favorite;" .. fgettext("Remove favorite") .. "]" retval = retval .. "style[btn_delete_favorite;padding=6]" @@ -367,6 +374,11 @@ local function main_button_handler(tabview, fields, name, tabdata) return true end + if fields.btn_server_url then + core.open_url_dialog(find_selected_server().url) + return true + end + if fields.btn_view_clients then local dlg = create_clientslist_dialog(find_selected_server()) dlg:set_parent(tabview) diff --git a/textures/base/pack/server_url.png b/textures/base/pack/server_url.png new file mode 100644 index 0000000000000000000000000000000000000000..3f04900833fe4df446a6d7eedf2d00b22afbc404 GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^3qY8K8Aw(>tdav#asfUet_C`Ksqr!4K>?wDem<^l zKrT?`{ z*7;}I>^5_8L-IsTe*qlcq603 zfkO}0)l{th_vTbvqyB6rmNlGaroqaa1#X_n;u6@PR Date: Fri, 20 Dec 2024 19:04:56 +0100 Subject: [PATCH 135/136] Fix incorrect handling of skinned meshes as mesh nodes fixes #15576 --- src/nodedef.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/nodedef.cpp b/src/nodedef.cpp index 81348cf23..2f0307d11 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -13,6 +13,7 @@ #include "client/texturesource.h" #include "client/tile.h" #include +#include #endif #include "log.h" #include "settings.h" @@ -953,6 +954,12 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc infostream << "ContentFeatures: recalculating normals for mesh " << mesh << std::endl; meshmanip->recalculateNormals(mesh_ptr, true, false); + } else { + // Animation is not supported, but we need to reset it to + // default state if it is animated. + // Note: recalculateNormals() also does this hence the else-block + if (mesh_ptr->getMeshType() == scene::EAMT_SKINNED) + ((scene::SkinnedMesh*) mesh_ptr)->resetAnimation(); } } } From 83bc27d99dacbb249b95387a9511d9b38830bf55 Mon Sep 17 00:00:00 2001 From: cx384 Date: Fri, 20 Dec 2024 11:02:20 +0100 Subject: [PATCH 136/136] Move formspec code from game.cpp to separate file --- src/client/CMakeLists.txt | 1 + src/client/game.cpp | 512 ++-------------------------------- src/client/game_formspec.cpp | 524 +++++++++++++++++++++++++++++++++++ src/client/game_formspec.h | 62 +++++ src/client/gameui.cpp | 12 - src/client/gameui.h | 15 - 6 files changed, 605 insertions(+), 521 deletions(-) create mode 100644 src/client/game_formspec.cpp create mode 100644 src/client/game_formspec.h diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 0bcb667bc..c17148a35 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -51,6 +51,7 @@ set(client_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/fontengine.cpp ${CMAKE_CURRENT_SOURCE_DIR}/game.cpp ${CMAKE_CURRENT_SOURCE_DIR}/gameui.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/game_formspec.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiscalingfilter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/hud.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imagefilters.cpp diff --git a/src/client/game.cpp b/src/client/game.cpp index 8bd6f5f29..97b50183c 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -11,6 +11,7 @@ #include "client.h" #include "client/clientevent.h" #include "client/gameui.h" +#include "client/game_formspec.h" #include "client/inputhandler.h" #include "client/texturepaths.h" #include "client/keys.h" @@ -26,18 +27,13 @@ #include "client/event_manager.h" #include "fontengine.h" #include "gui/touchcontrols.h" -#include "gui/touchscreeneditor.h" #include "itemdef.h" #include "log.h" #include "log_internal.h" #include "gameparams.h" #include "gettext.h" #include "gui/guiChatConsole.h" -#include "gui/guiFormSpecMenu.h" -#include "gui/guiKeyChangeMenu.h" -#include "gui/guiPasswordChange.h" -#include "gui/guiOpenURL.h" -#include "gui/guiVolumeChange.h" +#include "texturesource.h" #include "gui/mainmenumanager.h" #include "gui/profilergraph.h" #include "minimap.h" @@ -69,176 +65,6 @@ #include "client/sound/sound_openal.h" #endif -/* - Text input system -*/ - -struct TextDestNodeMetadata : public TextDest -{ - TextDestNodeMetadata(v3s16 p, Client *client) - { - m_p = p; - m_client = client; - } - // This is deprecated I guess? -celeron55 - void gotText(const std::wstring &text) - { - std::string ntext = wide_to_utf8(text); - infostream << "Submitting 'text' field of node at (" << m_p.X << "," - << m_p.Y << "," << m_p.Z << "): " << ntext << std::endl; - StringMap fields; - fields["text"] = ntext; - m_client->sendNodemetaFields(m_p, "", fields); - } - void gotText(const StringMap &fields) - { - m_client->sendNodemetaFields(m_p, "", fields); - } - - v3s16 m_p; - Client *m_client; -}; - -struct TextDestPlayerInventory : public TextDest -{ - TextDestPlayerInventory(Client *client) - { - m_client = client; - m_formname.clear(); - } - TextDestPlayerInventory(Client *client, const std::string &formname) - { - m_client = client; - m_formname = formname; - } - void gotText(const StringMap &fields) - { - m_client->sendInventoryFields(m_formname, fields); - } - - Client *m_client; -}; - -struct LocalFormspecHandler : public TextDest -{ - LocalFormspecHandler(const std::string &formname) - { - m_formname = formname; - } - - LocalFormspecHandler(const std::string &formname, Client *client): - m_client(client) - { - m_formname = formname; - } - - void gotText(const StringMap &fields) - { - if (m_formname == "MT_PAUSE_MENU") { - if (fields.find("btn_sound") != fields.end()) { - g_gamecallback->changeVolume(); - return; - } - - if (fields.find("btn_key_config") != fields.end()) { - g_gamecallback->keyConfig(); - return; - } - - if (fields.find("btn_touchscreen_layout") != fields.end()) { - g_gamecallback->touchscreenLayout(); - return; - } - - if (fields.find("btn_exit_menu") != fields.end()) { - g_gamecallback->disconnect(); - return; - } - - if (fields.find("btn_exit_os") != fields.end()) { - g_gamecallback->exitToOS(); -#ifndef __ANDROID__ - RenderingEngine::get_raw_device()->closeDevice(); -#endif - return; - } - - if (fields.find("btn_change_password") != fields.end()) { - g_gamecallback->changePassword(); - return; - } - - return; - } - - if (m_formname == "MT_DEATH_SCREEN") { - assert(m_client != nullptr); - - if (fields.find("quit") != fields.end()) - m_client->sendRespawnLegacy(); - - return; - } - - if (m_client->modsLoaded()) - m_client->getScript()->on_formspec_input(m_formname, fields); - } - - Client *m_client = nullptr; -}; - -/* Form update callback */ - -class NodeMetadataFormSource: public IFormSource -{ -public: - NodeMetadataFormSource(ClientMap *map, v3s16 p): - m_map(map), - m_p(p) - { - } - const std::string &getForm() const - { - static const std::string empty_string = ""; - NodeMetadata *meta = m_map->getNodeMetadata(m_p); - - if (!meta) - return empty_string; - - return meta->getString("formspec"); - } - - virtual std::string resolveText(const std::string &str) - { - NodeMetadata *meta = m_map->getNodeMetadata(m_p); - - if (!meta) - return str; - - return meta->resolveString(str); - } - - ClientMap *m_map; - v3s16 m_p; -}; - -class PlayerInventoryFormSource: public IFormSource -{ -public: - PlayerInventoryFormSource(Client *client): - m_client(client) - { - } - - const std::string &getForm() const - { - LocalPlayer *player = m_client->getEnv().getLocalPlayer(); - return player->inventory_formspec; - } - - Client *m_client; -}; - class NodeDugEvent : public MtEvent { public: @@ -596,8 +422,6 @@ public: } }; -#define SIZE_TAG "size[11,5.5,true]" // Fixed size (ignored in touchscreen mode) - /**************************************************************************** ****************************************************************************/ @@ -699,7 +523,6 @@ protected: void updateInteractTimers(f32 dtime); bool checkConnection(); - bool handleCallbacks(); void processQueues(); void updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime); void updateDebugState(); @@ -713,7 +536,6 @@ protected: bool shouldShowTouchControls(); void dropSelectedItem(bool single_item = false); - void openInventory(); void openConsole(float scale, const wchar_t *line=NULL); void toggleFreeMove(); void toggleFreeMoveAlt(); @@ -815,9 +637,6 @@ private: bool disable_camera_update = false; }; - void showDeathFormspecLegacy(); - void showPauseMenu(); - void pauseAnimation(); void resumeAnimation(); @@ -882,6 +701,7 @@ private: irr_ptr sky; Hud *hud = nullptr; Minimap *mapper = nullptr; + GameFormSpec m_game_formspec; // Map server hud ids to client hud ids std::unordered_map m_hud_server_to_client; @@ -1089,6 +909,8 @@ bool Game::startup(bool *kill, m_rendering_engine->initialize(client, hud); + m_game_formspec.init(client, m_rendering_engine, input); + return true; } @@ -1159,7 +981,7 @@ void Game::run() if (!checkConnection()) break; - if (!handleCallbacks()) + if (!m_game_formspec.handleCallbacks()) break; processQueues(); @@ -1191,7 +1013,7 @@ void Game::run() updateProfilerGraphs(&graph); if (m_does_lost_focus_pause_game && !device->isWindowFocused() && !isMenuActive()) { - showPauseMenu(); + m_game_formspec.showPauseMenu(); } } @@ -1203,10 +1025,6 @@ void Game::run() void Game::shutdown() { - auto formspec = m_game_ui->getFormspecGUI(); - if (formspec) - formspec->quitMenu(); - // Clear text when exiting. m_game_ui->clearText(); @@ -1228,8 +1046,6 @@ void Game::shutdown() g_menumgr.deleteFront(); } - m_game_ui->deleteFormspec(); - chat_backend->addMessage(L"", L"# Disconnected."); chat_backend->addMessage(L"", L""); @@ -1822,55 +1638,6 @@ inline bool Game::checkConnection() return true; } - -/* returns false if game should exit, otherwise true - */ -inline bool Game::handleCallbacks() -{ - if (g_gamecallback->disconnect_requested) { - g_gamecallback->disconnect_requested = false; - return false; - } - - if (g_gamecallback->changepassword_requested) { - (void)make_irr(guienv, guiroot, -1, - &g_menumgr, client, texture_src); - g_gamecallback->changepassword_requested = false; - } - - if (g_gamecallback->changevolume_requested) { - (void)make_irr(guienv, guiroot, -1, - &g_menumgr, texture_src); - g_gamecallback->changevolume_requested = false; - } - - if (g_gamecallback->keyconfig_requested) { - (void)make_irr(guienv, guiroot, -1, - &g_menumgr, texture_src); - g_gamecallback->keyconfig_requested = false; - } - - if (g_gamecallback->touchscreenlayout_requested) { - (new GUITouchscreenLayout(guienv, guiroot, -1, - &g_menumgr, texture_src))->drop(); - g_gamecallback->touchscreenlayout_requested = false; - } - - if (!g_gamecallback->show_open_url_dialog.empty()) { - (void)make_irr(guienv, guiroot, -1, - &g_menumgr, texture_src, g_gamecallback->show_open_url_dialog); - g_gamecallback->show_open_url_dialog.clear(); - } - - if (g_gamecallback->keyconfig_changed) { - input->keycache.populate(); // update the cache with new settings - g_gamecallback->keyconfig_changed = false; - } - - return true; -} - - void Game::processQueues() { texture_src->processQueue(); @@ -1897,10 +1664,7 @@ void Game::updateDebugState() if (!has_debug) { draw_control->show_wireframe = false; m_flags.disable_camera_update = false; - auto formspec = m_game_ui->getFormspecGUI(); - if (formspec) { - formspec->setDebugView(false); - } + m_game_formspec.disableDebugView(); } // noclip @@ -2044,10 +1808,7 @@ void Game::processUserInput(f32 dtime) input->step(dtime); #ifdef __ANDROID__ - auto formspec = m_game_ui->getFormspecGUI(); - if (formspec) - formspec->getAndroidUIInput(); - else + if (!m_game_formspec.handleAndroidUIInput()) handleAndroidChatInput(); #endif @@ -2072,13 +1833,13 @@ void Game::processKeyInput() if (g_settings->getBool("continuous_forward")) toggleAutoforward(); } else if (wasKeyDown(KeyType::INVENTORY)) { - openInventory(); + m_game_formspec.showPlayerInventory(); } else if (input->cancelPressed()) { #ifdef __ANDROID__ m_android_chat_open = false; #endif if (!gui_chat_console->isOpenInhibited()) { - showPauseMenu(); + m_game_formspec.showPauseMenu(); } } else if (wasKeyDown(KeyType::CHAT)) { openConsole(0.2, L""); @@ -2246,45 +2007,6 @@ void Game::dropSelectedItem(bool single_item) client->inventoryAction(a); } - -void Game::openInventory() -{ - /* - * Don't permit to open inventory is CAO or player doesn't exists. - * This prevent showing an empty inventory at player load - */ - - LocalPlayer *player = client->getEnv().getLocalPlayer(); - if (!player || !player->getCAO()) - return; - - infostream << "Game: Launching inventory" << std::endl; - - PlayerInventoryFormSource *fs_src = new PlayerInventoryFormSource(client); - - InventoryLocation inventoryloc; - inventoryloc.setCurrentPlayer(); - - if (client->modsLoaded() && client->getScript()->on_inventory_open(fs_src->m_client->getInventory(inventoryloc))) { - delete fs_src; - return; - } - - if (fs_src->getForm().empty()) { - delete fs_src; - return; - } - - TextDest *txt_dst = new TextDestPlayerInventory(client); - auto *&formspec = m_game_ui->updateFormspec(""); - GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(), - &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), - sound_manager.get()); - - formspec->setFormSpec(fs_src->getForm(), inventoryloc); -} - - void Game::openConsole(float scale, const wchar_t *line) { assert(scale > 0.0f && scale <= 1.0f); @@ -2886,28 +2608,13 @@ void Game::handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientati void Game::handleClientEvent_DeathscreenLegacy(ClientEvent *event, CameraOrientation *cam) { - showDeathFormspecLegacy(); + m_game_formspec.showDeathFormspecLegacy(); } void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam) { - if (event->show_formspec.formspec->empty()) { - auto formspec = m_game_ui->getFormspecGUI(); - if (formspec && (event->show_formspec.formname->empty() - || *(event->show_formspec.formname) == m_game_ui->getFormspecName())) { - formspec->quitMenu(); - } - } else { - FormspecFormSource *fs_src = - new FormspecFormSource(*(event->show_formspec.formspec)); - TextDestPlayerInventory *txt_dst = - new TextDestPlayerInventory(client, *(event->show_formspec.formname)); - - auto *&formspec = m_game_ui->updateFormspec(*(event->show_formspec.formname)); - GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(), - &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), - sound_manager.get()); - } + m_game_formspec.showFormSpec(*event->show_formspec.formspec, + *event->show_formspec.formname); delete event->show_formspec.formspec; delete event->show_formspec.formname; @@ -2915,11 +2622,8 @@ void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam) { - FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec); - LocalFormspecHandler *txt_dst = - new LocalFormspecHandler(*event->show_formspec.formname, client); - GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, m_rendering_engine->get_gui_env(), - &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound_manager.get()); + m_game_formspec.showLocalFormSpec(*event->show_formspec.formspec, + *event->show_formspec.formname); delete event->show_formspec.formspec; delete event->show_formspec.formname; @@ -3657,21 +3361,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def, if (nodedef_manager->get(map.getNode(nodepos)).rightclickable) client->interact(INTERACT_PLACE, pointed); - infostream << "Launching custom inventory view" << std::endl; - - InventoryLocation inventoryloc; - inventoryloc.setNodeMeta(nodepos); - - NodeMetadataFormSource *fs_src = new NodeMetadataFormSource( - &client->getEnv().getClientMap(), nodepos); - TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client); - - auto *&formspec = m_game_ui->updateFormspec(""); - GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(), - &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), - sound_manager.get()); - - formspec->setFormSpec(meta->getString("formspec"), inventoryloc); + m_game_formspec.showNodeFormspec(meta->getString("formspec"), nodepos); return false; } @@ -4207,34 +3897,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, m_game_ui->update(*stats, client, draw_control, cam, runData.pointed_old, gui_chat_console.get(), dtime); - /* - make sure menu is on top - 1. Delete formspec menu reference if menu was removed - 2. Else, make sure formspec menu is on top - */ - auto formspec = m_game_ui->getFormspecGUI(); - do { // breakable. only runs for one iteration - if (!formspec) - break; - - if (formspec->getReferenceCount() == 1) { - // See GUIFormSpecMenu::create what refcnt = 1 means - m_game_ui->deleteFormspec(); - break; - } - - auto &loc = formspec->getFormspecLocation(); - if (loc.type == InventoryLocation::NODEMETA) { - NodeMetadata *meta = client->getEnv().getClientMap().getNodeMetadata(loc.p); - if (!meta || meta->getString("formspec").empty()) { - formspec->quitMenu(); - break; - } - } - - if (isMenuActive()) - guiroot->bringToFront(formspec); - } while (false); + m_game_formspec.update(); /* ==================== Drawing begins ==================== @@ -4451,145 +4114,6 @@ void Game::readSettings() m_does_lost_focus_pause_game = g_settings->getBool("pause_on_lost_focus"); } -/****************************************************************************/ -/**************************************************************************** - Shutdown / cleanup - ****************************************************************************/ -/****************************************************************************/ - -void Game::showDeathFormspecLegacy() -{ - static std::string formspec_str = - std::string("formspec_version[1]") + - SIZE_TAG - "bgcolor[#320000b4;true]" - "label[4.85,1.35;" + gettext("You died") + "]" - "button_exit[4,3;3,0.5;btn_respawn;" + gettext("Respawn") + "]" - ; - - /* Create menu */ - /* Note: FormspecFormSource and LocalFormspecHandler * - * are deleted by guiFormSpecMenu */ - FormspecFormSource *fs_src = new FormspecFormSource(formspec_str); - LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", client); - - auto *&formspec = m_game_ui->getFormspecGUI(); - GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(), - &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), - sound_manager.get()); - formspec->setFocus("btn_respawn"); -} - -#define GET_KEY_NAME(KEY) gettext(getKeySetting(#KEY).name()) -void Game::showPauseMenu() -{ - std::string control_text; - - if (g_touchcontrols) { - control_text = strgettext("Controls:\n" - "No menu open:\n" - "- slide finger: look around\n" - "- tap: place/punch/use (default)\n" - "- long tap: dig/use (default)\n" - "Menu/inventory open:\n" - "- double tap (outside):\n" - " --> close\n" - "- touch stack, touch slot:\n" - " --> move stack\n" - "- touch&drag, tap 2nd finger\n" - " --> place single item to slot\n" - ); - } - - float ypos = simple_singleplayer_mode ? 0.7f : 0.1f; - std::ostringstream os; - - os << "formspec_version[1]" << SIZE_TAG - << "button_exit[4," << (ypos++) << ";3,0.5;btn_continue;" - << strgettext("Continue") << "]"; - - if (!simple_singleplayer_mode) { - os << "button_exit[4," << (ypos++) << ";3,0.5;btn_change_password;" - << strgettext("Change Password") << "]"; - } else { - os << "field[4.95,0;5,1.5;;" << strgettext("Game paused") << ";]"; - } - -#ifndef __ANDROID__ -#if USE_SOUND - if (g_settings->getBool("enable_sound")) { - 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") << "]"; - } else { - os << "button_exit[4," << (ypos++) << ";3,0.5;btn_key_config;" - << strgettext("Controls") << "]"; - } - os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_menu;" - << strgettext("Exit to Menu") << "]"; - os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_os;" - << strgettext("Exit to OS") << "]"; - if (!control_text.empty()) { - os << "textarea[7.5,0.25;3.9,6.25;;" << control_text << ";]"; - } - os << "textarea[0.4,0.25;3.9,6.25;;" << PROJECT_NAME_C " " VERSION_STRING "\n" - << "\n" - << strgettext("Game info:") << "\n"; - const std::string &address = client->getAddressName(); - os << strgettext("- Mode: "); - if (!simple_singleplayer_mode) { - if (address.empty()) - os << strgettext("Hosting server"); - else - os << strgettext("Remote server"); - } else { - os << strgettext("Singleplayer"); - } - os << "\n"; - if (simple_singleplayer_mode || address.empty()) { - static const std::string on = strgettext("On"); - static const std::string off = strgettext("Off"); - // Note: Status of enable_damage and creative_mode settings is intentionally - // NOT shown here because the game might roll its own damage system and/or do - // a per-player Creative Mode, in which case writing it here would mislead. - bool damage = g_settings->getBool("enable_damage"); - const std::string &announced = g_settings->getBool("server_announce") ? on : off; - if (!simple_singleplayer_mode) { - if (damage) { - const std::string &pvp = g_settings->getBool("enable_pvp") ? on : off; - //~ PvP = Player versus Player - os << strgettext("- PvP: ") << pvp << "\n"; - } - os << strgettext("- Public: ") << announced << "\n"; - std::string server_name = g_settings->get("server_name"); - str_formspec_escape(server_name); - if (announced == on && !server_name.empty()) - os << strgettext("- Server Name: ") << server_name; - - } - } - os << ";]"; - - /* Create menu */ - /* Note: FormspecFormSource and LocalFormspecHandler * - * are deleted by guiFormSpecMenu */ - FormspecFormSource *fs_src = new FormspecFormSource(os.str()); - LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU"); - - auto *&formspec = m_game_ui->getFormspecGUI(); - GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(), - &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), - sound_manager.get()); - formspec->setFocus("btn_continue"); - // game will be paused in next step, if in singleplayer (see m_is_paused) - formspec->doPause = true; -} - /****************************************************************************/ /**************************************************************************** extern function for launching the game diff --git a/src/client/game_formspec.cpp b/src/client/game_formspec.cpp new file mode 100644 index 000000000..4c3bbb04a --- /dev/null +++ b/src/client/game_formspec.cpp @@ -0,0 +1,524 @@ +// Luanti +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright (C) 2010-2013 celeron55, Perttu Ahola + +#include "game_formspec.h" + +#include "gettext.h" +#include "nodemetadata.h" +#include "renderingengine.h" +#include "client.h" +#include "scripting_client.h" +#include "clientmap.h" +#include "gui/guiFormSpecMenu.h" +#include "gui/mainmenumanager.h" +#include "gui/touchcontrols.h" +#include "gui/touchscreeneditor.h" +#include "gui/guiPasswordChange.h" +#include "gui/guiKeyChangeMenu.h" +#include "gui/guiPasswordChange.h" +#include "gui/guiOpenURL.h" +#include "gui/guiVolumeChange.h" + +/* + Text input system +*/ + +struct TextDestNodeMetadata : public TextDest +{ + TextDestNodeMetadata(v3s16 p, Client *client) + { + m_p = p; + m_client = client; + } + // This is deprecated I guess? -celeron55 + void gotText(const std::wstring &text) + { + std::string ntext = wide_to_utf8(text); + infostream << "Submitting 'text' field of node at (" << m_p.X << "," + << m_p.Y << "," << m_p.Z << "): " << ntext << std::endl; + StringMap fields; + fields["text"] = ntext; + m_client->sendNodemetaFields(m_p, "", fields); + } + void gotText(const StringMap &fields) + { + m_client->sendNodemetaFields(m_p, "", fields); + } + + v3s16 m_p; + Client *m_client; +}; + +struct TextDestPlayerInventory : public TextDest +{ + TextDestPlayerInventory(Client *client) + { + m_client = client; + m_formname.clear(); + } + TextDestPlayerInventory(Client *client, const std::string &formname) + { + m_client = client; + m_formname = formname; + } + void gotText(const StringMap &fields) + { + m_client->sendInventoryFields(m_formname, fields); + } + + Client *m_client; +}; + +struct LocalFormspecHandler : public TextDest +{ + LocalFormspecHandler(const std::string &formname) + { + m_formname = formname; + } + + LocalFormspecHandler(const std::string &formname, Client *client): + m_client(client) + { + m_formname = formname; + } + + void gotText(const StringMap &fields) + { + if (m_formname == "MT_PAUSE_MENU") { + if (fields.find("btn_sound") != fields.end()) { + g_gamecallback->changeVolume(); + return; + } + + if (fields.find("btn_key_config") != fields.end()) { + g_gamecallback->keyConfig(); + return; + } + + if (fields.find("btn_touchscreen_layout") != fields.end()) { + g_gamecallback->touchscreenLayout(); + return; + } + + if (fields.find("btn_exit_menu") != fields.end()) { + g_gamecallback->disconnect(); + return; + } + + if (fields.find("btn_exit_os") != fields.end()) { + g_gamecallback->exitToOS(); +#ifndef __ANDROID__ + RenderingEngine::get_raw_device()->closeDevice(); +#endif + return; + } + + if (fields.find("btn_change_password") != fields.end()) { + g_gamecallback->changePassword(); + return; + } + + return; + } + + if (m_formname == "MT_DEATH_SCREEN") { + assert(m_client != nullptr); + + if (fields.find("quit") != fields.end()) + m_client->sendRespawnLegacy(); + + return; + } + + if (m_client->modsLoaded()) + m_client->getScript()->on_formspec_input(m_formname, fields); + } + + Client *m_client = nullptr; +}; + +/* Form update callback */ + +class NodeMetadataFormSource: public IFormSource +{ +public: + NodeMetadataFormSource(ClientMap *map, v3s16 p): + m_map(map), + m_p(p) + { + } + const std::string &getForm() const + { + static const std::string empty_string = ""; + NodeMetadata *meta = m_map->getNodeMetadata(m_p); + + if (!meta) + return empty_string; + + return meta->getString("formspec"); + } + + virtual std::string resolveText(const std::string &str) + { + NodeMetadata *meta = m_map->getNodeMetadata(m_p); + + if (!meta) + return str; + + return meta->resolveString(str); + } + + ClientMap *m_map; + v3s16 m_p; +}; + +class PlayerInventoryFormSource: public IFormSource +{ +public: + PlayerInventoryFormSource(Client *client): + m_client(client) + { + } + + const std::string &getForm() const + { + LocalPlayer *player = m_client->getEnv().getLocalPlayer(); + return player->inventory_formspec; + } + + Client *m_client; +}; + + +//// GameFormSpec + +void GameFormSpec::deleteFormspec() +{ + if (m_formspec) { + m_formspec->drop(); + m_formspec = nullptr; + } + m_formname.clear(); +} + +GameFormSpec::~GameFormSpec() { + if (m_formspec) + m_formspec->quitMenu(); + this->deleteFormspec(); +} + +void GameFormSpec::showFormSpec(const std::string &formspec, const std::string &formname) +{ + if (formspec.empty()) { + if (m_formspec && (formname.empty() || formname == m_formname)) { + m_formspec->quitMenu(); + } + } else { + FormspecFormSource *fs_src = + new FormspecFormSource(formspec); + TextDestPlayerInventory *txt_dst = + new TextDestPlayerInventory(m_client, formname); + + m_formname = formname; + GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(), + &m_input->joystick, fs_src, txt_dst, m_client->getFormspecPrepend(), + m_client->getSoundManager()); + } +} + +void GameFormSpec::showLocalFormSpec(const std::string &formspec, const std::string &formname) +{ + FormspecFormSource *fs_src = new FormspecFormSource(formspec); + LocalFormspecHandler *txt_dst = + new LocalFormspecHandler(formname, m_client); + GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(), + &m_input->joystick, fs_src, txt_dst, m_client->getFormspecPrepend(), + m_client->getSoundManager()); +} + +void GameFormSpec::showNodeFormspec(const std::string &formspec, const v3s16 &nodepos) +{ + infostream << "Launching custom inventory view" << std::endl; + + InventoryLocation inventoryloc; + inventoryloc.setNodeMeta(nodepos); + + NodeMetadataFormSource *fs_src = new NodeMetadataFormSource( + &m_client->getEnv().getClientMap(), nodepos); + TextDest *txt_dst = new TextDestNodeMetadata(nodepos, m_client); + + m_formname = ""; + GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(), + &m_input->joystick, fs_src, txt_dst, m_client->getFormspecPrepend(), + m_client->getSoundManager()); + + m_formspec->setFormSpec(formspec, inventoryloc); +} + +void GameFormSpec::showPlayerInventory() +{ + /* + * Don't permit to open inventory is CAO or player doesn't exists. + * This prevent showing an empty inventory at player load + */ + + LocalPlayer *player = m_client->getEnv().getLocalPlayer(); + if (!player || !player->getCAO()) + return; + + infostream << "Game: Launching inventory" << std::endl; + + PlayerInventoryFormSource *fs_src = new PlayerInventoryFormSource(m_client); + + InventoryLocation inventoryloc; + inventoryloc.setCurrentPlayer(); + + if (m_client->modsLoaded() && m_client->getScript()->on_inventory_open(m_client->getInventory(inventoryloc))) { + delete fs_src; + return; + } + + if (fs_src->getForm().empty()) { + delete fs_src; + return; + } + + TextDest *txt_dst = new TextDestPlayerInventory(m_client); + m_formname = ""; + GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(), + &m_input->joystick, fs_src, txt_dst, m_client->getFormspecPrepend(), + m_client->getSoundManager()); + + m_formspec->setFormSpec(fs_src->getForm(), inventoryloc); +} + +#define SIZE_TAG "size[11,5.5,true]" // Fixed size (ignored in touchscreen mode) + +void GameFormSpec::showPauseMenu() +{ + std::string control_text; + + if (g_touchcontrols) { + control_text = strgettext("Controls:\n" + "No menu open:\n" + "- slide finger: look around\n" + "- tap: place/punch/use (default)\n" + "- long tap: dig/use (default)\n" + "Menu/inventory open:\n" + "- double tap (outside):\n" + " --> close\n" + "- touch stack, touch slot:\n" + " --> move stack\n" + "- touch&drag, tap 2nd finger\n" + " --> place single item to slot\n" + ); + } + + auto simple_singleplayer_mode = m_client->m_simple_singleplayer_mode; + + float ypos = simple_singleplayer_mode ? 0.7f : 0.1f; + std::ostringstream os; + + os << "formspec_version[1]" << SIZE_TAG + << "button_exit[4," << (ypos++) << ";3,0.5;btn_continue;" + << strgettext("Continue") << "]"; + + if (!simple_singleplayer_mode) { + os << "button_exit[4," << (ypos++) << ";3,0.5;btn_change_password;" + << strgettext("Change Password") << "]"; + } else { + os << "field[4.95,0;5,1.5;;" << strgettext("Game paused") << ";]"; + } + +#ifndef __ANDROID__ +#if USE_SOUND + if (g_settings->getBool("enable_sound")) { + 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") << "]"; + } else { + os << "button_exit[4," << (ypos++) << ";3,0.5;btn_key_config;" + << strgettext("Controls") << "]"; + } + os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_menu;" + << strgettext("Exit to Menu") << "]"; + os << "button_exit[4," << (ypos++) << ";3,0.5;btn_exit_os;" + << strgettext("Exit to OS") << "]"; + if (!control_text.empty()) { + os << "textarea[7.5,0.25;3.9,6.25;;" << control_text << ";]"; + } + os << "textarea[0.4,0.25;3.9,6.25;;" << PROJECT_NAME_C " " VERSION_STRING "\n" + << "\n" + << strgettext("Game info:") << "\n"; + const std::string &address = m_client->getAddressName(); + os << strgettext("- Mode: "); + if (!simple_singleplayer_mode) { + if (address.empty()) + os << strgettext("Hosting server"); + else + os << strgettext("Remote server"); + } else { + os << strgettext("Singleplayer"); + } + os << "\n"; + if (simple_singleplayer_mode || address.empty()) { + static const std::string on = strgettext("On"); + static const std::string off = strgettext("Off"); + // Note: Status of enable_damage and creative_mode settings is intentionally + // NOT shown here because the game might roll its own damage system and/or do + // a per-player Creative Mode, in which case writing it here would mislead. + bool damage = g_settings->getBool("enable_damage"); + const std::string &announced = g_settings->getBool("server_announce") ? on : off; + if (!simple_singleplayer_mode) { + if (damage) { + const std::string &pvp = g_settings->getBool("enable_pvp") ? on : off; + //~ PvP = Player versus Player + os << strgettext("- PvP: ") << pvp << "\n"; + } + os << strgettext("- Public: ") << announced << "\n"; + std::string server_name = g_settings->get("server_name"); + str_formspec_escape(server_name); + if (announced == on && !server_name.empty()) + os << strgettext("- Server Name: ") << server_name; + + } + } + os << ";]"; + + /* Create menu */ + /* Note: FormspecFormSource and LocalFormspecHandler * + * are deleted by guiFormSpecMenu */ + FormspecFormSource *fs_src = new FormspecFormSource(os.str()); + LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU"); + + GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(), + &m_input->joystick, fs_src, txt_dst, m_client->getFormspecPrepend(), + m_client->getSoundManager()); + m_formspec->setFocus("btn_continue"); + // game will be paused in next step, if in singleplayer (see m_is_paused) + m_formspec->doPause = true; +} + +void GameFormSpec::showDeathFormspecLegacy() +{ + static std::string formspec_str = + std::string("formspec_version[1]") + + SIZE_TAG + "bgcolor[#320000b4;true]" + "label[4.85,1.35;" + gettext("You died") + "]" + "button_exit[4,3;3,0.5;btn_respawn;" + gettext("Respawn") + "]" + ; + + /* Create menu */ + /* Note: FormspecFormSource and LocalFormspecHandler * + * are deleted by guiFormSpecMenu */ + FormspecFormSource *fs_src = new FormspecFormSource(formspec_str); + LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", m_client); + + GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(), + &m_input->joystick, fs_src, txt_dst, m_client->getFormspecPrepend(), + m_client->getSoundManager()); + m_formspec->setFocus("btn_respawn"); +} + +void GameFormSpec::update() +{ + /* + make sure menu is on top + 1. Delete formspec menu reference if menu was removed + 2. Else, make sure formspec menu is on top + */ + if (!m_formspec) + return; + + if (m_formspec->getReferenceCount() == 1) { + // See GUIFormSpecMenu::create what refcnt = 1 means + this->deleteFormspec(); + return; + } + + auto &loc = m_formspec->getFormspecLocation(); + if (loc.type == InventoryLocation::NODEMETA) { + NodeMetadata *meta = m_client->getEnv().getClientMap().getNodeMetadata(loc.p); + if (!meta || meta->getString("formspec").empty()) { + m_formspec->quitMenu(); + return; + } + } + + if (isMenuActive()) + guiroot->bringToFront(m_formspec); +} + +void GameFormSpec::disableDebugView() +{ + if (m_formspec) { + m_formspec->setDebugView(false); + } +} + +/* returns false if game should exit, otherwise true + */ +bool GameFormSpec::handleCallbacks() +{ + auto texture_src = m_client->getTextureSource(); + + if (g_gamecallback->disconnect_requested) { + g_gamecallback->disconnect_requested = false; + return false; + } + + if (g_gamecallback->changepassword_requested) { + (void)make_irr(guienv, guiroot, -1, + &g_menumgr, m_client, texture_src); + g_gamecallback->changepassword_requested = false; + } + + if (g_gamecallback->changevolume_requested) { + (void)make_irr(guienv, guiroot, -1, + &g_menumgr, texture_src); + g_gamecallback->changevolume_requested = false; + } + + if (g_gamecallback->keyconfig_requested) { + (void)make_irr(guienv, guiroot, -1, + &g_menumgr, texture_src); + g_gamecallback->keyconfig_requested = false; + } + + if (g_gamecallback->touchscreenlayout_requested) { + (new GUITouchscreenLayout(guienv, guiroot, -1, + &g_menumgr, texture_src))->drop(); + g_gamecallback->touchscreenlayout_requested = false; + } + + if (!g_gamecallback->show_open_url_dialog.empty()) { + (void)make_irr(guienv, guiroot, -1, + &g_menumgr, texture_src, g_gamecallback->show_open_url_dialog); + g_gamecallback->show_open_url_dialog.clear(); + } + + if (g_gamecallback->keyconfig_changed) { + m_input->keycache.populate(); // update the cache with new settings + g_gamecallback->keyconfig_changed = false; + } + + return true; +} + +#ifdef __ANDROID__ +bool GameFormSpec::handleAndroidUIInput() +{ + if (m_formspec) { + m_formspec->getAndroidUIInput(); + return true; + } + return false; +} +#endif diff --git a/src/client/game_formspec.h b/src/client/game_formspec.h new file mode 100644 index 000000000..370370151 --- /dev/null +++ b/src/client/game_formspec.h @@ -0,0 +1,62 @@ +// Luanti +// SPDX-License-Identifier: LGPL-2.1-or-later +// Copyright (C) 2024 cx384 + +#pragma once + +#include +#include "irr_v3d.h" + +class Client; +class RenderingEngine; +class InputHandler; +class ISoundManager; +class GUIFormSpecMenu; + +/* +This object intend to contain the core fromspec functionality. +It includes: + - methods to show specific formspec menus + - storing the opened fromspec + - handling fromspec related callbacks + */ +struct GameFormSpec +{ + void init(Client *client, RenderingEngine *rendering_engine, InputHandler *input) + { + m_client = client; + m_rendering_engine = rendering_engine; + m_input = input; + } + + ~GameFormSpec(); + + void showFormSpec(const std::string &formspec, const std::string &formname); + void showLocalFormSpec(const std::string &formspec, const std::string &formname); + void showNodeFormspec(const std::string &formspec, const v3s16 &nodepos); + void showPlayerInventory(); + void showDeathFormspecLegacy(); + void showPauseMenu(); + + void update(); + void disableDebugView(); + + bool handleCallbacks(); + +#ifdef __ANDROID__ + // Returns false if no formspec open + bool handleAndroidUIInput(); +#endif + +private: + Client *m_client; + RenderingEngine *m_rendering_engine; + InputHandler *m_input; + + // Default: "". If other than "": Empty show_formspec packets will only + // close the formspec when the formname matches + std::string m_formname; + GUIFormSpecMenu *m_formspec = nullptr; + + void deleteFormspec(); +}; diff --git a/src/client/gameui.cpp b/src/client/gameui.cpp index c2693c6ae..e09875934 100644 --- a/src/client/gameui.cpp +++ b/src/client/gameui.cpp @@ -8,7 +8,6 @@ #include #include "gui/mainmenumanager.h" #include "gui/guiChatConsole.h" -#include "gui/guiFormSpecMenu.h" #include "gui/touchcontrols.h" #include "util/enriched_string.h" #include "util/pointedthing.h" @@ -319,17 +318,6 @@ void GameUI::toggleProfiler() } } - -void GameUI::deleteFormspec() -{ - if (m_formspec) { - m_formspec->drop(); - m_formspec = nullptr; - } - - m_formname.clear(); -} - void GameUI::clearText() { if (m_guitext_chat) { diff --git a/src/client/gameui.h b/src/client/gameui.h index 95674232a..03cbb3b2c 100644 --- a/src/client/gameui.h +++ b/src/client/gameui.h @@ -13,7 +13,6 @@ using namespace irr; class Client; class EnrichedString; class GUIChatConsole; -class GUIFormSpecMenu; struct MapDrawControl; struct PointedThing; @@ -79,15 +78,6 @@ public: void toggleHud(); void toggleProfiler(); - GUIFormSpecMenu *&updateFormspec(const std::string &formname) - { - m_formname = formname; - return m_formspec; - } - - const std::string &getFormspecName() { return m_formname; } - GUIFormSpecMenu *&getFormspecGUI() { return m_formspec; } - void deleteFormspec(); void clearText(); private: @@ -113,9 +103,4 @@ private: gui::IGUIStaticText *m_guitext_profiler = nullptr; // Profiler text u8 m_profiler_current_page = 0; const u8 m_profiler_max_page = 3; - - // Default: "". If other than "": Empty show_formspec packets will only - // close the formspec when the formname matches - std::string m_formname; - GUIFormSpecMenu *m_formspec = nullptr; };