aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt38
-rw-r--r--src/client/camera.cpp6
-rw-r--r--src/client/camera.h3
-rw-r--r--src/client/client.cpp55
-rw-r--r--src/client/client.h6
-rw-r--r--src/client/clientenvironment.cpp28
-rw-r--r--src/client/clientlauncher.cpp59
-rw-r--r--src/client/clientlauncher.h1
-rw-r--r--src/client/clientmap.cpp16
-rw-r--r--src/client/clientmap.h1
-rw-r--r--src/client/clientmedia.cpp8
-rw-r--r--src/client/clientmedia.h1
-rw-r--r--src/client/clientobject.h2
-rw-r--r--src/client/clouds.cpp4
-rw-r--r--src/client/clouds.h3
-rw-r--r--src/client/content_cao.cpp41
-rw-r--r--src/client/content_cao.h4
-rw-r--r--src/client/content_mapblock.cpp32
-rw-r--r--src/client/content_mapblock.h5
-rw-r--r--src/client/fontengine.cpp95
-rw-r--r--src/client/fontengine.h8
-rw-r--r--src/client/game.cpp134
-rw-r--r--src/client/game.h31
-rw-r--r--src/client/gameui.cpp15
-rw-r--r--src/client/guiscalingfilter.cpp5
-rw-r--r--src/client/hud.cpp122
-rw-r--r--src/client/hud.h27
-rw-r--r--src/client/imagefilters.cpp107
-rw-r--r--src/client/imagefilters.h6
-rw-r--r--src/client/inputhandler.cpp1
-rw-r--r--src/client/keycode.cpp2
-rw-r--r--src/client/keys.h1
-rw-r--r--src/client/mapblock_mesh.cpp4
-rw-r--r--src/client/mesh.cpp8
-rw-r--r--src/client/minimap.cpp5
-rw-r--r--src/client/particles.cpp4
-rw-r--r--src/client/render/core.cpp1
-rw-r--r--src/client/renderingengine.cpp32
-rw-r--r--src/client/renderingengine.h85
-rw-r--r--src/client/shader.cpp12
-rw-r--r--src/client/sky.cpp35
-rw-r--r--src/client/sky.h24
-rw-r--r--src/client/tile.cpp46
-rw-r--r--src/client/tile.h3
-rw-r--r--src/client/wieldmesh.cpp27
-rw-r--r--src/clientiface.cpp1
-rw-r--r--src/clientiface.h1
-rw-r--r--src/convert_json.cpp47
-rw-r--r--src/convert_json.h3
-rw-r--r--src/defaultsettings.cpp8
-rw-r--r--src/filesys.cpp64
-rw-r--r--src/filesys.h6
-rw-r--r--src/gui/cheatMenu.cpp2
-rw-r--r--src/gui/guiButtonItemImage.cpp4
-rw-r--r--src/gui/guiButtonItemImage.h6
-rw-r--r--src/gui/guiChatConsole.cpp9
-rw-r--r--src/gui/guiChatConsole.h2
-rw-r--r--src/gui/guiEditBox.cpp67
-rw-r--r--src/gui/guiEditBox.h3
-rw-r--r--src/gui/guiEngine.cpp31
-rw-r--r--src/gui/guiEngine.h3
-rw-r--r--src/gui/guiFormSpecMenu.cpp14
-rw-r--r--src/gui/guiFormSpecMenu.h6
-rw-r--r--src/gui/guiKeyChangeMenu.cpp88
-rw-r--r--src/httpfetch.cpp21
-rw-r--r--src/inventory.cpp7
-rw-r--r--src/irrlicht_changes/CGUITTFont.cpp111
-rw-r--r--src/irrlicht_changes/CGUITTFont.h12
-rw-r--r--src/irrlicht_changes/CMakeLists.txt2
-rw-r--r--src/irrlicht_changes/irrUString.h3891
-rw-r--r--src/irrlicht_changes/static_text.cpp11
-rw-r--r--src/irrlicht_changes/static_text.h4
-rw-r--r--src/irrlichttypes.h26
-rw-r--r--src/main.cpp3
-rw-r--r--src/mapnode.cpp26
-rw-r--r--src/mapnode.h3
-rw-r--r--src/network/serverpackethandler.cpp6
-rw-r--r--src/nodedef.cpp17
-rw-r--r--src/nodedef.h10
-rw-r--r--src/nodemetadata.cpp16
-rw-r--r--src/pathfinder.cpp2
-rw-r--r--src/script/common/c_content.cpp3
-rw-r--r--src/script/common/c_content.h4
-rw-r--r--src/script/cpp_api/s_node.cpp1
-rw-r--r--src/script/cpp_api/s_security.cpp44
-rw-r--r--src/script/lua_api/l_mainmenu.cpp117
-rw-r--r--src/script/lua_api/l_mainmenu.h2
-rw-r--r--src/script/lua_api/l_util.cpp24
-rw-r--r--src/script/lua_api/l_util.h3
-rw-r--r--src/server/unit_sao.cpp11
-rw-r--r--src/settings.cpp5
-rw-r--r--src/unittest/test_clientactiveobjectmgr.cpp1
-rw-r--r--src/util/areastore.cpp9
-rw-r--r--src/util/container.h23
-rw-r--r--src/util/enriched_string.cpp10
-rw-r--r--src/util/enriched_string.h34
-rw-r--r--src/util/string.cpp415
-rw-r--r--src/voxelalgorithms.cpp14
-rw-r--r--src/voxelalgorithms.h2
99 files changed, 1357 insertions, 5051 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8a6eabccc..9526e88f9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -55,7 +55,7 @@ if(NOT USE_CURL)
endif()
-option(ENABLE_GETTEXT "Use GetText for internationalization" TRUE)
+option(ENABLE_GETTEXT "Use GetText for internationalization" ${BUILD_CLIENT})
set(USE_GETTEXT FALSE)
if(ENABLE_GETTEXT)
@@ -102,11 +102,11 @@ endif()
option(ENABLE_GLES "Use OpenGL ES instead of OpenGL" FALSE)
mark_as_advanced(ENABLE_GLES)
if(BUILD_CLIENT)
- if(ENABLE_GLES)
- find_package(OpenGLES2 REQUIRED)
- else()
- # transitive dependency from Irrlicht (see longer explanation below)
- if(NOT WIN32)
+ # transitive dependency from Irrlicht (see longer explanation below)
+ if(NOT WIN32)
+ if(ENABLE_GLES)
+ find_package(OpenGLES2 REQUIRED)
+ else()
set(OPENGL_GL_PREFERENCE "LEGACY" CACHE STRING
"See CMake Policy CMP0072 for reference. GLVND is broken on some nvidia setups")
set(OpenGL_GL_PREFERENCE ${OPENGL_GL_PREFERENCE})
@@ -120,13 +120,13 @@ endif()
option(ENABLE_FREETYPE "Enable FreeType2 (TrueType fonts and basic unicode support)" TRUE)
set(USE_FREETYPE FALSE)
-if(ENABLE_FREETYPE)
+if(BUILD_CLIENT AND ENABLE_FREETYPE)
find_package(Freetype)
if(FREETYPE_FOUND)
message(STATUS "Freetype enabled.")
set(USE_FREETYPE TRUE)
endif()
-endif(ENABLE_FREETYPE)
+endif()
option(ENABLE_CURSES "Enable ncurses console" TRUE)
set(USE_CURSES FALSE)
@@ -146,7 +146,17 @@ option(ENABLE_POSTGRESQL "Enable PostgreSQL backend" TRUE)
set(USE_POSTGRESQL FALSE)
if(ENABLE_POSTGRESQL)
- find_package("PostgreSQL")
+ if(CMAKE_VERSION VERSION_LESS "3.20")
+ find_package(PostgreSQL QUIET)
+ # Before CMake 3.20 FindPostgreSQL.cmake always looked for server includes
+ # but we don't need them, so continue anyway if only those are missing.
+ if(PostgreSQL_INCLUDE_DIR AND PostgreSQL_LIBRARY)
+ set(PostgreSQL_FOUND TRUE)
+ set(PostgreSQL_INCLUDE_DIRS ${PostgreSQL_INCLUDE_DIR})
+ endif()
+ else()
+ find_package(PostgreSQL)
+ endif()
if(PostgreSQL_FOUND)
set(USE_POSTGRESQL TRUE)
@@ -526,8 +536,11 @@ if(USE_CURL)
endif()
-set(EXECUTABLE_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/bin")
-
+# When cross-compiling assume the user doesn't want to run the executable anyway,
+# otherwise place it in <source dir>/bin/ since Minetest can only run from there.
+if(NOT CMAKE_CROSSCOMPILING)
+ set(EXECUTABLE_OUTPUT_PATH "${CMAKE_SOURCE_DIR}/bin")
+endif()
if(BUILD_CLIENT)
add_executable(${PROJECT_NAME} ${client_SRCS} ${extra_windows_SRCS})
@@ -668,7 +681,10 @@ endif(BUILD_SERVER)
# see issue #4638
set(GETTEXT_BLACKLISTED_LOCALES
ar
+ dv
he
+ hi
+ kn
ky
ms_Arab
th
diff --git a/src/client/camera.cpp b/src/client/camera.cpp
index 854d9eae8..52bedcba9 100644
--- a/src/client/camera.cpp
+++ b/src/client/camera.cpp
@@ -44,11 +44,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define WIELDMESH_AMPLITUDE_X 7.0f
#define WIELDMESH_AMPLITUDE_Y 10.0f
-Camera::Camera(MapDrawControl &draw_control, Client *client):
+Camera::Camera(MapDrawControl &draw_control, Client *client, RenderingEngine *rendering_engine):
m_draw_control(draw_control),
m_client(client)
{
- scene::ISceneManager *smgr = RenderingEngine::get_scene_manager();
+ auto smgr = rendering_engine->get_scene_manager();
// note: making the camera node a child of the player node
// would lead to unexpected behaviour, so we don't do that.
m_playernode = smgr->addEmptySceneNode(smgr->getRootSceneNode());
@@ -542,7 +542,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, f32 tool_r
m_curr_fov_degrees = rangelim(m_curr_fov_degrees, 1.0f, 160.0f);
// FOV and aspect ratio
- const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
+ const v2u32 &window_size = RenderingEngine::getWindowSize();
m_aspect = (f32) window_size.X / (f32) window_size.Y;
m_fov_y = m_curr_fov_degrees * M_PI / 180.0;
// Increase vertical FOV on lower aspect ratios (<16:10)
diff --git a/src/client/camera.h b/src/client/camera.h
index c162df515..30fac5289 100644
--- a/src/client/camera.h
+++ b/src/client/camera.h
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class LocalPlayer;
struct MapDrawControl;
class Client;
+class RenderingEngine;
class WieldMeshSceneNode;
struct Nametag
@@ -104,7 +105,7 @@ enum CameraMode {CAMERA_MODE_FIRST, CAMERA_MODE_THIRD, CAMERA_MODE_THIRD_FRONT};
class Camera
{
public:
- Camera(MapDrawControl &draw_control, Client *client);
+ Camera(MapDrawControl &draw_control, Client *client, RenderingEngine *rendering_engine);
~Camera();
// Get camera scene node.
diff --git a/src/client/client.cpp b/src/client/client.cpp
index e6025ed7b..57f8e6593 100644
--- a/src/client/client.cpp
+++ b/src/client/client.cpp
@@ -98,6 +98,7 @@ Client::Client(
NodeDefManager *nodedef,
ISoundManager *sound,
MtEventManager *event,
+ RenderingEngine *rendering_engine,
bool ipv6,
GameUI *game_ui
):
@@ -108,8 +109,9 @@ Client::Client(
m_nodedef(nodedef),
m_sound(sound),
m_event(event),
+ m_rendering_engine(rendering_engine),
m_env(
- new ClientMap(this, control, 666),
+ new ClientMap(this, rendering_engine, control, 666),
tsrc, this
),
m_particle_manager(&m_env),
@@ -301,12 +303,7 @@ Client::~Client()
}
// cleanup 3d model meshes on client shutdown
- while (RenderingEngine::get_mesh_cache()->getMeshCount() != 0) {
- scene::IAnimatedMesh *mesh = RenderingEngine::get_mesh_cache()->getMeshByIndex(0);
-
- if (mesh)
- RenderingEngine::get_mesh_cache()->removeMesh(mesh);
- }
+ m_rendering_engine->cleanupMeshCache();
delete m_minimap;
m_minimap = nullptr;
@@ -663,18 +660,11 @@ bool Client::loadMedia(const std::string &data, const std::string &filename,
TRACESTREAM(<< "Client: Attempting to load image "
<< "file \"" << filename << "\"" << std::endl);
- io::IFileSystem *irrfs = RenderingEngine::get_filesystem();
- video::IVideoDriver *vdrv = RenderingEngine::get_video_driver();
+ io::IFileSystem *irrfs = m_rendering_engine->get_filesystem();
+ video::IVideoDriver *vdrv = m_rendering_engine->get_video_driver();
-#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8
io::IReadFile *rfile = irrfs->createMemoryReadFile(
data.c_str(), data.size(), "_tempreadfile");
-#else
- // Silly irrlicht's const-incorrectness
- Buffer<char> data_rw(data.c_str(), data.size());
- io::IReadFile *rfile = irrfs->createMemoryReadFile(
- *data_rw, data_rw.getSize(), "_tempreadfile");
-#endif
FATAL_ERROR_IF(!rfile, "Could not create irrlicht memory file.");
@@ -1430,6 +1420,11 @@ bool Client::updateWieldedItem()
return true;
}
+scene::ISceneManager* Client::getSceneManager()
+{
+ return m_rendering_engine->get_scene_manager();
+}
+
Inventory* Client::getInventory(const InventoryLocation &loc)
{
switch(loc.type){
@@ -1692,7 +1687,7 @@ typedef struct TextureUpdateArgs {
ITextureSource *tsrc;
} TextureUpdateArgs;
-void texture_update_progress(void *args, u32 progress, u32 max_progress)
+void Client::showUpdateProgressTexture(void *args, u32 progress, u32 max_progress)
{
TextureUpdateArgs* targs = (TextureUpdateArgs*) args;
u16 cur_percent = ceil(progress / (double) max_progress * 100.);
@@ -1711,7 +1706,7 @@ void texture_update_progress(void *args, u32 progress, u32 max_progress)
targs->last_time_ms = time_ms;
std::basic_stringstream<wchar_t> strm;
strm << targs->text_base << " " << targs->last_percent << "%...";
- RenderingEngine::draw_load_screen(strm.str(), targs->guienv, targs->tsrc, 0,
+ m_rendering_engine->draw_load_screen(strm.str(), targs->guienv, targs->tsrc, 0,
72 + (u16) ((18. / 100.) * (double) targs->last_percent), true);
}
}
@@ -1732,21 +1727,21 @@ void Client::afterContentReceived()
// Rebuild inherited images and recreate textures
infostream<<"- Rebuilding images and textures"<<std::endl;
- RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 70);
+ m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 70);
m_tsrc->rebuildImagesAndTextures();
delete[] text;
// Rebuild shaders
infostream<<"- Rebuilding shaders"<<std::endl;
text = wgettext("Rebuilding shaders...");
- RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 71);
+ m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 71);
m_shsrc->rebuildShaders();
delete[] text;
// Update node aliases
infostream<<"- Updating node aliases"<<std::endl;
text = wgettext("Initializing nodes...");
- RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 72);
+ m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 72);
m_nodedef->updateAliases(m_itemdef);
for (const auto &path : getTextureDirs()) {
TextureOverrideSource override_source(path + DIR_DELIM + "override.txt");
@@ -1765,7 +1760,7 @@ void Client::afterContentReceived()
tu_args.last_percent = 0;
tu_args.text_base = wgettext("Initializing nodes");
tu_args.tsrc = m_tsrc;
- m_nodedef->updateTextures(this, texture_update_progress, &tu_args);
+ m_nodedef->updateTextures(this, &tu_args);
delete[] tu_args.text_base;
// Start mesh update thread after setting up content definitions
@@ -1779,7 +1774,7 @@ void Client::afterContentReceived()
m_script->on_client_ready(m_env.getLocalPlayer());
text = wgettext("Done!");
- RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 100);
+ m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 100);
infostream<<"Client::afterContentReceived() done"<<std::endl;
delete[] text;
}
@@ -1797,7 +1792,7 @@ float Client::getCurRate()
void Client::makeScreenshot()
{
- irr::video::IVideoDriver *driver = RenderingEngine::get_video_driver();
+ irr::video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
irr::video::IImage* const raw_image = driver->createScreenShot();
if (!raw_image)
@@ -1947,23 +1942,17 @@ scene::IAnimatedMesh* Client::getMesh(const std::string &filename, bool cache)
// Create the mesh, remove it from cache and return it
// This allows unique vertex colors and other properties for each instance
-#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8
- io::IReadFile *rfile = RenderingEngine::get_filesystem()->createMemoryReadFile(
+ io::IReadFile *rfile = m_rendering_engine->get_filesystem()->createMemoryReadFile(
data.c_str(), data.size(), filename.c_str());
-#else
- Buffer<char> data_rw(data.c_str(), data.size()); // Const-incorrect Irrlicht
- io::IReadFile *rfile = RenderingEngine::get_filesystem()->createMemoryReadFile(
- *data_rw, data_rw.getSize(), filename.c_str());
-#endif
FATAL_ERROR_IF(!rfile, "Could not create/open RAM file");
- scene::IAnimatedMesh *mesh = RenderingEngine::get_scene_manager()->getMesh(rfile);
+ scene::IAnimatedMesh *mesh = m_rendering_engine->get_scene_manager()->getMesh(rfile);
rfile->drop();
if (!mesh)
return nullptr;
mesh->grab();
if (!cache)
- RenderingEngine::get_mesh_cache()->removeMesh(mesh);
+ m_rendering_engine->removeMesh(mesh);
return mesh;
}
diff --git a/src/client/client.h b/src/client/client.h
index 3e346369b..8d7f63c0c 100644
--- a/src/client/client.h
+++ b/src/client/client.h
@@ -45,6 +45,7 @@ struct ClientEvent;
struct MeshMakeData;
struct ChatMessage;
class MapBlockMesh;
+class RenderingEngine;
class IWritableTextureSource;
class IWritableShaderSource;
class ISoundManager;
@@ -122,6 +123,7 @@ public:
NodeDefManager *nodedef,
ISoundManager *sound,
MtEventManager *event,
+ RenderingEngine *rendering_engine,
bool ipv6,
GameUI *game_ui
);
@@ -346,6 +348,7 @@ public:
float mediaReceiveProgress();
void afterContentReceived();
+ void showUpdateProgressTexture(void *args, u32 progress, u32 max_progress);
float getRTT();
float getCurRate();
@@ -354,6 +357,7 @@ public:
void setCamera(Camera* camera) { m_camera = camera; }
Camera* getCamera () { return m_camera; }
+ scene::ISceneManager *getSceneManager();
bool shouldShowMinimap() const;
@@ -381,6 +385,7 @@ public:
// Insert a media file appropriately into the appropriate manager
bool loadMedia(const std::string &data, const std::string &filename,
bool from_media_push = false);
+
// Send a request for conventional media transfer
void request_media(const std::vector<std::string> &file_requests);
@@ -476,6 +481,7 @@ private:
NodeDefManager *m_nodedef;
ISoundManager *m_sound;
MtEventManager *m_event;
+ RenderingEngine *m_rendering_engine;
ClientEnvironment m_env;
diff --git a/src/client/clientenvironment.cpp b/src/client/clientenvironment.cpp
index 8e0d00bc9..f9c20b2df 100644
--- a/src/client/clientenvironment.cpp
+++ b/src/client/clientenvironment.cpp
@@ -235,7 +235,16 @@ void ClientEnvironment::step(float dtime)
&player_collisions);
}
- bool player_immortal = lplayer->getCAO() && lplayer->getCAO()->isImmortal();
+ bool player_immortal = false;
+ f32 player_fall_factor = 1.0f;
+ GenericCAO *playercao = lplayer->getCAO();
+ if (playercao) {
+ player_immortal = playercao->isImmortal();
+ int addp_p = itemgroup_get(playercao->getGroups(),
+ "fall_damage_add_percent");
+ // convert armor group into an usable fall damage factor
+ player_fall_factor = 1.0f + (float)addp_p / 100.0f;
+ }
for (const CollisionInfo &info : player_collisions) {
v3f speed_diff = info.new_speed - info.old_speed;;
@@ -248,17 +257,20 @@ void ClientEnvironment::step(float dtime)
speed_diff.Z = 0;
f32 pre_factor = 1; // 1 hp per node/s
f32 tolerance = BS*14; // 5 without damage
- f32 post_factor = 1; // 1 hp per node/s
if (info.type == COLLISION_NODE) {
const ContentFeatures &f = m_client->ndef()->
get(m_map->getNode(info.node_p));
- // Determine fall damage multiplier
- int addp = itemgroup_get(f.groups, "fall_damage_add_percent");
- pre_factor = 1.0f + (float)addp / 100.0f;
+ // Determine fall damage modifier
+ int addp_n = itemgroup_get(f.groups, "fall_damage_add_percent");
+ // convert node group to an usable fall damage factor
+ f32 node_fall_factor = 1.0f + (float)addp_n / 100.0f;
+ // combine both player fall damage modifiers
+ pre_factor = node_fall_factor * player_fall_factor;
}
float speed = pre_factor * speed_diff.getLength();
- if (speed > tolerance && !player_immortal) {
- f32 damage_f = (speed - tolerance) / BS * post_factor;
+
+ if (speed > tolerance && !player_immortal && pre_factor > 0.0f) {
+ f32 damage_f = (speed - tolerance) / BS;
u16 damage = (u16)MYMIN(damage_f + 0.5, U16_MAX);
if (damage != 0) {
damageLocalPlayer(damage, true);
@@ -340,7 +352,7 @@ u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
if (!m_ao_manager.registerObject(object))
return 0;
- object->addToScene(m_texturesource);
+ object->addToScene(m_texturesource, m_client->getSceneManager());
// Update lighting immediately
object->updateLight(getDayNightRatio());
diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp
index 2bb0bc385..6db5f2e70 100644
--- a/src/client/clientlauncher.cpp
+++ b/src/client/clientlauncher.cpp
@@ -80,7 +80,7 @@ ClientLauncher::~ClientLauncher()
delete g_fontengine;
delete g_gamecallback;
- delete RenderingEngine::get_instance();
+ delete m_rendering_engine;
#if USE_SOUND
g_sound_manager_singleton.reset();
@@ -101,7 +101,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
// List video modes if requested
if (list_video_modes)
- return RenderingEngine::print_video_modes();
+ return m_rendering_engine->print_video_modes();
#if USE_SOUND
if (g_settings->getBool("enable_sound"))
@@ -120,12 +120,12 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
return true;
}
- if (RenderingEngine::get_video_driver() == NULL) {
+ if (m_rendering_engine->get_video_driver() == NULL) {
errorstream << "Could not initialize video driver." << std::endl;
return false;
}
- RenderingEngine::get_instance()->setupTopLevelWindow(PROJECT_NAME_C);
+ m_rendering_engine->setupTopLevelWindow(PROJECT_NAME_C);
/*
This changes the minimum allowed number of vertices in a VBO.
@@ -136,15 +136,15 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
// Create game callback for menus
g_gamecallback = new MainGameCallback();
- RenderingEngine::get_instance()->setResizable(true);
+ m_rendering_engine->setResizable(true);
init_input();
- RenderingEngine::get_scene_manager()->getParameters()->
+ m_rendering_engine->get_scene_manager()->getParameters()->
setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true);
- guienv = RenderingEngine::get_gui_env();
- skin = RenderingEngine::get_gui_env()->getSkin();
+ guienv = m_rendering_engine->get_gui_env();
+ skin = guienv->getSkin();
skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255, 255, 255, 255));
skin->setColor(gui::EGDC_3D_LIGHT, video::SColor(0, 0, 0, 0));
skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255, 30, 30, 30));
@@ -166,7 +166,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
sprite_path.append("checkbox_16.png");
// Texture dimensions should be a power of 2
gui::IGUISpriteBank *sprites = skin->getSpriteBank();
- video::IVideoDriver *driver = RenderingEngine::get_video_driver();
+ video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
video::ITexture *sprite_texture = driver->getTexture(sprite_path.c_str());
if (sprite_texture) {
s32 sprite_id = sprites->addTextureAsSprite(sprite_texture);
@@ -178,15 +178,13 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
g_fontengine = new FontEngine(guienv);
FATAL_ERROR_IF(g_fontengine == NULL, "Font engine creation failed.");
-#if (IRRLICHT_VERSION_MAJOR >= 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2
// Irrlicht 1.8 input colours
skin->setColor(gui::EGDC_EDITABLE, video::SColor(255, 128, 128, 128));
skin->setColor(gui::EGDC_FOCUSED_EDITABLE, video::SColor(255, 96, 134, 49));
-#endif
// Create the menu clouds
if (!g_menucloudsmgr)
- g_menucloudsmgr = RenderingEngine::get_scene_manager()->createNewSceneManager();
+ g_menucloudsmgr = m_rendering_engine->get_scene_manager()->createNewSceneManager();
if (!g_menuclouds)
g_menuclouds = new Clouds(g_menucloudsmgr, -1, rand());
g_menuclouds->setHeight(100.0f);
@@ -214,11 +212,11 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
bool retval = true;
bool *kill = porting::signal_handler_killstatus();
- while (RenderingEngine::run() && !*kill &&
+ while (m_rendering_engine->run() && !*kill &&
!g_gamecallback->shutdown_requested) {
// Set the window caption
const wchar_t *text = wgettext("Main Menu");
- RenderingEngine::get_raw_device()->
+ m_rendering_engine->get_raw_device()->
setWindowCaption((utf8_to_wide(PROJECT_NAME_C) +
L" " + utf8_to_wide(g_version_hash) +
L" [" + text + L"]").c_str());
@@ -226,14 +224,14 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
try { // This is used for catching disconnects
- RenderingEngine::get_gui_env()->clear();
+ m_rendering_engine->get_gui_env()->clear();
/*
We need some kind of a root node to be able to add
custom gui elements directly on the screen.
Otherwise they won't be automatically drawn.
*/
- guiroot = RenderingEngine::get_gui_env()->addStaticText(L"",
+ guiroot = m_rendering_engine->get_gui_env()->addStaticText(L"",
core::rect<s32>(0, 0, 10000, 10000));
bool game_has_run = launch_game(error_message, reconnect_requested,
@@ -256,29 +254,30 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
}
// Break out of menu-game loop to shut down cleanly
- if (!RenderingEngine::get_raw_device()->run() || *kill) {
+ if (!m_rendering_engine->run() || *kill) {
if (!g_settings_path.empty())
g_settings->updateConfigFile(g_settings_path.c_str());
break;
}
- RenderingEngine::get_video_driver()->setTextureCreationFlag(
+ m_rendering_engine->get_video_driver()->setTextureCreationFlag(
video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map"));
#ifdef HAVE_TOUCHSCREENGUI
- receiver->m_touchscreengui = new TouchScreenGUI(RenderingEngine::get_raw_device(), receiver);
+ receiver->m_touchscreengui = new TouchScreenGUI(m_rendering_engine->get_raw_device(), receiver);
g_touchscreengui = receiver->m_touchscreengui;
#endif
the_game(
kill,
input,
+ m_rendering_engine,
start_data,
error_message,
chat_backend,
&reconnect_requested
);
- RenderingEngine::get_scene_manager()->clear();
+ m_rendering_engine->get_scene_manager()->clear();
#ifdef HAVE_TOUCHSCREENGUI
delete g_touchscreengui;
@@ -346,8 +345,8 @@ void ClientLauncher::init_args(GameStartData &start_data, const Settings &cmd_ar
bool ClientLauncher::init_engine()
{
receiver = new MyEventReceiver();
- new RenderingEngine(receiver);
- return RenderingEngine::get_raw_device() != nullptr;
+ m_rendering_engine = new RenderingEngine(receiver);
+ return m_rendering_engine->get_raw_device() != nullptr;
}
void ClientLauncher::init_input()
@@ -364,7 +363,7 @@ void ClientLauncher::init_input()
// Make sure this is called maximum once per
// irrlicht device, otherwise it will give you
// multiple events for the same joystick.
- if (RenderingEngine::get_raw_device()->activateJoysticks(infos)) {
+ if (m_rendering_engine->get_raw_device()->activateJoysticks(infos)) {
infostream << "Joystick support enabled" << std::endl;
joystick_infos.reserve(infos.size());
for (u32 i = 0; i < infos.size(); i++) {
@@ -471,7 +470,7 @@ bool ClientLauncher::launch_game(std::string &error_message,
start_data.address.empty() && !start_data.name.empty();
}
- if (!RenderingEngine::run())
+ if (!m_rendering_engine->run())
return false;
if (!start_data.isSinglePlayer() && start_data.name.empty()) {
@@ -543,14 +542,14 @@ bool ClientLauncher::launch_game(std::string &error_message,
void ClientLauncher::main_menu(MainMenuData *menudata)
{
bool *kill = porting::signal_handler_killstatus();
- video::IVideoDriver *driver = RenderingEngine::get_video_driver();
+ video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
infostream << "Waiting for other menus" << std::endl;
- while (RenderingEngine::get_raw_device()->run() && !*kill) {
+ while (m_rendering_engine->run() && !*kill) {
if (!isMenuActive())
break;
driver->beginScene(true, true, video::SColor(255, 128, 128, 128));
- RenderingEngine::get_gui_env()->drawAll();
+ m_rendering_engine->get_gui_env()->drawAll();
driver->endScene();
// On some computers framerate doesn't seem to be automatically limited
sleep_ms(25);
@@ -559,14 +558,14 @@ void ClientLauncher::main_menu(MainMenuData *menudata)
// Cursor can be non-visible when coming from the game
#ifndef ANDROID
- RenderingEngine::get_raw_device()->getCursorControl()->setVisible(true);
+ m_rendering_engine->get_raw_device()->getCursorControl()->setVisible(true);
#endif
/* show main menu */
- GUIEngine mymenu(&input->joystick, guiroot, &g_menumgr, menudata, *kill);
+ GUIEngine mymenu(&input->joystick, guiroot, m_rendering_engine, &g_menumgr, menudata, *kill);
/* leave scene manager in a clean state */
- RenderingEngine::get_scene_manager()->clear();
+ m_rendering_engine->get_scene_manager()->clear();
}
void ClientLauncher::speed_tests()
diff --git a/src/client/clientlauncher.h b/src/client/clientlauncher.h
index b280d8e6b..79727e1fe 100644
--- a/src/client/clientlauncher.h
+++ b/src/client/clientlauncher.h
@@ -49,6 +49,7 @@ private:
bool list_video_modes = false;
bool skip_main_menu = false;
bool random_input = false;
+ RenderingEngine *m_rendering_engine = nullptr;
InputHandler *input = nullptr;
MyEventReceiver *receiver = nullptr;
gui::IGUISkin *skin = nullptr;
diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp
index 6110c90e3..29a7fd3ba 100644
--- a/src/client/clientmap.cpp
+++ b/src/client/clientmap.cpp
@@ -64,12 +64,13 @@ void MeshBufListList::add(scene::IMeshBuffer *buf, v3s16 position, u8 layer)
ClientMap::ClientMap(
Client *client,
+ RenderingEngine *rendering_engine,
MapDrawControl &control,
s32 id
):
Map(client),
- scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(),
- RenderingEngine::get_scene_manager(), id),
+ scene::ISceneNode(rendering_engine->get_scene_manager()->getRootSceneNode(),
+ rendering_engine->get_scene_manager(), id),
m_client(client),
m_control(control)
{
@@ -317,7 +318,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
v3f block_pos_r = intToFloat(block->getPosRelative() + MAP_BLOCKSIZE / 2, BS);
float d = camera_position.getDistanceFrom(block_pos_r);
d = MYMAX(0,d - BLOCK_MAX_RADIUS);
-
+
// Mesh animation
if (pass == scene::ESNRP_SOLID) {
//MutexAutoLock lock(block->mesh_mutex);
@@ -499,12 +500,12 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
static v3f z_directions[50] = {
v3f(-100, 0, 0)
};
- static f32 z_offsets[sizeof(z_directions)/sizeof(*z_directions)] = {
+ static f32 z_offsets[50] = {
-1000,
};
- if(z_directions[0].X < -99){
- for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++){
+ if (z_directions[0].X < -99) {
+ for (u32 i = 0; i < ARRLEN(z_directions); i++) {
// Assumes FOV of 72 and 16/9 aspect ratio
z_directions[i] = v3f(
0.02 * myrand_range(-100, 100),
@@ -520,7 +521,8 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
if(sunlight_min_d > 35*BS)
sunlight_min_d = 35*BS;
std::vector<int> values;
- for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++){
+ values.reserve(ARRLEN(z_directions));
+ for (u32 i = 0; i < ARRLEN(z_directions); i++) {
v3f z_dir = z_directions[i];
core::CMatrix4<f32> a;
a.buildRotateFromTo(v3f(0,1,0), z_dir);
diff --git a/src/client/clientmap.h b/src/client/clientmap.h
index 57cc4427e..80add4a44 100644
--- a/src/client/clientmap.h
+++ b/src/client/clientmap.h
@@ -68,6 +68,7 @@ class ClientMap : public Map, public scene::ISceneNode
public:
ClientMap(
Client *client,
+ RenderingEngine *rendering_engine,
MapDrawControl &control,
s32 id
);
diff --git a/src/client/clientmedia.cpp b/src/client/clientmedia.cpp
index c4c08c05d..0f9ba5356 100644
--- a/src/client/clientmedia.cpp
+++ b/src/client/clientmedia.cpp
@@ -216,7 +216,6 @@ void ClientMediaDownloader::initialStep(Client *client)
// This is the first time we use httpfetch, so alloc a caller ID
m_httpfetch_caller = httpfetch_caller_alloc();
- m_httpfetch_timeout = g_settings->getS32("curl_timeout");
// Set the active fetch limit to curl_parallel_limit or 84,
// whichever is greater. This gives us some leeway so that
@@ -258,8 +257,6 @@ void ClientMediaDownloader::initialStep(Client *client)
remote->baseurl + MTHASHSET_FILE_NAME;
fetch_request.caller = m_httpfetch_caller;
fetch_request.request_id = m_httpfetch_next_id; // == i
- fetch_request.timeout = m_httpfetch_timeout;
- fetch_request.connect_timeout = m_httpfetch_timeout;
fetch_request.method = HTTP_POST;
fetch_request.raw_data = required_hash_set;
fetch_request.extra_headers.emplace_back(
@@ -432,9 +429,8 @@ void ClientMediaDownloader::startRemoteMediaTransfers()
fetch_request.url = url;
fetch_request.caller = m_httpfetch_caller;
fetch_request.request_id = m_httpfetch_next_id;
- fetch_request.timeout = 0; // no data timeout!
- fetch_request.connect_timeout =
- m_httpfetch_timeout;
+ fetch_request.timeout =
+ g_settings->getS32("curl_file_download_timeout");
httpfetch_async(fetch_request);
m_remote_file_transfers.insert(std::make_pair(
diff --git a/src/client/clientmedia.h b/src/client/clientmedia.h
index 5a918535b..e97a0f24b 100644
--- a/src/client/clientmedia.h
+++ b/src/client/clientmedia.h
@@ -137,7 +137,6 @@ private:
// Status of remote transfers
unsigned long m_httpfetch_caller;
unsigned long m_httpfetch_next_id = 0;
- long m_httpfetch_timeout = 0;
s32 m_httpfetch_active = 0;
s32 m_httpfetch_active_limit = 0;
s32 m_outstanding_hash_sets = 0;
diff --git a/src/client/clientobject.h b/src/client/clientobject.h
index 4a1743d72..c0b14497c 100644
--- a/src/client/clientobject.h
+++ b/src/client/clientobject.h
@@ -44,7 +44,7 @@ public:
ClientActiveObject(u16 id, Client *client, ClientEnvironment *env);
virtual ~ClientActiveObject();
- virtual void addToScene(ITextureSource *tsrc) {}
+ virtual void addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) = 0;
virtual void removeFromScene(bool permanent) {}
virtual void updateLight(u32 day_night_ratio) {}
diff --git a/src/client/clouds.cpp b/src/client/clouds.cpp
index 253dee8b9..5008047af 100644
--- a/src/client/clouds.cpp
+++ b/src/client/clouds.cpp
@@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
// Menu clouds are created later
class Clouds;
Clouds *g_menuclouds = NULL;
-irr::scene::ISceneManager *g_menucloudsmgr = NULL;
+scene::ISceneManager *g_menucloudsmgr = NULL;
// Constant for now
static constexpr const float cloud_size = BS * 64.0f;
@@ -170,7 +170,7 @@ void Clouds::render()
// Read noise
- std::vector<char> grid(m_cloud_radius_i * 2 * m_cloud_radius_i * 2); // vector<bool> is broken
+ std::vector<bool> grid(m_cloud_radius_i * 2 * m_cloud_radius_i * 2);
std::vector<video::S3DVertex> vertices;
vertices.reserve(16 * m_cloud_radius_i * m_cloud_radius_i);
diff --git a/src/client/clouds.h b/src/client/clouds.h
index a4d810faa..c009a05b7 100644
--- a/src/client/clouds.h
+++ b/src/client/clouds.h
@@ -29,8 +29,7 @@ class Clouds;
extern Clouds *g_menuclouds;
// Scene manager used for menu clouds
-namespace irr{namespace scene{class ISceneManager;}}
-extern irr::scene::ISceneManager *g_menucloudsmgr;
+extern scene::ISceneManager *g_menucloudsmgr;
class Clouds : public scene::ISceneNode
{
diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp
index 5e9060fc8..1259fcbd3 100644
--- a/src/client/content_cao.cpp
+++ b/src/client/content_cao.cpp
@@ -24,7 +24,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <IMeshManipulator.h>
#include <IAnimatedMeshSceneNode.h>
#include "client/client.h"
-#include "client/renderingengine.h"
#include "client/sound.h"
#include "client/tile.h"
#include "util/basic_macros.h"
@@ -190,7 +189,7 @@ public:
static ClientActiveObject* create(Client *client, ClientEnvironment *env);
- void addToScene(ITextureSource *tsrc);
+ void addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr);
void removeFromScene(bool permanent);
void updateLight(u32 day_night_ratio);
void updateNodePos();
@@ -221,7 +220,7 @@ ClientActiveObject* TestCAO::create(Client *client, ClientEnvironment *env)
return new TestCAO(client, env);
}
-void TestCAO::addToScene(ITextureSource *tsrc)
+void TestCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
{
if(m_node != NULL)
return;
@@ -250,7 +249,7 @@ void TestCAO::addToScene(ITextureSource *tsrc)
// Add to mesh
mesh->addMeshBuffer(buf);
buf->drop();
- m_node = RenderingEngine::get_scene_manager()->addMeshSceneNode(mesh, NULL);
+ m_node = smgr->addMeshSceneNode(mesh, NULL);
mesh->drop();
updateNodePos();
}
@@ -595,9 +594,9 @@ void GenericCAO::removeFromScene(bool permanent)
m_client->getMinimap()->removeMarker(&m_marker);
}
-void GenericCAO::addToScene(ITextureSource *tsrc)
+void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr)
{
- m_smgr = RenderingEngine::get_scene_manager();
+ m_smgr = smgr;
if (getSceneNode() != NULL) {
return;
@@ -629,8 +628,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
}
auto grabMatrixNode = [this] {
- m_matrixnode = RenderingEngine::get_scene_manager()->
- addDummyTransformationSceneNode();
+ m_matrixnode = m_smgr->addDummyTransformationSceneNode();
m_matrixnode->grab();
};
@@ -648,7 +646,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
if (m_prop.visual == "sprite") {
grabMatrixNode();
- m_spritenode = RenderingEngine::get_scene_manager()->addBillboardSceneNode(
+ m_spritenode = m_smgr->addBillboardSceneNode(
m_matrixnode, v2f(1, 1), v3f(0,0,0), -1);
m_spritenode->grab();
m_spritenode->setMaterialTexture(0,
@@ -733,8 +731,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
mesh->addMeshBuffer(buf);
buf->drop();
}
- m_meshnode = RenderingEngine::get_scene_manager()->
- addMeshSceneNode(mesh, m_matrixnode);
+ m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode);
m_meshnode->grab();
mesh->drop();
// Set it to use the materials of the meshbuffers directly.
@@ -743,8 +740,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
} else if (m_prop.visual == "cube") {
grabMatrixNode();
scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS));
- m_meshnode = RenderingEngine::get_scene_manager()->
- addMeshSceneNode(mesh, m_matrixnode);
+ m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode);
m_meshnode->grab();
mesh->drop();
@@ -757,8 +753,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
grabMatrixNode();
scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true);
if (mesh) {
- m_animated_meshnode = RenderingEngine::get_scene_manager()->
- addAnimatedMeshSceneNode(mesh, m_matrixnode);
+ m_animated_meshnode = m_smgr->addAnimatedMeshSceneNode(mesh, m_matrixnode);
m_animated_meshnode->grab();
mesh->drop(); // The scene node took hold of it
@@ -799,8 +794,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
infostream << "serialized form: " << m_prop.wield_item << std::endl;
item.deSerialize(m_prop.wield_item, m_client->idef());
}
- m_wield_meshnode = new WieldMeshSceneNode(
- RenderingEngine::get_scene_manager(), -1);
+ m_wield_meshnode = new WieldMeshSceneNode(m_smgr, -1);
m_wield_meshnode->setItem(item, m_client,
(m_prop.visual == "wielditem"));
@@ -1089,7 +1083,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
}
removeFromScene(false);
- addToScene(m_client->tsrc());
+ addToScene(m_client->tsrc(), m_smgr);
// Attachments, part 2: Now that the parent has been refreshed, put its attachments back
for (u16 cao_id : m_attachment_child_ids) {
@@ -1488,11 +1482,8 @@ void GenericCAO::updateAnimation()
if (m_animated_meshnode->getAnimationSpeed() != m_animation_speed)
m_animated_meshnode->setAnimationSpeed(m_animation_speed);
m_animated_meshnode->setTransitionTime(m_animation_blend);
-// Requires Irrlicht 1.8 or greater
-#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR > 1
if (m_animated_meshnode->getLoopMode() != m_animation_loop)
m_animated_meshnode->setLoopMode(m_animation_loop);
-#endif
}
void GenericCAO::updateAnimationSpeed()
@@ -1508,10 +1499,10 @@ void GenericCAO::updateBonePosition()
if (m_bone_position.empty() || !m_animated_meshnode)
return;
- m_animated_meshnode->setJointMode(irr::scene::EJUOR_CONTROL); // To write positions to the mesh on render
+ m_animated_meshnode->setJointMode(scene::EJUOR_CONTROL); // To write positions to the mesh on render
for (auto &it : m_bone_position) {
std::string bone_name = it.first;
- irr::scene::IBoneSceneNode* bone = m_animated_meshnode->getJointNode(bone_name.c_str());
+ scene::IBoneSceneNode* bone = m_animated_meshnode->getJointNode(bone_name.c_str());
if (bone) {
bone->setPosition(it.second.X);
bone->setRotation(it.second.Y);
@@ -1520,7 +1511,7 @@ void GenericCAO::updateBonePosition()
// search through bones to find mistakenly rotated bones due to bug in Irrlicht
for (u32 i = 0; i < m_animated_meshnode->getJointCount(); ++i) {
- irr::scene::IBoneSceneNode *bone = m_animated_meshnode->getJointNode(i);
+ scene::IBoneSceneNode *bone = m_animated_meshnode->getJointNode(i);
if (!bone)
continue;
@@ -1965,7 +1956,7 @@ void GenericCAO::updateMeshCulling()
return;
}
- irr::scene::ISceneNode *node = getSceneNode();
+ scene::ISceneNode *node = getSceneNode();
if (!node)
return;
diff --git a/src/client/content_cao.h b/src/client/content_cao.h
index 450023d19..7e9bb6671 100644
--- a/src/client/content_cao.h
+++ b/src/client/content_cao.h
@@ -189,6 +189,8 @@ public:
const bool isImmortal();
+ inline const ObjectProperties &getProperties() const { return m_prop; }
+
scene::ISceneNode *getSceneNode() const;
scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode() const;
@@ -260,7 +262,7 @@ public:
void removeFromScene(bool permanent);
- void addToScene(ITextureSource *tsrc);
+ void addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr);
inline void expireVisuals()
{
diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp
index 90284ecce..810c57138 100644
--- a/src/client/content_mapblock.cpp
+++ b/src/client/content_mapblock.cpp
@@ -60,18 +60,16 @@ static constexpr u16 quad_indices[] = {0, 1, 2, 2, 3, 0};
const std::string MapblockMeshGenerator::raillike_groupname = "connect_to_raillike";
-MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output)
+MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output,
+ scene::IMeshManipulator *mm):
+ data(input),
+ collector(output),
+ nodedef(data->m_client->ndef()),
+ meshmanip(mm),
+ blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE)
{
- data = input;
- collector = output;
-
- nodedef = data->m_client->ndef();
- meshmanip = RenderingEngine::get_scene_manager()->getMeshManipulator();
-
enable_mesh_cache = g_settings->getBool("enable_mesh_cache") &&
!data->m_smooth_lighting; // Mesh cache is not supported with smooth lighting
-
- blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE;
}
void MapblockMeshGenerator::useTile(int index, u8 set_flags, u8 reset_flags, bool special)
@@ -968,7 +966,7 @@ void MapblockMeshGenerator::drawPlantlike()
draw_style = PLANT_STYLE_CROSS;
scale = BS / 2 * f->visual_scale;
offset = v3f(0, 0, 0);
- rotate_degree = 0;
+ rotate_degree = 0.0f;
random_offset_Y = false;
face_num = 0;
plant_height = 1.0;
@@ -988,7 +986,8 @@ void MapblockMeshGenerator::drawPlantlike()
break;
case CPT2_DEGROTATE:
- rotate_degree = n.param2 * 2;
+ case CPT2_COLORED_DEGROTATE:
+ rotate_degree = 1.5f * n.getDegRotate(nodedef);
break;
case CPT2_LEVELED:
@@ -1343,6 +1342,7 @@ 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 (f->param_type_2 == CPT2_FACEDIR ||
f->param_type_2 == CPT2_COLORED_FACEDIR) {
@@ -1354,9 +1354,12 @@ void MapblockMeshGenerator::drawMeshNode()
facedir = n.getWallMounted(nodedef);
if (!enable_mesh_cache)
facedir = wallmounted_to_facedir[facedir];
+ } else if (f->param_type_2 == CPT2_DEGROTATE ||
+ f->param_type_2 == CPT2_COLORED_DEGROTATE) {
+ degrotate = n.getDegRotate(nodedef);
}
- if (!data->m_smooth_lighting && f->mesh_ptr[facedir]) {
+ if (!data->m_smooth_lighting && f->mesh_ptr[facedir] && !degrotate) {
// use cached meshes
private_mesh = false;
mesh = f->mesh_ptr[facedir];
@@ -1364,7 +1367,10 @@ void MapblockMeshGenerator::drawMeshNode()
// no cache, clone and rotate mesh
private_mesh = true;
mesh = cloneMesh(f->mesh_ptr[0]);
- rotateMeshBy6dFacedir(mesh, facedir);
+ if (facedir)
+ rotateMeshBy6dFacedir(mesh, facedir);
+ else if (degrotate)
+ rotateMeshXZby(mesh, 1.5f * degrotate);
recalculateBoundingBox(mesh);
meshmanip->recalculateNormals(mesh, true, false);
} else
diff --git a/src/client/content_mapblock.h b/src/client/content_mapblock.h
index 487d84a07..237cc7847 100644
--- a/src/client/content_mapblock.h
+++ b/src/client/content_mapblock.h
@@ -139,7 +139,7 @@ public:
// plantlike-specific
PlantlikeStyle draw_style;
v3f offset;
- int rotate_degree;
+ float rotate_degree;
bool random_offset_Y;
int face_num;
float plant_height;
@@ -172,7 +172,8 @@ public:
void drawNode();
public:
- MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output);
+ MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output,
+ scene::IMeshManipulator *mm);
void generate();
void renderSingle(content_t node, u8 param2 = 0x00);
};
diff --git a/src/client/fontengine.cpp b/src/client/fontengine.cpp
index 47218c0d9..0382c2f18 100644
--- a/src/client/fontengine.cpp
+++ b/src/client/fontengine.cpp
@@ -56,7 +56,7 @@ FontEngine::FontEngine(gui::IGUIEnvironment* env) :
readSettings();
- if (m_currentMode == FM_Standard) {
+ if (m_currentMode != FM_Simple) {
g_settings->registerChangedCallback("font_size", font_setting_changed, NULL);
g_settings->registerChangedCallback("font_bold", font_setting_changed, NULL);
g_settings->registerChangedCallback("font_italic", font_setting_changed, NULL);
@@ -66,12 +66,7 @@ FontEngine::FontEngine(gui::IGUIEnvironment* env) :
g_settings->registerChangedCallback("font_path_bolditalic", font_setting_changed, NULL);
g_settings->registerChangedCallback("font_shadow", font_setting_changed, NULL);
g_settings->registerChangedCallback("font_shadow_alpha", font_setting_changed, NULL);
- }
- else if (m_currentMode == FM_Fallback) {
- g_settings->registerChangedCallback("fallback_font_size", font_setting_changed, NULL);
g_settings->registerChangedCallback("fallback_font_path", font_setting_changed, NULL);
- g_settings->registerChangedCallback("fallback_font_shadow", font_setting_changed, NULL);
- g_settings->registerChangedCallback("fallback_font_shadow_alpha", font_setting_changed, NULL);
}
g_settings->registerChangedCallback("mono_font_path", font_setting_changed, NULL);
@@ -102,6 +97,11 @@ void FontEngine::cleanCache()
/******************************************************************************/
irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec)
{
+ return getFont(spec, false);
+}
+
+irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec, bool may_fail)
+{
if (spec.mode == FM_Unspecified) {
spec.mode = m_currentMode;
} else if (m_currentMode == FM_Simple) {
@@ -112,6 +112,10 @@ irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec)
// Support for those could be added, but who cares?
spec.bold = false;
spec.italic = false;
+ } else if (spec.mode == _FM_Fallback) {
+ // Fallback font doesn't support these either
+ spec.bold = false;
+ spec.italic = false;
}
// Fallback to default size
@@ -130,6 +134,13 @@ irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec)
else
font = initFont(spec);
+ if (!font && !may_fail) {
+ errorstream << "Minetest cannot continue without a valid font. "
+ "Please correct the 'font_path' setting or install the font "
+ "file in the proper location." << std::endl;
+ abort();
+ }
+
m_font_cache[spec.getHash()][spec.size] = font;
return font;
@@ -204,20 +215,9 @@ unsigned int FontEngine::getFontSize(FontMode mode)
void FontEngine::readSettings()
{
if (USE_FREETYPE && g_settings->getBool("freetype")) {
- m_default_size[FM_Standard] = g_settings->getU16("font_size");
- m_default_size[FM_Fallback] = g_settings->getU16("fallback_font_size");
- m_default_size[FM_Mono] = g_settings->getU16("mono_font_size");
-
- /*~ DO NOT TRANSLATE THIS LITERALLY!
- This is a special string. Put either "no" or "yes"
- into the translation field (literally).
- Choose "yes" if the language requires use of the fallback
- font, "no" otherwise.
- The fallback font is (normally) required for languages with
- non-Latin script, like Chinese.
- When in doubt, test your translation. */
- m_currentMode = is_yes(gettext("needs_fallback_font")) ?
- FM_Fallback : FM_Standard;
+ m_default_size[FM_Standard] = g_settings->getU16("font_size");
+ m_default_size[_FM_Fallback] = g_settings->getU16("font_size");
+ m_default_size[FM_Mono] = g_settings->getU16("mono_font_size");
m_default_bold = g_settings->getBool("font_bold");
m_default_italic = g_settings->getBool("font_italic");
@@ -271,18 +271,8 @@ gui::IGUIFont *FontEngine::initFont(const FontSpec &spec)
assert(spec.size != FONT_SIZE_UNSPECIFIED);
std::string setting_prefix = "";
-
- switch (spec.mode) {
- case FM_Fallback:
- setting_prefix = "fallback_";
- break;
- case FM_Mono:
- case FM_SimpleMono:
- setting_prefix = "mono_";
- break;
- default:
- break;
- }
+ if (spec.mode == FM_Mono)
+ setting_prefix = "mono_";
std::string setting_suffix = "";
if (spec.bold)
@@ -305,38 +295,41 @@ gui::IGUIFont *FontEngine::initFont(const FontSpec &spec)
g_settings->getU16NoEx(setting_prefix + "font_shadow_alpha",
font_shadow_alpha);
- std::string wanted_font_path;
- wanted_font_path = g_settings->get(setting_prefix + "font_path" + setting_suffix);
+ std::string path_setting;
+ if (spec.mode == _FM_Fallback)
+ path_setting = "fallback_font_path";
+ else
+ path_setting = setting_prefix + "font_path" + setting_suffix;
std::string fallback_settings[] = {
- wanted_font_path,
- g_settings->get("fallback_font_path"),
- Settings::getLayer(SL_DEFAULTS)->get(setting_prefix + "font_path")
+ g_settings->get(path_setting),
+ Settings::getLayer(SL_DEFAULTS)->get(path_setting)
};
#if USE_FREETYPE
for (const std::string &font_path : fallback_settings) {
- irr::gui::IGUIFont *font = gui::CGUITTFont::createTTFont(m_env,
+ gui::CGUITTFont *font = gui::CGUITTFont::createTTFont(m_env,
font_path.c_str(), size, true, true, font_shadow,
font_shadow_alpha);
- if (font)
- return font;
-
- errorstream << "FontEngine: Cannot load '" << font_path <<
+ if (!font) {
+ errorstream << "FontEngine: Cannot load '" << font_path <<
"'. Trying to fall back to another path." << std::endl;
- }
-
+ continue;
+ }
- // give up
- errorstream << "minetest can not continue without a valid font. "
- "Please correct the 'font_path' setting or install the font "
- "file in the proper location" << std::endl;
+ if (spec.mode != _FM_Fallback) {
+ FontSpec spec2(spec);
+ spec2.mode = _FM_Fallback;
+ font->setFallback(getFont(spec2, true));
+ }
+ return font;
+ }
#else
- errorstream << "FontEngine: Tried to load freetype fonts but Minetest was"
- " not compiled with that library." << std::endl;
+ errorstream << "FontEngine: Tried to load TTF font but Minetest was"
+ " compiled without Freetype." << std::endl;
#endif
- abort();
+ return nullptr;
}
/** initialize a font without freetype */
diff --git a/src/client/fontengine.h b/src/client/fontengine.h
index e27ef60e9..3d389ea48 100644
--- a/src/client/fontengine.h
+++ b/src/client/fontengine.h
@@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
enum FontMode : u8 {
FM_Standard = 0,
FM_Mono,
- FM_Fallback,
+ _FM_Fallback, // do not use directly
FM_Simple,
FM_SimpleMono,
FM_MaxMode,
@@ -47,7 +47,7 @@ struct FontSpec {
bold(bold),
italic(italic) {}
- u16 getHash()
+ u16 getHash() const
{
return (mode << 2) | (static_cast<u8>(bold) << 1) | static_cast<u8>(italic);
}
@@ -132,10 +132,12 @@ public:
void readSettings();
private:
+ irr::gui::IGUIFont *getFont(FontSpec spec, bool may_fail);
+
/** update content of font cache in case of a setting change made it invalid */
void updateFontCache();
- /** initialize a new font */
+ /** initialize a new TTF font */
gui::IGUIFont *initFont(const FontSpec &spec);
/** initialize a font without freetype */
diff --git a/src/client/game.cpp b/src/client/game.cpp
index e1f2fbe75..5bfe55e66 100644
--- a/src/client/game.cpp
+++ b/src/client/game.cpp
@@ -153,7 +153,7 @@ Game::~Game()
delete itemdef_manager;
delete draw_control;
- extendedResourceCleanup();
+ clearTextureNameCache();
g_settings->deregisterChangedCallback("doubletap_jump",
&settingChangedCallback, this);
@@ -191,6 +191,7 @@ Game::~Game()
bool Game::startup(bool *kill,
InputHandler *input,
+ RenderingEngine *rendering_engine,
const GameStartData &start_data,
std::string &error_message,
bool *reconnect,
@@ -198,21 +199,21 @@ bool Game::startup(bool *kill,
{
// "cache"
- this->device = RenderingEngine::get_raw_device();
+ m_rendering_engine = rendering_engine;
+ device = m_rendering_engine->get_raw_device();
this->kill = kill;
this->error_message = &error_message;
- this->reconnect_requested = reconnect;
+ reconnect_requested = reconnect;
this->input = input;
this->chat_backend = chat_backend;
- this->simple_singleplayer_mode = start_data.isSinglePlayer();
+ simple_singleplayer_mode = start_data.isSinglePlayer();
input->keycache.populate();
driver = device->getVideoDriver();
- smgr = RenderingEngine::get_scene_manager();
+ smgr = m_rendering_engine->get_scene_manager();
- RenderingEngine::get_scene_manager()->getParameters()->
- setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true);
+ smgr->getParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true);
// Reinit runData
runData = GameRunData();
@@ -233,7 +234,7 @@ bool Game::startup(bool *kill,
if (!createClient(start_data))
return false;
- RenderingEngine::initialize(client, hud);
+ m_rendering_engine->initialize(client, hud);
return true;
}
@@ -250,7 +251,7 @@ void Game::run()
Profiler::GraphValues dummyvalues;
g_profiler->graphGet(dummyvalues);
- draw_times.last_time = RenderingEngine::get_timer_time();
+ draw_times.last_time = m_rendering_engine->get_timer_time();
set_light_table(g_settings->getFloat("display_gamma"));
@@ -262,12 +263,12 @@ void Game::run()
irr::core::dimension2d<u32> previous_screen_size(g_settings->getU16("screen_w"),
g_settings->getU16("screen_h"));
- while (RenderingEngine::run()
+ while (m_rendering_engine->run()
&& !(*kill || g_gamecallback->shutdown_requested
|| (server && server->isShutdownRequested()))) {
const irr::core::dimension2d<u32> &current_screen_size =
- RenderingEngine::get_video_driver()->getScreenSize();
+ m_rendering_engine->get_video_driver()->getScreenSize();
// Verify if window size has changed and save it if it's the case
// Ensure evaluating settings->getBool after verifying screensize
// First condition is cheaper
@@ -280,7 +281,7 @@ void Game::run()
}
// Calculate dtime =
- // RenderingEngine::run() from this iteration
+ // m_rendering_engine->run() from this iteration
// + Sleep time until the wanted FPS are reached
limitFps(&draw_times, &dtime);
@@ -329,7 +330,7 @@ void Game::run()
void Game::shutdown()
{
- RenderingEngine::finalize();
+ m_rendering_engine->finalize();
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 8
if (g_settings->get("3d_mode") == "pageflip") {
driver->setRenderTarget(irr::video::ERT_STEREO_BOTH_BUFFERS);
@@ -488,7 +489,7 @@ bool Game::createClient(const GameStartData &start_data)
{
showOverlayMessage(N_("Creating client..."), 0, 10);
- draw_control = new MapDrawControl;
+ draw_control = new MapDrawControl();
if (!draw_control)
return false;
@@ -529,7 +530,7 @@ bool Game::createClient(const GameStartData &start_data)
/* Camera
*/
- camera = new Camera(*draw_control, client);
+ camera = new Camera(*draw_control, client, m_rendering_engine);
if (!camera->successfullyCreated(*error_message))
return false;
client->setCamera(camera);
@@ -541,7 +542,7 @@ bool Game::createClient(const GameStartData &start_data)
/* Skybox
*/
- sky = new Sky(-1, texture_src, shader_src);
+ sky = new Sky(-1, m_rendering_engine, texture_src, shader_src);
scsf->setSky(sky);
skybox = NULL; // This is used/set later on in the main run loop
@@ -563,16 +564,28 @@ bool Game::createClient(const GameStartData &start_data)
std::wstring str = utf8_to_wide(PROJECT_NAME_C);
str += L" ";
str += utf8_to_wide(g_version_hash);
+ {
+ const wchar_t *text = nullptr;
+ if (simple_singleplayer_mode)
+ text = wgettext("Singleplayer");
+ else
+ text = wgettext("Multiplayer");
+ str += L" [";
+ str += text;
+ str += L"]";
+ delete text;
+ }
str += L" [";
str += L"Minetest Hackclient";
str += L"]";
+
device->setWindowCaption(str.c_str());
LocalPlayer *player = client->getEnv().getLocalPlayer();
player->hurt_tilt_timer = 0;
player->hurt_tilt_strength = 0;
- hud = new Hud(guienv, client, player, &player->inventory);
+ hud = new Hud(client, player, &player->inventory);
mapper = client->getMinimap();
@@ -663,7 +676,7 @@ bool Game::connectToServer(const GameStartData &start_data,
start_data.password, start_data.address,
*draw_control, texture_src, shader_src,
itemdef_manager, nodedef_manager, sound, eventmgr,
- connect_address.isIPv6(), m_game_ui.get());
+ m_rendering_engine, connect_address.isIPv6(), m_game_ui.get());
client->m_simple_singleplayer_mode = simple_singleplayer_mode;
@@ -685,9 +698,9 @@ bool Game::connectToServer(const GameStartData &start_data,
f32 dtime;
f32 wait_time = 0; // in seconds
- fps_control.last_time = RenderingEngine::get_timer_time();
+ fps_control.last_time = m_rendering_engine->get_timer_time();
- while (RenderingEngine::run()) {
+ while (m_rendering_engine->run()) {
limitFps(&fps_control, &dtime);
@@ -724,7 +737,7 @@ bool Game::connectToServer(const GameStartData &start_data,
if (client->m_is_registration_confirmation_state) {
if (registration_confirmation_shown) {
// Keep drawing the GUI
- RenderingEngine::draw_menu_scene(guienv, dtime, true);
+ m_rendering_engine->draw_menu_scene(guienv, dtime, true);
} else {
registration_confirmation_shown = true;
(new GUIConfirmRegistration(guienv, guienv->getRootGUIElement(), -1,
@@ -734,7 +747,7 @@ bool Game::connectToServer(const GameStartData &start_data,
} else {
wait_time += dtime;
// Only time out if we aren't waiting for the server we started
- if (!start_data.local_server && !start_data.isSinglePlayer() && wait_time > 10) {
+ if (!start_data.address.empty() && wait_time > 10) {
*error_message = "Connection timed out.";
errorstream << *error_message << std::endl;
break;
@@ -760,9 +773,9 @@ bool Game::getServerContent(bool *aborted)
FpsControl fps_control = { 0 };
f32 dtime; // in seconds
- fps_control.last_time = RenderingEngine::get_timer_time();
+ fps_control.last_time = m_rendering_engine->get_timer_time();
- while (RenderingEngine::run()) {
+ while (m_rendering_engine->run()) {
limitFps(&fps_control, &dtime);
@@ -800,13 +813,13 @@ bool Game::getServerContent(bool *aborted)
if (!client->itemdefReceived()) {
const wchar_t *text = wgettext("Item definitions...");
progress = 25;
- RenderingEngine::draw_load_screen(text, guienv, texture_src,
+ m_rendering_engine->draw_load_screen(text, guienv, texture_src,
dtime, progress);
delete[] text;
} else if (!client->nodedefReceived()) {
const wchar_t *text = wgettext("Node definitions...");
progress = 30;
- RenderingEngine::draw_load_screen(text, guienv, texture_src,
+ m_rendering_engine->draw_load_screen(text, guienv, texture_src,
dtime, progress);
delete[] text;
} else {
@@ -833,7 +846,7 @@ bool Game::getServerContent(bool *aborted)
}
progress = 30 + client->mediaReceiveProgress() * 35 + 0.5;
- RenderingEngine::draw_load_screen(utf8_to_wide(message.str()), guienv,
+ m_rendering_engine->draw_load_screen(utf8_to_wide(message.str()), guienv,
texture_src, dtime, progress);
}
}
@@ -1150,6 +1163,8 @@ void Game::processKeyInput()
toggleCinematic();
} else if (wasKeyDown(KeyType::SCREENSHOT)) {
client->makeScreenshot();
+ } else if (wasKeyDown(KeyType::TOGGLE_BLOCK_BOUNDS)) {
+ hud->toggleBlockBounds();
} else if (wasKeyDown(KeyType::TOGGLE_HUD)) {
m_game_ui->toggleHud();
} else if (wasKeyDown(KeyType::MINIMAP)) {
@@ -1264,8 +1279,8 @@ void Game::openInventory()
|| !client->getScript()->on_inventory_open(fs_src->m_client->getInventory(inventoryloc))) {
TextDest *txt_dst = new TextDestPlayerInventory(client);
auto *&formspec = m_game_ui->updateFormspec("");
- GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src,
- txt_dst, client->getFormspecPrepend(), sound);
+ GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
+ &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
formspec->setFormSpec(fs_src->getForm(), inventoryloc);
}
@@ -1838,14 +1853,18 @@ void Game::handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation
// Damage flash and hurt tilt are not used at death
if (client->getHP() > 0) {
- runData.damage_flash += 95.0f + 3.2f * event->player_damage.amount;
- runData.damage_flash = MYMIN(runData.damage_flash, 127.0f);
-
LocalPlayer *player = client->getEnv().getLocalPlayer();
+ f32 hp_max = player->getCAO() ?
+ player->getCAO()->getProperties()->hp_max : PLAYER_MAX_HP_DEFAULT;
+ f32 damage_ratio = event->player_damage.amount / hp_max;
+
+ runData.damage_flash += 95.0f + 64.f * damage_ratio;
+ runData.damage_flash = MYMIN(runData.damage_flash, 127.0f);
+
player->hurt_tilt_timer = 1.5f;
player->hurt_tilt_strength =
- rangelim(event->player_damage.amount / 4.0f, 1.0f, 4.0f);
+ rangelim(damage_ratio * 5.0f, 1.0f, 4.0f);
}
// Play damage sound
@@ -1889,8 +1908,8 @@ void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation
new TextDestPlayerInventory(client, *(event->show_formspec.formname));
auto *&formspec = m_game_ui->updateFormspec(*(event->show_formspec.formname));
- GUIFormSpecMenu::create(formspec, client, &input->joystick,
- fs_src, txt_dst, client->getFormspecPrepend(), sound);
+ GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
+ &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
}
delete event->show_formspec.formspec;
@@ -1909,7 +1928,7 @@ void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrienta
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, &input->joystick,
+ GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, m_rendering_engine->get_gui_env(), &input->joystick,
fs_src, txt_dst, client->getFormspecPrepend(), sound);
}
@@ -2075,6 +2094,7 @@ void Game::handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam)
"custom"
);
}
+
delete event->set_sky;
}
@@ -2607,8 +2627,8 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client);
auto *&formspec = m_game_ui->updateFormspec("");
- GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src,
- txt_dst, client->getFormspecPrepend(), sound);
+ GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
+ &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
formspec->setFormSpec(meta->getString("formspec"), inventoryloc);
return false;
@@ -3170,7 +3190,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
} catch (SettingNotFoundException) {
}
#endif
- RenderingEngine::draw_scene(skycolor, m_game_ui->m_flags.show_hud,
+ m_rendering_engine->draw_scene(skycolor, m_game_ui->m_flags.show_hud,
m_game_ui->m_flags.show_minimap, draw_wield_tool, draw_crosshair);
/*
@@ -3309,7 +3329,7 @@ inline void Game::limitFps(FpsControl *fps_timings, f32 *dtime)
void Game::showOverlayMessage(const char *msg, float dtime, int percent, bool draw_clouds)
{
const wchar_t *wmsg = wgettext(msg);
- RenderingEngine::draw_load_screen(wmsg, guienv, texture_src, dtime, percent,
+ m_rendering_engine->draw_load_screen(wmsg, guienv, texture_src, dtime, percent,
draw_clouds);
delete[] wmsg;
}
@@ -3392,27 +3412,6 @@ bool Game::wasKeyReleased(GameKeyType k)
****************************************************************************/
/****************************************************************************/
-void Game::extendedResourceCleanup()
-{
- // Extended resource accounting
- infostream << "Irrlicht resources after cleanup:" << std::endl;
- infostream << "\tRemaining meshes : "
- << RenderingEngine::get_mesh_cache()->getMeshCount() << std::endl;
- infostream << "\tRemaining textures : "
- << driver->getTextureCount() << std::endl;
-
- for (unsigned int i = 0; i < driver->getTextureCount(); i++) {
- irr::video::ITexture *texture = driver->getTextureByIndex(i);
- infostream << "\t\t" << i << ":" << texture->getName().getPath().c_str()
- << std::endl;
- }
-
- clearTextureNameCache();
- infostream << "\tRemaining materials: "
- << driver-> getMaterialRendererCount()
- << " (note: irrlicht doesn't support removing renderers)" << std::endl;
-}
-
void Game::showDeathFormspec()
{
static std::string formspec_str =
@@ -3430,8 +3429,8 @@ void Game::showDeathFormspec()
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", client);
auto *&formspec = m_game_ui->getFormspecGUI();
- GUIFormSpecMenu::create(formspec, client, &input->joystick,
- fs_src, txt_dst, client->getFormspecPrepend(), sound);
+ GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
+ &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
formspec->setFocus("btn_respawn");
}
@@ -3572,8 +3571,8 @@ void Game::showPauseMenu()
LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU");
auto *&formspec = m_game_ui->getFormspecGUI();
- GUIFormSpecMenu::create(formspec, client, &input->joystick,
- fs_src, txt_dst, client->getFormspecPrepend(), sound);
+ GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(),
+ &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound);
formspec->setFocus("btn_continue");
formspec->doPause = true;
@@ -3591,6 +3590,7 @@ Game *g_game;
void the_game(bool *kill,
InputHandler *input,
+ RenderingEngine *rendering_engine,
const GameStartData &start_data,
std::string &error_message,
ChatBackend &chat_backend,
@@ -3607,8 +3607,8 @@ void the_game(bool *kill,
try {
- if (game.startup(kill, input, start_data, error_message,
- reconnect_requested, &chat_backend)) {
+ if (game.startup(kill, input, rendering_engine, start_data,
+ error_message, reconnect_requested, &chat_backend)) {
game.run();
}
diff --git a/src/client/game.h b/src/client/game.h
index 4a5b829d5..8197b9a9b 100644
--- a/src/client/game.h
+++ b/src/client/game.h
@@ -76,7 +76,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string>
class InputHandler;
-class ChatBackend; /* to avoid having to include chat.h */
+class ChatBackend;
+class RenderingEngine;
struct SubgameSpec;
struct GameStartData;
@@ -417,12 +418,7 @@ public:
};
-// before 1.8 there isn't a "integer interface", only float
-#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
-typedef f32 SamplerLayer_t;
-#else
typedef s32 SamplerLayer_t;
-#endif
class GameGlobalShaderConstantSetter : public IShaderConstantSetter
@@ -530,38 +526,20 @@ public:
float eye_position_array[3];
v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition();
-#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
- eye_position_array[0] = epos.X;
- eye_position_array[1] = epos.Y;
- eye_position_array[2] = epos.Z;
-#else
epos.getAs3Values(eye_position_array);
-#endif
m_eye_position_pixel.set(eye_position_array, services);
m_eye_position_vertex.set(eye_position_array, services);
if (m_client->getMinimap()) {
float minimap_yaw_array[3];
v3f minimap_yaw = m_client->getMinimap()->getYawVec();
-#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
- minimap_yaw_array[0] = minimap_yaw.X;
- minimap_yaw_array[1] = minimap_yaw.Y;
- minimap_yaw_array[2] = minimap_yaw.Z;
-#else
minimap_yaw.getAs3Values(minimap_yaw_array);
-#endif
m_minimap_yaw.set(minimap_yaw_array, services);
}
float camera_offset_array[3];
v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS);
-#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
- camera_offset_array[0] = offset.X;
- camera_offset_array[1] = offset.Y;
- camera_offset_array[2] = offset.Z;
-#else
offset.getAs3Values(camera_offset_array);
-#endif
m_camera_offset_pixel.set(camera_offset_array, services);
m_camera_offset_vertex.set(camera_offset_array, services);
@@ -673,6 +651,7 @@ public:
bool startup(bool *kill,
InputHandler *input,
+ RenderingEngine *rendering_engine,
const GameStartData &game_params,
std::string &error_message,
bool *reconnect,
@@ -682,8 +661,6 @@ public:
void run();
void shutdown();
- void extendedResourceCleanup();
-
// Basic initialisation
bool init(const std::string &map_dir, const std::string &address,
u16 port, const SubgameSpec &gamespec);
@@ -881,6 +858,7 @@ public:
these items (e.g. device)
*/
IrrlichtDevice *device;
+ RenderingEngine *m_rendering_engine;
video::IVideoDriver *driver;
scene::ISceneManager *smgr;
bool *kill;
@@ -936,6 +914,7 @@ extern Game *g_game;
void the_game(bool *kill,
InputHandler *input,
+ RenderingEngine *rendering_engine,
const GameStartData &start_data,
std::string &error_message,
ChatBackend &chat_backend,
diff --git a/src/client/gameui.cpp b/src/client/gameui.cpp
index 0c1da3915..c97ae93b8 100644
--- a/src/client/gameui.cpp
+++ b/src/client/gameui.cpp
@@ -55,7 +55,7 @@ void GameUI::init()
{
m_guitext_coords = gui::StaticText::add(guienv, L"", core::rect<s32>(0, 0, 0, 0), false,
false, guiroot);
-
+
// First line of debug text
m_guitext = gui::StaticText::add(guienv, utf8_to_wide(PROJECT_NAME_C).c_str(),
core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
@@ -102,7 +102,8 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
{
LocalPlayer *player = client->getEnv().getLocalPlayer();
v3f player_position = player->getPosition();
- v2u32 screensize = RenderingEngine::get_instance()->getWindowSize();
+
+ v2u32 screensize = RenderingEngine::getWindowSize();
bool show_coords = g_settings->getBool("coords");
@@ -115,7 +116,7 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
setStaticText(m_guitext_coords, utf8_to_wide(os.str()).c_str());
m_guitext_coords->setRelativePosition(core::rect<s32>(5, screensize.Y - 5 - g_fontengine->getTextHeight(), screensize.X, screensize.Y));
}
-
+
m_guitext_coords->setVisible(show_coords);
if (m_flags.show_debug) {
@@ -238,9 +239,9 @@ void GameUI::setChatText(const EnrichedString &chat_text, u32 recent_chat_count)
{
// Update gui element size and position
-
- const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
-
+
+ const v2u32 &window_size = RenderingEngine::getWindowSize();
+
s32 chat_y = window_size.Y - 150 - m_guitext_chat->getTextHeight();
if (m_flags.show_debug)
@@ -276,7 +277,7 @@ void GameUI::updateProfiler()
core::position2di upper_left(6, 50);
core::position2di lower_right = upper_left;
lower_right.X += size.Width + 10;
- lower_right.Y += size.Height;
+ lower_right.Y += size.Height;
m_guitext_profiler->setRelativePosition(core::rect<s32>(upper_left, lower_right));
}
diff --git a/src/client/guiscalingfilter.cpp b/src/client/guiscalingfilter.cpp
index 8c565a52f..232219237 100644
--- a/src/client/guiscalingfilter.cpp
+++ b/src/client/guiscalingfilter.cpp
@@ -23,7 +23,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/numeric.h"
#include <cstdio>
#include "client/renderingengine.h"
-#include "client/tile.h" // hasNPotSupport()
/* Maintain a static cache to store the images that correspond to textures
* in a format that's manipulable by code. Some platforms exhibit issues
@@ -102,7 +101,7 @@ video::ITexture *guiScalingResizeCached(video::IVideoDriver *driver,
if (!g_settings->getBool("gui_scaling_filter_txr2img"))
return src;
srcimg = driver->createImageFromData(src->getColorFormat(),
- src->getSize(), src->lock(), false);
+ src->getSize(), src->lock(video::ETLM_READ_ONLY), false);
src->unlock();
g_imgCache[origname] = srcimg;
}
@@ -117,7 +116,7 @@ video::ITexture *guiScalingResizeCached(video::IVideoDriver *driver,
#if ENABLE_GLES
// Some platforms are picky about textures being powers of 2, so expand
// the image dimensions to the next power of 2, if necessary.
- if (!hasNPotSupport()) {
+ if (!driver->queryFeature(video::EVDF_TEXTURE_NPOT)) {
video::IImage *po2img = driver->createImage(src->getColorFormat(),
core::dimension2d<u32>(npot2((u32)destrect.getWidth()),
npot2((u32)destrect.getHeight())));
diff --git a/src/client/hud.cpp b/src/client/hud.cpp
index 5971948fd..391af0995 100644
--- a/src/client/hud.cpp
+++ b/src/client/hud.cpp
@@ -45,11 +45,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define OBJECT_CROSSHAIR_LINE_SIZE 8
#define CROSSHAIR_LINE_SIZE 10
-Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player,
+Hud::Hud(Client *client, LocalPlayer *player,
Inventory *inventory)
{
driver = RenderingEngine::get_video_driver();
- this->guienv = guienv;
this->client = client;
this->player = player;
this->inventory = inventory;
@@ -315,7 +314,7 @@ bool Hud::calculateScreenPos(const v3s16 &camera_offset, HudElement *e, v2s32 *p
{
v3f w_pos = e->world_pos * BS;
scene::ICameraSceneNode* camera =
- RenderingEngine::get_scene_manager()->getActiveCamera();
+ client->getSceneManager()->getActiveCamera();
w_pos -= intToFloat(camera_offset, BS);
core::matrix4 trans = camera->getProjectionMatrix();
trans *= camera->getViewMatrix();
@@ -336,22 +335,22 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
irr::gui::IGUIFont* font = g_fontengine->getFont();
// Reorder elements by z_index
- std::vector<size_t> ids;
+ std::vector<HudElement*> elems;
+ elems.reserve(player->maxHudId());
for (size_t i = 0; i != player->maxHudId(); i++) {
HudElement *e = player->getHud(i);
if (!e)
continue;
- auto it = ids.begin();
- while (it != ids.end() && player->getHud(*it)->z_index <= e->z_index)
+ auto it = elems.begin();
+ while (it != elems.end() && (*it)->z_index <= e->z_index)
++it;
- ids.insert(it, i);
+ elems.insert(it, e);
}
- for (size_t i : ids) {
- HudElement *e = player->getHud(i);
+ for (HudElement *e : elems) {
v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 0.5),
floor(e->pos.Y * (float) m_screensize.Y + 0.5));
@@ -475,7 +474,7 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
// Angle according to camera view
v3f fore(0.f, 0.f, 1.f);
- scene::ICameraSceneNode *cam = RenderingEngine::get_scene_manager()->getActiveCamera();
+ scene::ICameraSceneNode *cam = client->getSceneManager()->getActiveCamera();
cam->getAbsoluteTransformation().rotateVect(fore);
int angle = - fore.getHorizontalAngle().Y;
@@ -522,8 +521,8 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
client->getMinimap()->drawMinimap(rect);
break; }
default:
- infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
- " of hud element ID " << i << " due to unrecognized type" << std::endl;
+ infostream << "Hud::drawLuaElements: ignoring drawform " << e->type
+ << " due to unrecognized type" << std::endl;
}
}
}
@@ -747,7 +746,7 @@ void Hud::drawHotbar(u16 playeritem) {
s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2);
v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3);
- const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
+ const v2u32 &window_size = RenderingEngine::getWindowSize();
if ((float) width / (float) window_size.X <=
g_settings->getFloat("hud_hotbar_max_width")) {
if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) {
@@ -862,6 +861,54 @@ void Hud::drawSelectionMesh()
}
}
+void Hud::toggleBlockBounds()
+{
+ m_block_bounds_mode = static_cast<BlockBoundsMode>(m_block_bounds_mode + 1);
+
+ if (m_block_bounds_mode >= BLOCK_BOUNDS_MAX) {
+ m_block_bounds_mode = BLOCK_BOUNDS_OFF;
+ }
+}
+
+void Hud::drawBlockBounds()
+{
+ if (m_block_bounds_mode == BLOCK_BOUNDS_OFF) {
+ return;
+ }
+
+ video::SMaterial old_material = driver->getMaterial2D();
+ driver->setMaterial(m_selection_material);
+
+ v3s16 pos = player->getStandingNodePos();
+
+ v3s16 blockPos(
+ floorf((float) pos.X / MAP_BLOCKSIZE),
+ floorf((float) pos.Y / MAP_BLOCKSIZE),
+ floorf((float) pos.Z / MAP_BLOCKSIZE)
+ );
+
+ v3f offset = intToFloat(client->getCamera()->getOffset(), BS);
+
+ s8 radius = m_block_bounds_mode == BLOCK_BOUNDS_ALL ? 2 : 0;
+
+ v3f halfNode = v3f(BS, BS, BS) / 2.0f;
+
+ for (s8 x = -radius; x <= radius; x++)
+ for (s8 y = -radius; y <= radius; y++)
+ for (s8 z = -radius; z <= radius; z++) {
+ v3s16 blockOffset(x, y, z);
+
+ aabb3f box(
+ intToFloat((blockPos + blockOffset) * MAP_BLOCKSIZE, BS) - offset - halfNode,
+ intToFloat(((blockPos + blockOffset) * MAP_BLOCKSIZE) + (MAP_BLOCKSIZE - 1), BS) - offset + halfNode
+ );
+
+ driver->draw3DBox(box, video::SColor(255, 255, 0, 0));
+ }
+
+ driver->setMaterial(old_material);
+}
+
void Hud::updateSelectionMesh(const v3s16 &camera_offset)
{
m_camera_offset = camera_offset;
@@ -908,7 +955,7 @@ void Hud::updateSelectionMesh(const v3s16 &camera_offset)
}
void Hud::resizeHotbar() {
- const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
+ const v2u32 &window_size = RenderingEngine::getWindowSize();
if (m_screensize != window_size) {
m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE *
@@ -945,10 +992,18 @@ void drawItemStack(
return;
}
+ const static thread_local bool enable_animations =
+ g_settings->getBool("inventory_items_animations");
+
const ItemDefinition &def = item.getDefinition(client->idef());
- ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client);
- if (imesh && imesh->mesh) {
+ bool draw_overlay = false;
+
+ // Render as mesh if animated or no inventory image
+ if ((enable_animations && rotation_kind < IT_ROT_NONE) || def.inventory_image.empty()) {
+ ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client);
+ if (!imesh || !imesh->mesh)
+ return;
scene::IMesh *mesh = imesh->mesh;
driver->clearBuffers(video::ECBF_DEPTH);
s32 delta = 0;
@@ -992,9 +1047,6 @@ void drawItemStack(
core::matrix4 matrix;
matrix.makeIdentity();
- static thread_local bool enable_animations =
- g_settings->getBool("inventory_items_animations");
-
if (enable_animations) {
float timer_f = (float) delta / 5000.f;
matrix.setRotationDegrees(v3f(
@@ -1040,15 +1092,29 @@ void drawItemStack(
driver->setTransform(video::ETS_PROJECTION, oldProjMat);
driver->setViewPort(oldViewPort);
- // draw the inventory_overlay
- if (def.type == ITEM_NODE && def.inventory_image.empty() &&
- !def.inventory_overlay.empty()) {
- ITextureSource *tsrc = client->getTextureSource();
- video::ITexture *overlay_texture = tsrc->getTexture(def.inventory_overlay);
- core::dimension2d<u32> dimens = overlay_texture->getOriginalSize();
- core::rect<s32> srcrect(0, 0, dimens.Width, dimens.Height);
- draw2DImageFilterScaled(driver, overlay_texture, rect, srcrect, clip, 0, true);
- }
+ draw_overlay = def.type == ITEM_NODE && def.inventory_image.empty();
+ } else { // Otherwise just draw as 2D
+ video::ITexture *texture = client->idef()->getInventoryTexture(def.name, client);
+ if (!texture)
+ return;
+ video::SColor color =
+ client->idef()->getItemstackColor(item, client);
+ const video::SColor colors[] = { color, color, color, color };
+
+ draw2DImageFilterScaled(driver, texture, rect,
+ core::rect<s32>({0, 0}, core::dimension2di(texture->getOriginalSize())),
+ clip, colors, true);
+
+ draw_overlay = true;
+ }
+
+ // draw the inventory_overlay
+ if (!def.inventory_overlay.empty() && draw_overlay) {
+ ITextureSource *tsrc = client->getTextureSource();
+ video::ITexture *overlay_texture = tsrc->getTexture(def.inventory_overlay);
+ core::dimension2d<u32> dimens = overlay_texture->getOriginalSize();
+ core::rect<s32> srcrect(0, 0, dimens.Width, dimens.Height);
+ draw2DImageFilterScaled(driver, overlay_texture, rect, srcrect, clip, 0, true);
}
if (def.type == ITEM_TOOL && item.wear != 0) {
diff --git a/src/client/hud.h b/src/client/hud.h
index d46545d71..d341105d2 100644
--- a/src/client/hud.h
+++ b/src/client/hud.h
@@ -35,14 +35,6 @@ struct ItemStack;
class Hud
{
public:
- video::IVideoDriver *driver;
- scene::ISceneManager *smgr;
- gui::IGUIEnvironment *guienv;
- Client *client;
- LocalPlayer *player;
- Inventory *inventory;
- ITextureSource *tsrc;
-
video::SColor crosshair_argb;
video::SColor selectionbox_argb;
@@ -55,10 +47,13 @@ public:
bool pointing_at_object = false;
- Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player,
+ Hud(Client *client, LocalPlayer *player,
Inventory *inventory);
~Hud();
+ void toggleBlockBounds();
+ void drawBlockBounds();
+
void drawHotbar(u16 playeritem);
void resizeHotbar();
void drawCrosshair();
@@ -103,6 +98,12 @@ private:
void drawCompassRotate(HudElement *e, video::ITexture *texture,
const core::rect<s32> &rect, int way);
+ Client *client = nullptr;
+ video::IVideoDriver *driver = nullptr;
+ LocalPlayer *player = nullptr;
+ Inventory *inventory = nullptr;
+ ITextureSource *tsrc = nullptr;
+
float m_hud_scaling; // cached minetest setting
float m_scale_factor;
v3s16 m_camera_offset;
@@ -125,6 +126,14 @@ private:
scene::SMeshBuffer m_rotation_mesh_buffer;
+ enum BlockBoundsMode
+ {
+ BLOCK_BOUNDS_OFF,
+ BLOCK_BOUNDS_CURRENT,
+ BLOCK_BOUNDS_ALL,
+ BLOCK_BOUNDS_MAX
+ } m_block_bounds_mode = BLOCK_BOUNDS_OFF;
+
enum
{
HIGHLIGHT_BOX,
diff --git a/src/client/imagefilters.cpp b/src/client/imagefilters.cpp
index 0fa501410..7b2ef9822 100644
--- a/src/client/imagefilters.cpp
+++ b/src/client/imagefilters.cpp
@@ -19,63 +19,134 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "imagefilters.h"
#include "util/numeric.h"
#include <cmath>
+#include <cassert>
+#include <vector>
+
+// Simple 2D bitmap class with just the functionality needed here
+class Bitmap {
+ u32 linesize, lines;
+ std::vector<u8> data;
+
+ static inline u32 bytepos(u32 index) { return index >> 3; }
+ static inline u8 bitpos(u32 index) { return index & 7; }
+
+public:
+ Bitmap(u32 width, u32 height) : linesize(width), lines(height),
+ data(bytepos(width * height) + 1) {}
+
+ inline bool get(u32 x, u32 y) const {
+ u32 index = y * linesize + x;
+ return data[bytepos(index)] & (1 << bitpos(index));
+ }
+
+ inline void set(u32 x, u32 y) {
+ u32 index = y * linesize + x;
+ data[bytepos(index)] |= 1 << bitpos(index);
+ }
+
+ inline bool all() const {
+ for (u32 i = 0; i < data.size() - 1; i++) {
+ if (data[i] != 0xff)
+ return false;
+ }
+ // last byte not entirely filled
+ for (u8 i = 0; i < bitpos(linesize * lines); i++) {
+ bool value_of_bit = data.back() & (1 << i);
+ if (!value_of_bit)
+ return false;
+ }
+ return true;
+ }
+
+ inline void copy(Bitmap &to) const {
+ assert(to.linesize == linesize && to.lines == lines);
+ to.data = data;
+ }
+};
/* Fill in RGB values for transparent pixels, to correct for odd colors
* appearing at borders when blending. This is because many PNG optimizers
* like to discard RGB values of transparent pixels, but when blending then
- * with non-transparent neighbors, their RGB values will shpw up nonetheless.
+ * with non-transparent neighbors, their RGB values will show up nonetheless.
*
* This function modifies the original image in-place.
*
* Parameter "threshold" is the alpha level below which pixels are considered
- * transparent. Should be 127 for 3d where alpha is threshold, but 0 for
- * 2d where alpha is blended.
+ * transparent. Should be 127 when the texture is used with ALPHA_CHANNEL_REF,
+ * 0 when alpha blending is used.
*/
void imageCleanTransparent(video::IImage *src, u32 threshold)
{
core::dimension2d<u32> dim = src->getDimension();
- // Walk each pixel looking for fully transparent ones.
+ Bitmap bitmap(dim.Width, dim.Height);
+
+ // First pass: Mark all opaque pixels
// Note: loop y around x for better cache locality.
for (u32 ctry = 0; ctry < dim.Height; ctry++)
for (u32 ctrx = 0; ctrx < dim.Width; ctrx++) {
+ if (src->getPixel(ctrx, ctry).getAlpha() > threshold)
+ bitmap.set(ctrx, ctry);
+ }
+
+ // Exit early if all pixels opaque
+ if (bitmap.all())
+ return;
+
+ Bitmap newmap = bitmap;
+
+ // Then repeatedly look for transparent pixels, filling them in until
+ // we're finished (capped at 50 iterations).
+ for (u32 iter = 0; iter < 50; iter++) {
- // Ignore opaque pixels.
- irr::video::SColor c = src->getPixel(ctrx, ctry);
- if (c.getAlpha() > threshold)
+ for (u32 ctry = 0; ctry < dim.Height; ctry++)
+ for (u32 ctrx = 0; ctrx < dim.Width; ctrx++) {
+ // Skip pixels we have already processed
+ if (bitmap.get(ctrx, ctry))
continue;
- // Sample size and total weighted r, g, b values.
+ video::SColor c = src->getPixel(ctrx, ctry);
+
+ // Sample size and total weighted r, g, b values
u32 ss = 0, sr = 0, sg = 0, sb = 0;
- // Walk each neighbor pixel (clipped to image bounds).
+ // Walk each neighbor pixel (clipped to image bounds)
for (u32 sy = (ctry < 1) ? 0 : (ctry - 1);
sy <= (ctry + 1) && sy < dim.Height; sy++)
for (u32 sx = (ctrx < 1) ? 0 : (ctrx - 1);
sx <= (ctrx + 1) && sx < dim.Width; sx++) {
-
- // Ignore transparent pixels.
- irr::video::SColor d = src->getPixel(sx, sy);
- if (d.getAlpha() <= threshold)
+ // Ignore pixels we haven't processed
+ if (!bitmap.get(sx, sy))
continue;
-
- // Add RGB values weighted by alpha.
- u32 a = d.getAlpha();
+
+ // Add RGB values weighted by alpha IF the pixel is opaque, otherwise
+ // use full weight since we want to propagate colors.
+ video::SColor d = src->getPixel(sx, sy);
+ u32 a = d.getAlpha() <= threshold ? 255 : d.getAlpha();
ss += a;
sr += a * d.getRed();
sg += a * d.getGreen();
sb += a * d.getBlue();
}
- // If we found any neighbor RGB data, set pixel to average
- // weighted by alpha.
+ // Set pixel to average weighted by alpha
if (ss > 0) {
c.setRed(sr / ss);
c.setGreen(sg / ss);
c.setBlue(sb / ss);
src->setPixel(ctrx, ctry, c);
+ newmap.set(ctrx, ctry);
}
}
+
+ if (newmap.all())
+ return;
+
+ // Apply changes to bitmap for next run. This is done so we don't introduce
+ // a bias in color propagation in the direction pixels are processed.
+ newmap.copy(bitmap);
+
+ }
}
/* Scale a region of an image into another image, using nearest-neighbor with
diff --git a/src/client/imagefilters.h b/src/client/imagefilters.h
index 5676faf85..c9bdefbb6 100644
--- a/src/client/imagefilters.h
+++ b/src/client/imagefilters.h
@@ -23,13 +23,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
/* Fill in RGB values for transparent pixels, to correct for odd colors
* appearing at borders when blending. This is because many PNG optimizers
* like to discard RGB values of transparent pixels, but when blending then
- * with non-transparent neighbors, their RGB values will shpw up nonetheless.
+ * with non-transparent neighbors, their RGB values will show up nonetheless.
*
* This function modifies the original image in-place.
*
* Parameter "threshold" is the alpha level below which pixels are considered
- * transparent. Should be 127 for 3d where alpha is threshold, but 0 for
- * 2d where alpha is blended.
+ * transparent. Should be 127 when the texture is used with ALPHA_CHANNEL_REF,
+ * 0 when alpha blending is used.
*/
void imageCleanTransparent(video::IImage *src, u32 threshold);
diff --git a/src/client/inputhandler.cpp b/src/client/inputhandler.cpp
index 8b9cb64f5..d833db2f1 100644
--- a/src/client/inputhandler.cpp
+++ b/src/client/inputhandler.cpp
@@ -61,6 +61,7 @@ void KeyCache::populate()
key[KeyType::DEC_VOLUME] = getKeySetting("keymap_decrease_volume");
key[KeyType::CINEMATIC] = getKeySetting("keymap_cinematic");
key[KeyType::SCREENSHOT] = getKeySetting("keymap_screenshot");
+ key[KeyType::TOGGLE_BLOCK_BOUNDS] = getKeySetting("keymap_toggle_block_bounds");
key[KeyType::TOGGLE_HUD] = getKeySetting("keymap_toggle_hud");
key[KeyType::TOGGLE_CHAT] = getKeySetting("keymap_toggle_chat");
key[KeyType::TOGGLE_FOG] = getKeySetting("keymap_toggle_fog");
diff --git a/src/client/keycode.cpp b/src/client/keycode.cpp
index ce5214f54..fac077f0f 100644
--- a/src/client/keycode.cpp
+++ b/src/client/keycode.cpp
@@ -197,7 +197,6 @@ static const struct table_key table[] = {
DEFINEKEY1(KEY_MODECHANGE, N_("IME Mode Change"))
DEFINEKEY1(KEY_APPS, N_("Apps"))
DEFINEKEY1(KEY_SLEEP, N_("Sleep"))
-#if !(IRRLICHT_VERSION_MAJOR <= 1 && IRRLICHT_VERSION_MINOR <= 7 && IRRLICHT_VERSION_REVISION < 3)
DEFINEKEY1(KEY_OEM_1, "OEM 1") // KEY_OEM_[0-9] and KEY_OEM_102 are assigned to multiple
DEFINEKEY1(KEY_OEM_2, "OEM 2") // different chars (on different platforms too) and thus w/o char
DEFINEKEY1(KEY_OEM_3, "OEM 3")
@@ -208,7 +207,6 @@ static const struct table_key table[] = {
DEFINEKEY1(KEY_OEM_8, "OEM 8")
DEFINEKEY1(KEY_OEM_AX, "OEM AX")
DEFINEKEY1(KEY_OEM_102, "OEM 102")
-#endif
DEFINEKEY1(KEY_ATTN, "Attn")
DEFINEKEY1(KEY_CRSEL, "CrSel")
DEFINEKEY1(KEY_EXSEL, "ExSel")
diff --git a/src/client/keys.h b/src/client/keys.h
index 1be398ff3..b81b571b2 100644
--- a/src/client/keys.h
+++ b/src/client/keys.h
@@ -60,6 +60,7 @@ public:
DEC_VOLUME,
CINEMATIC,
SCREENSHOT,
+ TOGGLE_BLOCK_BOUNDS,
TOGGLE_HUD,
TOGGLE_CHAT,
TOGGLE_FOG,
diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp
index 25f734f0e..8877e0549 100644
--- a/src/client/mapblock_mesh.cpp
+++ b/src/client/mapblock_mesh.cpp
@@ -1140,8 +1140,8 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
*/
{
- MapblockMeshGenerator generator(data, &collector);
- generator.generate();
+ MapblockMeshGenerator(data, &collector,
+ data->m_client->getSceneManager()->getMeshManipulator()).generate();
}
/*
diff --git a/src/client/mesh.cpp b/src/client/mesh.cpp
index 2400a374c..e43139218 100644
--- a/src/client/mesh.cpp
+++ b/src/client/mesh.cpp
@@ -27,14 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <SAnimatedMesh.h>
#include <IAnimatedMeshSceneNode.h>
-// In Irrlicht 1.8 the signature of ITexture::lock was changed from
-// (bool, u32) to (E_TEXTURE_LOCK_MODE, u32).
-#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
-#define MY_ETLM_READ_ONLY true
-#else
-#define MY_ETLM_READ_ONLY video::ETLM_READ_ONLY
-#endif
-
inline static void applyShadeFactor(video::SColor& color, float factor)
{
color.setRed(core::clamp(core::round32(color.getRed()*factor), 0, 255));
diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp
index 165fa80bd..3013e1406 100644
--- a/src/client/minimap.cpp
+++ b/src/client/minimap.cpp
@@ -491,7 +491,8 @@ video::ITexture *Minimap::getMinimapTexture()
// Want to use texture source, to : 1 find texture, 2 cache it
video::ITexture* texture = m_tsrc->getTexture(data->mode.texture);
video::IImage* image = driver->createImageFromData(
- texture->getColorFormat(), texture->getSize(), texture->lock(), true, false);
+ texture->getColorFormat(), texture->getSize(),
+ texture->lock(video::ETLM_READ_ONLY), true, false);
texture->unlock();
auto dim = image->getDimension();
@@ -576,7 +577,7 @@ scene::SMeshBuffer *Minimap::getMinimapMeshBuffer()
void Minimap::drawMinimap()
{
// Non hud managed minimap drawing (legacy minimap)
- v2u32 screensize = RenderingEngine::get_instance()->getWindowSize();
+ v2u32 screensize = RenderingEngine::getWindowSize();
const u32 size = 0.25 * screensize.Y;
drawMinimap(core::rect<s32>(
diff --git a/src/client/particles.cpp b/src/client/particles.cpp
index 7acd996dc..288826a5f 100644
--- a/src/client/particles.cpp
+++ b/src/client/particles.cpp
@@ -64,8 +64,8 @@ Particle::Particle(
v2f texsize,
video::SColor color
):
- scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(),
- RenderingEngine::get_scene_manager())
+ scene::ISceneNode(((Client *)gamedef)->getSceneManager()->getRootSceneNode(),
+ ((Client *)gamedef)->getSceneManager())
{
// Misc
m_gamedef = gamedef;
diff --git a/src/client/render/core.cpp b/src/client/render/core.cpp
index 794ec0186..99af085f9 100644
--- a/src/client/render/core.cpp
+++ b/src/client/render/core.cpp
@@ -163,6 +163,7 @@ void RenderingCore::draw3D()
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
if (!show_hud)
return;
+ hud->drawBlockBounds();
hud->drawSelectionMesh();
if (draw_entity_esp || draw_entity_tracers || draw_player_esp || draw_player_tracers || draw_node_esp || draw_node_tracers)
drawTracersAndESP();
diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp
index 703a988b5..138012414 100644
--- a/src/client/renderingengine.cpp
+++ b/src/client/renderingengine.cpp
@@ -159,7 +159,7 @@ RenderingEngine::~RenderingEngine()
s_singleton = nullptr;
}
-v2u32 RenderingEngine::getWindowSize() const
+v2u32 RenderingEngine::_getWindowSize() const
{
if (core)
return core->getVirtualSize();
@@ -225,6 +225,20 @@ bool RenderingEngine::print_video_modes()
return videomode_list != NULL;
}
+void RenderingEngine::removeMesh(const scene::IMesh* mesh)
+{
+ m_device->getSceneManager()->getMeshCache()->removeMesh(mesh);
+}
+
+void RenderingEngine::cleanupMeshCache()
+{
+ auto mesh_cache = m_device->getSceneManager()->getMeshCache();
+ while (mesh_cache->getMeshCount() != 0) {
+ if (scene::IAnimatedMesh *mesh = mesh_cache->getMeshByIndex(0))
+ mesh_cache->removeMesh(mesh);
+ }
+}
+
bool RenderingEngine::setupTopLevelWindow(const std::string &name)
{
// FIXME: It would make more sense for there to be a switch of some
@@ -335,6 +349,10 @@ static bool getWindowHandle(irr::video::IVideoDriver *driver, HWND &hWnd)
case video::EDT_DIRECT3D9:
hWnd = reinterpret_cast<HWND>(exposedData.D3D9.HWnd);
break;
+#if ENABLE_GLES
+ case video::EDT_OGLES1:
+ case video::EDT_OGLES2:
+#endif
case video::EDT_OPENGL:
hWnd = reinterpret_cast<HWND>(exposedData.OpenGLWin32.HWnd);
break;
@@ -474,11 +492,11 @@ bool RenderingEngine::setXorgWindowIconFromPath(const std::string &icon_file)
Text will be removed when the screen is drawn the next time.
Additionally, a progressbar can be drawn when percent is set between 0 and 100.
*/
-void RenderingEngine::_draw_load_screen(const std::wstring &text,
+void RenderingEngine::draw_load_screen(const std::wstring &text,
gui::IGUIEnvironment *guienv, ITextureSource *tsrc, float dtime,
int percent, bool clouds)
{
- v2u32 screensize = RenderingEngine::get_instance()->getWindowSize();
+ v2u32 screensize = getWindowSize();
v2s32 textsize(g_fontengine->getTextWidth(text), g_fontengine->getLineHeight());
v2s32 center(screensize.X / 2, screensize.Y / 2);
@@ -546,7 +564,7 @@ void RenderingEngine::_draw_load_screen(const std::wstring &text,
/*
Draws the menu scene including (optional) cloud background.
*/
-void RenderingEngine::_draw_menu_scene(gui::IGUIEnvironment *guienv,
+void RenderingEngine::draw_menu_scene(gui::IGUIEnvironment *guienv,
float dtime, bool clouds)
{
bool cloud_menu_background = clouds && g_settings->getBool("menu_clouds");
@@ -594,19 +612,19 @@ std::vector<irr::video::E_DRIVER_TYPE> RenderingEngine::getSupportedVideoDrivers
return drivers;
}
-void RenderingEngine::_initialize(Client *client, Hud *hud)
+void RenderingEngine::initialize(Client *client, Hud *hud)
{
const std::string &draw_mode = g_settings->get("3d_mode");
core.reset(createRenderingCore(draw_mode, m_device, client, hud));
core->initialize();
}
-void RenderingEngine::_finalize()
+void RenderingEngine::finalize()
{
core.reset();
}
-void RenderingEngine::_draw_scene(video::SColor skycolor, bool show_hud,
+void RenderingEngine::draw_scene(video::SColor skycolor, bool show_hud,
bool show_minimap, bool draw_wield_tool, bool draw_crosshair)
{
core->draw(skycolor, show_hud, show_minimap, draw_wield_tool, draw_crosshair);
diff --git a/src/client/renderingengine.h b/src/client/renderingengine.h
index 34cc60630..28ddc8652 100644
--- a/src/client/renderingengine.h
+++ b/src/client/renderingengine.h
@@ -41,7 +41,6 @@ public:
RenderingEngine(IEventReceiver *eventReceiver);
~RenderingEngine();
- v2u32 getWindowSize() const;
void setResizable(bool resize);
video::IVideoDriver *getVideoDriver() { return driver; }
@@ -56,31 +55,30 @@ public:
bool setWindowIcon();
bool setXorgWindowIconFromPath(const std::string &icon_file);
static bool print_video_modes();
+ void cleanupMeshCache();
- static RenderingEngine *get_instance() { return s_singleton; }
+ void removeMesh(const scene::IMesh* mesh);
- static io::IFileSystem *get_filesystem()
+ static v2u32 getWindowSize()
{
- sanity_check(s_singleton && s_singleton->m_device);
- return s_singleton->m_device->getFileSystem();
+ sanity_check(s_singleton);
+ return s_singleton->_getWindowSize();
}
- static video::IVideoDriver *get_video_driver()
+ io::IFileSystem *get_filesystem()
{
- sanity_check(s_singleton && s_singleton->m_device);
- return s_singleton->m_device->getVideoDriver();
+ return m_device->getFileSystem();
}
- static scene::IMeshCache *get_mesh_cache()
+ static video::IVideoDriver *get_video_driver()
{
sanity_check(s_singleton && s_singleton->m_device);
- return s_singleton->m_device->getSceneManager()->getMeshCache();
+ return s_singleton->m_device->getVideoDriver();
}
- static scene::ISceneManager *get_scene_manager()
+ scene::ISceneManager *get_scene_manager()
{
- sanity_check(s_singleton && s_singleton->m_device);
- return s_singleton->m_device->getSceneManager();
+ return m_device->getSceneManager();
}
static irr::IrrlichtDevice *get_raw_device()
@@ -89,70 +87,37 @@ public:
return s_singleton->m_device;
}
- static u32 get_timer_time()
+ u32 get_timer_time()
{
- sanity_check(s_singleton && s_singleton->m_device &&
- s_singleton->m_device->getTimer());
- return s_singleton->m_device->getTimer()->getTime();
+ return m_device->getTimer()->getTime();
}
- static gui::IGUIEnvironment *get_gui_env()
+ gui::IGUIEnvironment *get_gui_env()
{
- sanity_check(s_singleton && s_singleton->m_device);
- return s_singleton->m_device->getGUIEnvironment();
+ return m_device->getGUIEnvironment();
}
- inline static void draw_load_screen(const std::wstring &text,
+ void draw_load_screen(const std::wstring &text,
gui::IGUIEnvironment *guienv, ITextureSource *tsrc,
- float dtime = 0, int percent = 0, bool clouds = true)
- {
- s_singleton->_draw_load_screen(
- text, guienv, tsrc, dtime, percent, clouds);
- }
+ float dtime = 0, int percent = 0, bool clouds = true);
- inline static void draw_menu_scene(
- gui::IGUIEnvironment *guienv, float dtime, bool clouds)
- {
- s_singleton->_draw_menu_scene(guienv, dtime, clouds);
- }
+ void draw_menu_scene(gui::IGUIEnvironment *guienv, float dtime, bool clouds);
+ void draw_scene(video::SColor skycolor, bool show_hud,
+ bool show_minimap, bool draw_wield_tool, bool draw_crosshair);
- inline static void draw_scene(video::SColor skycolor, bool show_hud,
- bool show_minimap, bool draw_wield_tool, bool draw_crosshair)
- {
- s_singleton->_draw_scene(skycolor, show_hud, show_minimap,
- draw_wield_tool, draw_crosshair);
- }
+ void initialize(Client *client, Hud *hud);
+ void finalize();
- inline static void initialize(Client *client, Hud *hud)
+ bool run()
{
- s_singleton->_initialize(client, hud);
- }
-
- inline static void finalize() { s_singleton->_finalize(); }
-
- static bool run()
- {
- sanity_check(s_singleton && s_singleton->m_device);
- return s_singleton->m_device->run();
+ return m_device->run();
}
static std::vector<core::vector3d<u32>> getSupportedVideoModes();
static std::vector<irr::video::E_DRIVER_TYPE> getSupportedVideoDrivers();
private:
- void _draw_load_screen(const std::wstring &text, gui::IGUIEnvironment *guienv,
- ITextureSource *tsrc, float dtime = 0, int percent = 0,
- bool clouds = true);
-
- void _draw_menu_scene(gui::IGUIEnvironment *guienv, float dtime = 0,
- bool clouds = true);
-
- void _draw_scene(video::SColor skycolor, bool show_hud, bool show_minimap,
- bool draw_wield_tool, bool draw_crosshair);
-
- void _initialize(Client *client, Hud *hud);
-
- void _finalize();
+ v2u32 _getWindowSize() const;
std::unique_ptr<RenderingCore> core;
irr::IrrlichtDevice *m_device = nullptr;
diff --git a/src/client/shader.cpp b/src/client/shader.cpp
index b3e4911f4..58946b90f 100644
--- a/src/client/shader.cpp
+++ b/src/client/shader.cpp
@@ -579,8 +579,10 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
if (use_gles) {
shaders_header << R"(
#version 100
- )";
+ )";
vertex_header = R"(
+ precision mediump float;
+
uniform highp mat4 mWorldView;
uniform highp mat4 mWorldViewProj;
uniform mediump mat4 mTexture;
@@ -592,17 +594,17 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
attribute mediump vec3 inVertexNormal;
attribute mediump vec4 inVertexTangent;
attribute mediump vec4 inVertexBinormal;
- )";
+ )";
fragment_header = R"(
precision mediump float;
- )";
+ )";
} else {
shaders_header << R"(
#version 120
#define lowp
#define mediump
#define highp
- )";
+ )";
vertex_header = R"(
#define mWorldView gl_ModelViewMatrix
#define mWorldViewProj gl_ModelViewProjectionMatrix
@@ -615,7 +617,7 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
#define inVertexNormal gl_Normal
#define inVertexTangent gl_MultiTexCoord1
#define inVertexBinormal gl_MultiTexCoord2
- )";
+ )";
}
bool use_discard = use_gles;
diff --git a/src/client/sky.cpp b/src/client/sky.cpp
index caf695e7a..47296a7a5 100644
--- a/src/client/sky.cpp
+++ b/src/client/sky.cpp
@@ -53,10 +53,12 @@ static video::SMaterial baseMaterial()
return mat;
};
-Sky::Sky(s32 id, ITextureSource *tsrc, IShaderSource *ssrc) :
- scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(),
- RenderingEngine::get_scene_manager(), id)
+Sky::Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShaderSource *ssrc) :
+ scene::ISceneNode(rendering_engine->get_scene_manager()->getRootSceneNode(),
+ rendering_engine->get_scene_manager(), id)
{
+ m_seed = (u64)myrand() << 32 | myrand();
+
setAutomaticCulling(scene::EAC_OFF);
m_box.MaxEdge.set(0, 0, 0);
m_box.MinEdge.set(0, 0, 0);
@@ -82,13 +84,13 @@ Sky::Sky(s32 id, ITextureSource *tsrc, IShaderSource *ssrc) :
// Ensures that sun and moon textures and tonemaps are correct.
setSkyDefaults();
m_sun_texture = tsrc->isKnownSourceImage(m_sun_params.texture) ?
- tsrc->getTextureForMesh(m_sun_params.texture) : NULL;
+ tsrc->getTextureForMesh(m_sun_params.texture) : nullptr;
m_moon_texture = tsrc->isKnownSourceImage(m_moon_params.texture) ?
- tsrc->getTextureForMesh(m_moon_params.texture) : NULL;
+ tsrc->getTextureForMesh(m_moon_params.texture) : nullptr;
m_sun_tonemap = tsrc->isKnownSourceImage(m_sun_params.tonemap) ?
- tsrc->getTexture(m_sun_params.tonemap) : NULL;
+ tsrc->getTexture(m_sun_params.tonemap) : nullptr;
m_moon_tonemap = tsrc->isKnownSourceImage(m_moon_params.tonemap) ?
- tsrc->getTexture(m_moon_params.tonemap) : NULL;
+ tsrc->getTexture(m_moon_params.tonemap) : nullptr;
if (m_sun_texture) {
m_materials[3] = baseMaterial();
@@ -744,14 +746,14 @@ void Sky::place_sky_body(
}
}
-void Sky::setSunTexture(std::string sun_texture,
- std::string sun_tonemap, ITextureSource *tsrc)
+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(m_sun_params.tonemap) ?
- tsrc->getTexture(m_sun_params.tonemap) : NULL;
+ tsrc->getTexture(m_sun_params.tonemap) : nullptr;
m_materials[3].Lighting = !!m_sun_tonemap;
if (m_sun_params.texture == sun_texture)
@@ -780,7 +782,7 @@ void Sky::setSunTexture(std::string sun_texture,
}
}
-void Sky::setSunriseTexture(std::string sunglow_texture,
+void Sky::setSunriseTexture(const std::string &sunglow_texture,
ITextureSource* tsrc)
{
// Ignore matching textures (with modifiers) entirely.
@@ -792,14 +794,14 @@ void Sky::setSunriseTexture(std::string sunglow_texture,
);
}
-void Sky::setMoonTexture(std::string moon_texture,
- std::string moon_tonemap, ITextureSource *tsrc)
+void Sky::setMoonTexture(const std::string &moon_texture,
+ const std::string &moon_tonemap, ITextureSource *tsrc)
{
// 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(m_moon_params.tonemap) ?
- tsrc->getTexture(m_moon_params.tonemap) : NULL;
+ tsrc->getTexture(m_moon_params.tonemap) : nullptr;
m_materials[4].Lighting = !!m_moon_tonemap;
if (m_moon_params.texture == moon_texture)
@@ -833,7 +835,6 @@ void Sky::setStarCount(u16 star_count, bool force_update)
// Allow force updating star count at game init.
if (m_star_params.count != star_count || force_update) {
m_star_params.count = star_count;
- m_seed = (u64)myrand() << 32 | myrand();
updateStars();
}
}
@@ -893,7 +894,7 @@ void Sky::setSkyColors(const SkyColor &sky_color)
}
void Sky::setHorizonTint(video::SColor sun_tint, video::SColor moon_tint,
- std::string use_sun_tint)
+ const std::string &use_sun_tint)
{
// Change sun and moon tinting:
m_sky_params.fog_sun_tint = sun_tint;
@@ -907,7 +908,7 @@ void Sky::setHorizonTint(video::SColor sun_tint, video::SColor moon_tint,
m_default_tint = true;
}
-void Sky::addTextureToSkybox(std::string texture, int material_id,
+void Sky::addTextureToSkybox(const std::string &texture, int material_id,
ITextureSource *tsrc)
{
// Sanity check for more than six textures.
diff --git a/src/client/sky.h b/src/client/sky.h
index 342a97596..121a16bb7 100644
--- a/src/client/sky.h
+++ b/src/client/sky.h
@@ -36,7 +36,7 @@ class Sky : public scene::ISceneNode
{
public:
//! constructor
- Sky(s32 id, ITextureSource *tsrc, IShaderSource *ssrc);
+ Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShaderSource *ssrc);
virtual void OnRegisterSceneNode();
@@ -65,15 +65,15 @@ public:
}
void setSunVisible(bool sun_visible) { m_sun_params.visible = sun_visible; }
- void setSunTexture(std::string sun_texture,
- std::string sun_tonemap, ITextureSource *tsrc);
+ void setSunTexture(const std::string &sun_texture,
+ const std::string &sun_tonemap, ITextureSource *tsrc);
void setSunScale(f32 sun_scale) { m_sun_params.scale = sun_scale; }
void setSunriseVisible(bool glow_visible) { m_sun_params.sunrise_visible = glow_visible; }
- void setSunriseTexture(std::string sunglow_texture, ITextureSource* tsrc);
+ void setSunriseTexture(const std::string &sunglow_texture, ITextureSource* tsrc);
void setMoonVisible(bool moon_visible) { m_moon_params.visible = moon_visible; }
- void setMoonTexture(std::string moon_texture,
- std::string moon_tonemap, ITextureSource *tsrc);
+ void setMoonTexture(const std::string &moon_texture,
+ const std::string &moon_tonemap, ITextureSource *tsrc);
void setMoonScale(f32 moon_scale) { m_moon_params.scale = moon_scale; }
void setStarsVisible(bool stars_visible) { m_star_params.visible = stars_visible; }
@@ -87,21 +87,21 @@ public:
void setVisible(bool visible) { m_visible = visible; }
// Set only from set_sky API
void setCloudsEnabled(bool clouds_enabled) { m_clouds_enabled = clouds_enabled; }
- void setFallbackBgColor(const video::SColor &fallback_bg_color)
+ void setFallbackBgColor(video::SColor fallback_bg_color)
{
m_fallback_bg_color = fallback_bg_color;
}
- void overrideColors(const video::SColor &bgcolor, const video::SColor &skycolor)
+ void overrideColors(video::SColor bgcolor, video::SColor skycolor)
{
m_bgcolor = bgcolor;
m_skycolor = skycolor;
}
void setSkyColors(const SkyColor &sky_color);
void setHorizonTint(video::SColor sun_tint, video::SColor moon_tint,
- std::string use_sun_tint);
+ const std::string &use_sun_tint);
void setInClouds(bool clouds) { m_in_clouds = clouds; }
void clearSkyboxTextures() { m_sky_params.textures.clear(); }
- void addTextureToSkybox(std::string texture, int material_id,
+ void addTextureToSkybox(const std::string &texture, int material_id,
ITextureSource *tsrc);
const video::SColorf &getCurrentStarColor() const { return m_star_color; }
@@ -126,7 +126,7 @@ private:
}
// Mix two colors by a given amount
- video::SColor m_mix_scolor(video::SColor col1, video::SColor col2, f32 factor)
+ static video::SColor m_mix_scolor(video::SColor col1, video::SColor col2, f32 factor)
{
video::SColor result = video::SColor(
col1.getAlpha() * (1 - factor) + col2.getAlpha() * factor,
@@ -135,7 +135,7 @@ private:
col1.getBlue() * (1 - factor) + col2.getBlue() * factor);
return result;
}
- video::SColorf m_mix_scolorf(video::SColorf col1, video::SColorf col2, f32 factor)
+ static video::SColorf m_mix_scolorf(video::SColorf col1, video::SColorf col2, f32 factor)
{
video::SColorf result =
video::SColorf(col1.r * (1 - factor) + col2.r * factor,
diff --git a/src/client/tile.cpp b/src/client/tile.cpp
index 7e3901247..96312ea27 100644
--- a/src/client/tile.cpp
+++ b/src/client/tile.cpp
@@ -34,15 +34,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiscalingfilter.h"
#include "renderingengine.h"
-
-#if ENABLE_GLES
-#ifdef _IRR_COMPILE_WITH_OGLES1_
-#include <GLES/gl.h>
-#else
-#include <GLES2/gl2.h>
-#endif
-#endif
-
/*
A cache from texture name to texture path
*/
@@ -427,6 +418,7 @@ private:
std::unordered_map<std::string, Palette> m_palettes;
// Cached settings needed for making textures from meshes
+ bool m_setting_mipmap;
bool m_setting_trilinear_filter;
bool m_setting_bilinear_filter;
};
@@ -447,6 +439,7 @@ TextureSource::TextureSource()
// Cache some settings
// Note: Since this is only done once, the game must be restarted
// for these settings to take effect
+ m_setting_mipmap = g_settings->getBool("mip_map");
m_setting_trilinear_filter = g_settings->getBool("trilinear_filter");
m_setting_bilinear_filter = g_settings->getBool("bilinear_filter");
}
@@ -667,7 +660,7 @@ video::ITexture* TextureSource::getTexture(const std::string &name, u32 *id)
video::ITexture* TextureSource::getTextureForMesh(const std::string &name, u32 *id)
{
static thread_local bool filter_needed =
- g_settings->getBool("texture_clean_transparent") ||
+ g_settings->getBool("texture_clean_transparent") || m_setting_mipmap ||
((m_setting_trilinear_filter || m_setting_bilinear_filter) &&
g_settings->getS32("texture_min_size") > 1);
// Avoid duplicating texture if it won't actually change
@@ -1011,42 +1004,19 @@ video::IImage* TextureSource::generateImage(const std::string &name)
#if ENABLE_GLES
-
-static inline u16 get_GL_major_version()
-{
- const GLubyte *gl_version = glGetString(GL_VERSION);
- return (u16) (gl_version[0] - '0');
-}
-
-/**
- * Check if hardware requires npot2 aligned textures
- * @return true if alignment NOT(!) requires, false otherwise
- */
-
-bool hasNPotSupport()
-{
- // Only GLES2 is trusted to correctly report npot support
- // Note: we cache the boolean result, the GL context will never change.
- static const bool supported = get_GL_major_version() > 1 &&
- glGetString(GL_EXTENSIONS) &&
- strstr((char *)glGetString(GL_EXTENSIONS), "GL_OES_texture_npot");
- return supported;
-}
-
/**
* Check and align image to npot2 if required by hardware
* @param image image to check for npot2 alignment
* @param driver driver to use for image operations
* @return image or copy of image aligned to npot2
*/
-
-video::IImage * Align2Npot2(video::IImage * image,
- video::IVideoDriver* driver)
+video::IImage *Align2Npot2(video::IImage *image,
+ video::IVideoDriver *driver)
{
if (image == NULL)
return image;
- if (hasNPotSupport())
+ if (driver->queryFeature(video::EVDF_TEXTURE_NPOT))
return image;
core::dimension2d<u32> dim = image->getDimension();
@@ -1636,8 +1606,8 @@ bool TextureSource::generateImagePart(std::string part_of_name,
return false;
}
- // Apply the "clean transparent" filter, if configured.
- if (g_settings->getBool("texture_clean_transparent"))
+ // Apply the "clean transparent" filter, if needed
+ if (m_setting_mipmap || g_settings->getBool("texture_clean_transparent"))
imageCleanTransparent(baseimg, 127);
/* Upscale textures to user's requested minimum size. This is a trick to make
diff --git a/src/client/tile.h b/src/client/tile.h
index 49c46f749..fcdc46460 100644
--- a/src/client/tile.h
+++ b/src/client/tile.h
@@ -134,8 +134,7 @@ public:
IWritableTextureSource *createTextureSource();
#if ENABLE_GLES
-bool hasNPotSupport();
-video::IImage * Align2Npot2(video::IImage * image, irr::video::IVideoDriver* driver);
+video::IImage *Align2Npot2(video::IImage *image, video::IVideoDriver *driver);
#endif
enum MaterialType{
diff --git a/src/client/wieldmesh.cpp b/src/client/wieldmesh.cpp
index 387eb17c3..08fd49fc0 100644
--- a/src/client/wieldmesh.cpp
+++ b/src/client/wieldmesh.cpp
@@ -294,9 +294,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
}
material.setFlag(video::EMF_ANISOTROPIC_FILTER, m_anisotropic_filter);
// mipmaps cause "thin black line" artifacts
-#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2
material.setFlag(video::EMF_USE_MIP_MAPS, false);
-#endif
if (m_enable_shaders) {
material.setTexture(2, tsrc->getShaderFlagsTexture(false));
}
@@ -309,18 +307,21 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n,
MeshMakeData mesh_make_data(client, false);
MeshCollector collector;
mesh_make_data.setSmoothLighting(false);
- MapblockMeshGenerator gen(&mesh_make_data, &collector);
+ MapblockMeshGenerator gen(&mesh_make_data, &collector,
+ client->getSceneManager()->getMeshManipulator());
if (n.getParam2()) {
// keep it
} else if (f.param_type_2 == CPT2_WALLMOUNTED ||
f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
- if (f.drawtype == NDT_TORCHLIKE)
- n.setParam2(1);
- else if (f.drawtype == NDT_SIGNLIKE ||
+ if (f.drawtype == NDT_TORCHLIKE ||
+ f.drawtype == NDT_SIGNLIKE ||
f.drawtype == NDT_NODEBOX ||
- f.drawtype == NDT_MESH)
+ f.drawtype == NDT_MESH) {
n.setParam2(4);
+ }
+ } else if (f.drawtype == NDT_SIGNLIKE || f.drawtype == NDT_TORCHLIKE) {
+ n.setParam2(1);
}
gen.renderSingle(n.getContent(), n.getParam2());
@@ -395,7 +396,6 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
case NDT_TORCHLIKE:
case NDT_RAILLIKE:
case NDT_PLANTLIKE:
- case NDT_PLANTLIKE_ROOTED:
case NDT_FLOWINGLIQUID: {
v3f wscale = def.wield_scale;
if (f.drawtype == NDT_FLOWINGLIQUID)
@@ -411,6 +411,15 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
m_colors.emplace_back(l1.has_color, l1.color);
break;
}
+ case NDT_PLANTLIKE_ROOTED: {
+ setExtruded(tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id),
+ "", def.wield_scale, tsrc,
+ f.special_tiles[0].layers[0].animation_frame_count);
+ // Add color
+ const TileLayer &l0 = f.special_tiles[0].layers[0];
+ m_colors.emplace_back(l0.has_color, l0.color);
+ break;
+ }
case NDT_NORMAL:
case NDT_ALLFACES:
case NDT_LIQUID:
@@ -530,7 +539,7 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
content_t id = ndef->getId(def.name);
FATAL_ERROR_IF(!g_extrusion_mesh_cache, "Extrusion mesh cache is not yet initialized");
-
+
scene::SMesh *mesh = nullptr;
// Shading is on by default
diff --git a/src/clientiface.cpp b/src/clientiface.cpp
index 797afd3c1..f35dcd0eb 100644
--- a/src/clientiface.cpp
+++ b/src/clientiface.cpp
@@ -671,7 +671,6 @@ void ClientInterface::UpdatePlayerList()
std::vector<session_t> clients = getClientIDs();
m_clients_names.clear();
-
if (!clients.empty())
infostream<<"Players:"<<std::endl;
diff --git a/src/clientiface.h b/src/clientiface.h
index cc5292b71..dfd976741 100644
--- a/src/clientiface.h
+++ b/src/clientiface.h
@@ -31,6 +31,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <list>
#include <vector>
#include <set>
+#include <memory>
#include <mutex>
class MapBlock;
diff --git a/src/convert_json.cpp b/src/convert_json.cpp
index e9ff1e56c..686113fa8 100644
--- a/src/convert_json.cpp
+++ b/src/convert_json.cpp
@@ -17,56 +17,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include <vector>
#include <iostream>
#include <sstream>
+#include <memory>
#include "convert_json.h"
-#include "content/mods.h"
-#include "config.h"
-#include "log.h"
-#include "settings.h"
-#include "httpfetch.h"
-#include "porting.h"
-
-Json::Value fetchJsonValue(const std::string &url,
- std::vector<std::string> *extra_headers)
-{
- HTTPFetchRequest fetch_request;
- HTTPFetchResult fetch_result;
- fetch_request.url = url;
- fetch_request.caller = HTTPFETCH_SYNC;
-
- if (extra_headers != NULL)
- fetch_request.extra_headers = *extra_headers;
-
- httpfetch_sync(fetch_request, fetch_result);
-
- if (!fetch_result.succeeded) {
- return Json::Value();
- }
- Json::Value root;
- std::istringstream stream(fetch_result.data);
-
- Json::CharReaderBuilder builder;
- builder.settings_["collectComments"] = false;
- std::string errs;
-
- if (!Json::parseFromStream(builder, stream, &root, &errs)) {
- errorstream << "URL: " << url << std::endl;
- errorstream << "Failed to parse json data " << errs << std::endl;
- if (fetch_result.data.size() > 100) {
- errorstream << "Data (" << fetch_result.data.size()
- << " bytes) printed to warningstream." << std::endl;
- warningstream << "data: \"" << fetch_result.data << "\"" << std::endl;
- } else {
- errorstream << "data: \"" << fetch_result.data << "\"" << std::endl;
- }
- return Json::Value();
- }
-
- return root;
-}
void fastWriteJson(const Json::Value &value, std::ostream &to)
{
diff --git a/src/convert_json.h b/src/convert_json.h
index 2c094a946..d1d487e77 100644
--- a/src/convert_json.h
+++ b/src/convert_json.h
@@ -22,9 +22,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <json/json.h>
#include <ostream>
-Json::Value fetchJsonValue(const std::string &url,
- std::vector<std::string> *extra_headers);
-
void fastWriteJson(const Json::Value &value, std::ostream &to);
std::string fastWriteJson(const Json::Value &value);
diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp
index 313963c26..e16f15512 100644
--- a/src/defaultsettings.cpp
+++ b/src/defaultsettings.cpp
@@ -56,7 +56,7 @@ void set_default_settings()
settings->setDefault("client_unload_unused_data_timeout", "600");
settings->setDefault("client_mapblock_limit", "7500");
settings->setDefault("enable_build_where_you_stand", "true");
- settings->setDefault("curl_timeout", "5000");
+ settings->setDefault("curl_timeout", "20000");
settings->setDefault("curl_parallel_limit", "8");
settings->setDefault("curl_file_download_timeout", "300000");
settings->setDefault("curl_verify_cert", "true");
@@ -156,6 +156,7 @@ void set_default_settings()
settings->setDefault("keymap_increase_volume", "");
settings->setDefault("keymap_decrease_volume", "");
settings->setDefault("keymap_cinematic", "");
+ settings->setDefault("keymap_toggle_block_bounds", "");
settings->setDefault("keymap_toggle_hud", "KEY_F1");
settings->setDefault("keymap_toggle_chat", "KEY_F2");
settings->setDefault("keymap_toggle_fog", "KEY_F3");
@@ -372,12 +373,7 @@ void set_default_settings()
settings->setDefault("mono_font_path_bold_italic", porting::getDataPath("fonts" DIR_DELIM "Cousine-BoldItalic.ttf"));
settings->setDefault("fallback_font_path", porting::getDataPath("fonts" DIR_DELIM "DroidSansFallbackFull.ttf"));
- settings->setDefault("fallback_font_shadow", "1");
- settings->setDefault("fallback_font_shadow_alpha", "128");
-
std::string font_size_str = std::to_string(TTF_DEFAULT_FONT_SIZE);
-
- settings->setDefault("fallback_font_size", font_size_str);
#else
settings->setDefault("freetype", "false");
settings->setDefault("font_path", porting::getDataPath("fonts" DIR_DELIM "mono_dejavu_sans"));
diff --git a/src/filesys.cpp b/src/filesys.cpp
index 5ffb4506e..99b030624 100644
--- a/src/filesys.cpp
+++ b/src/filesys.cpp
@@ -727,6 +727,70 @@ bool safeWriteToFile(const std::string &path, const std::string &content)
return true;
}
+bool extractZipFile(io::IFileSystem *fs, const char *filename, const std::string &destination)
+{
+ if (!fs->addFileArchive(filename, false, false, io::EFAT_ZIP)) {
+ return false;
+ }
+
+ sanity_check(fs->getFileArchiveCount() > 0);
+
+ /**********************************************************************/
+ /* WARNING this is not threadsafe!! */
+ /**********************************************************************/
+ io::IFileArchive* opened_zip = fs->getFileArchive(fs->getFileArchiveCount() - 1);
+
+ const io::IFileList* files_in_zip = opened_zip->getFileList();
+
+ unsigned int number_of_files = files_in_zip->getFileCount();
+
+ for (unsigned int i=0; i < number_of_files; i++) {
+ std::string fullpath = destination;
+ fullpath += DIR_DELIM;
+ fullpath += files_in_zip->getFullFileName(i).c_str();
+ std::string fullpath_dir = fs::RemoveLastPathComponent(fullpath);
+
+ if (!files_in_zip->isDirectory(i)) {
+ if (!fs::PathExists(fullpath_dir) && !fs::CreateAllDirs(fullpath_dir)) {
+ fs->removeFileArchive(fs->getFileArchiveCount()-1);
+ return false;
+ }
+
+ io::IReadFile* toread = opened_zip->createAndOpenFile(i);
+
+ FILE *targetfile = fopen(fullpath.c_str(),"wb");
+
+ if (targetfile == NULL) {
+ fs->removeFileArchive(fs->getFileArchiveCount()-1);
+ return false;
+ }
+
+ char read_buffer[1024];
+ long total_read = 0;
+
+ while (total_read < toread->getSize()) {
+
+ unsigned int bytes_read =
+ toread->read(read_buffer,sizeof(read_buffer));
+ if ((bytes_read == 0 ) ||
+ (fwrite(read_buffer, 1, bytes_read, targetfile) != bytes_read))
+ {
+ fclose(targetfile);
+ fs->removeFileArchive(fs->getFileArchiveCount() - 1);
+ return false;
+ }
+ total_read += bytes_read;
+ }
+
+ fclose(targetfile);
+ }
+
+ }
+
+ fs->removeFileArchive(fs->getFileArchiveCount() - 1);
+ return true;
+}
+
bool ReadFile(const std::string &path, std::string &out)
{
std::ifstream is(path, std::ios::binary | std::ios::ate);
diff --git a/src/filesys.h b/src/filesys.h
index cfbfa02bf..a9584b036 100644
--- a/src/filesys.h
+++ b/src/filesys.h
@@ -36,6 +36,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define PATH_DELIM ":"
#endif
+namespace irr { namespace io {
+class IFileSystem;
+}}
+
namespace fs
{
@@ -125,6 +129,8 @@ const char *GetFilenameFromPath(const char *path);
bool safeWriteToFile(const std::string &path, const std::string &content);
+bool extractZipFile(irr::io::IFileSystem *fs, const char *filename, const std::string &destination);
+
bool ReadFile(const std::string &path, std::string &out);
bool Rename(const std::string &from, const std::string &to);
diff --git a/src/gui/cheatMenu.cpp b/src/gui/cheatMenu.cpp
index 7687f10d9..31acfb780 100644
--- a/src/gui/cheatMenu.cpp
+++ b/src/gui/cheatMenu.cpp
@@ -30,7 +30,7 @@ FontMode CheatMenu::fontStringToEnum(std::string str)
else if (str == "FM_Mono")
return FM_Mono;
else if (str == "FM_Fallback")
- return FM_Fallback;
+ return _FM_Fallback;
else if (str == "FM_Simple")
return FM_Simple;
else if (str == "FM_SimpleMono")
diff --git a/src/gui/guiButtonItemImage.cpp b/src/gui/guiButtonItemImage.cpp
index 39272fe37..d9ab4b935 100644
--- a/src/gui/guiButtonItemImage.cpp
+++ b/src/gui/guiButtonItemImage.cpp
@@ -30,7 +30,7 @@ using namespace gui;
GUIButtonItemImage::GUIButtonItemImage(gui::IGUIEnvironment *environment,
gui::IGUIElement *parent, s32 id, core::rect<s32> rectangle,
- ISimpleTextureSource *tsrc, std::string item, Client *client,
+ ISimpleTextureSource *tsrc, const std::string &item, Client *client,
bool noclip)
: GUIButton (environment, parent, id, rectangle, tsrc, noclip)
{
@@ -44,7 +44,7 @@ GUIButtonItemImage::GUIButtonItemImage(gui::IGUIEnvironment *environment,
GUIButtonItemImage *GUIButtonItemImage::addButton(IGUIEnvironment *environment,
const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
- IGUIElement *parent, s32 id, const wchar_t *text, std::string item,
+ IGUIElement *parent, s32 id, const wchar_t *text, const std::string &item,
Client *client)
{
GUIButtonItemImage *button = new GUIButtonItemImage(environment,
diff --git a/src/gui/guiButtonItemImage.h b/src/gui/guiButtonItemImage.h
index b90ac757e..205e957a7 100644
--- a/src/gui/guiButtonItemImage.h
+++ b/src/gui/guiButtonItemImage.h
@@ -33,13 +33,13 @@ public:
//! constructor
GUIButtonItemImage(gui::IGUIEnvironment *environment, gui::IGUIElement *parent,
s32 id, core::rect<s32> rectangle, ISimpleTextureSource *tsrc,
- std::string item, Client *client, bool noclip = false);
+ const std::string &item, Client *client, bool noclip = false);
//! Do not drop returned handle
static GUIButtonItemImage *addButton(gui::IGUIEnvironment *environment,
const core::rect<s32> &rectangle, ISimpleTextureSource *tsrc,
- IGUIElement *parent, s32 id, const wchar_t *text, std::string item,
- Client *client);
+ IGUIElement *parent, s32 id, const wchar_t *text,
+ const std::string &item, Client *client);
private:
Client *m_client;
diff --git a/src/gui/guiChatConsole.cpp b/src/gui/guiChatConsole.cpp
index a4e91fe78..baaaea5e8 100644
--- a/src/gui/guiChatConsole.cpp
+++ b/src/gui/guiChatConsole.cpp
@@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "IrrCompileConfig.h"
#include "guiChatConsole.h"
#include "chat.h"
#include "client/client.h"
@@ -326,7 +327,6 @@ void GUIChatConsole::drawText()
tmp->draw(
fragment.text,
destrect,
- video::SColor(255, 255, 255, 255),
false,
false,
&AbsoluteClippingRect);
@@ -619,6 +619,13 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
m_chat_backend->scroll(rows);
}
}
+#if (IRRLICHT_VERSION_MT_REVISION >= 2)
+ else if(event.EventType == EET_STRING_INPUT_EVENT)
+ {
+ prompt.input(std::wstring(event.StringInput.Str->c_str()));
+ return true;
+ }
+#endif
return Parent ? Parent->OnEvent(event) : false;
}
diff --git a/src/gui/guiChatConsole.h b/src/gui/guiChatConsole.h
index 896342ab0..1152f2b2d 100644
--- a/src/gui/guiChatConsole.h
+++ b/src/gui/guiChatConsole.h
@@ -72,6 +72,8 @@ public:
virtual void setVisible(bool visible);
+ virtual bool acceptsIME() { return true; }
+
private:
void reformatConsole();
void recalculateConsolePosition();
diff --git a/src/gui/guiEditBox.cpp b/src/gui/guiEditBox.cpp
index cd5a0868d..ba548aa2d 100644
--- a/src/gui/guiEditBox.cpp
+++ b/src/gui/guiEditBox.cpp
@@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "guiEditBox.h"
+#include "IrrCompileConfig.h"
#include "IGUISkin.h"
#include "IGUIEnvironment.h"
#include "IGUIFont.h"
@@ -216,6 +217,11 @@ bool GUIEditBox::OnEvent(const SEvent &event)
if (processMouse(event))
return true;
break;
+#if (IRRLICHT_VERSION_MT_REVISION >= 2)
+ case EET_STRING_INPUT_EVENT:
+ inputString(*event.StringInput.Str);
+ return true;
+#endif
default:
break;
}
@@ -670,39 +676,44 @@ bool GUIEditBox::onKeyDelete(const SEvent &event, s32 &mark_begin, s32 &mark_end
void GUIEditBox::inputChar(wchar_t c)
{
- if (!isEnabled() || !m_writable)
+ if (c == 0)
return;
+ core::stringw s(&c, 1);
+ inputString(s);
+}
- if (c != 0) {
- if (Text.size() < m_max || m_max == 0) {
- core::stringw s;
-
- if (m_mark_begin != m_mark_end) {
- // clang-format off
- // replace marked text
- s32 real_begin = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
- s32 real_end = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
-
- s = Text.subString(0, real_begin);
- s.append(c);
- s.append(Text.subString(real_end, Text.size() - real_end));
- Text = s;
- m_cursor_pos = real_begin + 1;
- // clang-format on
- } else {
- // add new character
- s = Text.subString(0, m_cursor_pos);
- s.append(c);
- s.append(Text.subString(m_cursor_pos,
- Text.size() - m_cursor_pos));
- Text = s;
- ++m_cursor_pos;
- }
+void GUIEditBox::inputString(const core::stringw &str)
+{
+ if (!isEnabled() || !m_writable)
+ return;
- m_blink_start_time = porting::getTimeMs();
- setTextMarkers(0, 0);
+ u32 len = str.size();
+ if (Text.size()+len <= m_max || m_max == 0) {
+ core::stringw s;
+ if (m_mark_begin != m_mark_end) {
+ // replace marked text
+ s32 real_begin = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
+ s32 real_end = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
+
+ s = Text.subString(0, real_begin);
+ s.append(str);
+ s.append(Text.subString(real_end, Text.size() - real_end));
+ Text = s;
+ m_cursor_pos = real_begin + len;
+ } else {
+ // append string
+ s = Text.subString(0, m_cursor_pos);
+ s.append(str);
+ s.append(Text.subString(m_cursor_pos,
+ Text.size() - m_cursor_pos));
+ Text = s;
+ m_cursor_pos += len;
}
+
+ m_blink_start_time = porting::getTimeMs();
+ setTextMarkers(0, 0);
}
+
breakText();
sendGuiEvent(EGET_EDITBOX_CHANGED);
calculateScrollPos();
diff --git a/src/gui/guiEditBox.h b/src/gui/guiEditBox.h
index c616d75d1..2a5c911bc 100644
--- a/src/gui/guiEditBox.h
+++ b/src/gui/guiEditBox.h
@@ -138,6 +138,8 @@ public:
virtual void deserializeAttributes(
io::IAttributes *in, io::SAttributeReadWriteOptions *options);
+ virtual bool acceptsIME() { return isEnabled() && m_writable; };
+
protected:
virtual void breakText() = 0;
@@ -156,6 +158,7 @@ protected:
virtual s32 getCursorPos(s32 x, s32 y) = 0;
bool processKey(const SEvent &event);
+ virtual void inputString(const core::stringw &str);
virtual void inputChar(wchar_t c);
//! returns the line number that the cursor is on
diff --git a/src/gui/guiEngine.cpp b/src/gui/guiEngine.cpp
index 93463ad70..694baf482 100644
--- a/src/gui/guiEngine.cpp
+++ b/src/gui/guiEngine.cpp
@@ -121,12 +121,14 @@ void MenuMusicFetcher::fetchSounds(const std::string &name,
/******************************************************************************/
GUIEngine::GUIEngine(JoystickController *joystick,
gui::IGUIElement *parent,
+ RenderingEngine *rendering_engine,
IMenuManager *menumgr,
MainMenuData *data,
bool &kill) :
+ m_rendering_engine(rendering_engine),
m_parent(parent),
m_menumanager(menumgr),
- m_smgr(RenderingEngine::get_scene_manager()),
+ m_smgr(rendering_engine->get_scene_manager()),
m_data(data),
m_kill(kill)
{
@@ -138,7 +140,7 @@ GUIEngine::GUIEngine(JoystickController *joystick,
m_buttonhandler = new TextDestGuiEngine(this);
//create texture source
- m_texture_source = new MenuTextureSource(RenderingEngine::get_video_driver());
+ m_texture_source = new MenuTextureSource(rendering_engine->get_video_driver());
//create soundmanager
MenuMusicFetcher soundfetcher;
@@ -156,7 +158,7 @@ GUIEngine::GUIEngine(JoystickController *joystick,
g_fontengine->getTextHeight());
rect += v2s32(4, 0);
- m_irr_toplefttext = gui::StaticText::add(RenderingEngine::get_gui_env(),
+ m_irr_toplefttext = gui::StaticText::add(rendering_engine->get_gui_env(),
m_toplefttext, rect, false, true, 0, -1);
//create formspecsource
@@ -168,6 +170,7 @@ GUIEngine::GUIEngine(JoystickController *joystick,
-1,
m_menumanager,
NULL /* &client */,
+ m_rendering_engine->get_gui_env(),
m_texture_source,
m_sound_manager,
m_formspecgui,
@@ -232,7 +235,7 @@ void GUIEngine::run()
{
// Always create clouds because they may or may not be
// needed based on the game selected
- video::IVideoDriver *driver = RenderingEngine::get_video_driver();
+ video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
cloudInit();
@@ -259,10 +262,10 @@ void GUIEngine::run()
fog_pixelfog, fog_rangefog);
}
- while (RenderingEngine::run() && (!m_startgame) && (!m_kill)) {
+ while (m_rendering_engine->run() && (!m_startgame) && (!m_kill)) {
const irr::core::dimension2d<u32> &current_screen_size =
- RenderingEngine::get_video_driver()->getScreenSize();
+ m_rendering_engine->get_video_driver()->getScreenSize();
// Verify if window size has changed and save it if it's the case
// Ensure evaluating settings->getBool after verifying screensize
// First condition is cheaper
@@ -293,11 +296,11 @@ void GUIEngine::run()
drawHeader(driver);
drawFooter(driver);
- RenderingEngine::get_gui_env()->drawAll();
+ m_rendering_engine->get_gui_env()->drawAll();
driver->endScene();
- IrrlichtDevice *device = RenderingEngine::get_raw_device();
+ IrrlichtDevice *device = m_rendering_engine->get_raw_device();
u32 frametime_min = 1000 / (device->isWindowFocused()
? g_settings->getFloat("fps_max")
: g_settings->getFloat("fps_max_unfocused"));
@@ -330,7 +333,7 @@ GUIEngine::~GUIEngine()
//clean up texture pointers
for (image_definition &texture : m_textures) {
if (texture.texture)
- RenderingEngine::get_video_driver()->removeTexture(texture.texture);
+ m_rendering_engine->get_video_driver()->removeTexture(texture.texture);
}
delete m_texture_source;
@@ -350,13 +353,13 @@ void GUIEngine::cloudInit()
v3f(0,0,0), v3f(0, 60, 100));
m_cloud.camera->setFarValue(10000);
- m_cloud.lasttime = RenderingEngine::get_timer_time();
+ m_cloud.lasttime = m_rendering_engine->get_timer_time();
}
/******************************************************************************/
void GUIEngine::cloudPreProcess()
{
- u32 time = RenderingEngine::get_timer_time();
+ u32 time = m_rendering_engine->get_timer_time();
if(time > m_cloud.lasttime)
m_cloud.dtime = (time - m_cloud.lasttime) / 1000.0;
@@ -377,7 +380,7 @@ void GUIEngine::cloudPostProcess(u32 frametime_min, IrrlichtDevice *device)
u32 busytime_u32;
// not using getRealTime is necessary for wine
- u32 time = RenderingEngine::get_timer_time();
+ u32 time = m_rendering_engine->get_timer_time();
if(time > m_cloud.lasttime)
busytime_u32 = time - m_cloud.lasttime;
else
@@ -528,7 +531,7 @@ void GUIEngine::drawFooter(video::IVideoDriver *driver)
bool GUIEngine::setTexture(texture_layer layer, const std::string &texturepath,
bool tile_image, unsigned int minsize)
{
- video::IVideoDriver *driver = RenderingEngine::get_video_driver();
+ video::IVideoDriver *driver = m_rendering_engine->get_video_driver();
if (m_textures[layer].texture) {
driver->removeTexture(m_textures[layer].texture);
@@ -595,7 +598,7 @@ void GUIEngine::updateTopLeftTextSize()
rect += v2s32(4, 0);
m_irr_toplefttext->remove();
- m_irr_toplefttext = gui::StaticText::add(RenderingEngine::get_gui_env(),
+ m_irr_toplefttext = gui::StaticText::add(m_rendering_engine->get_gui_env(),
m_toplefttext, rect, false, true, 0, -1);
}
diff --git a/src/gui/guiEngine.h b/src/gui/guiEngine.h
index eef1ad8aa..70abce181 100644
--- a/src/gui/guiEngine.h
+++ b/src/gui/guiEngine.h
@@ -50,6 +50,7 @@ struct image_definition {
/* forward declarations */
/******************************************************************************/
class GUIEngine;
+class RenderingEngine;
class MainMenuScripting;
class Clouds;
struct MainMenuData;
@@ -150,6 +151,7 @@ public:
*/
GUIEngine(JoystickController *joystick,
gui::IGUIElement *parent,
+ RenderingEngine *rendering_engine,
IMenuManager *menumgr,
MainMenuData *data,
bool &kill);
@@ -188,6 +190,7 @@ private:
/** update size of topleftext element */
void updateTopLeftTextSize();
+ RenderingEngine *m_rendering_engine = nullptr;
/** parent gui element */
gui::IGUIElement *m_parent = nullptr;
/** manager to add menus to */
diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp
index fd35f2d84..c6435804f 100644
--- a/src/gui/guiFormSpecMenu.cpp
+++ b/src/gui/guiFormSpecMenu.cpp
@@ -96,10 +96,10 @@ inline u32 clamp_u8(s32 value)
GUIFormSpecMenu::GUIFormSpecMenu(JoystickController *joystick,
gui::IGUIElement *parent, s32 id, IMenuManager *menumgr,
- Client *client, ISimpleTextureSource *tsrc, ISoundManager *sound_manager,
- IFormSource *fsrc, TextDest *tdst,
+ Client *client, gui::IGUIEnvironment *guienv, ISimpleTextureSource *tsrc,
+ ISoundManager *sound_manager, IFormSource *fsrc, TextDest *tdst,
const std::string &formspecPrepend, bool remap_dbl_click):
- GUIModalMenu(RenderingEngine::get_gui_env(), parent, id, menumgr, remap_dbl_click),
+ GUIModalMenu(guienv, parent, id, menumgr, remap_dbl_click),
m_invmgr(client),
m_tsrc(tsrc),
m_sound_manager(sound_manager),
@@ -145,12 +145,12 @@ GUIFormSpecMenu::~GUIFormSpecMenu()
}
void GUIFormSpecMenu::create(GUIFormSpecMenu *&cur_formspec, Client *client,
- JoystickController *joystick, IFormSource *fs_src, TextDest *txt_dest,
- const std::string &formspecPrepend, ISoundManager *sound_manager)
+ gui::IGUIEnvironment *guienv, JoystickController *joystick, IFormSource *fs_src,
+ TextDest *txt_dest, const std::string &formspecPrepend, ISoundManager *sound_manager)
{
if (cur_formspec == nullptr) {
cur_formspec = new GUIFormSpecMenu(joystick, guiroot, -1, &g_menumgr,
- client, client->getTextureSource(), sound_manager, fs_src,
+ client, guienv, client->getTextureSource(), sound_manager, fs_src,
txt_dest, formspecPrepend);
cur_formspec->doPause = false;
@@ -2794,7 +2794,7 @@ void GUIFormSpecMenu::parseModel(parserData *data, const std::string &element)
core::rect<s32> rect(pos, pos + geom);
- GUIScene *e = new GUIScene(Environment, RenderingEngine::get_scene_manager(),
+ GUIScene *e = new GUIScene(Environment, m_client->getSceneManager(),
data->current_parent, rect, spec.fid);
auto meshnode = e->setMesh(mesh);
diff --git a/src/gui/guiFormSpecMenu.h b/src/gui/guiFormSpecMenu.h
index d658aba7b..926de66d5 100644
--- a/src/gui/guiFormSpecMenu.h
+++ b/src/gui/guiFormSpecMenu.h
@@ -152,6 +152,7 @@ public:
gui::IGUIElement* parent, s32 id,
IMenuManager *menumgr,
Client *client,
+ gui::IGUIEnvironment *guienv,
ISimpleTextureSource *tsrc,
ISoundManager *sound_manager,
IFormSource* fs_src,
@@ -162,8 +163,9 @@ public:
~GUIFormSpecMenu();
static void create(GUIFormSpecMenu *&cur_formspec, Client *client,
- JoystickController *joystick, IFormSource *fs_src, TextDest *txt_dest,
- const std::string &formspecPrepend, ISoundManager *sound_manager);
+ gui::IGUIEnvironment *guienv, JoystickController *joystick, IFormSource *fs_src,
+ TextDest *txt_dest, const std::string &formspecPrepend,
+ ISoundManager *sound_manager);
void setFormSpec(const std::string &formspec_string,
const InventoryLocation &current_inventory_location)
diff --git a/src/gui/guiKeyChangeMenu.cpp b/src/gui/guiKeyChangeMenu.cpp
index b4ee8b728..719a4101a 100644
--- a/src/gui/guiKeyChangeMenu.cpp
+++ b/src/gui/guiKeyChangeMenu.cpp
@@ -71,6 +71,7 @@ enum
GUI_ID_KEY_MINIMAP_BUTTON,
GUI_ID_KEY_SCREENSHOT_BUTTON,
GUI_ID_KEY_CHATLOG_BUTTON,
+ GUI_ID_KEY_BLOCK_BOUNDS_BUTTON,
GUI_ID_KEY_HUD_BUTTON,
GUI_ID_KEY_FOG_BUTTON,
GUI_ID_KEY_CHEAT_MENU_BUTTON,
@@ -422,47 +423,48 @@ void GUIKeyChangeMenu::add_key(int id, const wchar_t *button_name, const std::st
void GUIKeyChangeMenu::init_keys()
{
- this->add_key(GUI_ID_KEY_FORWARD_BUTTON, wgettext("Forward"), "keymap_forward");
- this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, wgettext("Backward"), "keymap_backward");
- this->add_key(GUI_ID_KEY_LEFT_BUTTON, wgettext("Left"), "keymap_left");
- this->add_key(GUI_ID_KEY_RIGHT_BUTTON, wgettext("Right"), "keymap_right");
- this->add_key(GUI_ID_KEY_AUX1_BUTTON, wgettext("Aux1"), "keymap_aux1");
- this->add_key(GUI_ID_KEY_JUMP_BUTTON, wgettext("Jump"), "keymap_jump");
- this->add_key(GUI_ID_KEY_SNEAK_BUTTON, wgettext("Sneak"), "keymap_sneak");
- this->add_key(GUI_ID_KEY_DROP_BUTTON, wgettext("Drop"), "keymap_drop");
- this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"), "keymap_inventory");
- this->add_key(GUI_ID_KEY_ENDERCHEST_BUTTON,wgettext("Enderchest"), "keymap_enderchest");
- this->add_key(GUI_ID_KEY_HOTBAR_PREV_BUTTON,wgettext("Prev. item"), "keymap_hotbar_previous");
- this->add_key(GUI_ID_KEY_HOTBAR_NEXT_BUTTON,wgettext("Next item"), "keymap_hotbar_next");
- this->add_key(GUI_ID_KEY_ZOOM_BUTTON, wgettext("Zoom"), "keymap_zoom");
- this->add_key(GUI_ID_KEY_CAMERA_BUTTON, wgettext("Change camera"), "keymap_camera_mode");
- this->add_key(GUI_ID_KEY_MINIMAP_BUTTON, wgettext("Toggle minimap"), "keymap_minimap");
- this->add_key(GUI_ID_KEY_FLY_BUTTON, wgettext("Toggle fly"), "keymap_freemove");
- this->add_key(GUI_ID_KEY_PITCH_MOVE, wgettext("Toggle pitchmove"), "keymap_pitchmove");
- this->add_key(GUI_ID_KEY_FAST_BUTTON, wgettext("Toggle fast"), "keymap_fastmove");
- this->add_key(GUI_ID_KEY_NOCLIP_BUTTON, wgettext("Toggle noclip"), "keymap_noclip");
- this->add_key(GUI_ID_KEY_MUTE_BUTTON, wgettext("Mute"), "keymap_mute");
- this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON,wgettext("Dec. volume"), "keymap_decrease_volume");
- this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON,wgettext("Inc. volume"), "keymap_increase_volume");
- this->add_key(GUI_ID_KEY_AUTOFWD_BUTTON, wgettext("Autoforward"), "keymap_autoforward");
- this->add_key(GUI_ID_KEY_CHAT_BUTTON, wgettext("Chat"), "keymap_chat");
- this->add_key(GUI_ID_KEY_SCREENSHOT_BUTTON,wgettext("Screenshot"), "keymap_screenshot");
- this->add_key(GUI_ID_KEY_RANGE_BUTTON, wgettext("Range select"), "keymap_rangeselect");
- this->add_key(GUI_ID_KEY_DEC_RANGE_BUTTON, wgettext("Dec. range"), "keymap_decrease_viewing_range_min");
- this->add_key(GUI_ID_KEY_INC_RANGE_BUTTON, wgettext("Inc. range"), "keymap_increase_viewing_range_min");
- this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, wgettext("Console"), "keymap_console");
- this->add_key(GUI_ID_KEY_CMD_BUTTON, wgettext("Command"), "keymap_cmd");
- this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON, wgettext("Local command"), "keymap_cmd_local");
- this->add_key(GUI_ID_KEY_HUD_BUTTON, wgettext("Toggle HUD"), "keymap_toggle_hud");
- this->add_key(GUI_ID_KEY_CHATLOG_BUTTON, wgettext("Toggle chat log"), "keymap_toggle_chat");
- this->add_key(GUI_ID_KEY_FOG_BUTTON, wgettext("Toggle fog"), "keymap_toggle_fog");
- this->add_key(GUI_ID_KEY_CHEAT_MENU_BUTTON,wgettext("Toggle C. Menu"),"keymap_toggle_cheat_menu");
- this->add_key(GUI_ID_KEY_KILLAURA_BUTTON, wgettext("Killaura"), "keymap_toggle_killaura");
- this->add_key(GUI_ID_KEY_FREECAM_BUTTON, wgettext("Freecam"), "keymap_toggle_freecam");
- this->add_key(GUI_ID_KEY_SCAFFOLD_BUTTON, wgettext("Scaffold"), "keymap_toggle_scaffold");
- this->add_key(GUI_ID_KEY_SELECT_UP_BUTTON, wgettext("C. Menu Up"), "keymap_select_up");
- this->add_key(GUI_ID_KEY_SELECT_DOWN_BUTTON,wgettext("C. Menu Down"), "keymap_select_down");
- this->add_key(GUI_ID_KEY_SELECT_LEFT_BUTTON,wgettext("C. Menu Left"), "keymap_select_left");
- this->add_key(GUI_ID_KEY_SELECT_RIGHT_BUTTON,wgettext("C. Menu Right"),"keymap_select_right");
- this->add_key(GUI_ID_KEY_SELECT_CONFIRM_BUTTON,wgettext("C. Menu Enter"),"keymap_select_confirm");
+ this->add_key(GUI_ID_KEY_FORWARD_BUTTON, wgettext("Forward"), "keymap_forward");
+ this->add_key(GUI_ID_KEY_BACKWARD_BUTTON, wgettext("Backward"), "keymap_backward");
+ this->add_key(GUI_ID_KEY_LEFT_BUTTON, wgettext("Left"), "keymap_left");
+ this->add_key(GUI_ID_KEY_RIGHT_BUTTON, wgettext("Right"), "keymap_right");
+ this->add_key(GUI_ID_KEY_AUX1_BUTTON, wgettext("Aux1"), "keymap_aux1");
+ this->add_key(GUI_ID_KEY_JUMP_BUTTON, wgettext("Jump"), "keymap_jump");
+ this->add_key(GUI_ID_KEY_SNEAK_BUTTON, wgettext("Sneak"), "keymap_sneak");
+ this->add_key(GUI_ID_KEY_DROP_BUTTON, wgettext("Drop"), "keymap_drop");
+ this->add_key(GUI_ID_KEY_INVENTORY_BUTTON, wgettext("Inventory"), "keymap_inventory");
+ this->add_key(GUI_ID_KEY_ENDERCHEST_BUTTON, wgettext("Enderchest"), "keymap_enderchest");
+ this->add_key(GUI_ID_KEY_HOTBAR_PREV_BUTTON, wgettext("Prev. item"), "keymap_hotbar_previous");
+ this->add_key(GUI_ID_KEY_HOTBAR_NEXT_BUTTON, wgettext("Next item"), "keymap_hotbar_next");
+ this->add_key(GUI_ID_KEY_ZOOM_BUTTON, wgettext("Zoom"), "keymap_zoom");
+ this->add_key(GUI_ID_KEY_CAMERA_BUTTON, wgettext("Change camera"), "keymap_camera_mode");
+ this->add_key(GUI_ID_KEY_MINIMAP_BUTTON, wgettext("Toggle minimap"), "keymap_minimap");
+ this->add_key(GUI_ID_KEY_FLY_BUTTON, wgettext("Toggle fly"), "keymap_freemove");
+ this->add_key(GUI_ID_KEY_PITCH_MOVE, wgettext("Toggle pitchmove"), "keymap_pitchmove");
+ this->add_key(GUI_ID_KEY_FAST_BUTTON, wgettext("Toggle fast"), "keymap_fastmove");
+ this->add_key(GUI_ID_KEY_NOCLIP_BUTTON, wgettext("Toggle noclip"), "keymap_noclip");
+ this->add_key(GUI_ID_KEY_MUTE_BUTTON, wgettext("Mute"), "keymap_mute");
+ this->add_key(GUI_ID_KEY_DEC_VOLUME_BUTTON, wgettext("Dec. volume"), "keymap_decrease_volume");
+ this->add_key(GUI_ID_KEY_INC_VOLUME_BUTTON, wgettext("Inc. volume"), "keymap_increase_volume");
+ this->add_key(GUI_ID_KEY_AUTOFWD_BUTTON, wgettext("Autoforward"), "keymap_autoforward");
+ this->add_key(GUI_ID_KEY_CHAT_BUTTON, wgettext("Chat"), "keymap_chat");
+ this->add_key(GUI_ID_KEY_SCREENSHOT_BUTTON, wgettext("Screenshot"), "keymap_screenshot");
+ this->add_key(GUI_ID_KEY_RANGE_BUTTON, wgettext("Range select"), "keymap_rangeselect");
+ this->add_key(GUI_ID_KEY_DEC_RANGE_BUTTON, wgettext("Dec. range"), "keymap_decrease_viewing_range_min");
+ this->add_key(GUI_ID_KEY_INC_RANGE_BUTTON, wgettext("Inc. range"), "keymap_increase_viewing_range_min");
+ this->add_key(GUI_ID_KEY_CONSOLE_BUTTON, wgettext("Console"), "keymap_console");
+ this->add_key(GUI_ID_KEY_CMD_BUTTON, wgettext("Command"), "keymap_cmd");
+ this->add_key(GUI_ID_KEY_CMD_LOCAL_BUTTON, wgettext("Local command"), "keymap_cmd_local");
+ this->add_key(GUI_ID_KEY_BLOCK_BOUNDS_BUTTON, wgettext("Block bounds"), "keymap_toggle_block_bounds");
+ this->add_key(GUI_ID_KEY_HUD_BUTTON, wgettext("Toggle HUD"), "keymap_toggle_hud");
+ this->add_key(GUI_ID_KEY_CHATLOG_BUTTON, wgettext("Toggle chat log"), "keymap_toggle_chat");
+ this->add_key(GUI_ID_KEY_FOG_BUTTON, wgettext("Toggle fog"), "keymap_toggle_fog");
+ this->add_key(GUI_ID_KEY_CHEAT_MENU_BUTTON, wgettext("Toggle C. Menu"), "keymap_toggle_cheat_menu");
+ this->add_key(GUI_ID_KEY_KILLAURA_BUTTON, wgettext("Killaura"), "keymap_toggle_killaura");
+ this->add_key(GUI_ID_KEY_FREECAM_BUTTON, wgettext("Freecam"), "keymap_toggle_freecam");
+ this->add_key(GUI_ID_KEY_SCAFFOLD_BUTTON, wgettext("Scaffold"), "keymap_toggle_scaffold");
+ this->add_key(GUI_ID_KEY_SELECT_UP_BUTTON, wgettext("C. Menu Up"), "keymap_select_up");
+ this->add_key(GUI_ID_KEY_SELECT_DOWN_BUTTON, wgettext("C. Menu Down"), "keymap_select_down");
+ this->add_key(GUI_ID_KEY_SELECT_LEFT_BUTTON, wgettext("C. Menu Left"), "keymap_select_left");
+ this->add_key(GUI_ID_KEY_SELECT_RIGHT_BUTTON, wgettext("C. Menu Right"), "keymap_select_right");
+ this->add_key(GUI_ID_KEY_SELECT_CONFIRM_BUTTON, wgettext("C. Menu Enter"), "keymap_select_confirm");
}
diff --git a/src/httpfetch.cpp b/src/httpfetch.cpp
index 65202ce3e..6137782ff 100644
--- a/src/httpfetch.cpp
+++ b/src/httpfetch.cpp
@@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <iostream>
#include <sstream>
#include <list>
-#include <map>
+#include <unordered_map>
#include <cerrno>
#include <mutex>
#include "network/socket.h" // for select()
@@ -37,13 +37,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "settings.h"
#include "noise.h"
-std::mutex g_httpfetch_mutex;
-std::map<unsigned long, std::queue<HTTPFetchResult> > g_httpfetch_results;
-PcgRandom g_callerid_randomness;
+static std::mutex g_httpfetch_mutex;
+static std::unordered_map<unsigned long, std::queue<HTTPFetchResult>>
+ g_httpfetch_results;
+static PcgRandom g_callerid_randomness;
HTTPFetchRequest::HTTPFetchRequest() :
timeout(g_settings->getS32("curl_timeout")),
- connect_timeout(timeout),
+ connect_timeout(10 * 1000),
useragent(std::string(PROJECT_NAME_C "/") + g_version_hash + " (" + porting::get_sysinfo() + ")")
{
}
@@ -54,7 +55,7 @@ static void httpfetch_deliver_result(const HTTPFetchResult &fetch_result)
unsigned long caller = fetch_result.caller;
if (caller != HTTPFETCH_DISCARD) {
MutexAutoLock lock(g_httpfetch_mutex);
- g_httpfetch_results[caller].push(fetch_result);
+ g_httpfetch_results[caller].emplace(fetch_result);
}
}
@@ -67,8 +68,7 @@ unsigned long httpfetch_caller_alloc()
// Check each caller ID except HTTPFETCH_DISCARD
const unsigned long discard = HTTPFETCH_DISCARD;
for (unsigned long caller = discard + 1; caller != discard; ++caller) {
- std::map<unsigned long, std::queue<HTTPFetchResult> >::iterator
- it = g_httpfetch_results.find(caller);
+ auto it = g_httpfetch_results.find(caller);
if (it == g_httpfetch_results.end()) {
verbosestream << "httpfetch_caller_alloc: allocating "
<< caller << std::endl;
@@ -127,8 +127,7 @@ bool httpfetch_async_get(unsigned long caller, HTTPFetchResult &fetch_result)
MutexAutoLock lock(g_httpfetch_mutex);
// Check that caller exists
- std::map<unsigned long, std::queue<HTTPFetchResult> >::iterator
- it = g_httpfetch_results.find(caller);
+ auto it = g_httpfetch_results.find(caller);
if (it == g_httpfetch_results.end())
return false;
@@ -138,7 +137,7 @@ bool httpfetch_async_get(unsigned long caller, HTTPFetchResult &fetch_result)
return false;
// Pop first result
- fetch_result = caller_results.front();
+ fetch_result = std::move(caller_results.front());
caller_results.pop();
return true;
}
diff --git a/src/inventory.cpp b/src/inventory.cpp
index 1ef9b13cd..fc1aaf371 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -965,13 +965,14 @@ InventoryList * Inventory::getList(const std::string &name)
{
s32 i = getListIndex(name);
if(i == -1)
- return NULL;
+ return nullptr;
return m_lists[i];
}
std::vector<const InventoryList*> Inventory::getLists()
{
std::vector<const InventoryList*> lists;
+ lists.reserve(m_lists.size());
for (auto list : m_lists) {
lists.push_back(list);
}
@@ -990,11 +991,11 @@ bool Inventory::deleteList(const std::string &name)
return true;
}
-const InventoryList * Inventory::getList(const std::string &name) const
+const InventoryList *Inventory::getList(const std::string &name) const
{
s32 i = getListIndex(name);
if(i == -1)
- return NULL;
+ return nullptr;
return m_lists[i];
}
diff --git a/src/irrlicht_changes/CGUITTFont.cpp b/src/irrlicht_changes/CGUITTFont.cpp
index 960b2320a..e785ea837 100644
--- a/src/irrlicht_changes/CGUITTFont.cpp
+++ b/src/irrlicht_changes/CGUITTFont.cpp
@@ -275,7 +275,8 @@ CGUITTFont* CGUITTFont::create(IrrlichtDevice *device, const io::path& filename,
//! Constructor.
CGUITTFont::CGUITTFont(IGUIEnvironment *env)
: use_monochrome(false), use_transparency(true), use_hinting(true), use_auto_hinting(true),
-batch_load_size(1), Device(0), Environment(env), Driver(0), GlobalKerningWidth(0), GlobalKerningHeight(0)
+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");
@@ -546,12 +547,12 @@ void CGUITTFont::setFontHinting(const bool enable, const bool enable_auto_hintin
void CGUITTFont::draw(const core::stringw& text, const core::rect<s32>& position, video::SColor color, bool hcenter, bool vcenter, const core::rect<s32>* clip)
{
- draw(EnrichedString(std::wstring(text.c_str()), color), position, color, hcenter, vcenter, clip);
+ draw(EnrichedString(std::wstring(text.c_str()), color), position, hcenter, vcenter, clip);
}
-void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& position, video::SColor color, bool hcenter, bool vcenter, const core::rect<s32>* clip)
+void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& position, bool hcenter, bool vcenter, const core::rect<s32>* clip)
{
- std::vector<video::SColor> colors = text.getColors();
+ const std::vector<video::SColor> &colors = text.getColors();
if (!Driver)
return;
@@ -561,6 +562,7 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio
{
Glyph_Pages[i]->render_positions.clear();
Glyph_Pages[i]->render_source_rects.clear();
+ Glyph_Pages[i]->render_colors.clear();
}
// Set up some variables.
@@ -589,7 +591,6 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio
u32 n;
uchar32_t previousChar = 0;
core::ustring::const_iterator iter(utext);
- std::vector<video::SColor> applied_colors;
while (!iter.atEnd())
{
uchar32_t currentChar = *iter;
@@ -635,12 +636,36 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio
CGUITTGlyphPage* const page = Glyph_Pages[glyph.glyph_page];
page->render_positions.push_back(core::position2di(offset.X + offx, offset.Y + offy));
page->render_source_rects.push_back(glyph.source_rect);
+ if (iter.getPos() < colors.size())
+ page->render_colors.push_back(colors[iter.getPos()]);
+ else
+ page->render_colors.push_back(video::SColor(255,255,255,255));
Render_Map.set(glyph.glyph_page, page);
- u32 current_color = iter.getPos();
- if (current_color < colors.size())
- applied_colors.push_back(colors[current_color]);
}
- offset.X += getWidthFromCharacter(currentChar);
+ if (n > 0)
+ {
+ offset.X += getWidthFromCharacter(currentChar);
+ }
+ else if (fallback != 0)
+ {
+ // Let the fallback font draw it, this isn't super efficient but hopefully that doesn't matter
+ wchar_t l1[] = { (wchar_t) currentChar, 0 }, l2 = (wchar_t) previousChar;
+
+ if (visible)
+ {
+ // Apply kerning.
+ offset.X += fallback->getKerningWidth(l1, &l2);
+ offset.Y += fallback->getKerningHeight();
+
+ u32 current_color = iter.getPos();
+ fallback->draw(core::stringw(l1),
+ core::rect<s32>({offset.X-1, offset.Y-1}, position.LowerRightCorner), // ???
+ current_color < colors.size() ? colors[current_color] : video::SColor(255, 255, 255, 255),
+ false, false, clip);
+ }
+
+ offset.X += fallback->getDimension(l1).Width;
+ }
previousChar = currentChar;
++iter;
@@ -664,16 +689,24 @@ void CGUITTFont::draw(const EnrichedString &text, const core::rect<s32>& positio
for (size_t i = 0; i < page->render_positions.size(); ++i)
page->render_positions[i] -= core::vector2di(shadow_offset, shadow_offset);
}
+ // render runs of matching color in batch
+ size_t ibegin;
+ video::SColor colprev;
for (size_t i = 0; i < page->render_positions.size(); ++i) {
- irr::video::SColor col;
- if (!applied_colors.empty()) {
- col = applied_colors[i < applied_colors.size() ? i : 0];
- } else {
- col = irr::video::SColor(255, 255, 255, 255);
- }
+ ibegin = i;
+ colprev = page->render_colors[i];
+ do
+ ++i;
+ while (i < page->render_positions.size() && page->render_colors[i] == colprev);
+ core::array<core::vector2di> tmp_positions;
+ core::array<core::recti> tmp_source_rects;
+ tmp_positions.set_pointer(&page->render_positions[ibegin], i - ibegin, false, false); // no copy
+ tmp_source_rects.set_pointer(&page->render_source_rects[ibegin], i - ibegin, false, false);
+ --i;
+
if (!use_transparency)
- col.color |= 0xff000000;
- Driver->draw2DImage(page->texture, page->render_positions[i], page->render_source_rects[i], clip, col, true);
+ colprev.color |= 0xff000000;
+ Driver->draw2DImageBatch(page->texture, tmp_positions, tmp_source_rects, clip, colprev, true);
}
}
}
@@ -766,6 +799,12 @@ inline u32 CGUITTFont::getWidthFromCharacter(uchar32_t c) const
int w = Glyphs[n-1].advance.x / 64;
return w;
}
+ if (fallback != 0)
+ {
+ wchar_t s[] = { (wchar_t) c, 0 };
+ return fallback->getDimension(s).Width;
+ }
+
if (c >= 0x2000)
return (font_metrics.ascender / 64);
else return (font_metrics.ascender / 64) / 2;
@@ -789,6 +828,12 @@ inline u32 CGUITTFont::getHeightFromCharacter(uchar32_t c) const
s32 height = (font_metrics.ascender / 64) - Glyphs[n-1].offset.Y + Glyphs[n-1].source_rect.getHeight();
return height;
}
+ if (fallback != 0)
+ {
+ wchar_t s[] = { (wchar_t) c, 0 };
+ return fallback->getDimension(s).Height;
+ }
+
if (c >= 0x2000)
return (font_metrics.ascender / 64);
else return (font_metrics.ascender / 64) / 2;
@@ -804,9 +849,9 @@ u32 CGUITTFont::getGlyphIndexByChar(uchar32_t c) const
// Get the glyph.
u32 glyph = FT_Get_Char_Index(tt_face, c);
- // Check for a valid glyph. If it is invalid, attempt to use the replacement character.
+ // Check for a valid glyph.
if (glyph == 0)
- glyph = FT_Get_Char_Index(tt_face, core::unicode::UTF_REPLACEMENT_CHARACTER);
+ return 0;
// If our glyph is already loaded, don't bother doing any batch loading code.
if (glyph != 0 && Glyphs[glyph - 1].isLoaded)
@@ -922,13 +967,26 @@ core::vector2di CGUITTFont::getKerning(const uchar32_t thisLetter, const uchar32
core::vector2di ret(GlobalKerningWidth, GlobalKerningHeight);
+ u32 n = getGlyphIndexByChar(thisLetter);
+
+ // If we don't have this glyph, ask fallback font
+ if (n == 0)
+ {
+ if (fallback != 0) {
+ wchar_t l1 = (wchar_t) thisLetter, l2 = (wchar_t) previousLetter;
+ ret.X = fallback->getKerningWidth(&l1, &l2);
+ ret.Y = fallback->getKerningHeight();
+ }
+ return ret;
+ }
+
// If we don't have kerning, no point in continuing.
if (!FT_HAS_KERNING(tt_face))
return ret;
// Get the kerning information.
FT_Vector v;
- FT_Get_Kerning(tt_face, getGlyphIndexByChar(previousLetter), getGlyphIndexByChar(thisLetter), FT_KERNING_DEFAULT, &v);
+ FT_Get_Kerning(tt_face, getGlyphIndexByChar(previousLetter), n, FT_KERNING_DEFAULT, &v);
// If we have a scalable font, the return value will be in font points.
if (FT_IS_SCALABLE(tt_face))
@@ -960,6 +1018,9 @@ void CGUITTFont::setInvisibleCharacters(const core::ustring& s)
video::IImage* CGUITTFont::createTextureFromChar(const uchar32_t& ch)
{
u32 n = getGlyphIndexByChar(ch);
+ if (n == 0)
+ n = getGlyphIndexByChar((uchar32_t) core::unicode::UTF_REPLACEMENT_CHARACTER);
+
const SGUITTGlyph& glyph = Glyphs[n-1];
CGUITTGlyphPage* page = Glyph_Pages[glyph.glyph_page];
@@ -969,11 +1030,7 @@ video::IImage* CGUITTFont::createTextureFromChar(const uchar32_t& ch)
video::ITexture* tex = page->texture;
// Acquire a read-only lock of the corresponding page texture.
- #if IRRLICHT_VERSION_MAJOR==1 && IRRLICHT_VERSION_MINOR>=8
void* ptr = tex->lock(video::ETLM_READ_ONLY);
- #else
- void* ptr = tex->lock(true);
- #endif
video::ECOLOR_FORMAT format = tex->getColorFormat();
core::dimension2du tex_size = tex->getOriginalSize();
@@ -1130,11 +1187,7 @@ core::array<scene::ISceneNode*> CGUITTFont::addTextSceneNode(const wchar_t* text
// Now we copy planes corresponding to the letter size.
IMeshManipulator* mani = smgr->getMeshManipulator();
IMesh* meshcopy = mani->createMeshCopy(shared_plane_ptr_);
- #if IRRLICHT_VERSION_MAJOR==1 && IRRLICHT_VERSION_MINOR>=8
mani->scale(meshcopy, vector3df((f32)letter_size.Width, (f32)letter_size.Height, 1));
- #else
- mani->scaleMesh(meshcopy, vector3df((f32)letter_size.Width, (f32)letter_size.Height, 1));
- #endif
ISceneNode* current_node = smgr->addMeshSceneNode(meshcopy, parent, -1, current_pos);
meshcopy->drop();
@@ -1147,6 +1200,8 @@ core::array<scene::ISceneNode*> CGUITTFont::addTextSceneNode(const wchar_t* text
container.push_back(current_node);
}
offset.X += getWidthFromCharacter(current_char);
+ // Note that fallback font handling is missing here (Minetest never uses this)
+
previous_char = current_char;
++text;
}
diff --git a/src/irrlicht_changes/CGUITTFont.h b/src/irrlicht_changes/CGUITTFont.h
index 310f74f67..7b04ae828 100644
--- a/src/irrlicht_changes/CGUITTFont.h
+++ b/src/irrlicht_changes/CGUITTFont.h
@@ -34,7 +34,7 @@
#include <irrlicht.h>
#include <ft2build.h>
#include <vector>
-#include "irrUString.h"
+#include <irrUString.h>
#include "util/enriched_string.h"
#include FT_FREETYPE_H
@@ -199,6 +199,7 @@ namespace gui
core::array<core::vector2di> render_positions;
core::array<core::recti> render_source_rects;
+ core::array<video::SColor> render_colors;
private:
core::array<const SGUITTGlyph*> glyph_to_be_paged;
@@ -269,8 +270,8 @@ namespace gui
video::SColor color, bool hcenter=false, bool vcenter=false,
const core::rect<s32>* clip=0);
- virtual void draw(const EnrichedString& text, const core::rect<s32>& position,
- video::SColor color, bool hcenter=false, bool vcenter=false,
+ void draw(const EnrichedString& text, const core::rect<s32>& position,
+ bool hcenter=false, bool vcenter=false,
const core::rect<s32>* clip=0);
//! Returns the dimension of a character produced by this font.
@@ -313,6 +314,9 @@ namespace gui
//! Get the last glyph page's index.
u32 getLastGlyphPageIndex() const { return Glyph_Pages.size() - 1; }
+ //! Set font that should be used for glyphs not present in ours
+ void setFallback(gui::IGUIFont* font) { fallback = font; }
+
//! Create corresponding character's software image copy from the font,
//! so you can use this data just like any ordinary video::IImage.
//! \param ch The character you need
@@ -387,6 +391,8 @@ namespace gui
core::ustring Invisible;
u32 shadow_offset;
u32 shadow_alpha;
+
+ gui::IGUIFont* fallback;
};
} // end namespace gui
diff --git a/src/irrlicht_changes/CMakeLists.txt b/src/irrlicht_changes/CMakeLists.txt
index d2f66ab77..87c88f7e8 100644
--- a/src/irrlicht_changes/CMakeLists.txt
+++ b/src/irrlicht_changes/CMakeLists.txt
@@ -3,7 +3,7 @@ if (BUILD_CLIENT)
${CMAKE_CURRENT_SOURCE_DIR}/static_text.cpp
)
- if (ENABLE_FREETYPE)
+ if (USE_FREETYPE)
set(client_irrlicht_changes_SRCS ${client_irrlicht_changes_SRCS}
${CMAKE_CURRENT_SOURCE_DIR}/CGUITTFont.cpp
)
diff --git a/src/irrlicht_changes/irrUString.h b/src/irrlicht_changes/irrUString.h
deleted file mode 100644
index 09172ee6d..000000000
--- a/src/irrlicht_changes/irrUString.h
+++ /dev/null
@@ -1,3891 +0,0 @@
-/*
- Basic Unicode string class for Irrlicht.
- Copyright (c) 2009-2011 John Norman
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any
- damages arising from the use of this software.
-
- Permission is granted to anyone to use this software for any
- purpose, including commercial applications, and to alter it and
- redistribute it freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you
- must not claim that you wrote the original software. If you use
- this software in a product, an acknowledgment in the product
- documentation would be appreciated but is not required.
-
- 2. Altered source versions must be plainly marked as such, and
- must not be misrepresented as being the original software.
-
- 3. This notice may not be removed or altered from any source
- distribution.
-
- The original version of this class can be located at:
- http://irrlicht.suckerfreegames.com/
-
- John Norman
- john@suckerfreegames.com
-*/
-
-#pragma once
-
-#if (__cplusplus > 199711L) || (_MSC_VER >= 1600) || defined(__GXX_EXPERIMENTAL_CXX0X__)
-# define USTRING_CPP0X
-# if defined(__GXX_EXPERIMENTAL_CXX0X__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)))
-# define USTRING_CPP0X_NEWLITERALS
-# endif
-#endif
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <cstddef>
-
-#ifdef _WIN32
-#define __BYTE_ORDER 0
-#define __LITTLE_ENDIAN 0
-#define __BIG_ENDIAN 1
-#elif defined(__MACH__) && defined(__APPLE__)
-#include <machine/endian.h>
-#elif defined(__FreeBSD__) || defined(__DragonFly__)
-#include <sys/endian.h>
-#else
-#include <endian.h>
-#endif
-
-#ifdef USTRING_CPP0X
-# include <utility>
-#endif
-
-#ifndef USTRING_NO_STL
-# include <string>
-# include <iterator>
-# include <ostream>
-#endif
-
-#include "irrTypes.h"
-#include "irrAllocator.h"
-#include "irrArray.h"
-#include "irrMath.h"
-#include "irrString.h"
-#include "path.h"
-
-//! UTF-16 surrogate start values.
-static const irr::u16 UTF16_HI_SURROGATE = 0xD800;
-static const irr::u16 UTF16_LO_SURROGATE = 0xDC00;
-
-//! Is a UTF-16 code point a surrogate?
-#define UTF16_IS_SURROGATE(c) (((c) & 0xF800) == 0xD800)
-#define UTF16_IS_SURROGATE_HI(c) (((c) & 0xFC00) == 0xD800)
-#define UTF16_IS_SURROGATE_LO(c) (((c) & 0xFC00) == 0xDC00)
-
-
-namespace irr
-{
-
- // Define our character types.
-#ifdef USTRING_CPP0X_NEWLITERALS // C++0x
- typedef char32_t uchar32_t;
- typedef char16_t uchar16_t;
- typedef char uchar8_t;
-#else
- typedef u32 uchar32_t;
- typedef u16 uchar16_t;
- typedef u8 uchar8_t;
-#endif
-
-namespace core
-{
-
-namespace unicode
-{
-
-//! The unicode replacement character. Used to replace invalid characters.
-const irr::u16 UTF_REPLACEMENT_CHARACTER = 0xFFFD;
-
-//! Convert a UTF-16 surrogate pair into a UTF-32 character.
-//! \param high The high value of the pair.
-//! \param low The low value of the pair.
-//! \return The UTF-32 character expressed by the surrogate pair.
-inline uchar32_t toUTF32(uchar16_t high, uchar16_t low)
-{
- // Convert the surrogate pair into a single UTF-32 character.
- uchar32_t x = ((high & ((1 << 6) -1)) << 10) | (low & ((1 << 10) -1));
- uchar32_t wu = ((high >> 6) & ((1 << 5) - 1)) + 1;
- return (wu << 16) | x;
-}
-
-//! Swaps the endianness of a 16-bit value.
-//! \return The new value.
-inline uchar16_t swapEndian16(const uchar16_t& c)
-{
- return ((c >> 8) & 0x00FF) | ((c << 8) & 0xFF00);
-}
-
-//! Swaps the endianness of a 32-bit value.
-//! \return The new value.
-inline uchar32_t swapEndian32(const uchar32_t& c)
-{
- return ((c >> 24) & 0x000000FF) |
- ((c >> 8) & 0x0000FF00) |
- ((c << 8) & 0x00FF0000) |
- ((c << 24) & 0xFF000000);
-}
-
-//! The Unicode byte order mark.
-const u16 BOM = 0xFEFF;
-
-//! The size of the Unicode byte order mark in terms of the Unicode character size.
-const u8 BOM_UTF8_LEN = 3;
-const u8 BOM_UTF16_LEN = 1;
-const u8 BOM_UTF32_LEN = 1;
-
-//! Unicode byte order marks for file operations.
-const u8 BOM_ENCODE_UTF8[3] = { 0xEF, 0xBB, 0xBF };
-const u8 BOM_ENCODE_UTF16_BE[2] = { 0xFE, 0xFF };
-const u8 BOM_ENCODE_UTF16_LE[2] = { 0xFF, 0xFE };
-const u8 BOM_ENCODE_UTF32_BE[4] = { 0x00, 0x00, 0xFE, 0xFF };
-const u8 BOM_ENCODE_UTF32_LE[4] = { 0xFF, 0xFE, 0x00, 0x00 };
-
-//! The size in bytes of the Unicode byte marks for file operations.
-const u8 BOM_ENCODE_UTF8_LEN = 3;
-const u8 BOM_ENCODE_UTF16_LEN = 2;
-const u8 BOM_ENCODE_UTF32_LEN = 4;
-
-//! Unicode encoding type.
-enum EUTF_ENCODE
-{
- EUTFE_NONE = 0,
- EUTFE_UTF8,
- EUTFE_UTF16,
- EUTFE_UTF16_LE,
- EUTFE_UTF16_BE,
- EUTFE_UTF32,
- EUTFE_UTF32_LE,
- EUTFE_UTF32_BE
-};
-
-//! Unicode endianness.
-enum EUTF_ENDIAN
-{
- EUTFEE_NATIVE = 0,
- EUTFEE_LITTLE,
- EUTFEE_BIG
-};
-
-//! Returns the specified unicode byte order mark in a byte array.
-//! The byte order mark is the first few bytes in a text file that signifies its encoding.
-/** \param mode The Unicode encoding method that we want to get the byte order mark for.
- If EUTFE_UTF16 or EUTFE_UTF32 is passed, it uses the native system endianness. **/
-//! \return An array that contains a byte order mark.
-inline core::array<u8> getUnicodeBOM(EUTF_ENCODE mode)
-{
-#define COPY_ARRAY(source, size) \
- memcpy(ret.pointer(), source, size); \
- ret.set_used(size)
-
- core::array<u8> ret(4);
- switch (mode)
- {
- case EUTFE_UTF8:
- COPY_ARRAY(BOM_ENCODE_UTF8, BOM_ENCODE_UTF8_LEN);
- break;
- case EUTFE_UTF16:
- #ifdef __BIG_ENDIAN__
- COPY_ARRAY(BOM_ENCODE_UTF16_BE, BOM_ENCODE_UTF16_LEN);
- #else
- COPY_ARRAY(BOM_ENCODE_UTF16_LE, BOM_ENCODE_UTF16_LEN);
- #endif
- break;
- case EUTFE_UTF16_BE:
- COPY_ARRAY(BOM_ENCODE_UTF16_BE, BOM_ENCODE_UTF16_LEN);
- break;
- case EUTFE_UTF16_LE:
- COPY_ARRAY(BOM_ENCODE_UTF16_LE, BOM_ENCODE_UTF16_LEN);
- break;
- case EUTFE_UTF32:
- #ifdef __BIG_ENDIAN__
- COPY_ARRAY(BOM_ENCODE_UTF32_BE, BOM_ENCODE_UTF32_LEN);
- #else
- COPY_ARRAY(BOM_ENCODE_UTF32_LE, BOM_ENCODE_UTF32_LEN);
- #endif
- break;
- case EUTFE_UTF32_BE:
- COPY_ARRAY(BOM_ENCODE_UTF32_BE, BOM_ENCODE_UTF32_LEN);
- break;
- case EUTFE_UTF32_LE:
- COPY_ARRAY(BOM_ENCODE_UTF32_LE, BOM_ENCODE_UTF32_LEN);
- break;
- case EUTFE_NONE:
- // TODO sapier: fixed warning only,
- // don't know if something needs to be done here
- break;
- }
- return ret;
-
-#undef COPY_ARRAY
-}
-
-//! Detects if the given data stream starts with a unicode BOM.
-//! \param data The data stream to check.
-//! \return The unicode BOM associated with the data stream, or EUTFE_NONE if none was found.
-inline EUTF_ENCODE determineUnicodeBOM(const char* data)
-{
- if (memcmp(data, BOM_ENCODE_UTF8, 3) == 0) return EUTFE_UTF8;
- if (memcmp(data, BOM_ENCODE_UTF16_BE, 2) == 0) return EUTFE_UTF16_BE;
- if (memcmp(data, BOM_ENCODE_UTF16_LE, 2) == 0) return EUTFE_UTF16_LE;
- if (memcmp(data, BOM_ENCODE_UTF32_BE, 4) == 0) return EUTFE_UTF32_BE;
- if (memcmp(data, BOM_ENCODE_UTF32_LE, 4) == 0) return EUTFE_UTF32_LE;
- return EUTFE_NONE;
-}
-
-} // end namespace unicode
-
-
-//! UTF-16 string class.
-template <typename TAlloc = irrAllocator<uchar16_t> >
-class ustring16
-{
-public:
-
- ///------------------///
- /// iterator classes ///
- ///------------------///
-
- //! Access an element in a unicode string, allowing one to change it.
- class _ustring16_iterator_access
- {
- public:
- _ustring16_iterator_access(const ustring16<TAlloc>* s, u32 p) : ref(s), pos(p) {}
-
- //! Allow the class to be interpreted as a single UTF-32 character.
- operator uchar32_t() const
- {
- return _get();
- }
-
- //! Allow one to change the character in the unicode string.
- //! \param c The new character to use.
- //! \return Myself.
- _ustring16_iterator_access& operator=(const uchar32_t c)
- {
- _set(c);
- return *this;
- }
-
- //! Increments the value by 1.
- //! \return Myself.
- _ustring16_iterator_access& operator++()
- {
- _set(_get() + 1);
- return *this;
- }
-
- //! Increments the value by 1, returning the old value.
- //! \return A unicode character.
- uchar32_t operator++(int)
- {
- uchar32_t old = _get();
- _set(old + 1);
- return old;
- }
-
- //! Decrements the value by 1.
- //! \return Myself.
- _ustring16_iterator_access& operator--()
- {
- _set(_get() - 1);
- return *this;
- }
-
- //! Decrements the value by 1, returning the old value.
- //! \return A unicode character.
- uchar32_t operator--(int)
- {
- uchar32_t old = _get();
- _set(old - 1);
- return old;
- }
-
- //! Adds to the value by a specified amount.
- //! \param val The amount to add to this character.
- //! \return Myself.
- _ustring16_iterator_access& operator+=(int val)
- {
- _set(_get() + val);
- return *this;
- }
-
- //! Subtracts from the value by a specified amount.
- //! \param val The amount to subtract from this character.
- //! \return Myself.
- _ustring16_iterator_access& operator-=(int val)
- {
- _set(_get() - val);
- return *this;
- }
-
- //! Multiples the value by a specified amount.
- //! \param val The amount to multiply this character by.
- //! \return Myself.
- _ustring16_iterator_access& operator*=(int val)
- {
- _set(_get() * val);
- return *this;
- }
-
- //! Divides the value by a specified amount.
- //! \param val The amount to divide this character by.
- //! \return Myself.
- _ustring16_iterator_access& operator/=(int val)
- {
- _set(_get() / val);
- return *this;
- }
-
- //! Modulos the value by a specified amount.
- //! \param val The amount to modulo this character by.
- //! \return Myself.
- _ustring16_iterator_access& operator%=(int val)
- {
- _set(_get() % val);
- return *this;
- }
-
- //! Adds to the value by a specified amount.
- //! \param val The amount to add to this character.
- //! \return A unicode character.
- uchar32_t operator+(int val) const
- {
- return _get() + val;
- }
-
- //! Subtracts from the value by a specified amount.
- //! \param val The amount to subtract from this character.
- //! \return A unicode character.
- uchar32_t operator-(int val) const
- {
- return _get() - val;
- }
-
- //! Multiplies the value by a specified amount.
- //! \param val The amount to multiply this character by.
- //! \return A unicode character.
- uchar32_t operator*(int val) const
- {
- return _get() * val;
- }
-
- //! Divides the value by a specified amount.
- //! \param val The amount to divide this character by.
- //! \return A unicode character.
- uchar32_t operator/(int val) const
- {
- return _get() / val;
- }
-
- //! Modulos the value by a specified amount.
- //! \param val The amount to modulo this character by.
- //! \return A unicode character.
- uchar32_t operator%(int val) const
- {
- return _get() % val;
- }
-
- private:
- //! Gets a uchar32_t from our current position.
- uchar32_t _get() const
- {
- const uchar16_t* a = ref->c_str();
- if (!UTF16_IS_SURROGATE(a[pos]))
- return static_cast<uchar32_t>(a[pos]);
- else
- {
- if (pos + 1 >= ref->size_raw())
- return 0;
-
- return unicode::toUTF32(a[pos], a[pos + 1]);
- }
- }
-
- //! Sets a uchar32_t at our current position.
- void _set(uchar32_t c)
- {
- ustring16<TAlloc>* ref2 = const_cast<ustring16<TAlloc>*>(ref);
- const uchar16_t* a = ref2->c_str();
- if (c > 0xFFFF)
- {
- // c will be multibyte, so split it up into the high and low surrogate pairs.
- uchar16_t x = static_cast<uchar16_t>(c);
- uchar16_t vh = UTF16_HI_SURROGATE | ((((c >> 16) & ((1 << 5) - 1)) - 1) << 6) | (x >> 10);
- uchar16_t vl = UTF16_LO_SURROGATE | (x & ((1 << 10) - 1));
-
- // If the previous position was a surrogate pair, just replace them. Else, insert the low pair.
- if (UTF16_IS_SURROGATE_HI(a[pos]) && pos + 1 != ref2->size_raw())
- ref2->replace_raw(vl, static_cast<u32>(pos) + 1);
- else ref2->insert_raw(vl, static_cast<u32>(pos) + 1);
-
- ref2->replace_raw(vh, static_cast<u32>(pos));
- }
- else
- {
- // c will be a single byte.
- uchar16_t vh = static_cast<uchar16_t>(c);
-
- // If the previous position was a surrogate pair, remove the extra byte.
- if (UTF16_IS_SURROGATE_HI(a[pos]))
- ref2->erase_raw(static_cast<u32>(pos) + 1);
-
- ref2->replace_raw(vh, static_cast<u32>(pos));
- }
- }
-
- const ustring16<TAlloc>* ref;
- u32 pos;
- };
- typedef typename ustring16<TAlloc>::_ustring16_iterator_access access;
-
-
- //! Iterator to iterate through a UTF-16 string.
-#ifndef USTRING_NO_STL
- class _ustring16_const_iterator : public std::iterator<
- std::bidirectional_iterator_tag, // iterator_category
- access, // value_type
- ptrdiff_t, // difference_type
- const access, // pointer
- const access // reference
- >
-#else
- class _ustring16_const_iterator
-#endif
- {
- public:
- typedef _ustring16_const_iterator _Iter;
- typedef std::iterator<std::bidirectional_iterator_tag, access, ptrdiff_t, const access, const access> _Base;
- typedef const access const_pointer;
- typedef const access const_reference;
-
-#ifndef USTRING_NO_STL
- typedef typename _Base::value_type value_type;
- typedef typename _Base::difference_type difference_type;
- typedef typename _Base::difference_type distance_type;
- typedef typename _Base::pointer pointer;
- typedef const_reference reference;
-#else
- typedef access value_type;
- typedef u32 difference_type;
- typedef u32 distance_type;
- typedef const_pointer pointer;
- typedef const_reference reference;
-#endif
-
- //! Constructors.
- _ustring16_const_iterator(const _Iter& i) : ref(i.ref), pos(i.pos) {}
- _ustring16_const_iterator(const ustring16<TAlloc>& s) : ref(&s), pos(0) {}
- _ustring16_const_iterator(const ustring16<TAlloc>& s, const u32 p) : ref(&s), pos(0)
- {
- if (ref->size_raw() == 0 || p == 0)
- return;
-
- // Go to the appropriate position.
- u32 i = p;
- u32 sr = ref->size_raw();
- const uchar16_t* a = ref->c_str();
- while (i != 0 && pos < sr)
- {
- if (UTF16_IS_SURROGATE_HI(a[pos]))
- pos += 2;
- else ++pos;
- --i;
- }
- }
-
- //! Test for equalness.
- bool operator==(const _Iter& iter) const
- {
- if (ref == iter.ref && pos == iter.pos)
- return true;
- return false;
- }
-
- //! Test for unequalness.
- bool operator!=(const _Iter& iter) const
- {
- if (ref != iter.ref || pos != iter.pos)
- return true;
- return false;
- }
-
- //! Switch to the next full character in the string.
- _Iter& operator++()
- { // ++iterator
- if (pos == ref->size_raw()) return *this;
- const uchar16_t* a = ref->c_str();
- if (UTF16_IS_SURROGATE_HI(a[pos]))
- pos += 2; // TODO: check for valid low surrogate?
- else ++pos;
- if (pos > ref->size_raw()) pos = ref->size_raw();
- return *this;
- }
-
- //! Switch to the next full character in the string, returning the previous position.
- _Iter operator++(int)
- { // iterator++
- _Iter _tmp(*this);
- ++*this;
- return _tmp;
- }
-
- //! Switch to the previous full character in the string.
- _Iter& operator--()
- { // --iterator
- if (pos == 0) return *this;
- const uchar16_t* a = ref->c_str();
- --pos;
- if (UTF16_IS_SURROGATE_LO(a[pos]) && pos != 0) // low surrogate, go back one more.
- --pos;
- return *this;
- }
-
- //! Switch to the previous full character in the string, returning the previous position.
- _Iter operator--(int)
- { // iterator--
- _Iter _tmp(*this);
- --*this;
- return _tmp;
- }
-
- //! Advance a specified number of full characters in the string.
- //! \return Myself.
- _Iter& operator+=(const difference_type v)
- {
- if (v == 0) return *this;
- if (v < 0) return operator-=(v * -1);
-
- if (pos >= ref->size_raw())
- return *this;
-
- // Go to the appropriate position.
- // TODO: Don't force u32 on an x64 OS. Make it agnostic.
- u32 i = (u32)v;
- u32 sr = ref->size_raw();
- const uchar16_t* a = ref->c_str();
- while (i != 0 && pos < sr)
- {
- if (UTF16_IS_SURROGATE_HI(a[pos]))
- pos += 2;
- else ++pos;
- --i;
- }
- if (pos > sr)
- pos = sr;
-
- return *this;
- }
-
- //! Go back a specified number of full characters in the string.
- //! \return Myself.
- _Iter& operator-=(const difference_type v)
- {
- if (v == 0) return *this;
- if (v > 0) return operator+=(v * -1);
-
- if (pos == 0)
- return *this;
-
- // Go to the appropriate position.
- // TODO: Don't force u32 on an x64 OS. Make it agnostic.
- u32 i = (u32)v;
- const uchar16_t* a = ref->c_str();
- while (i != 0 && pos != 0)
- {
- --pos;
- if (UTF16_IS_SURROGATE_LO(a[pos]) != 0 && pos != 0)
- --pos;
- --i;
- }
-
- return *this;
- }
-
- //! Return a new iterator that is a variable number of full characters forward from the current position.
- _Iter operator+(const difference_type v) const
- {
- _Iter ret(*this);
- ret += v;
- return ret;
- }
-
- //! Return a new iterator that is a variable number of full characters backward from the current position.
- _Iter operator-(const difference_type v) const
- {
- _Iter ret(*this);
- ret -= v;
- return ret;
- }
-
- //! Returns the distance between two iterators.
- difference_type operator-(const _Iter& iter) const
- {
- // Make sure we reference the same object!
- if (ref != iter.ref)
- return difference_type();
-
- _Iter i = iter;
- difference_type ret;
-
- // Walk up.
- if (pos > i.pos)
- {
- while (pos > i.pos)
- {
- ++i;
- ++ret;
- }
- return ret;
- }
-
- // Walk down.
- while (pos < i.pos)
- {
- --i;
- --ret;
- }
- return ret;
- }
-
- //! Accesses the full character at the iterator's position.
- const_reference operator*() const
- {
- if (pos >= ref->size_raw())
- {
- const uchar16_t* a = ref->c_str();
- u32 p = ref->size_raw();
- if (UTF16_IS_SURROGATE_LO(a[p]))
- --p;
- reference ret(ref, p);
- return ret;
- }
- const_reference ret(ref, pos);
- return ret;
- }
-
- //! Accesses the full character at the iterator's position.
- reference operator*()
- {
- if (pos >= ref->size_raw())
- {
- const uchar16_t* a = ref->c_str();
- u32 p = ref->size_raw();
- if (UTF16_IS_SURROGATE_LO(a[p]))
- --p;
- reference ret(ref, p);
- return ret;
- }
- reference ret(ref, pos);
- return ret;
- }
-
- //! Accesses the full character at the iterator's position.
- const_pointer operator->() const
- {
- return operator*();
- }
-
- //! Accesses the full character at the iterator's position.
- pointer operator->()
- {
- return operator*();
- }
-
- //! Is the iterator at the start of the string?
- bool atStart() const
- {
- return pos == 0;
- }
-
- //! Is the iterator at the end of the string?
- bool atEnd() const
- {
- const uchar16_t* a = ref->c_str();
- if (UTF16_IS_SURROGATE(a[pos]))
- return (pos + 1) >= ref->size_raw();
- else return pos >= ref->size_raw();
- }
-
- //! Moves the iterator to the start of the string.
- void toStart()
- {
- pos = 0;
- }
-
- //! Moves the iterator to the end of the string.
- void toEnd()
- {
- pos = ref->size_raw();
- }
-
- //! Returns the iterator's position.
- //! \return The iterator's position.
- u32 getPos() const
- {
- return pos;
- }
-
- protected:
- const ustring16<TAlloc>* ref;
- u32 pos;
- };
-
- //! Iterator to iterate through a UTF-16 string.
- class _ustring16_iterator : public _ustring16_const_iterator
- {
- public:
- typedef _ustring16_iterator _Iter;
- typedef _ustring16_const_iterator _Base;
- typedef typename _Base::const_pointer const_pointer;
- typedef typename _Base::const_reference const_reference;
-
-
- typedef typename _Base::value_type value_type;
- typedef typename _Base::difference_type difference_type;
- typedef typename _Base::distance_type distance_type;
- typedef access pointer;
- typedef access reference;
-
- using _Base::pos;
- using _Base::ref;
-
- //! Constructors.
- _ustring16_iterator(const _Iter& i) : _ustring16_const_iterator(i) {}
- _ustring16_iterator(const ustring16<TAlloc>& s) : _ustring16_const_iterator(s) {}
- _ustring16_iterator(const ustring16<TAlloc>& s, const u32 p) : _ustring16_const_iterator(s, p) {}
-
- //! Accesses the full character at the iterator's position.
- reference operator*() const
- {
- if (pos >= ref->size_raw())
- {
- const uchar16_t* a = ref->c_str();
- u32 p = ref->size_raw();
- if (UTF16_IS_SURROGATE_LO(a[p]))
- --p;
- reference ret(ref, p);
- return ret;
- }
- reference ret(ref, pos);
- return ret;
- }
-
- //! Accesses the full character at the iterator's position.
- reference operator*()
- {
- if (pos >= ref->size_raw())
- {
- const uchar16_t* a = ref->c_str();
- u32 p = ref->size_raw();
- if (UTF16_IS_SURROGATE_LO(a[p]))
- --p;
- reference ret(ref, p);
- return ret;
- }
- reference ret(ref, pos);
- return ret;
- }
-
- //! Accesses the full character at the iterator's position.
- pointer operator->() const
- {
- return operator*();
- }
-
- //! Accesses the full character at the iterator's position.
- pointer operator->()
- {
- return operator*();
- }
- };
-
- typedef typename ustring16<TAlloc>::_ustring16_iterator iterator;
- typedef typename ustring16<TAlloc>::_ustring16_const_iterator const_iterator;
-
- ///----------------------///
- /// end iterator classes ///
- ///----------------------///
-
- //! Default constructor
- ustring16()
- : array(0), allocated(1), used(0)
- {
-#if __BYTE_ORDER == __BIG_ENDIAN
- encoding = unicode::EUTFE_UTF16_BE;
-#else
- encoding = unicode::EUTFE_UTF16_LE;
-#endif
- array = allocator.allocate(1); // new u16[1];
- array[0] = 0x0;
- }
-
-
- //! Constructor
- ustring16(const ustring16<TAlloc>& other)
- : array(0), allocated(0), used(0)
- {
-#if __BYTE_ORDER == __BIG_ENDIAN
- encoding = unicode::EUTFE_UTF16_BE;
-#else
- encoding = unicode::EUTFE_UTF16_LE;
-#endif
- *this = other;
- }
-
-
- //! Constructor from other string types
- template <class B, class A>
- ustring16(const string<B, A>& other)
- : array(0), allocated(0), used(0)
- {
-#if __BYTE_ORDER == __BIG_ENDIAN
- encoding = unicode::EUTFE_UTF16_BE;
-#else
- encoding = unicode::EUTFE_UTF16_LE;
-#endif
- *this = other;
- }
-
-
-#ifndef USTRING_NO_STL
- //! Constructor from std::string
- template <class B, class A, typename Alloc>
- ustring16(const std::basic_string<B, A, Alloc>& other)
- : array(0), allocated(0), used(0)
- {
-#if __BYTE_ORDER == __BIG_ENDIAN
- encoding = unicode::EUTFE_UTF16_BE;
-#else
- encoding = unicode::EUTFE_UTF16_LE;
-#endif
- *this = other.c_str();
- }
-
-
- //! Constructor from iterator.
- template <typename Itr>
- ustring16(Itr first, Itr last)
- : array(0), allocated(0), used(0)
- {
-#if __BYTE_ORDER == __BIG_ENDIAN
- encoding = unicode::EUTFE_UTF16_BE;
-#else
- encoding = unicode::EUTFE_UTF16_LE;
-#endif
- reserve(std::distance(first, last));
- array[used] = 0;
-
- for (; first != last; ++first)
- append((uchar32_t)*first);
- }
-#endif
-
-
-#ifndef USTRING_CPP0X_NEWLITERALS
- //! Constructor for copying a character string from a pointer.
- ustring16(const char* const c)
- : array(0), allocated(0), used(0)
- {
-#if __BYTE_ORDER == __BIG_ENDIAN
- encoding = unicode::EUTFE_UTF16_BE;
-#else
- encoding = unicode::EUTFE_UTF16_LE;
-#endif
-
- loadDataStream(c, strlen(c));
- //append((uchar8_t*)c);
- }
-
-
- //! Constructor for copying a character string from a pointer with a given length.
- ustring16(const char* const c, u32 length)
- : array(0), allocated(0), used(0)
- {
-#if __BYTE_ORDER == __BIG_ENDIAN
- encoding = unicode::EUTFE_UTF16_BE;
-#else
- encoding = unicode::EUTFE_UTF16_LE;
-#endif
-
- loadDataStream(c, length);
- }
-#endif
-
-
- //! Constructor for copying a UTF-8 string from a pointer.
- ustring16(const uchar8_t* const c)
- : array(0), allocated(0), used(0)
- {
-#if __BYTE_ORDER == __BIG_ENDIAN
- encoding = unicode::EUTFE_UTF16_BE;
-#else
- encoding = unicode::EUTFE_UTF16_LE;
-#endif
-
- append(c);
- }
-
-
- //! Constructor for copying a UTF-8 string from a single char.
- ustring16(const char c)
- : array(0), allocated(0), used(0)
- {
-#if __BYTE_ORDER == __BIG_ENDIAN
- encoding = unicode::EUTFE_UTF16_BE;
-#else
- encoding = unicode::EUTFE_UTF16_LE;
-#endif
-
- append((uchar32_t)c);
- }
-
-
- //! Constructor for copying a UTF-8 string from a pointer with a given length.
- ustring16(const uchar8_t* const c, u32 length)
- : array(0), allocated(0), used(0)
- {
-#if __BYTE_ORDER == __BIG_ENDIAN
- encoding = unicode::EUTFE_UTF16_BE;
-#else
- encoding = unicode::EUTFE_UTF16_LE;
-#endif
-
- append(c, length);
- }
-
-
- //! Constructor for copying a UTF-16 string from a pointer.
- ustring16(const uchar16_t* const c)
- : array(0), allocated(0), used(0)
- {
-#if __BYTE_ORDER == __BIG_ENDIAN
- encoding = unicode::EUTFE_UTF16_BE;
-#else
- encoding = unicode::EUTFE_UTF16_LE;
-#endif
-
- append(c);
- }
-
-
- //! Constructor for copying a UTF-16 string from a pointer with a given length
- ustring16(const uchar16_t* const c, u32 length)
- : array(0), allocated(0), used(0)
- {
-#if __BYTE_ORDER == __BIG_ENDIAN
- encoding = unicode::EUTFE_UTF16_BE;
-#else
- encoding = unicode::EUTFE_UTF16_LE;
-#endif
-
- append(c, length);
- }
-
-
- //! Constructor for copying a UTF-32 string from a pointer.
- ustring16(const uchar32_t* const c)
- : array(0), allocated(0), used(0)
- {
-#if __BYTE_ORDER == __BIG_ENDIAN
- encoding = unicode::EUTFE_UTF16_BE;
-#else
- encoding = unicode::EUTFE_UTF16_LE;
-#endif
-
- append(c);
- }
-
-
- //! Constructor for copying a UTF-32 from a pointer with a given length.
- ustring16(const uchar32_t* const c, u32 length)
- : array(0), allocated(0), used(0)
- {
-#if __BYTE_ORDER == __BIG_ENDIAN
- encoding = unicode::EUTFE_UTF16_BE;
-#else
- encoding = unicode::EUTFE_UTF16_LE;
-#endif
-
- append(c, length);
- }
-
-
- //! Constructor for copying a wchar_t string from a pointer.
- ustring16(const wchar_t* const c)
- : array(0), allocated(0), used(0)
- {
-#if __BYTE_ORDER == __BIG_ENDIAN
- encoding = unicode::EUTFE_UTF16_BE;
-#else
- encoding = unicode::EUTFE_UTF16_LE;
-#endif
-
- if (sizeof(wchar_t) == 4)
- append(reinterpret_cast<const uchar32_t* const>(c));
- else if (sizeof(wchar_t) == 2)
- append(reinterpret_cast<const uchar16_t* const>(c));
- else if (sizeof(wchar_t) == 1)
- append(reinterpret_cast<const uchar8_t* const>(c));
- }
-
-
- //! Constructor for copying a wchar_t string from a pointer with a given length.
- ustring16(const wchar_t* const c, u32 length)
- : array(0), allocated(0), used(0)
- {
-#if __BYTE_ORDER == __BIG_ENDIAN
- encoding = unicode::EUTFE_UTF16_BE;
-#else
- encoding = unicode::EUTFE_UTF16_LE;
-#endif
-
- if (sizeof(wchar_t) == 4)
- append(reinterpret_cast<const uchar32_t* const>(c), length);
- else if (sizeof(wchar_t) == 2)
- append(reinterpret_cast<const uchar16_t* const>(c), length);
- else if (sizeof(wchar_t) == 1)
- append(reinterpret_cast<const uchar8_t* const>(c), length);
- }
-
-
-#ifdef USTRING_CPP0X
- //! Constructor for moving a ustring16
- ustring16(ustring16<TAlloc>&& other)
- : array(other.array), encoding(other.encoding), allocated(other.allocated), used(other.used)
- {
- //std::cout << "MOVE constructor" << std::endl;
- other.array = 0;
- other.allocated = 0;
- other.used = 0;
- }
-#endif
-
-
- //! Destructor
- ~ustring16()
- {
- allocator.deallocate(array); // delete [] array;
- }
-
-
- //! Assignment operator
- ustring16& operator=(const ustring16<TAlloc>& other)
- {
- if (this == &other)
- return *this;
-
- used = other.size_raw();
- if (used >= allocated)
- {
- allocator.deallocate(array); // delete [] array;
- allocated = used + 1;
- array = allocator.allocate(used + 1); //new u16[used];
- }
-
- const uchar16_t* p = other.c_str();
- for (u32 i=0; i<=used; ++i, ++p)
- array[i] = *p;
-
- array[used] = 0;
-
- // Validate our new UTF-16 string.
- validate();
-
- return *this;
- }
-
-
-#ifdef USTRING_CPP0X
- //! Move assignment operator
- ustring16& operator=(ustring16<TAlloc>&& other)
- {
- if (this != &other)
- {
- //std::cout << "MOVE operator=" << std::endl;
- allocator.deallocate(array);
-
- array = other.array;
- allocated = other.allocated;
- encoding = other.encoding;
- used = other.used;
- other.array = 0;
- other.used = 0;
- }
- return *this;
- }
-#endif
-
-
- //! Assignment operator for other string types
- template <class B, class A>
- ustring16<TAlloc>& operator=(const string<B, A>& other)
- {
- *this = other.c_str();
- return *this;
- }
-
-
- //! Assignment operator for UTF-8 strings
- ustring16<TAlloc>& operator=(const uchar8_t* const c)
- {
- if (!array)
- {
- array = allocator.allocate(1); //new u16[1];
- allocated = 1;
- }
- used = 0;
- array[used] = 0x0;
- if (!c) return *this;
-
- //! Append our string now.
- append(c);
- return *this;
- }
-
-
- //! Assignment operator for UTF-16 strings
- ustring16<TAlloc>& operator=(const uchar16_t* const c)
- {
- if (!array)
- {
- array = allocator.allocate(1); //new u16[1];
- allocated = 1;
- }
- used = 0;
- array[used] = 0x0;
- if (!c) return *this;
-
- //! Append our string now.
- append(c);
- return *this;
- }
-
-
- //! Assignment operator for UTF-32 strings
- ustring16<TAlloc>& operator=(const uchar32_t* const c)
- {
- if (!array)
- {
- array = allocator.allocate(1); //new u16[1];
- allocated = 1;
- }
- used = 0;
- array[used] = 0x0;
- if (!c) return *this;
-
- //! Append our string now.
- append(c);
- return *this;
- }
-
-
- //! Assignment operator for wchar_t strings.
- /** Note that this assumes that a correct unicode string is stored in the wchar_t string.
- Since wchar_t changes depending on its platform, it could either be a UTF-8, -16, or -32 string.
- This function assumes you are storing the correct unicode encoding inside the wchar_t string. **/
- ustring16<TAlloc>& operator=(const wchar_t* const c)
- {
- if (sizeof(wchar_t) == 4)
- *this = reinterpret_cast<const uchar32_t* const>(c);
- else if (sizeof(wchar_t) == 2)
- *this = reinterpret_cast<const uchar16_t* const>(c);
- else if (sizeof(wchar_t) == 1)
- *this = reinterpret_cast<const uchar8_t* const>(c);
-
- return *this;
- }
-
-
- //! Assignment operator for other strings.
- /** Note that this assumes that a correct unicode string is stored in the string. **/
- template <class B>
- ustring16<TAlloc>& operator=(const B* const c)
- {
- if (sizeof(B) == 4)
- *this = reinterpret_cast<const uchar32_t* const>(c);
- else if (sizeof(B) == 2)
- *this = reinterpret_cast<const uchar16_t* const>(c);
- else if (sizeof(B) == 1)
- *this = reinterpret_cast<const uchar8_t* const>(c);
-
- return *this;
- }
-
-
- //! Direct access operator
- access operator [](const u32 index)
- {
- _IRR_DEBUG_BREAK_IF(index>=size()) // bad index
- iterator iter(*this, index);
- return iter.operator*();
- }
-
-
- //! Direct access operator
- const access operator [](const u32 index) const
- {
- _IRR_DEBUG_BREAK_IF(index>=size()) // bad index
- const_iterator iter(*this, index);
- return iter.operator*();
- }
-
-
- //! Equality operator
- bool operator ==(const uchar16_t* const str) const
- {
- if (!str)
- return false;
-
- u32 i;
- for(i=0; array[i] && str[i]; ++i)
- if (array[i] != str[i])
- return false;
-
- return !array[i] && !str[i];
- }
-
-
- //! Equality operator
- bool operator ==(const ustring16<TAlloc>& other) const
- {
- for(u32 i=0; array[i] && other.array[i]; ++i)
- if (array[i] != other.array[i])
- return false;
-
- return used == other.used;
- }
-
-
- //! Is smaller comparator
- bool operator <(const ustring16<TAlloc>& other) const
- {
- for(u32 i=0; array[i] && other.array[i]; ++i)
- {
- s32 diff = array[i] - other.array[i];
- if ( diff )
- return diff < 0;
- }
-
- return used < other.used;
- }
-
-
- //! Inequality operator
- bool operator !=(const uchar16_t* const str) const
- {
- return !(*this == str);
- }
-
-
- //! Inequality operator
- bool operator !=(const ustring16<TAlloc>& other) const
- {
- return !(*this == other);
- }
-
-
- //! Returns the length of a ustring16 in full characters.
- //! \return Length of a ustring16 in full characters.
- u32 size() const
- {
- const_iterator i(*this, 0);
- u32 pos = 0;
- while (!i.atEnd())
- {
- ++i;
- ++pos;
- }
- return pos;
- }
-
-
- //! Informs if the ustring is empty or not.
- //! \return True if the ustring is empty, false if not.
- bool empty() const
- {
- return (size_raw() == 0);
- }
-
-
- //! Returns a pointer to the raw UTF-16 string data.
- //! \return pointer to C-style NUL terminated array of UTF-16 code points.
- const uchar16_t* c_str() const
- {
- return array;
- }
-
-
- //! Compares the first n characters of this string with another.
- //! \param other Other string to compare to.
- //! \param n Number of characters to compare.
- //! \return True if the n first characters of both strings are equal.
- bool equalsn(const ustring16<TAlloc>& other, u32 n) const
- {
- u32 i;
- const uchar16_t* oa = other.c_str();
- for(i=0; i < n && array[i] && oa[i]; ++i)
- if (array[i] != oa[i])
- return false;
-
- // if one (or both) of the strings was smaller then they
- // are only equal if they have the same length
- return (i == n) || (used == other.used);
- }
-
-
- //! Compares the first n characters of this string with another.
- //! \param str Other string to compare to.
- //! \param n Number of characters to compare.
- //! \return True if the n first characters of both strings are equal.
- bool equalsn(const uchar16_t* const str, u32 n) const
- {
- if (!str)
- return false;
- u32 i;
- for(i=0; i < n && array[i] && str[i]; ++i)
- if (array[i] != str[i])
- return false;
-
- // if one (or both) of the strings was smaller then they
- // are only equal if they have the same length
- return (i == n) || (array[i] == 0 && str[i] == 0);
- }
-
-
- //! Appends a character to this ustring16
- //! \param character The character to append.
- //! \return A reference to our current string.
- ustring16<TAlloc>& append(uchar32_t character)
- {
- if (used + 2 >= allocated)
- reallocate(used + 2);
-
- if (character > 0xFFFF)
- {
- used += 2;
-
- // character will be multibyte, so split it up into a surrogate pair.
- uchar16_t x = static_cast<uchar16_t>(character);
- uchar16_t vh = UTF16_HI_SURROGATE | ((((character >> 16) & ((1 << 5) - 1)) - 1) << 6) | (x >> 10);
- uchar16_t vl = UTF16_LO_SURROGATE | (x & ((1 << 10) - 1));
- array[used-2] = vh;
- array[used-1] = vl;
- }
- else
- {
- ++used;
- array[used-1] = character;
- }
- array[used] = 0;
-
- return *this;
- }
-
-
- //! Appends a UTF-8 string to this ustring16
- //! \param other The UTF-8 string to append.
- //! \param length The length of the string to append.
- //! \return A reference to our current string.
- ustring16<TAlloc>& append(const uchar8_t* const other, u32 length=0xffffffff)
- {
- if (!other)
- return *this;
-
- // Determine if the string is long enough for a BOM.
- u32 len = 0;
- const uchar8_t* p = other;
- do
- {
- ++len;
- } while (*p++ && len < unicode::BOM_ENCODE_UTF8_LEN);
-
- // Check for BOM.
- unicode::EUTF_ENCODE c_bom = unicode::EUTFE_NONE;
- if (len == unicode::BOM_ENCODE_UTF8_LEN)
- {
- if (memcmp(other, unicode::BOM_ENCODE_UTF8, unicode::BOM_ENCODE_UTF8_LEN) == 0)
- c_bom = unicode::EUTFE_UTF8;
- }
-
- // If a BOM was found, don't include it in the string.
- const uchar8_t* c2 = other;
- if (c_bom != unicode::EUTFE_NONE)
- {
- c2 = other + unicode::BOM_UTF8_LEN;
- length -= unicode::BOM_UTF8_LEN;
- }
-
- // Calculate the size of the string to read in.
- len = 0;
- p = c2;
- do
- {
- ++len;
- } while(*p++ && len < length);
- if (len > length)
- len = length;
-
- // If we need to grow the array, do it now.
- if (used + len >= allocated)
- reallocate(used + (len * 2));
- u32 start = used;
-
- // Convert UTF-8 to UTF-16.
- u32 pos = start;
- for (u32 l = 0; l<len;)
- {
- ++used;
- if (((c2[l] >> 6) & 0x03) == 0x02)
- { // Invalid continuation byte.
- array[pos++] = unicode::UTF_REPLACEMENT_CHARACTER;
- ++l;
- }
- else if (c2[l] == 0xC0 || c2[l] == 0xC1)
- { // Invalid byte - overlong encoding.
- array[pos++] = unicode::UTF_REPLACEMENT_CHARACTER;
- ++l;
- }
- else if ((c2[l] & 0xF8) == 0xF0)
- { // 4 bytes UTF-8, 2 bytes UTF-16.
- // Check for a full string.
- if ((l + 3) >= len)
- {
- array[pos++] = unicode::UTF_REPLACEMENT_CHARACTER;
- l += 3;
- break;
- }
-
- // Validate.
- bool valid = true;
- u8 l2 = 0;
- if (valid && (((c2[l+1] >> 6) & 0x03) == 0x02)) ++l2; else valid = false;
- if (valid && (((c2[l+2] >> 6) & 0x03) == 0x02)) ++l2; else valid = false;
- if (valid && (((c2[l+3] >> 6) & 0x03) == 0x02)) ++l2; else valid = false;
- if (!valid)
- {
- array[pos++] = unicode::UTF_REPLACEMENT_CHARACTER;
- l += l2;
- continue;
- }
-
- // Decode.
- uchar8_t b1 = ((c2[l] & 0x7) << 2) | ((c2[l+1] >> 4) & 0x3);
- uchar8_t b2 = ((c2[l+1] & 0xF) << 4) | ((c2[l+2] >> 2) & 0xF);
- uchar8_t b3 = ((c2[l+2] & 0x3) << 6) | (c2[l+3] & 0x3F);
- uchar32_t v = b3 | ((uchar32_t)b2 << 8) | ((uchar32_t)b1 << 16);
-
- // Split v up into a surrogate pair.
- uchar16_t x = static_cast<uchar16_t>(v);
- uchar16_t vh = UTF16_HI_SURROGATE | ((((v >> 16) & ((1 << 5) - 1)) - 1) << 6) | (x >> 10);
- uchar16_t vl = UTF16_LO_SURROGATE | (x & ((1 << 10) - 1));
-
- array[pos++] = vh;
- array[pos++] = vl;
- l += 4;
- ++used; // Using two shorts this time, so increase used by 1.
- }
- else if ((c2[l] & 0xF0) == 0xE0)
- { // 3 bytes UTF-8, 1 byte UTF-16.
- // Check for a full string.
- if ((l + 2) >= len)
- {
- array[pos++] = unicode::UTF_REPLACEMENT_CHARACTER;
- l += 2;
- break;
- }
-
- // Validate.
- bool valid = true;
- u8 l2 = 0;
- if (valid && (((c2[l+1] >> 6) & 0x03) == 0x02)) ++l2; else valid = false;
- if (valid && (((c2[l+2] >> 6) & 0x03) == 0x02)) ++l2; else valid = false;
- if (!valid)
- {
- array[pos++] = unicode::UTF_REPLACEMENT_CHARACTER;
- l += l2;
- continue;
- }
-
- // Decode.
- uchar8_t b1 = ((c2[l] & 0xF) << 4) | ((c2[l+1] >> 2) & 0xF);
- uchar8_t b2 = ((c2[l+1] & 0x3) << 6) | (c2[l+2] & 0x3F);
- uchar16_t ch = b2 | ((uchar16_t)b1 << 8);
- array[pos++] = ch;
- l += 3;
- }
- else if ((c2[l] & 0xE0) == 0xC0)
- { // 2 bytes UTF-8, 1 byte UTF-16.
- // Check for a full string.
- if ((l + 1) >= len)
- {
- array[pos++] = unicode::UTF_REPLACEMENT_CHARACTER;
- l += 1;
- break;
- }
-
- // Validate.
- if (((c2[l+1] >> 6) & 0x03) != 0x02)
- {
- array[pos++] = unicode::UTF_REPLACEMENT_CHARACTER;
- ++l;
- continue;
- }
-
- // Decode.
- uchar8_t b1 = (c2[l] >> 2) & 0x7;
- uchar8_t b2 = ((c2[l] & 0x3) << 6) | (c2[l+1] & 0x3F);
- uchar16_t ch = b2 | ((uchar16_t)b1 << 8);
- array[pos++] = ch;
- l += 2;
- }
- else
- { // 1 byte UTF-8, 1 byte UTF-16.
- // Validate.
- if (c2[l] > 0x7F)
- { // Values above 0xF4 are restricted and aren't used. By now, anything above 0x7F is invalid.
- array[pos++] = unicode::UTF_REPLACEMENT_CHARACTER;
- }
- else array[pos++] = static_cast<uchar16_t>(c2[l]);
- ++l;
- }
- }
- array[used] = 0;
-
- // Validate our new UTF-16 string.
- validate();
-
- return *this;
- }
-
-
- //! Appends a UTF-16 string to this ustring16
- //! \param other The UTF-16 string to append.
- //! \param length The length of the string to append.
- //! \return A reference to our current string.
- ustring16<TAlloc>& append(const uchar16_t* const other, u32 length=0xffffffff)
- {
- if (!other)
- return *this;
-
- // Determine if the string is long enough for a BOM.
- u32 len = 0;
- const uchar16_t* p = other;
- do
- {
- ++len;
- } while (*p++ && len < unicode::BOM_ENCODE_UTF16_LEN);
-
- // Check for the BOM to determine the string's endianness.
- unicode::EUTF_ENDIAN c_end = unicode::EUTFEE_NATIVE;
- if (memcmp(other, unicode::BOM_ENCODE_UTF16_LE, unicode::BOM_ENCODE_UTF16_LEN) == 0)
- c_end = unicode::EUTFEE_LITTLE;
- else if (memcmp(other, unicode::BOM_ENCODE_UTF16_BE, unicode::BOM_ENCODE_UTF16_LEN) == 0)
- c_end = unicode::EUTFEE_BIG;
-
- // If a BOM was found, don't include it in the string.
- const uchar16_t* c2 = other;
- if (c_end != unicode::EUTFEE_NATIVE)
- {
- c2 = other + unicode::BOM_UTF16_LEN;
- length -= unicode::BOM_UTF16_LEN;
- }
-
- // Calculate the size of the string to read in.
- len = 0;
- p = c2;
- do
- {
- ++len;
- } while(*p++ && len < length);
- if (len > length)
- len = length;
-
- // If we need to grow the size of the array, do it now.
- if (used + len >= allocated)
- reallocate(used + (len * 2));
- u32 start = used;
- used += len;
-
- // Copy the string now.
- unicode::EUTF_ENDIAN m_end = getEndianness();
- for (u32 l = start; l < start + len; ++l)
- {
- array[l] = (uchar16_t)c2[l];
- if (c_end != unicode::EUTFEE_NATIVE && c_end != m_end)
- array[l] = unicode::swapEndian16(array[l]);
- }
-
- array[used] = 0;
-
- // Validate our new UTF-16 string.
- validate();
- return *this;
- }
-
-
- //! Appends a UTF-32 string to this ustring16
- //! \param other The UTF-32 string to append.
- //! \param length The length of the string to append.
- //! \return A reference to our current string.
- ustring16<TAlloc>& append(const uchar32_t* const other, u32 length=0xffffffff)
- {
- if (!other)
- return *this;
-
- // Check for the BOM to determine the string's endianness.
- unicode::EUTF_ENDIAN c_end = unicode::EUTFEE_NATIVE;
- if (memcmp(other, unicode::BOM_ENCODE_UTF32_LE, unicode::BOM_ENCODE_UTF32_LEN) == 0)
- c_end = unicode::EUTFEE_LITTLE;
- else if (memcmp(other, unicode::BOM_ENCODE_UTF32_BE, unicode::BOM_ENCODE_UTF32_LEN) == 0)
- c_end = unicode::EUTFEE_BIG;
-
- // If a BOM was found, don't include it in the string.
- const uchar32_t* c2 = other;
- if (c_end != unicode::EUTFEE_NATIVE)
- {
- c2 = other + unicode::BOM_UTF32_LEN;
- length -= unicode::BOM_UTF32_LEN;
- }
-
- // Calculate the size of the string to read in.
- u32 len = 0;
- const uchar32_t* p = c2;
- do
- {
- ++len;
- } while(*p++ && len < length);
- if (len > length)
- len = length;
-
- // If we need to grow the size of the array, do it now.
- // In case all of the UTF-32 string is split into surrogate pairs, do len * 2.
- if (used + (len * 2) >= allocated)
- reallocate(used + ((len * 2) * 2));
- u32 start = used;
-
- // Convert UTF-32 to UTF-16.
- unicode::EUTF_ENDIAN m_end = getEndianness();
- u32 pos = start;
- for (u32 l = 0; l<len; ++l)
- {
- ++used;
-
- uchar32_t ch = c2[l];
- if (c_end != unicode::EUTFEE_NATIVE && c_end != m_end)
- ch = unicode::swapEndian32(ch);
-
- if (ch > 0xFFFF)
- {
- // Split ch up into a surrogate pair as it is over 16 bits long.
- uchar16_t x = static_cast<uchar16_t>(ch);
- uchar16_t vh = UTF16_HI_SURROGATE | ((((ch >> 16) & ((1 << 5) - 1)) - 1) << 6) | (x >> 10);
- uchar16_t vl = UTF16_LO_SURROGATE | (x & ((1 << 10) - 1));
- array[pos++] = vh;
- array[pos++] = vl;
- ++used; // Using two shorts, so increased used again.
- }
- else if (ch >= 0xD800 && ch <= 0xDFFF)
- {
- // Between possible UTF-16 surrogates (invalid!)
- array[pos++] = unicode::UTF_REPLACEMENT_CHARACTER;
- }
- else array[pos++] = static_cast<uchar16_t>(ch);
- }
- array[used] = 0;
-
- // Validate our new UTF-16 string.
- validate();
-
- return *this;
- }
-
-
- //! Appends a ustring16 to this ustring16
- //! \param other The string to append to this one.
- //! \return A reference to our current string.
- ustring16<TAlloc>& append(const ustring16<TAlloc>& other)
- {
- const uchar16_t* oa = other.c_str();
-
- u32 len = other.size_raw();
-
- if (used + len >= allocated)
- reallocate(used + len);
-
- for (u32 l=0; l<len; ++l)
- array[used+l] = oa[l];
-
- used += len;
- array[used] = 0;
-
- return *this;
- }
-
-
- //! Appends a certain amount of characters of a ustring16 to this ustring16.
- //! \param other The string to append to this one.
- //! \param length How many characters of the other string to add to this one.
- //! \return A reference to our current string.
- ustring16<TAlloc>& append(const ustring16<TAlloc>& other, u32 length)
- {
- if (other.size() == 0)
- return *this;
-
- if (other.size() < length)
- {
- append(other);
- return *this;
- }
-
- if (used + length * 2 >= allocated)
- reallocate(used + length * 2);
-
- const_iterator iter(other, 0);
- u32 l = length;
- while (!iter.atEnd() && l)
- {
- uchar32_t c = *iter;
- append(c);
- ++iter;
- --l;
- }
-
- return *this;
- }
-
-
- //! Reserves some memory.
- //! \param count The amount of characters to reserve.
- void reserve(u32 count)
- {
- if (count < allocated)
- return;
-
- reallocate(count);
- }
-
-
- //! Finds first occurrence of character.
- //! \param c The character to search for.
- //! \return Position where the character has been found, or -1 if not found.
- s32 findFirst(uchar32_t c) const
- {
- const_iterator i(*this, 0);
-
- s32 pos = 0;
- while (!i.atEnd())
- {
- uchar32_t t = *i;
- if (c == t)
- return pos;
- ++pos;
- ++i;
- }
-
- return -1;
- }
-
- //! Finds first occurrence of a character of a list.
- //! \param c A list of characters to find. For example if the method should find the first occurrence of 'a' or 'b', this parameter should be "ab".
- //! \param count The amount of characters in the list. Usually, this should be strlen(c).
- //! \return Position where one of the characters has been found, or -1 if not found.
- s32 findFirstChar(const uchar32_t* const c, u32 count=1) const
- {
- if (!c || !count)
- return -1;
-
- const_iterator i(*this, 0);
-
- s32 pos = 0;
- while (!i.atEnd())
- {
- uchar32_t t = *i;
- for (u32 j=0; j<count; ++j)
- if (t == c[j])
- return pos;
- ++pos;
- ++i;
- }
-
- return -1;
- }
-
-
- //! Finds first position of a character not in a given list.
- //! \param c A list of characters to NOT find. For example if the method should find the first occurrence of a character not 'a' or 'b', this parameter should be "ab".
- //! \param count The amount of characters in the list. Usually, this should be strlen(c).
- //! \return Position where the character has been found, or -1 if not found.
- s32 findFirstCharNotInList(const uchar32_t* const c, u32 count=1) const
- {
- if (!c || !count)
- return -1;
-
- const_iterator i(*this, 0);
-
- s32 pos = 0;
- while (!i.atEnd())
- {
- uchar32_t t = *i;
- u32 j;
- for (j=0; j<count; ++j)
- if (t == c[j])
- break;
-
- if (j==count)
- return pos;
- ++pos;
- ++i;
- }
-
- return -1;
- }
-
- //! Finds last position of a character not in a given list.
- //! \param c A list of characters to NOT find. For example if the method should find the first occurrence of a character not 'a' or 'b', this parameter should be "ab".
- //! \param count The amount of characters in the list. Usually, this should be strlen(c).
- //! \return Position where the character has been found, or -1 if not found.
- s32 findLastCharNotInList(const uchar32_t* const c, u32 count=1) const
- {
- if (!c || !count)
- return -1;
-
- const_iterator i(end());
- --i;
-
- s32 pos = size() - 1;
- while (!i.atStart())
- {
- uchar32_t t = *i;
- u32 j;
- for (j=0; j<count; ++j)
- if (t == c[j])
- break;
-
- if (j==count)
- return pos;
- --pos;
- --i;
- }
-
- return -1;
- }
-
- //! Finds next occurrence of character.
- //! \param c The character to search for.
- //! \param startPos The position in the string to start searching.
- //! \return Position where the character has been found, or -1 if not found.
- s32 findNext(uchar32_t c, u32 startPos) const
- {
- const_iterator i(*this, startPos);
-
- s32 pos = startPos;
- while (!i.atEnd())
- {
- uchar32_t t = *i;
- if (t == c)
- return pos;
- ++pos;
- ++i;
- }
-
- return -1;
- }
-
-
- //! Finds last occurrence of character.
- //! \param c The character to search for.
- //! \param start The start position of the reverse search ( default = -1, on end ).
- //! \return Position where the character has been found, or -1 if not found.
- s32 findLast(uchar32_t c, s32 start = -1) const
- {
- u32 s = size();
- start = core::clamp ( start < 0 ? (s32)s : start, 0, (s32)s ) - 1;
-
- const_iterator i(*this, start);
- u32 pos = start;
- while (!i.atStart())
- {
- uchar32_t t = *i;
- if (t == c)
- return pos;
- --pos;
- --i;
- }
-
- return -1;
- }
-
- //! Finds last occurrence of a character in a list.
- //! \param c A list of strings to find. For example if the method should find the last occurrence of 'a' or 'b', this parameter should be "ab".
- //! \param count The amount of characters in the list. Usually, this should be strlen(c).
- //! \return Position where one of the characters has been found, or -1 if not found.
- s32 findLastChar(const uchar32_t* const c, u32 count=1) const
- {
- if (!c || !count)
- return -1;
-
- const_iterator i(end());
- --i;
-
- s32 pos = size();
- while (!i.atStart())
- {
- uchar32_t t = *i;
- for (u32 j=0; j<count; ++j)
- if (t == c[j])
- return pos;
- --pos;
- --i;
- }
-
- return -1;
- }
-
-
- //! Finds another ustring16 in this ustring16.
- //! \param str The string to find.
- //! \param start The start position of the search.
- //! \return Positions where the ustring16 has been found, or -1 if not found.
- s32 find(const ustring16<TAlloc>& str, const u32 start = 0) const
- {
- u32 my_size = size();
- u32 their_size = str.size();
-
- if (their_size == 0 || my_size - start < their_size)
- return -1;
-
- const_iterator i(*this, start);
-
- s32 pos = start;
- while (!i.atEnd())
- {
- const_iterator i2(i);
- const_iterator j(str, 0);
- uchar32_t t1 = (uchar32_t)*i2;
- uchar32_t t2 = (uchar32_t)*j;
- while (t1 == t2)
- {
- ++i2;
- ++j;
- if (j.atEnd())
- return pos;
- t1 = (uchar32_t)*i2;
- t2 = (uchar32_t)*j;
- }
- ++i;
- ++pos;
- }
-
- return -1;
- }
-
-
- //! Finds another ustring16 in this ustring16.
- //! \param str The string to find.
- //! \param start The start position of the search.
- //! \return Positions where the string has been found, or -1 if not found.
- s32 find_raw(const ustring16<TAlloc>& str, const u32 start = 0) const
- {
- const uchar16_t* data = str.c_str();
- if (data && *data)
- {
- u32 len = 0;
-
- while (data[len])
- ++len;
-
- if (len > used)
- return -1;
-
- for (u32 i=start; i<=used-len; ++i)
- {
- u32 j=0;
-
- while(data[j] && array[i+j] == data[j])
- ++j;
-
- if (!data[j])
- return i;
- }
- }
-
- return -1;
- }
-
-
- //! Returns a substring.
- //! \param begin: Start of substring.
- //! \param length: Length of substring.
- //! \return A reference to our current string.
- ustring16<TAlloc> subString(u32 begin, s32 length) const
- {
- u32 len = size();
- // if start after ustring16
- // or no proper substring length
- if ((length <= 0) || (begin>=len))
- return ustring16<TAlloc>("");
- // clamp length to maximal value
- if ((length+begin) > len)
- length = len-begin;
-
- ustring16<TAlloc> o;
- o.reserve((length+1) * 2);
-
- const_iterator i(*this, begin);
- while (!i.atEnd() && length)
- {
- o.append(*i);
- ++i;
- --length;
- }
-
- return o;
- }
-
-
- //! Appends a character to this ustring16.
- //! \param c Character to append.
- //! \return A reference to our current string.
- ustring16<TAlloc>& operator += (char c)
- {
- append((uchar32_t)c);
- return *this;
- }
-
-
- //! Appends a character to this ustring16.
- //! \param c Character to append.
- //! \return A reference to our current string.
- ustring16<TAlloc>& operator += (uchar32_t c)
- {
- append(c);
- return *this;
- }
-
-
- //! Appends a number to this ustring16.
- //! \param c Number to append.
- //! \return A reference to our current string.
- ustring16<TAlloc>& operator += (short c)
- {
- append(core::stringc(c));
- return *this;
- }
-
-
- //! Appends a number to this ustring16.
- //! \param c Number to append.
- //! \return A reference to our current string.
- ustring16<TAlloc>& operator += (unsigned short c)
- {
- append(core::stringc(c));
- return *this;
- }
-
-
-#ifdef USTRING_CPP0X_NEWLITERALS
- //! Appends a number to this ustring16.
- //! \param c Number to append.
- //! \return A reference to our current string.
- ustring16<TAlloc>& operator += (int c)
- {
- append(core::stringc(c));
- return *this;
- }
-
-
- //! Appends a number to this ustring16.
- //! \param c Number to append.
- //! \return A reference to our current string.
- ustring16<TAlloc>& operator += (unsigned int c)
- {
- append(core::stringc(c));
- return *this;
- }
-#endif
-
-
- //! Appends a number to this ustring16.
- //! \param c Number to append.
- //! \return A reference to our current string.
- ustring16<TAlloc>& operator += (long c)
- {
- append(core::stringc(c));
- return *this;
- }
-
-
- //! Appends a number to this ustring16.
- //! \param c Number to append.
- //! \return A reference to our current string.
- ustring16<TAlloc>& operator += (unsigned long c)
- {
- append(core::stringc(c));
- return *this;
- }
-
-
- //! Appends a number to this ustring16.
- //! \param c Number to append.
- //! \return A reference to our current string.
- ustring16<TAlloc>& operator += (double c)
- {
- append(core::stringc(c));
- return *this;
- }
-
-
- //! Appends a char ustring16 to this ustring16.
- //! \param c Char ustring16 to append.
- //! \return A reference to our current string.
- ustring16<TAlloc>& operator += (const uchar16_t* const c)
- {
- append(c);
- return *this;
- }
-
-
- //! Appends a ustring16 to this ustring16.
- //! \param other ustring16 to append.
- //! \return A reference to our current string.
- ustring16<TAlloc>& operator += (const ustring16<TAlloc>& other)
- {
- append(other);
- return *this;
- }
-
-
- //! Replaces all characters of a given type with another one.
- //! \param toReplace Character to replace.
- //! \param replaceWith Character replacing the old one.
- //! \return A reference to our current string.
- ustring16<TAlloc>& replace(uchar32_t toReplace, uchar32_t replaceWith)
- {
- iterator i(*this, 0);
- while (!i.atEnd())
- {
- typename ustring16<TAlloc>::access a = *i;
- if ((uchar32_t)a == toReplace)
- a = replaceWith;
- ++i;
- }
- return *this;
- }
-
-
- //! Replaces all instances of a string with another one.
- //! \param toReplace The string to replace.
- //! \param replaceWith The string replacing the old one.
- //! \return A reference to our current string.
- ustring16<TAlloc>& replace(const ustring16<TAlloc>& toReplace, const ustring16<TAlloc>& replaceWith)
- {
- if (toReplace.size() == 0)
- return *this;
-
- const uchar16_t* other = toReplace.c_str();
- const uchar16_t* replace = replaceWith.c_str();
- const u32 other_size = toReplace.size_raw();
- const u32 replace_size = replaceWith.size_raw();
-
- // Determine the delta. The algorithm will change depending on the delta.
- s32 delta = replace_size - other_size;
-
- // A character for character replace. The string will not shrink or grow.
- if (delta == 0)
- {
- s32 pos = 0;
- while ((pos = find_raw(other, pos)) != -1)
- {
- for (u32 i = 0; i < replace_size; ++i)
- array[pos + i] = replace[i];
- ++pos;
- }
- return *this;
- }
-
- // We are going to be removing some characters. The string will shrink.
- if (delta < 0)
- {
- u32 i = 0;
- for (u32 pos = 0; pos <= used; ++i, ++pos)
- {
- // Is this potentially a match?
- if (array[pos] == *other)
- {
- // Check to see if we have a match.
- u32 j;
- for (j = 0; j < other_size; ++j)
- {
- if (array[pos + j] != other[j])
- break;
- }
-
- // If we have a match, replace characters.
- if (j == other_size)
- {
- for (j = 0; j < replace_size; ++j)
- array[i + j] = replace[j];
- i += replace_size - 1;
- pos += other_size - 1;
- continue;
- }
- }
-
- // No match found, just copy characters.
- array[i - 1] = array[pos];
- }
- array[i] = 0;
- used = i;
-
- return *this;
- }
-
- // We are going to be adding characters, so the string size will increase.
- // Count the number of times toReplace exists in the string so we can allocate the new size.
- u32 find_count = 0;
- s32 pos = 0;
- while ((pos = find_raw(other, pos)) != -1)
- {
- ++find_count;
- ++pos;
- }
-
- // Re-allocate the string now, if needed.
- u32 len = delta * find_count;
- if (used + len >= allocated)
- reallocate(used + len);
-
- // Start replacing.
- pos = 0;
- while ((pos = find_raw(other, pos)) != -1)
- {
- uchar16_t* start = array + pos + other_size - 1;
- uchar16_t* ptr = array + used;
- uchar16_t* end = array + used + delta;
-
- // Shift characters to make room for the string.
- while (ptr != start)
- {
- *end = *ptr;
- --ptr;
- --end;
- }
-
- // Add the new string now.
- for (u32 i = 0; i < replace_size; ++i)
- array[pos + i] = replace[i];
-
- pos += replace_size;
- used += delta;
- }
-
- // Terminate the string and return ourself.
- array[used] = 0;
- return *this;
- }
-
-
- //! Removes characters from a ustring16..
- //! \param c The character to remove.
- //! \return A reference to our current string.
- ustring16<TAlloc>& remove(uchar32_t c)
- {
- u32 pos = 0;
- u32 found = 0;
- u32 len = (c > 0xFFFF ? 2 : 1); // Remove characters equal to the size of c as a UTF-16 character.
- for (u32 i=0; i<=used; ++i)
- {
- uchar32_t uc32 = 0;
- if (!UTF16_IS_SURROGATE_HI(array[i]))
- uc32 |= array[i];
- else if (i + 1 <= used)
- {
- // Convert the surrogate pair into a single UTF-32 character.
- uc32 = unicode::toUTF32(array[i], array[i + 1]);
- }
- u32 len2 = (uc32 > 0xFFFF ? 2 : 1);
-
- if (uc32 == c)
- {
- found += len;
- continue;
- }
-
- array[pos++] = array[i];
- if (len2 == 2)
- array[pos++] = array[++i];
- }
- used -= found;
- array[used] = 0;
- return *this;
- }
-
-
- //! Removes a ustring16 from the ustring16.
- //! \param toRemove The string to remove.
- //! \return A reference to our current string.
- ustring16<TAlloc>& remove(const ustring16<TAlloc>& toRemove)
- {
- u32 size = toRemove.size_raw();
- if (size == 0) return *this;
-
- const uchar16_t* tra = toRemove.c_str();
- u32 pos = 0;
- u32 found = 0;
- for (u32 i=0; i<=used; ++i)
- {
- u32 j = 0;
- while (j < size)
- {
- if (array[i + j] != tra[j])
- break;
- ++j;
- }
- if (j == size)
- {
- found += size;
- i += size - 1;
- continue;
- }
-
- array[pos++] = array[i];
- }
- used -= found;
- array[used] = 0;
- return *this;
- }
-
-
- //! Removes characters from the ustring16.
- //! \param characters The characters to remove.
- //! \return A reference to our current string.
- ustring16<TAlloc>& removeChars(const ustring16<TAlloc>& characters)
- {
- if (characters.size_raw() == 0)
- return *this;
-
- u32 pos = 0;
- u32 found = 0;
- const_iterator iter(characters);
- for (u32 i=0; i<=used; ++i)
- {
- uchar32_t uc32 = 0;
- if (!UTF16_IS_SURROGATE_HI(array[i]))
- uc32 |= array[i];
- else if (i + 1 <= used)
- {
- // Convert the surrogate pair into a single UTF-32 character.
- uc32 = unicode::toUTF32(array[i], array[i+1]);
- }
- u32 len2 = (uc32 > 0xFFFF ? 2 : 1);
-
- bool cont = false;
- iter.toStart();
- while (!iter.atEnd())
- {
- uchar32_t c = *iter;
- if (uc32 == c)
- {
- found += (c > 0xFFFF ? 2 : 1); // Remove characters equal to the size of c as a UTF-16 character.
- ++i;
- cont = true;
- break;
- }
- ++iter;
- }
- if (cont) continue;
-
- array[pos++] = array[i];
- if (len2 == 2)
- array[pos++] = array[++i];
- }
- used -= found;
- array[used] = 0;
- return *this;
- }
-
-
- //! Trims the ustring16.
- //! Removes the specified characters (by default, Latin-1 whitespace) from the begining and the end of the ustring16.
- //! \param whitespace The characters that are to be considered as whitespace.
- //! \return A reference to our current string.
- ustring16<TAlloc>& trim(const ustring16<TAlloc>& whitespace = " \t\n\r")
- {
- core::array<uchar32_t> utf32white = whitespace.toUTF32();
-
- // find start and end of the substring without the specified characters
- const s32 begin = findFirstCharNotInList(utf32white.const_pointer(), whitespace.used + 1);
- if (begin == -1)
- return (*this="");
-
- const s32 end = findLastCharNotInList(utf32white.const_pointer(), whitespace.used + 1);
-
- return (*this = subString(begin, (end +1) - begin));
- }
-
-
- //! Erases a character from the ustring16.
- //! May be slow, because all elements following after the erased element have to be copied.
- //! \param index Index of element to be erased.
- //! \return A reference to our current string.
- ustring16<TAlloc>& erase(u32 index)
- {
- _IRR_DEBUG_BREAK_IF(index>used) // access violation
-
- iterator i(*this, index);
-
- uchar32_t t = *i;
- u32 len = (t > 0xFFFF ? 2 : 1);
-
- for (u32 j = static_cast<u32>(i.getPos()) + len; j <= used; ++j)
- array[j - len] = array[j];
-
- used -= len;
- array[used] = 0;
-
- return *this;
- }
-
-
- //! Validate the existing ustring16, checking for valid surrogate pairs and checking for proper termination.
- //! \return A reference to our current string.
- ustring16<TAlloc>& validate()
- {
- // Validate all unicode characters.
- for (u32 i=0; i<allocated; ++i)
- {
- // Terminate on existing null.
- if (array[i] == 0)
- {
- used = i;
- return *this;
- }
- if (UTF16_IS_SURROGATE(array[i]))
- {
- if (((i+1) >= allocated) || UTF16_IS_SURROGATE_LO(array[i]))
- array[i] = unicode::UTF_REPLACEMENT_CHARACTER;
- else if (UTF16_IS_SURROGATE_HI(array[i]) && !UTF16_IS_SURROGATE_LO(array[i+1]))
- array[i] = unicode::UTF_REPLACEMENT_CHARACTER;
- ++i;
- }
- if (array[i] >= 0xFDD0 && array[i] <= 0xFDEF)
- array[i] = unicode::UTF_REPLACEMENT_CHARACTER;
- }
-
- // terminate
- used = 0;
- if (allocated > 0)
- {
- used = allocated - 1;
- array[used] = 0;
- }
- return *this;
- }
-
-
- //! Gets the last char of the ustring16, or 0.
- //! \return The last char of the ustring16, or 0.
- uchar32_t lastChar() const
- {
- if (used < 1)
- return 0;
-
- if (UTF16_IS_SURROGATE_LO(array[used-1]))
- {
- // Make sure we have a paired surrogate.
- if (used < 2)
- return 0;
-
- // Check for an invalid surrogate.
- if (!UTF16_IS_SURROGATE_HI(array[used-2]))
- return 0;
-
- // Convert the surrogate pair into a single UTF-32 character.
- return unicode::toUTF32(array[used-2], array[used-1]);
- }
- else
- {
- return array[used-1];
- }
- }
-
-
- //! Split the ustring16 into parts.
- /** This method will split a ustring16 at certain delimiter characters
- into the container passed in as reference. The type of the container
- has to be given as template parameter. It must provide a push_back and
- a size method.
- \param ret The result container
- \param c C-style ustring16 of delimiter characters
- \param count Number of delimiter characters
- \param ignoreEmptyTokens Flag to avoid empty substrings in the result
- container. If two delimiters occur without a character in between, an
- empty substring would be placed in the result. If this flag is set,
- only non-empty strings are stored.
- \param keepSeparators Flag which allows to add the separator to the
- result ustring16. If this flag is true, the concatenation of the
- substrings results in the original ustring16. Otherwise, only the
- characters between the delimiters are returned.
- \return The number of resulting substrings
- */
- template<class container>
- u32 split(container& ret, const uchar32_t* const c, u32 count=1, bool ignoreEmptyTokens=true, bool keepSeparators=false) const
- {
- if (!c)
- return 0;
-
- const_iterator i(*this);
- const u32 oldSize=ret.size();
- u32 pos = 0;
- u32 lastpos = 0;
- u32 lastpospos = 0;
- bool lastWasSeparator = false;
- while (!i.atEnd())
- {
- uchar32_t ch = *i;
- bool foundSeparator = false;
- for (u32 j=0; j<count; ++j)
- {
- if (ch == c[j])
- {
- if ((!ignoreEmptyTokens || pos - lastpos != 0) &&
- !lastWasSeparator)
- ret.push_back(ustring16<TAlloc>(&array[lastpospos], pos - lastpos));
- foundSeparator = true;
- lastpos = (keepSeparators ? pos : pos + 1);
- lastpospos = (keepSeparators ? i.getPos() : i.getPos() + 1);
- break;
- }
- }
- lastWasSeparator = foundSeparator;
- ++pos;
- ++i;
- }
- u32 s = size() + 1;
- if (s > lastpos)
- ret.push_back(ustring16<TAlloc>(&array[lastpospos], s - lastpos));
- return ret.size()-oldSize;
- }
-
-
- //! Split the ustring16 into parts.
- /** This method will split a ustring16 at certain delimiter characters
- into the container passed in as reference. The type of the container
- has to be given as template parameter. It must provide a push_back and
- a size method.
- \param ret The result container
- \param c A unicode string of delimiter characters
- \param ignoreEmptyTokens Flag to avoid empty substrings in the result
- container. If two delimiters occur without a character in between, an
- empty substring would be placed in the result. If this flag is set,
- only non-empty strings are stored.
- \param keepSeparators Flag which allows to add the separator to the
- result ustring16. If this flag is true, the concatenation of the
- substrings results in the original ustring16. Otherwise, only the
- characters between the delimiters are returned.
- \return The number of resulting substrings
- */
- template<class container>
- u32 split(container& ret, const ustring16<TAlloc>& c, bool ignoreEmptyTokens=true, bool keepSeparators=false) const
- {
- core::array<uchar32_t> v = c.toUTF32();
- return split(ret, v.pointer(), v.size(), ignoreEmptyTokens, keepSeparators);
- }
-
-
- //! Gets the size of the allocated memory buffer for the string.
- //! \return The size of the allocated memory buffer.
- u32 capacity() const
- {
- return allocated;
- }
-
-
- //! Returns the raw number of UTF-16 code points in the string which includes the individual surrogates.
- //! \return The raw number of UTF-16 code points, excluding the trialing NUL.
- u32 size_raw() const
- {
- return used;
- }
-
-
- //! Inserts a character into the string.
- //! \param c The character to insert.
- //! \param pos The position to insert the character.
- //! \return A reference to our current string.
- ustring16<TAlloc>& insert(uchar32_t c, u32 pos)
- {
- u8 len = (c > 0xFFFF ? 2 : 1);
-
- if (used + len >= allocated)
- reallocate(used + len);
-
- used += len;
-
- iterator iter(*this, pos);
- for (u32 i = used - 2; i > iter.getPos(); --i)
- array[i] = array[i - len];
-
- if (c > 0xFFFF)
- {
- // c will be multibyte, so split it up into a surrogate pair.
- uchar16_t x = static_cast<uchar16_t>(c);
- uchar16_t vh = UTF16_HI_SURROGATE | ((((c >> 16) & ((1 << 5) - 1)) - 1) << 6) | (x >> 10);
- uchar16_t vl = UTF16_LO_SURROGATE | (x & ((1 << 10) - 1));
- array[iter.getPos()] = vh;
- array[iter.getPos()+1] = vl;
- }
- else
- {
- array[iter.getPos()] = static_cast<uchar16_t>(c);
- }
- array[used] = 0;
- return *this;
- }
-
-
- //! Inserts a string into the string.
- //! \param c The string to insert.
- //! \param pos The position to insert the string.
- //! \return A reference to our current string.
- ustring16<TAlloc>& insert(const ustring16<TAlloc>& c, u32 pos)
- {
- u32 len = c.size_raw();
- if (len == 0) return *this;
-
- if (used + len >= allocated)
- reallocate(used + len);
-
- used += len;
-
- iterator iter(*this, pos);
- for (u32 i = used - 2; i > iter.getPos() + len; --i)
- array[i] = array[i - len];
-
- const uchar16_t* s = c.c_str();
- for (u32 i = 0; i < len; ++i)
- {
- array[pos++] = *s;
- ++s;
- }
-
- array[used] = 0;
- return *this;
- }
-
-
- //! Inserts a character into the string.
- //! \param c The character to insert.
- //! \param pos The position to insert the character.
- //! \return A reference to our current string.
- ustring16<TAlloc>& insert_raw(uchar16_t c, u32 pos)
- {
- if (used + 1 >= allocated)
- reallocate(used + 1);
-
- ++used;
-
- for (u32 i = used - 1; i > pos; --i)
- array[i] = array[i - 1];
-
- array[pos] = c;
- array[used] = 0;
- return *this;
- }
-
-
- //! Removes a character from string.
- //! \param pos Position of the character to remove.
- //! \return A reference to our current string.
- ustring16<TAlloc>& erase_raw(u32 pos)
- {
- for (u32 i=pos; i<=used; ++i)
- {
- array[i] = array[i + 1];
- }
- --used;
- array[used] = 0;
- return *this;
- }
-
-
- //! Replaces a character in the string.
- //! \param c The new character.
- //! \param pos The position of the character to replace.
- //! \return A reference to our current string.
- ustring16<TAlloc>& replace_raw(uchar16_t c, u32 pos)
- {
- array[pos] = c;
- return *this;
- }
-
-
- //! Returns an iterator to the beginning of the string.
- //! \return An iterator to the beginning of the string.
- iterator begin()
- {
- iterator i(*this, 0);
- return i;
- }
-
-
- //! Returns an iterator to the beginning of the string.
- //! \return An iterator to the beginning of the string.
- const_iterator begin() const
- {
- const_iterator i(*this, 0);
- return i;
- }
-
-
- //! Returns an iterator to the beginning of the string.
- //! \return An iterator to the beginning of the string.
- const_iterator cbegin() const
- {
- const_iterator i(*this, 0);
- return i;
- }
-
-
- //! Returns an iterator to the end of the string.
- //! \return An iterator to the end of the string.
- iterator end()
- {
- iterator i(*this, 0);
- i.toEnd();
- return i;
- }
-
-
- //! Returns an iterator to the end of the string.
- //! \return An iterator to the end of the string.
- const_iterator end() const
- {
- const_iterator i(*this, 0);
- i.toEnd();
- return i;
- }
-
-
- //! Returns an iterator to the end of the string.
- //! \return An iterator to the end of the string.
- const_iterator cend() const
- {
- const_iterator i(*this, 0);
- i.toEnd();
- return i;
- }
-
-
- //! Converts the string to a UTF-8 encoded string.
- //! \param addBOM If true, the proper unicode byte-order mark will be prefixed to the string.
- //! \return A string containing the UTF-8 encoded string.
- core::string<uchar8_t> toUTF8_s(const bool addBOM = false) const
- {
- core::string<uchar8_t> ret;
- ret.reserve(used * 4 + (addBOM ? unicode::BOM_UTF8_LEN : 0) + 1);
- const_iterator iter(*this, 0);
-
- // Add the byte order mark if the user wants it.
- if (addBOM)
- {
- ret.append(unicode::BOM_ENCODE_UTF8[0]);
- ret.append(unicode::BOM_ENCODE_UTF8[1]);
- ret.append(unicode::BOM_ENCODE_UTF8[2]);
- }
-
- while (!iter.atEnd())
- {
- uchar32_t c = *iter;
- if (c > 0xFFFF)
- { // 4 bytes
- uchar8_t b1 = (0x1E << 3) | ((c >> 18) & 0x7);
- uchar8_t b2 = (0x2 << 6) | ((c >> 12) & 0x3F);
- uchar8_t b3 = (0x2 << 6) | ((c >> 6) & 0x3F);
- uchar8_t b4 = (0x2 << 6) | (c & 0x3F);
- ret.append(b1);
- ret.append(b2);
- ret.append(b3);
- ret.append(b4);
- }
- else if (c > 0x7FF)
- { // 3 bytes
- uchar8_t b1 = (0xE << 4) | ((c >> 12) & 0xF);
- uchar8_t b2 = (0x2 << 6) | ((c >> 6) & 0x3F);
- uchar8_t b3 = (0x2 << 6) | (c & 0x3F);
- ret.append(b1);
- ret.append(b2);
- ret.append(b3);
- }
- else if (c > 0x7F)
- { // 2 bytes
- uchar8_t b1 = (0x6 << 5) | ((c >> 6) & 0x1F);
- uchar8_t b2 = (0x2 << 6) | (c & 0x3F);
- ret.append(b1);
- ret.append(b2);
- }
- else
- { // 1 byte
- ret.append(static_cast<uchar8_t>(c));
- }
- ++iter;
- }
- return ret;
- }
-
-
- //! Converts the string to a UTF-8 encoded string array.
- //! \param addBOM If true, the proper unicode byte-order mark will be prefixed to the string.
- //! \return An array containing the UTF-8 encoded string.
- core::array<uchar8_t> toUTF8(const bool addBOM = false) const
- {
- core::array<uchar8_t> ret(used * 4 + (addBOM ? unicode::BOM_UTF8_LEN : 0) + 1);
- const_iterator iter(*this, 0);
-
- // Add the byte order mark if the user wants it.
- if (addBOM)
- {
- ret.push_back(unicode::BOM_ENCODE_UTF8[0]);
- ret.push_back(unicode::BOM_ENCODE_UTF8[1]);
- ret.push_back(unicode::BOM_ENCODE_UTF8[2]);
- }
-
- while (!iter.atEnd())
- {
- uchar32_t c = *iter;
- if (c > 0xFFFF)
- { // 4 bytes
- uchar8_t b1 = (0x1E << 3) | ((c >> 18) & 0x7);
- uchar8_t b2 = (0x2 << 6) | ((c >> 12) & 0x3F);
- uchar8_t b3 = (0x2 << 6) | ((c >> 6) & 0x3F);
- uchar8_t b4 = (0x2 << 6) | (c & 0x3F);
- ret.push_back(b1);
- ret.push_back(b2);
- ret.push_back(b3);
- ret.push_back(b4);
- }
- else if (c > 0x7FF)
- { // 3 bytes
- uchar8_t b1 = (0xE << 4) | ((c >> 12) & 0xF);
- uchar8_t b2 = (0x2 << 6) | ((c >> 6) & 0x3F);
- uchar8_t b3 = (0x2 << 6) | (c & 0x3F);
- ret.push_back(b1);
- ret.push_back(b2);
- ret.push_back(b3);
- }
- else if (c > 0x7F)
- { // 2 bytes
- uchar8_t b1 = (0x6 << 5) | ((c >> 6) & 0x1F);
- uchar8_t b2 = (0x2 << 6) | (c & 0x3F);
- ret.push_back(b1);
- ret.push_back(b2);
- }
- else
- { // 1 byte
- ret.push_back(static_cast<uchar8_t>(c));
- }
- ++iter;
- }
- ret.push_back(0);
- return ret;
- }
-
-
-#ifdef USTRING_CPP0X_NEWLITERALS // C++0x
- //! Converts the string to a UTF-16 encoded string.
- //! \param endian The desired endianness of the string.
- //! \param addBOM If true, the proper unicode byte-order mark will be prefixed to the string.
- //! \return A string containing the UTF-16 encoded string.
- core::string<char16_t> toUTF16_s(const unicode::EUTF_ENDIAN endian = unicode::EUTFEE_NATIVE, const bool addBOM = false) const
- {
- core::string<char16_t> ret;
- ret.reserve(used + (addBOM ? unicode::BOM_UTF16_LEN : 0) + 1);
-
- // Add the BOM if specified.
- if (addBOM)
- {
- if (endian == unicode::EUTFEE_NATIVE)
- ret[0] = unicode::BOM;
- else if (endian == unicode::EUTFEE_LITTLE)
- {
- uchar8_t* ptr8 = reinterpret_cast<uchar8_t*>(&ret[0]);
- *ptr8++ = unicode::BOM_ENCODE_UTF16_LE[0];
- *ptr8 = unicode::BOM_ENCODE_UTF16_LE[1];
- }
- else
- {
- uchar8_t* ptr8 = reinterpret_cast<uchar8_t*>(&ret[0]);
- *ptr8++ = unicode::BOM_ENCODE_UTF16_BE[0];
- *ptr8 = unicode::BOM_ENCODE_UTF16_BE[1];
- }
- }
-
- ret.append(array);
- if (endian != unicode::EUTFEE_NATIVE && getEndianness() != endian)
- {
- char16_t* ptr = ret.c_str();
- for (u32 i = 0; i < ret.size(); ++i)
- *ptr++ = unicode::swapEndian16(*ptr);
- }
- return ret;
- }
-#endif
-
-
- //! Converts the string to a UTF-16 encoded string array.
- //! Unfortunately, no toUTF16_s() version exists due to limitations with Irrlicht's string class.
- //! \param endian The desired endianness of the string.
- //! \param addBOM If true, the proper unicode byte-order mark will be prefixed to the string.
- //! \return An array containing the UTF-16 encoded string.
- core::array<uchar16_t> toUTF16(const unicode::EUTF_ENDIAN endian = unicode::EUTFEE_NATIVE, const bool addBOM = false) const
- {
- core::array<uchar16_t> ret(used + (addBOM ? unicode::BOM_UTF16_LEN : 0) + 1);
- uchar16_t* ptr = ret.pointer();
-
- // Add the BOM if specified.
- if (addBOM)
- {
- if (endian == unicode::EUTFEE_NATIVE)
- *ptr = unicode::BOM;
- else if (endian == unicode::EUTFEE_LITTLE)
- {
- uchar8_t* ptr8 = reinterpret_cast<uchar8_t*>(ptr);
- *ptr8++ = unicode::BOM_ENCODE_UTF16_LE[0];
- *ptr8 = unicode::BOM_ENCODE_UTF16_LE[1];
- }
- else
- {
- uchar8_t* ptr8 = reinterpret_cast<uchar8_t*>(ptr);
- *ptr8++ = unicode::BOM_ENCODE_UTF16_BE[0];
- *ptr8 = unicode::BOM_ENCODE_UTF16_BE[1];
- }
- ++ptr;
- }
-
- memcpy((void*)ptr, (void*)array, used * sizeof(uchar16_t));
- if (endian != unicode::EUTFEE_NATIVE && getEndianness() != endian)
- {
- for (u32 i = 0; i <= used; ++i)
- ptr[i] = unicode::swapEndian16(ptr[i]);
- }
- ret.set_used(used + (addBOM ? unicode::BOM_UTF16_LEN : 0));
- ret.push_back(0);
- return ret;
- }
-
-
-#ifdef USTRING_CPP0X_NEWLITERALS // C++0x
- //! Converts the string to a UTF-32 encoded string.
- //! \param endian The desired endianness of the string.
- //! \param addBOM If true, the proper unicode byte-order mark will be prefixed to the string.
- //! \return A string containing the UTF-32 encoded string.
- core::string<char32_t> toUTF32_s(const unicode::EUTF_ENDIAN endian = unicode::EUTFEE_NATIVE, const bool addBOM = false) const
- {
- core::string<char32_t> ret;
- ret.reserve(size() + 1 + (addBOM ? unicode::BOM_UTF32_LEN : 0));
- const_iterator iter(*this, 0);
-
- // Add the BOM if specified.
- if (addBOM)
- {
- if (endian == unicode::EUTFEE_NATIVE)
- ret.append(unicode::BOM);
- else
- {
- union
- {
- uchar32_t full;
- u8 chunk[4];
- } t;
-
- if (endian == unicode::EUTFEE_LITTLE)
- {
- t.chunk[0] = unicode::BOM_ENCODE_UTF32_LE[0];
- t.chunk[1] = unicode::BOM_ENCODE_UTF32_LE[1];
- t.chunk[2] = unicode::BOM_ENCODE_UTF32_LE[2];
- t.chunk[3] = unicode::BOM_ENCODE_UTF32_LE[3];
- }
- else
- {
- t.chunk[0] = unicode::BOM_ENCODE_UTF32_BE[0];
- t.chunk[1] = unicode::BOM_ENCODE_UTF32_BE[1];
- t.chunk[2] = unicode::BOM_ENCODE_UTF32_BE[2];
- t.chunk[3] = unicode::BOM_ENCODE_UTF32_BE[3];
- }
- ret.append(t.full);
- }
- }
-
- while (!iter.atEnd())
- {
- uchar32_t c = *iter;
- if (endian != unicode::EUTFEE_NATIVE && getEndianness() != endian)
- c = unicode::swapEndian32(c);
- ret.append(c);
- ++iter;
- }
- return ret;
- }
-#endif
-
-
- //! Converts the string to a UTF-32 encoded string array.
- //! Unfortunately, no toUTF32_s() version exists due to limitations with Irrlicht's string class.
- //! \param endian The desired endianness of the string.
- //! \param addBOM If true, the proper unicode byte-order mark will be prefixed to the string.
- //! \return An array containing the UTF-32 encoded string.
- core::array<uchar32_t> toUTF32(const unicode::EUTF_ENDIAN endian = unicode::EUTFEE_NATIVE, const bool addBOM = false) const
- {
- core::array<uchar32_t> ret(size() + (addBOM ? unicode::BOM_UTF32_LEN : 0) + 1);
- const_iterator iter(*this, 0);
-
- // Add the BOM if specified.
- if (addBOM)
- {
- if (endian == unicode::EUTFEE_NATIVE)
- ret.push_back(unicode::BOM);
- else
- {
- union
- {
- uchar32_t full;
- u8 chunk[4];
- } t;
-
- if (endian == unicode::EUTFEE_LITTLE)
- {
- t.chunk[0] = unicode::BOM_ENCODE_UTF32_LE[0];
- t.chunk[1] = unicode::BOM_ENCODE_UTF32_LE[1];
- t.chunk[2] = unicode::BOM_ENCODE_UTF32_LE[2];
- t.chunk[3] = unicode::BOM_ENCODE_UTF32_LE[3];
- }
- else
- {
- t.chunk[0] = unicode::BOM_ENCODE_UTF32_BE[0];
- t.chunk[1] = unicode::BOM_ENCODE_UTF32_BE[1];
- t.chunk[2] = unicode::BOM_ENCODE_UTF32_BE[2];
- t.chunk[3] = unicode::BOM_ENCODE_UTF32_BE[3];
- }
- ret.push_back(t.full);
- }
- }
- ret.push_back(0);
-
- while (!iter.atEnd())
- {
- uchar32_t c = *iter;
- if (endian != unicode::EUTFEE_NATIVE && getEndianness() != endian)
- c = unicode::swapEndian32(c);
- ret.push_back(c);
- ++iter;
- }
- return ret;
- }
-
-
- //! Converts the string to a wchar_t encoded string.
- /** The size of a wchar_t changes depending on the platform. This function will store a
- correct UTF-8, -16, or -32 encoded string depending on the size of a wchar_t. **/
- //! \param endian The desired endianness of the string.
- //! \param addBOM If true, the proper unicode byte-order mark will be prefixed to the string.
- //! \return A string containing the wchar_t encoded string.
- core::string<wchar_t> toWCHAR_s(const unicode::EUTF_ENDIAN endian = unicode::EUTFEE_NATIVE, const bool addBOM = false) const
- {
- if (sizeof(wchar_t) == 4)
- {
- core::array<uchar32_t> a(toUTF32(endian, addBOM));
- core::stringw ret(a.pointer());
- return ret;
- }
- else if (sizeof(wchar_t) == 2)
- {
- if (endian == unicode::EUTFEE_NATIVE && addBOM == false)
- {
- core::stringw ret(array);
- return ret;
- }
- else
- {
- core::array<uchar16_t> a(toUTF16(endian, addBOM));
- core::stringw ret(a.pointer());
- return ret;
- }
- }
- else if (sizeof(wchar_t) == 1)
- {
- core::array<uchar8_t> a(toUTF8(addBOM));
- core::stringw ret(a.pointer());
- return ret;
- }
-
- // Shouldn't happen.
- return core::stringw();
- }
-
-
- //! Converts the string to a wchar_t encoded string array.
- /** The size of a wchar_t changes depending on the platform. This function will store a
- correct UTF-8, -16, or -32 encoded string depending on the size of a wchar_t. **/
- //! \param endian The desired endianness of the string.
- //! \param addBOM If true, the proper unicode byte-order mark will be prefixed to the string.
- //! \return An array containing the wchar_t encoded string.
- core::array<wchar_t> toWCHAR(const unicode::EUTF_ENDIAN endian = unicode::EUTFEE_NATIVE, const bool addBOM = false) const
- {
- if (sizeof(wchar_t) == 4)
- {
- core::array<uchar32_t> a(toUTF32(endian, addBOM));
- core::array<wchar_t> ret(a.size());
- ret.set_used(a.size());
- memcpy((void*)ret.pointer(), (void*)a.pointer(), a.size() * sizeof(uchar32_t));
- return ret;
- }
- if (sizeof(wchar_t) == 2)
- {
- if (endian == unicode::EUTFEE_NATIVE && addBOM == false)
- {
- core::array<wchar_t> ret(used);
- ret.set_used(used);
- memcpy((void*)ret.pointer(), (void*)array, used * sizeof(uchar16_t));
- return ret;
- }
- else
- {
- core::array<uchar16_t> a(toUTF16(endian, addBOM));
- core::array<wchar_t> ret(a.size());
- ret.set_used(a.size());
- memcpy((void*)ret.pointer(), (void*)a.pointer(), a.size() * sizeof(uchar16_t));
- return ret;
- }
- }
- if (sizeof(wchar_t) == 1)
- {
- core::array<uchar8_t> a(toUTF8(addBOM));
- core::array<wchar_t> ret(a.size());
- ret.set_used(a.size());
- memcpy((void*)ret.pointer(), (void*)a.pointer(), a.size() * sizeof(uchar8_t));
- return ret;
- }
-
- // Shouldn't happen.
- return core::array<wchar_t>();
- }
-
- //! Converts the string to a properly encoded io::path string.
- //! \param endian The desired endianness of the string.
- //! \param addBOM If true, the proper unicode byte-order mark will be prefixed to the string.
- //! \return An io::path string containing the properly encoded string.
- io::path toPATH_s(const unicode::EUTF_ENDIAN endian = unicode::EUTFEE_NATIVE, const bool addBOM = false) const
- {
-#if defined(_IRR_WCHAR_FILESYSTEM)
- return toWCHAR_s(endian, addBOM);
-#else
- return toUTF8_s(addBOM);
-#endif
- }
-
- //! Loads an unknown stream of data.
- //! Will attempt to determine if the stream is unicode data. Useful for loading from files.
- //! \param data The data stream to load from.
- //! \param data_size The length of the data string.
- //! \return A reference to our current string.
- ustring16<TAlloc>& loadDataStream(const char* data, size_t data_size)
- {
- // Clear our string.
- *this = "";
- if (!data)
- return *this;
-
- unicode::EUTF_ENCODE e = unicode::determineUnicodeBOM(data);
- switch (e)
- {
- default:
- case unicode::EUTFE_UTF8:
- append((uchar8_t*)data, data_size);
- break;
-
- case unicode::EUTFE_UTF16:
- case unicode::EUTFE_UTF16_BE:
- case unicode::EUTFE_UTF16_LE:
- append((uchar16_t*)data, data_size / 2);
- break;
-
- case unicode::EUTFE_UTF32:
- case unicode::EUTFE_UTF32_BE:
- case unicode::EUTFE_UTF32_LE:
- append((uchar32_t*)data, data_size / 4);
- break;
- }
-
- return *this;
- }
-
- //! Gets the encoding of the Unicode string this class contains.
- //! \return An enum describing the current encoding of this string.
- const unicode::EUTF_ENCODE getEncoding() const
- {
- return encoding;
- }
-
- //! Gets the endianness of the Unicode string this class contains.
- //! \return An enum describing the endianness of this string.
- const unicode::EUTF_ENDIAN getEndianness() const
- {
- if (encoding == unicode::EUTFE_UTF16_LE ||
- encoding == unicode::EUTFE_UTF32_LE)
- return unicode::EUTFEE_LITTLE;
- else return unicode::EUTFEE_BIG;
- }
-
-private:
-
- //! Reallocate the string, making it bigger or smaller.
- //! \param new_size The new size of the string.
- void reallocate(u32 new_size)
- {
- uchar16_t* old_array = array;
-
- array = allocator.allocate(new_size + 1); //new u16[new_size];
- allocated = new_size + 1;
- if (old_array == 0) return;
-
- u32 amount = used < new_size ? used : new_size;
- for (u32 i=0; i<=amount; ++i)
- array[i] = old_array[i];
-
- if (allocated <= used)
- used = allocated - 1;
-
- array[used] = 0;
-
- allocator.deallocate(old_array); // delete [] old_array;
- }
-
- //--- member variables
-
- uchar16_t* array;
- unicode::EUTF_ENCODE encoding;
- u32 allocated;
- u32 used;
- TAlloc allocator;
- //irrAllocator<uchar16_t> allocator;
-};
-
-typedef ustring16<irrAllocator<uchar16_t> > ustring;
-
-
-//! Appends two ustring16s.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const ustring16<TAlloc>& left, const ustring16<TAlloc>& right)
-{
- ustring16<TAlloc> ret(left);
- ret += right;
- return ret;
-}
-
-
-//! Appends a ustring16 and a null-terminated unicode string.
-template <typename TAlloc, class B>
-inline ustring16<TAlloc> operator+(const ustring16<TAlloc>& left, const B* const right)
-{
- ustring16<TAlloc> ret(left);
- ret += right;
- return ret;
-}
-
-
-//! Appends a ustring16 and a null-terminated unicode string.
-template <class B, typename TAlloc>
-inline ustring16<TAlloc> operator+(const B* const left, const ustring16<TAlloc>& right)
-{
- ustring16<TAlloc> ret(left);
- ret += right;
- return ret;
-}
-
-
-//! Appends a ustring16 and an Irrlicht string.
-template <typename TAlloc, typename B, typename BAlloc>
-inline ustring16<TAlloc> operator+(const ustring16<TAlloc>& left, const string<B, BAlloc>& right)
-{
- ustring16<TAlloc> ret(left);
- ret += right;
- return ret;
-}
-
-
-//! Appends a ustring16 and an Irrlicht string.
-template <typename TAlloc, typename B, typename BAlloc>
-inline ustring16<TAlloc> operator+(const string<B, BAlloc>& left, const ustring16<TAlloc>& right)
-{
- ustring16<TAlloc> ret(left);
- ret += right;
- return ret;
-}
-
-
-//! Appends a ustring16 and a std::basic_string.
-template <typename TAlloc, typename B, typename A, typename BAlloc>
-inline ustring16<TAlloc> operator+(const ustring16<TAlloc>& left, const std::basic_string<B, A, BAlloc>& right)
-{
- ustring16<TAlloc> ret(left);
- ret += right;
- return ret;
-}
-
-
-//! Appends a ustring16 and a std::basic_string.
-template <typename TAlloc, typename B, typename A, typename BAlloc>
-inline ustring16<TAlloc> operator+(const std::basic_string<B, A, BAlloc>& left, const ustring16<TAlloc>& right)
-{
- ustring16<TAlloc> ret(left);
- ret += right;
- return ret;
-}
-
-
-//! Appends a ustring16 and a char.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const ustring16<TAlloc>& left, const char right)
-{
- ustring16<TAlloc> ret(left);
- ret += right;
- return ret;
-}
-
-
-//! Appends a ustring16 and a char.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const char left, const ustring16<TAlloc>& right)
-{
- ustring16<TAlloc> ret(left);
- ret += right;
- return ret;
-}
-
-
-#ifdef USTRING_CPP0X_NEWLITERALS
-//! Appends a ustring16 and a uchar32_t.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const ustring16<TAlloc>& left, const uchar32_t right)
-{
- ustring16<TAlloc> ret(left);
- ret += right;
- return ret;
-}
-
-
-//! Appends a ustring16 and a uchar32_t.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const uchar32_t left, const ustring16<TAlloc>& right)
-{
- ustring16<TAlloc> ret(left);
- ret += right;
- return ret;
-}
-#endif
-
-
-//! Appends a ustring16 and a short.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const ustring16<TAlloc>& left, const short right)
-{
- ustring16<TAlloc> ret(left);
- ret += core::stringc(right);
- return ret;
-}
-
-
-//! Appends a ustring16 and a short.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const short left, const ustring16<TAlloc>& right)
-{
- ustring16<TAlloc> ret((core::stringc(left)));
- ret += right;
- return ret;
-}
-
-
-//! Appends a ustring16 and an unsigned short.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const ustring16<TAlloc>& left, const unsigned short right)
-{
- ustring16<TAlloc> ret(left);
- ret += core::stringc(right);
- return ret;
-}
-
-
-//! Appends a ustring16 and an unsigned short.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const unsigned short left, const ustring16<TAlloc>& right)
-{
- ustring16<TAlloc> ret((core::stringc(left)));
- ret += right;
- return ret;
-}
-
-
-//! Appends a ustring16 and an int.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const ustring16<TAlloc>& left, const int right)
-{
- ustring16<TAlloc> ret(left);
- ret += core::stringc(right);
- return ret;
-}
-
-
-//! Appends a ustring16 and an int.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const int left, const ustring16<TAlloc>& right)
-{
- ustring16<TAlloc> ret((core::stringc(left)));
- ret += right;
- return ret;
-}
-
-
-//! Appends a ustring16 and an unsigned int.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const ustring16<TAlloc>& left, const unsigned int right)
-{
- ustring16<TAlloc> ret(left);
- ret += core::stringc(right);
- return ret;
-}
-
-
-//! Appends a ustring16 and an unsigned int.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const unsigned int left, const ustring16<TAlloc>& right)
-{
- ustring16<TAlloc> ret((core::stringc(left)));
- ret += right;
- return ret;
-}
-
-
-//! Appends a ustring16 and a long.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const ustring16<TAlloc>& left, const long right)
-{
- ustring16<TAlloc> ret(left);
- ret += core::stringc(right);
- return ret;
-}
-
-
-//! Appends a ustring16 and a long.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const long left, const ustring16<TAlloc>& right)
-{
- ustring16<TAlloc> ret((core::stringc(left)));
- ret += right;
- return ret;
-}
-
-
-//! Appends a ustring16 and an unsigned long.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const ustring16<TAlloc>& left, const unsigned long right)
-{
- ustring16<TAlloc> ret(left);
- ret += core::stringc(right);
- return ret;
-}
-
-
-//! Appends a ustring16 and an unsigned long.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const unsigned long left, const ustring16<TAlloc>& right)
-{
- ustring16<TAlloc> ret((core::stringc(left)));
- ret += right;
- return ret;
-}
-
-
-//! Appends a ustring16 and a float.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const ustring16<TAlloc>& left, const float right)
-{
- ustring16<TAlloc> ret(left);
- ret += core::stringc(right);
- return ret;
-}
-
-
-//! Appends a ustring16 and a float.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const float left, const ustring16<TAlloc>& right)
-{
- ustring16<TAlloc> ret((core::stringc(left)));
- ret += right;
- return ret;
-}
-
-
-//! Appends a ustring16 and a double.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const ustring16<TAlloc>& left, const double right)
-{
- ustring16<TAlloc> ret(left);
- ret += core::stringc(right);
- return ret;
-}
-
-
-//! Appends a ustring16 and a double.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const double left, const ustring16<TAlloc>& right)
-{
- ustring16<TAlloc> ret((core::stringc(left)));
- ret += right;
- return ret;
-}
-
-
-#ifdef USTRING_CPP0X
-//! Appends two ustring16s.
-template <typename TAlloc>
-inline ustring16<TAlloc>&& operator+(const ustring16<TAlloc>& left, ustring16<TAlloc>&& right)
-{
- //std::cout << "MOVE operator+(&, &&)" << std::endl;
- right.insert(left, 0);
- return std::move(right);
-}
-
-
-//! Appends two ustring16s.
-template <typename TAlloc>
-inline ustring16<TAlloc>&& operator+(ustring16<TAlloc>&& left, const ustring16<TAlloc>& right)
-{
- //std::cout << "MOVE operator+(&&, &)" << std::endl;
- left.append(right);
- return std::move(left);
-}
-
-
-//! Appends two ustring16s.
-template <typename TAlloc>
-inline ustring16<TAlloc>&& operator+(ustring16<TAlloc>&& left, ustring16<TAlloc>&& right)
-{
- //std::cout << "MOVE operator+(&&, &&)" << std::endl;
- if ((right.size_raw() <= left.capacity() - left.size_raw()) ||
- (right.capacity() - right.size_raw() < left.size_raw()))
- {
- left.append(right);
- return std::move(left);
- }
- else
- {
- right.insert(left, 0);
- return std::move(right);
- }
-}
-
-
-//! Appends a ustring16 and a null-terminated unicode string.
-template <typename TAlloc, class B>
-inline ustring16<TAlloc>&& operator+(ustring16<TAlloc>&& left, const B* const right)
-{
- //std::cout << "MOVE operator+(&&, B*)" << std::endl;
- left.append(right);
- return std::move(left);
-}
-
-
-//! Appends a ustring16 and a null-terminated unicode string.
-template <class B, typename TAlloc>
-inline ustring16<TAlloc>&& operator+(const B* const left, ustring16<TAlloc>&& right)
-{
- //std::cout << "MOVE operator+(B*, &&)" << std::endl;
- right.insert(left, 0);
- return std::move(right);
-}
-
-
-//! Appends a ustring16 and an Irrlicht string.
-template <typename TAlloc, typename B, typename BAlloc>
-inline ustring16<TAlloc>&& operator+(const string<B, BAlloc>& left, ustring16<TAlloc>&& right)
-{
- //std::cout << "MOVE operator+(&, &&)" << std::endl;
- right.insert(left, 0);
- return std::move(right);
-}
-
-
-//! Appends a ustring16 and an Irrlicht string.
-template <typename TAlloc, typename B, typename BAlloc>
-inline ustring16<TAlloc>&& operator+(ustring16<TAlloc>&& left, const string<B, BAlloc>& right)
-{
- //std::cout << "MOVE operator+(&&, &)" << std::endl;
- left.append(right);
- return std::move(left);
-}
-
-
-//! Appends a ustring16 and a std::basic_string.
-template <typename TAlloc, typename B, typename A, typename BAlloc>
-inline ustring16<TAlloc>&& operator+(const std::basic_string<B, A, BAlloc>& left, ustring16<TAlloc>&& right)
-{
- //std::cout << "MOVE operator+(&, &&)" << std::endl;
- right.insert(core::ustring16<TAlloc>(left), 0);
- return std::move(right);
-}
-
-
-//! Appends a ustring16 and a std::basic_string.
-template <typename TAlloc, typename B, typename A, typename BAlloc>
-inline ustring16<TAlloc>&& operator+(ustring16<TAlloc>&& left, const std::basic_string<B, A, BAlloc>& right)
-{
- //std::cout << "MOVE operator+(&&, &)" << std::endl;
- left.append(right);
- return std::move(left);
-}
-
-
-//! Appends a ustring16 and a char.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(ustring16<TAlloc>&& left, const char right)
-{
- left.append((uchar32_t)right);
- return std::move(left);
-}
-
-
-//! Appends a ustring16 and a char.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const char left, ustring16<TAlloc>&& right)
-{
- right.insert((uchar32_t)left, 0);
- return std::move(right);
-}
-
-
-#ifdef USTRING_CPP0X_NEWLITERALS
-//! Appends a ustring16 and a uchar32_t.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(ustring16<TAlloc>&& left, const uchar32_t right)
-{
- left.append(right);
- return std::move(left);
-}
-
-
-//! Appends a ustring16 and a uchar32_t.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const uchar32_t left, ustring16<TAlloc>&& right)
-{
- right.insert(left, 0);
- return std::move(right);
-}
-#endif
-
-
-//! Appends a ustring16 and a short.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(ustring16<TAlloc>&& left, const short right)
-{
- left.append(core::stringc(right));
- return std::move(left);
-}
-
-
-//! Appends a ustring16 and a short.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const short left, ustring16<TAlloc>&& right)
-{
- right.insert(core::stringc(left), 0);
- return std::move(right);
-}
-
-
-//! Appends a ustring16 and an unsigned short.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(ustring16<TAlloc>&& left, const unsigned short right)
-{
- left.append(core::stringc(right));
- return std::move(left);
-}
-
-
-//! Appends a ustring16 and an unsigned short.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const unsigned short left, ustring16<TAlloc>&& right)
-{
- right.insert(core::stringc(left), 0);
- return std::move(right);
-}
-
-
-//! Appends a ustring16 and an int.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(ustring16<TAlloc>&& left, const int right)
-{
- left.append(core::stringc(right));
- return std::move(left);
-}
-
-
-//! Appends a ustring16 and an int.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const int left, ustring16<TAlloc>&& right)
-{
- right.insert(core::stringc(left), 0);
- return std::move(right);
-}
-
-
-//! Appends a ustring16 and an unsigned int.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(ustring16<TAlloc>&& left, const unsigned int right)
-{
- left.append(core::stringc(right));
- return std::move(left);
-}
-
-
-//! Appends a ustring16 and an unsigned int.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const unsigned int left, ustring16<TAlloc>&& right)
-{
- right.insert(core::stringc(left), 0);
- return std::move(right);
-}
-
-
-//! Appends a ustring16 and a long.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(ustring16<TAlloc>&& left, const long right)
-{
- left.append(core::stringc(right));
- return std::move(left);
-}
-
-
-//! Appends a ustring16 and a long.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const long left, ustring16<TAlloc>&& right)
-{
- right.insert(core::stringc(left), 0);
- return std::move(right);
-}
-
-
-//! Appends a ustring16 and an unsigned long.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(ustring16<TAlloc>&& left, const unsigned long right)
-{
- left.append(core::stringc(right));
- return std::move(left);
-}
-
-
-//! Appends a ustring16 and an unsigned long.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const unsigned long left, ustring16<TAlloc>&& right)
-{
- right.insert(core::stringc(left), 0);
- return std::move(right);
-}
-
-
-//! Appends a ustring16 and a float.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(ustring16<TAlloc>&& left, const float right)
-{
- left.append(core::stringc(right));
- return std::move(left);
-}
-
-
-//! Appends a ustring16 and a float.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const float left, ustring16<TAlloc>&& right)
-{
- right.insert(core::stringc(left), 0);
- return std::move(right);
-}
-
-
-//! Appends a ustring16 and a double.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(ustring16<TAlloc>&& left, const double right)
-{
- left.append(core::stringc(right));
- return std::move(left);
-}
-
-
-//! Appends a ustring16 and a double.
-template <typename TAlloc>
-inline ustring16<TAlloc> operator+(const double left, ustring16<TAlloc>&& right)
-{
- right.insert(core::stringc(left), 0);
- return std::move(right);
-}
-#endif
-
-
-#ifndef USTRING_NO_STL
-//! Writes a ustring16 to an ostream.
-template <typename TAlloc>
-inline std::ostream& operator<<(std::ostream& out, const ustring16<TAlloc>& in)
-{
- out << in.toUTF8_s().c_str();
- return out;
-}
-
-//! Writes a ustring16 to a wostream.
-template <typename TAlloc>
-inline std::wostream& operator<<(std::wostream& out, const ustring16<TAlloc>& in)
-{
- out << in.toWCHAR_s().c_str();
- return out;
-}
-#endif
-
-
-#ifndef USTRING_NO_STL
-
-namespace unicode
-{
-
-//! Hashing algorithm for hashing a ustring. Used for things like unordered_maps.
-//! Algorithm taken from std::hash<std::string>.
-class hash : public std::unary_function<core::ustring, size_t>
-{
- public:
- size_t operator()(const core::ustring& s) const
- {
- size_t ret = 2166136261U;
- size_t index = 0;
- size_t stride = 1 + s.size_raw() / 10;
-
- core::ustring::const_iterator i = s.begin();
- while (i != s.end())
- {
- // TODO: Don't force u32 on an x64 OS. Make it agnostic.
- ret = 16777619U * ret ^ (size_t)s[(u32)index];
- index += stride;
- i += stride;
- }
- return (ret);
- }
-};
-
-} // end namespace unicode
-
-#endif
-
-} // end namespace core
-} // end namespace irr
diff --git a/src/irrlicht_changes/static_text.cpp b/src/irrlicht_changes/static_text.cpp
index a8cc33352..8908a91f7 100644
--- a/src/irrlicht_changes/static_text.cpp
+++ b/src/irrlicht_changes/static_text.cpp
@@ -108,16 +108,11 @@ void StaticText::draw()
font->getDimension(str.c_str()).Width;
}
- //str = colorizeText(BrokenText[i].c_str(), colors, previous_color);
- //if (!colors.empty())
- // previous_color = colors[colors.size() - 1];
-
#if USE_FREETYPE
if (font->getType() == irr::gui::EGFT_CUSTOM) {
irr::gui::CGUITTFont *tmp = static_cast<irr::gui::CGUITTFont*>(font);
tmp->draw(str,
- r, previous_color, // FIXME
- HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER,
+ r, HAlign == EGUIA_CENTER, VAlign == EGUIA_CENTER,
(RestrainTextInside ? &AbsoluteClippingRect : NULL));
} else
#endif
@@ -246,11 +241,7 @@ void StaticText::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vert
}
-#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
-const video::SColor& StaticText::getOverrideColor() const
-#else
video::SColor StaticText::getOverrideColor() const
-#endif
{
return ColoredText.getDefaultColor();
}
diff --git a/src/irrlicht_changes/static_text.h b/src/irrlicht_changes/static_text.h
index 786129d57..83bbf4c3d 100644
--- a/src/irrlicht_changes/static_text.h
+++ b/src/irrlicht_changes/static_text.h
@@ -134,11 +134,7 @@ namespace gui
virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical);
//! Gets the override color
- #if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7
- virtual const video::SColor& getOverrideColor() const;
- #else
virtual video::SColor getOverrideColor() const;
- #endif
#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8
//! Gets the currently used text color
diff --git a/src/irrlichttypes.h b/src/irrlichttypes.h
index 794776b26..93c2d105b 100644
--- a/src/irrlichttypes.h
+++ b/src/irrlichttypes.h
@@ -19,16 +19,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
-/* Ensure that <stdint.h> is included before <irrTypes.h>, unless building on
- * MSVC, to address an irrlicht issue: https://sourceforge.net/p/irrlicht/bugs/433/
- *
- * TODO: Decide whether or not we support non-compliant C++ compilers like old
- * versions of MSCV. If we do not then <stdint.h> can always be included
- * regardless of the compiler.
+/*
+ * IrrlichtMt already includes stdint.h in irrTypes.h. This works everywhere
+ * we need it to (including recent MSVC), so should be fine here too.
*/
-#ifndef _MSC_VER
-# include <cstdint>
-#endif
+#include <cstdint>
#include <irrTypes.h>
@@ -36,19 +31,6 @@ using namespace irr;
namespace irr {
-// Irrlicht 1.8+ defines 64bit unsigned symbol in irrTypes.h
-#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8)
-#ifdef _MSC_VER
- // Windows
- typedef long long s64;
- typedef unsigned long long u64;
-#else
- // Posix
- typedef int64_t s64;
- typedef uint64_t u64;
-#endif
-#endif
-
#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 9)
namespace core {
template <typename T>
diff --git a/src/main.cpp b/src/main.cpp
index 39b441d2c..7f96836b5 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -225,8 +225,7 @@ int main(int argc, char *argv[])
return run_dedicated_server(game_params, cmd_args) ? 0 : 1;
#ifndef SERVER
- ClientLauncher launcher;
- retval = launcher.run(game_params, cmd_args) ? 0 : 1;
+ retval = ClientLauncher().run(game_params, cmd_args) ? 0 : 1;
#else
retval = 0;
#endif
diff --git a/src/mapnode.cpp b/src/mapnode.cpp
index 0551f3b6f..c885bfe1d 100644
--- a/src/mapnode.cpp
+++ b/src/mapnode.cpp
@@ -159,8 +159,11 @@ u8 MapNode::getWallMounted(const NodeDefManager *nodemgr) const
{
const ContentFeatures &f = nodemgr->get(*this);
if (f.param_type_2 == CPT2_WALLMOUNTED ||
- f.param_type_2 == CPT2_COLORED_WALLMOUNTED)
+ f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
return getParam2() & 0x07;
+ } else if (f.drawtype == NDT_SIGNLIKE || f.drawtype == NDT_TORCHLIKE) {
+ return 1;
+ }
return 0;
}
@@ -177,6 +180,16 @@ v3s16 MapNode::getWallMountedDir(const NodeDefManager *nodemgr) const
}
}
+u8 MapNode::getDegRotate(const NodeDefManager *nodemgr) const
+{
+ const ContentFeatures &f = nodemgr->get(*this);
+ if (f.param_type_2 == CPT2_DEGROTATE)
+ return getParam2() % 240;
+ if (f.param_type_2 == CPT2_COLORED_DEGROTATE)
+ return 10 * ((getParam2() & 0x1F) % 24);
+ return 0;
+}
+
void MapNode::rotateAlongYAxis(const NodeDefManager *nodemgr, Rotation rot)
{
ContentParamType2 cpt2 = nodemgr->get(*this).param_type_2;
@@ -230,6 +243,17 @@ void MapNode::rotateAlongYAxis(const NodeDefManager *nodemgr, Rotation rot)
Rotation oldrot = wallmounted_to_rot[wmountface - 2];
param2 &= ~7;
param2 |= rot_to_wallmounted[(oldrot - rot) & 3];
+ } else if (cpt2 == CPT2_DEGROTATE) {
+ int angle = param2; // in 1.5°
+ angle += 60 * rot; // don’t do that on u8
+ angle %= 240;
+ param2 = angle;
+ } else if (cpt2 == CPT2_COLORED_DEGROTATE) {
+ int angle = param2 & 0x1F; // in 15°
+ int color = param2 & 0xE0;
+ angle += 6 * rot;
+ angle %= 24;
+ param2 = color | angle;
}
}
diff --git a/src/mapnode.h b/src/mapnode.h
index a9ae63ba3..28ff9e43d 100644
--- a/src/mapnode.h
+++ b/src/mapnode.h
@@ -240,6 +240,9 @@ struct MapNode
u8 getWallMounted(const NodeDefManager *nodemgr) const;
v3s16 getWallMountedDir(const NodeDefManager *nodemgr) const;
+ /// @returns Rotation in range 0–239 (in 1.5° steps)
+ u8 getDegRotate(const NodeDefManager *nodemgr) const;
+
void rotateAlongYAxis(const NodeDefManager *nodemgr, Rotation rot);
/*!
diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp
index 5b378a083..708ddbf20 100644
--- a/src/network/serverpackethandler.cpp
+++ b/src/network/serverpackethandler.cpp
@@ -1051,6 +1051,12 @@ void Server::handleCommand_Interact(NetworkPacket *pkt)
if (pointed.type == POINTEDTHING_NODE) {
target_pos = intToFloat(pointed.node_undersurface, BS);
} else if (pointed.type == POINTEDTHING_OBJECT) {
+ if (playersao->getId() == pointed_object->getId()) {
+ actionstream << "Server: " << player->getName()
+ << " attempted to interact with themselves" << std::endl;
+ m_script->on_cheat(playersao, "interacted_with_self");
+ return;
+ }
target_pos = pointed_object->getBasePosition();
}
float d = playersao->getEyePosition().getDistanceFrom(target_pos);
diff --git a/src/nodedef.cpp b/src/nodedef.cpp
index 3d598b76b..f27a8154b 100644
--- a/src/nodedef.cpp
+++ b/src/nodedef.cpp
@@ -944,7 +944,8 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc
if (param_type_2 == CPT2_COLOR ||
param_type_2 == CPT2_COLORED_FACEDIR ||
- param_type_2 == CPT2_COLORED_WALLMOUNTED)
+ param_type_2 == CPT2_COLORED_WALLMOUNTED ||
+ param_type_2 == CPT2_COLORED_DEGROTATE)
palette = tsrc->getPalette(palette_name);
if (drawtype == NDT_MESH && !mesh.empty()) {
@@ -1450,9 +1451,7 @@ void NodeDefManager::applyTextureOverrides(const std::vector<TextureOverride> &o
}
}
-void NodeDefManager::updateTextures(IGameDef *gamedef,
- void (*progress_callback)(void *progress_args, u32 progress, u32 max_progress),
- void *progress_callback_args)
+void NodeDefManager::updateTextures(IGameDef *gamedef, void *progress_callback_args)
{
#ifndef SERVER
infostream << "NodeDefManager::updateTextures(): Updating "
@@ -1461,8 +1460,8 @@ void NodeDefManager::updateTextures(IGameDef *gamedef,
Client *client = (Client *)gamedef;
ITextureSource *tsrc = client->tsrc();
IShaderSource *shdsrc = client->getShaderSource();
- scene::IMeshManipulator *meshmanip =
- RenderingEngine::get_scene_manager()->getMeshManipulator();
+ auto smgr = client->getSceneManager();
+ scene::IMeshManipulator *meshmanip = smgr->getMeshManipulator();
TextureSettings tsettings;
tsettings.readSettings();
@@ -1471,7 +1470,7 @@ void NodeDefManager::updateTextures(IGameDef *gamedef,
for (u32 i = 0; i < size; i++) {
ContentFeatures *f = &(m_content_features[i]);
f->updateTextures(tsrc, shdsrc, meshmanip, client, tsettings);
- progress_callback(progress_callback_args, i, size);
+ client->showUpdateProgressTexture(progress_callback_args, i, size);
}
#endif
}
@@ -1559,10 +1558,10 @@ void NodeDefManager::deSerialize(std::istream &is)
}
-void NodeDefManager::addNameIdMapping(content_t i, std::string name)
+void NodeDefManager::addNameIdMapping(content_t i, const std::string &name)
{
m_name_id_mapping.set(i, name);
- m_name_id_mapping_with_aliases.insert(std::make_pair(name, i));
+ m_name_id_mapping_with_aliases.emplace(name, i);
}
diff --git a/src/nodedef.h b/src/nodedef.h
index 3e77624eb..8a6d88071 100644
--- a/src/nodedef.h
+++ b/src/nodedef.h
@@ -67,7 +67,7 @@ enum ContentParamType2
CPT2_WALLMOUNTED,
// Block level like FLOWINGLIQUID
CPT2_LEVELED,
- // 2D rotation for things like plants
+ // 2D rotation
CPT2_DEGROTATE,
// Mesh options for plants
CPT2_MESHOPTIONS,
@@ -79,6 +79,8 @@ enum ContentParamType2
CPT2_COLORED_WALLMOUNTED,
// Glasslike framed drawtype internal liquid level, param2 values 0 to 63
CPT2_GLASSLIKE_LIQUID_LEVEL,
+ // 3 bits of palette index, then degrotate
+ CPT2_COLORED_DEGROTATE,
};
enum LiquidType
@@ -658,9 +660,7 @@ public:
* total ContentFeatures.
* @param progress_cbk_args passed to the callback function
*/
- void updateTextures(IGameDef *gamedef,
- void (*progress_cbk)(void *progress_args, u32 progress, u32 max_progress),
- void *progress_cbk_args);
+ void updateTextures(IGameDef *gamedef, void *progress_cbk_args);
/*!
* Writes the content of this manager to the given output stream.
@@ -723,7 +723,7 @@ private:
* @param i a content ID
* @param name a node name
*/
- void addNameIdMapping(content_t i, std::string name);
+ void addNameIdMapping(content_t i, const std::string &name);
/*!
* Removes a content ID from all groups.
diff --git a/src/nodemetadata.cpp b/src/nodemetadata.cpp
index 6447c8785..f98732385 100644
--- a/src/nodemetadata.cpp
+++ b/src/nodemetadata.cpp
@@ -206,10 +206,9 @@ NodeMetadataList::~NodeMetadataList()
std::vector<v3s16> NodeMetadataList::getAllKeys()
{
std::vector<v3s16> keys;
-
- NodeMetadataMap::const_iterator it;
- for (it = m_data.begin(); it != m_data.end(); ++it)
- keys.push_back(it->first);
+ keys.reserve(m_data.size());
+ for (const auto &it : m_data)
+ keys.push_back(it.first);
return keys;
}
@@ -218,7 +217,7 @@ NodeMetadata *NodeMetadataList::get(v3s16 p)
{
NodeMetadataMap::const_iterator n = m_data.find(p);
if (n == m_data.end())
- return NULL;
+ return nullptr;
return n->second;
}
@@ -235,7 +234,7 @@ void NodeMetadataList::remove(v3s16 p)
void NodeMetadataList::set(v3s16 p, NodeMetadata *d)
{
remove(p);
- m_data.insert(std::make_pair(p, d));
+ m_data.emplace(p, d);
}
void NodeMetadataList::clear()
@@ -251,9 +250,8 @@ void NodeMetadataList::clear()
int NodeMetadataList::countNonEmpty() const
{
int n = 0;
- NodeMetadataMap::const_iterator it;
- for (it = m_data.begin(); it != m_data.end(); ++it) {
- if (!it->second->empty())
+ for (const auto &it : m_data) {
+ if (!it.second->empty())
n++;
}
return n;
diff --git a/src/pathfinder.cpp b/src/pathfinder.cpp
index 1cb84997a..c45ce9158 100644
--- a/src/pathfinder.cpp
+++ b/src/pathfinder.cpp
@@ -1428,7 +1428,7 @@ std::string Pathfinder::dirToName(PathDirections dir)
}
/******************************************************************************/
-void Pathfinder::printPath(std::vector<v3s16> path)
+void Pathfinder::printPath(const std::vector<v3s16> &path)
{
unsigned int current = 0;
for (std::vector<v3s16>::iterator i = path.begin();
diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp
index e56d07cc6..897ca2862 100644
--- a/src/script/common/c_content.cpp
+++ b/src/script/common/c_content.cpp
@@ -717,7 +717,8 @@ void read_content_features(lua_State *L, ContentFeatures &f, int index)
if (!f.palette_name.empty() &&
!(f.param_type_2 == CPT2_COLOR ||
f.param_type_2 == CPT2_COLORED_FACEDIR ||
- f.param_type_2 == CPT2_COLORED_WALLMOUNTED))
+ f.param_type_2 == CPT2_COLORED_WALLMOUNTED ||
+ f.param_type_2 == CPT2_COLORED_DEGROTATE))
warningstream << "Node " << f.name.c_str()
<< " has a palette, but not a suitable paramtype2." << std::endl;
diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h
index 10b77a116..dc8f19ef3 100644
--- a/src/script/common/c_content.h
+++ b/src/script/common/c_content.h
@@ -39,7 +39,9 @@ extern "C" {
#include "itemgroup.h"
#include "itemdef.h"
#include "c_types.h"
-#include "hud.h"
+// We do a explicit path include because by default c_content.h include src/client/hud.h
+// prior to the src/hud.h, which is not good on server only build
+#include "../../hud.h"
namespace Json { class Value; }
diff --git a/src/script/cpp_api/s_node.cpp b/src/script/cpp_api/s_node.cpp
index f23fbfbde..029cb6308 100644
--- a/src/script/cpp_api/s_node.cpp
+++ b/src/script/cpp_api/s_node.cpp
@@ -65,6 +65,7 @@ struct EnumString ScriptApiNode::es_ContentParamType2[] =
{CPT2_COLORED_FACEDIR, "colorfacedir"},
{CPT2_COLORED_WALLMOUNTED, "colorwallmounted"},
{CPT2_GLASSLIKE_LIQUID_LEVEL, "glasslikeliquidlevel"},
+ {CPT2_COLORED_DEGROTATE, "colordegrotate"},
{0, NULL},
};
diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp
index 37c5b61dc..8fe5d2c5a 100644
--- a/src/script/cpp_api/s_security.cpp
+++ b/src/script/cpp_api/s_security.cpp
@@ -45,6 +45,21 @@ static inline void copy_safe(lua_State *L, const char *list[], unsigned len, int
}
}
+static void shallow_copy_table(lua_State *L, int from=-2, int to=-1)
+{
+ if (from < 0) from = lua_gettop(L) + from + 1;
+ if (to < 0) to = lua_gettop(L) + to + 1;
+ lua_pushnil(L);
+ while (lua_next(L, from) != 0) {
+ assert(lua_type(L, -1) != LUA_TTABLE);
+ // duplicate key and value for lua_rawset
+ lua_pushvalue(L, -2);
+ lua_pushvalue(L, -2);
+ lua_rawset(L, to);
+ lua_pop(L, 1);
+ }
+}
+
// Pushes the original version of a library function on the stack, from the old version
static inline void push_original(lua_State *L, const char *lib, const char *func)
{
@@ -83,7 +98,10 @@ void ScriptApiSecurity::initializeSecurity()
"unpack",
"_VERSION",
"xpcall",
- // Completely safe libraries
+ };
+ static const char *whitelist_tables[] = {
+ // These libraries are completely safe BUT we need to duplicate their table
+ // to ensure the sandbox can't affect the insecure env
"coroutine",
"string",
"table",
@@ -168,6 +186,17 @@ void ScriptApiSecurity::initializeSecurity()
lua_pop(L, 1);
+ // Copy safe libraries
+ for (const char *libname : whitelist_tables) {
+ lua_getfield(L, old_globals, libname);
+ lua_newtable(L);
+ shallow_copy_table(L);
+
+ lua_setglobal(L, libname);
+ lua_pop(L, 1);
+ }
+
+
// Copy safe IO functions
lua_getfield(L, old_globals, "io");
lua_newtable(L);
@@ -223,6 +252,19 @@ void ScriptApiSecurity::initializeSecurity()
#endif
lua_pop(L, 1); // Pop globals_backup
+
+
+ /*
+ * In addition to copying the tables in whitelist_tables, we also need to
+ * replace the string metatable. Otherwise old_globals.string would
+ * be accessible via getmetatable("").__index from inside the sandbox.
+ */
+ lua_pushliteral(L, "");
+ lua_newtable(L);
+ lua_getglobal(L, "string");
+ lua_setfield(L, -2, "__index");
+ lua_setmetatable(L, -2);
+ lua_pop(L, 1); // Pop empty string
}
void ScriptApiSecurity::initializeSecurityClient()
diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp
index 4d437b967..d88bf31c1 100644
--- a/src/script/lua_api/l_mainmenu.cpp
+++ b/src/script/lua_api/l_mainmenu.cpp
@@ -34,9 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "serverlist.h"
#include "mapgen/mapgen.h"
#include "settings.h"
-
-#include <IFileArchive.h>
-#include <IFileSystem.h>
+#include "client/client.h"
#include "client/renderingengine.h"
#include "network/networkprotocol.h"
@@ -399,7 +397,8 @@ int ModApiMainMenu::l_show_keys_menu(lua_State *L)
GUIEngine* engine = getGuiEngine(L);
sanity_check(engine != NULL);
- GUIKeyChangeMenu *kmenu = new GUIKeyChangeMenu(RenderingEngine::get_gui_env(),
+ GUIKeyChangeMenu *kmenu = new GUIKeyChangeMenu(
+ engine->m_rendering_engine->get_gui_env(),
engine->m_parent,
-1,
engine->m_menumanager,
@@ -629,75 +628,9 @@ int ModApiMainMenu::l_extract_zip(lua_State *L)
std::string absolute_destination = fs::RemoveRelativePathComponents(destination);
if (ModApiMainMenu::mayModifyPath(absolute_destination)) {
+ auto rendering_engine = getGuiEngine(L)->m_rendering_engine;
fs::CreateAllDirs(absolute_destination);
-
- io::IFileSystem *fs = RenderingEngine::get_filesystem();
-
- if (!fs->addFileArchive(zipfile, false, false, io::EFAT_ZIP)) {
- lua_pushboolean(L,false);
- return 1;
- }
-
- sanity_check(fs->getFileArchiveCount() > 0);
-
- /**********************************************************************/
- /* WARNING this is not threadsafe!! */
- /**********************************************************************/
- io::IFileArchive* opened_zip =
- fs->getFileArchive(fs->getFileArchiveCount()-1);
-
- const io::IFileList* files_in_zip = opened_zip->getFileList();
-
- unsigned int number_of_files = files_in_zip->getFileCount();
-
- for (unsigned int i=0; i < number_of_files; i++) {
- std::string fullpath = destination;
- fullpath += DIR_DELIM;
- fullpath += files_in_zip->getFullFileName(i).c_str();
- std::string fullpath_dir = fs::RemoveLastPathComponent(fullpath);
-
- if (!files_in_zip->isDirectory(i)) {
- if (!fs::PathExists(fullpath_dir) && !fs::CreateAllDirs(fullpath_dir)) {
- fs->removeFileArchive(fs->getFileArchiveCount()-1);
- lua_pushboolean(L,false);
- return 1;
- }
-
- io::IReadFile* toread = opened_zip->createAndOpenFile(i);
-
- FILE *targetfile = fopen(fullpath.c_str(),"wb");
-
- if (targetfile == NULL) {
- fs->removeFileArchive(fs->getFileArchiveCount()-1);
- lua_pushboolean(L,false);
- return 1;
- }
-
- char read_buffer[1024];
- long total_read = 0;
-
- while (total_read < toread->getSize()) {
-
- unsigned int bytes_read =
- toread->read(read_buffer,sizeof(read_buffer));
- if ((bytes_read == 0 ) ||
- (fwrite(read_buffer, 1, bytes_read, targetfile) != bytes_read))
- {
- fclose(targetfile);
- fs->removeFileArchive(fs->getFileArchiveCount()-1);
- lua_pushboolean(L,false);
- return 1;
- }
- total_read += bytes_read;
- }
-
- fclose(targetfile);
- }
-
- }
-
- fs->removeFileArchive(fs->getFileArchiveCount()-1);
- lua_pushboolean(L,true);
+ lua_pushboolean(L, fs::extractZipFile(rendering_engine->get_filesystem(), zipfile, destination));
return 1;
}
@@ -716,24 +649,28 @@ int ModApiMainMenu::l_get_mainmenu_path(lua_State *L)
}
/******************************************************************************/
-bool ModApiMainMenu::mayModifyPath(const std::string &path)
+bool ModApiMainMenu::mayModifyPath(std::string path)
{
+ path = fs::RemoveRelativePathComponents(path);
+
if (fs::PathStartsWith(path, fs::TempPath()))
return true;
- if (fs::PathStartsWith(path, fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM "games")))
- return true;
+ std::string path_user = fs::RemoveRelativePathComponents(porting::path_user);
- if (fs::PathStartsWith(path, fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM "mods")))
+ if (fs::PathStartsWith(path, path_user + DIR_DELIM "client"))
return true;
-
- if (fs::PathStartsWith(path, fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM "clientmods")))
+ if (fs::PathStartsWith(path, path_user + DIR_DELIM "clientmods"))
return true;
-
- if (fs::PathStartsWith(path, fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM "textures")))
+ if (fs::PathStartsWith(path, path_user + DIR_DELIM "textures"))
return true;
-
- if (fs::PathStartsWith(path, fs::RemoveRelativePathComponents(porting::path_user + DIR_DELIM "worlds")))
+ 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)))
@@ -763,7 +700,7 @@ int ModApiMainMenu::l_show_path_select_dialog(lua_State *L)
bool is_file_select = readParam<bool>(L, 3);
GUIFileSelectMenu* fileOpenMenu =
- new GUIFileSelectMenu(RenderingEngine::get_gui_env(),
+ new GUIFileSelectMenu(engine->m_rendering_engine->get_gui_env(),
engine->m_parent,
-1,
engine->m_menumanager,
@@ -859,15 +796,7 @@ int ModApiMainMenu::l_get_screen_info(lua_State *L)
lua_pushnumber(L,RenderingEngine::getDisplayDensity());
lua_settable(L, top);
- lua_pushstring(L,"display_width");
- lua_pushnumber(L,RenderingEngine::getDisplaySize().X);
- lua_settable(L, top);
-
- lua_pushstring(L,"display_height");
- lua_pushnumber(L,RenderingEngine::getDisplaySize().Y);
- lua_settable(L, top);
-
- const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize();
+ const v2u32 &window_size = RenderingEngine::getWindowSize();
lua_pushstring(L,"window_width");
lua_pushnumber(L, window_size.X);
lua_settable(L, top);
@@ -875,6 +804,10 @@ int ModApiMainMenu::l_get_screen_info(lua_State *L)
lua_pushstring(L,"window_height");
lua_pushnumber(L, window_size.Y);
lua_settable(L, top);
+
+ lua_pushstring(L, "render_info");
+ lua_pushstring(L, wide_to_utf8(RenderingEngine::get_video_driver()->getName()).c_str());
+ lua_settable(L, top);
return 1;
}
diff --git a/src/script/lua_api/l_mainmenu.h b/src/script/lua_api/l_mainmenu.h
index 49ce7c251..33ac9e721 100644
--- a/src/script/lua_api/l_mainmenu.h
+++ b/src/script/lua_api/l_mainmenu.h
@@ -58,7 +58,7 @@ private:
* @param path path to check
* @return true if the path may be modified
*/
- static bool mayModifyPath(const std::string &path);
+ static bool mayModifyPath(std::string path);
//api calls
diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp
index 60ae7871c..624828956 100644
--- a/src/script/lua_api/l_util.cpp
+++ b/src/script/lua_api/l_util.cpp
@@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "irrlichttypes_extrabloated.h"
#include "lua_api/l_util.h"
#include "lua_api/l_internal.h"
#include "lua_api/l_settings.h"
@@ -40,7 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/hex.h"
#include "util/sha1.h"
#include <algorithm>
-
+#include <cstdio>
// log([level,] text)
// Writes a line to the logger.
@@ -479,6 +480,23 @@ int ModApiUtil::l_sha1(lua_State *L)
return 1;
}
+// colorspec_to_colorstring(colorspec)
+int ModApiUtil::l_colorspec_to_colorstring(lua_State *L)
+{
+ NO_MAP_LOCK_REQUIRED;
+
+ video::SColor color(0);
+ if (read_color(L, 1, &color)) {
+ char colorstring[10];
+ snprintf(colorstring, 10, "#%02X%02X%02X%02X",
+ color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
+ lua_pushstring(L, colorstring);
+ return 1;
+ }
+
+ return 0;
+}
+
void ModApiUtil::Initialize(lua_State *L, int top)
{
API_FCT(log);
@@ -513,6 +531,7 @@ void ModApiUtil::Initialize(lua_State *L, int top)
API_FCT(get_version);
API_FCT(sha1);
+ API_FCT(colorspec_to_colorstring);
LuaSettings::create(L, g_settings, g_settings_path);
lua_setfield(L, top, "settings");
@@ -539,6 +558,7 @@ void ModApiUtil::InitializeClient(lua_State *L, int top)
API_FCT(get_version);
API_FCT(sha1);
+ API_FCT(colorspec_to_colorstring);
LuaSettings::create(L, g_settings, g_settings_path);
lua_setfield(L, top, "settings");
@@ -569,8 +589,8 @@ void ModApiUtil::InitializeAsync(lua_State *L, int top)
API_FCT(get_version);
API_FCT(sha1);
+ API_FCT(colorspec_to_colorstring);
LuaSettings::create(L, g_settings, g_settings_path);
lua_setfield(L, top, "settings");
}
-
diff --git a/src/script/lua_api/l_util.h b/src/script/lua_api/l_util.h
index dbdd62b99..6943a6afb 100644
--- a/src/script/lua_api/l_util.h
+++ b/src/script/lua_api/l_util.h
@@ -101,6 +101,9 @@ private:
// sha1(string, raw)
static int l_sha1(lua_State *L);
+ // colorspec_to_colorstring(colorspec)
+ static int l_colorspec_to_colorstring(lua_State *L);
+
public:
static void Initialize(lua_State *L, int top);
static void InitializeAsync(lua_State *L, int top);
diff --git a/src/server/unit_sao.cpp b/src/server/unit_sao.cpp
index 2371640ca..fa6c8f0f4 100644
--- a/src/server/unit_sao.cpp
+++ b/src/server/unit_sao.cpp
@@ -134,16 +134,21 @@ void UnitSAO::setAttachment(int parent_id, const std::string &bone, v3f position
int old_parent = m_attachment_parent_id;
m_attachment_parent_id = parent_id;
+
+ // The detach callbacks might call to setAttachment() again.
+ // Ensure the attachment params are applied after this callback is run.
+ if (parent_id != old_parent)
+ onDetach(old_parent);
+
+ m_attachment_parent_id = parent_id;
m_attachment_bone = bone;
m_attachment_position = position;
m_attachment_rotation = rotation;
m_force_visible = force_visible;
m_attachment_sent = false;
- if (parent_id != old_parent) {
- onDetach(old_parent);
+ if (parent_id != old_parent)
onAttach(parent_id);
- }
}
void UnitSAO::getAttachment(int *parent_id, std::string *bone, v3f *position,
diff --git a/src/settings.cpp b/src/settings.cpp
index 3415ff818..cff393e5f 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -43,11 +43,11 @@ std::unordered_map<std::string, const FlagDesc *> Settings::s_flags;
Settings *Settings::createLayer(SettingsLayer sl, const std::string &end_tag)
{
if ((int)sl < 0 || sl >= SL_TOTAL_COUNT)
- throw new BaseException("Invalid settings layer");
+ throw BaseException("Invalid settings layer");
Settings *&pos = s_layers[(size_t)sl];
if (pos)
- throw new BaseException("Setting layer " + std::to_string(sl) + " already exists");
+ throw BaseException("Setting layer " + std::to_string(sl) + " already exists");
pos = new Settings(end_tag);
pos->m_settingslayer = sl;
@@ -638,6 +638,7 @@ std::vector<std::string> Settings::getNames() const
MutexAutoLock lock(m_mutex);
std::vector<std::string> names;
+ names.reserve(m_settings.size());
for (const auto &settings_it : m_settings) {
names.push_back(settings_it.first);
}
diff --git a/src/unittest/test_clientactiveobjectmgr.cpp b/src/unittest/test_clientactiveobjectmgr.cpp
index 4d2846c8d..2d508cf32 100644
--- a/src/unittest/test_clientactiveobjectmgr.cpp
+++ b/src/unittest/test_clientactiveobjectmgr.cpp
@@ -29,6 +29,7 @@ public:
TestClientActiveObject() : ClientActiveObject(0, nullptr, nullptr) {}
~TestClientActiveObject() = default;
ActiveObjectType getType() const { return ACTIVEOBJECT_TYPE_TEST; }
+ virtual void addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) {}
};
class TestClientActiveObjectMgr : public TestBase
diff --git a/src/util/areastore.cpp b/src/util/areastore.cpp
index cea526336..67bfef0c0 100644
--- a/src/util/areastore.cpp
+++ b/src/util/areastore.cpp
@@ -96,16 +96,15 @@ void AreaStore::deserialize(std::istream &is)
u16 num_areas = readU16(is);
std::vector<Area> areas;
+ areas.reserve(num_areas);
for (u32 i = 0; i < num_areas; ++i) {
Area a(U32_MAX);
a.minedge = readV3S16(is);
a.maxedge = readV3S16(is);
u16 data_len = readU16(is);
- char *data = new char[data_len];
- is.read(data, data_len);
- a.data = std::string(data, data_len);
- areas.emplace_back(a);
- delete [] data;
+ a.data = std::string(data_len, '\0');
+ is.read(&a.data[0], data_len);
+ areas.emplace_back(std::move(a));
}
bool read_ids = is.good(); // EOF for old formats
diff --git a/src/util/container.h b/src/util/container.h
index 2ad2bbfc7..1c4a219f0 100644
--- a/src/util/container.h
+++ b/src/util/container.h
@@ -90,8 +90,7 @@ public:
bool get(const Key &name, Value *result) const
{
MutexAutoLock lock(m_mutex);
- typename std::map<Key, Value>::const_iterator n =
- m_values.find(name);
+ auto n = m_values.find(name);
if (n == m_values.end())
return false;
if (result)
@@ -103,11 +102,9 @@ public:
{
MutexAutoLock lock(m_mutex);
std::vector<Value> result;
- for (typename std::map<Key, Value>::const_iterator
- it = m_values.begin();
- it != m_values.end(); ++it){
+ result.reserve(m_values.size());
+ for (auto it = m_values.begin(); it != m_values.end(); ++it)
result.push_back(it->second);
- }
return result;
}
@@ -136,7 +133,7 @@ public:
return m_queue.empty();
}
- void push_back(T t)
+ void push_back(const T &t)
{
MutexAutoLock lock(m_mutex);
m_queue.push_back(t);
@@ -151,7 +148,7 @@ public:
if (m_signal.wait(wait_time_max_ms)) {
MutexAutoLock lock(m_mutex);
- T t = m_queue.front();
+ T t = std::move(m_queue.front());
m_queue.pop_front();
return t;
}
@@ -164,7 +161,7 @@ public:
if (m_signal.wait(wait_time_max_ms)) {
MutexAutoLock lock(m_mutex);
- T t = m_queue.front();
+ T t = std::move(m_queue.front());
m_queue.pop_front();
return t;
}
@@ -178,7 +175,7 @@ public:
MutexAutoLock lock(m_mutex);
- T t = m_queue.front();
+ T t = std::move(m_queue.front());
m_queue.pop_front();
return t;
}
@@ -188,7 +185,7 @@ public:
if (m_signal.wait(wait_time_max_ms)) {
MutexAutoLock lock(m_mutex);
- T t = m_queue.back();
+ T t = std::move(m_queue.back());
m_queue.pop_back();
return t;
}
@@ -204,7 +201,7 @@ public:
if (m_signal.wait(wait_time_max_ms)) {
MutexAutoLock lock(m_mutex);
- T t = m_queue.back();
+ T t = std::move(m_queue.back());
m_queue.pop_back();
return t;
}
@@ -218,7 +215,7 @@ public:
MutexAutoLock lock(m_mutex);
- T t = m_queue.back();
+ T t = std::move(m_queue.back());
m_queue.pop_back();
return t;
}
diff --git a/src/util/enriched_string.cpp b/src/util/enriched_string.cpp
index 762d094eb..b1f95215e 100644
--- a/src/util/enriched_string.cpp
+++ b/src/util/enriched_string.cpp
@@ -65,12 +65,14 @@ void EnrichedString::operator=(const wchar_t *str)
addAtEnd(translate_string(std::wstring(str)), m_default_color);
}
-void EnrichedString::addAtEnd(const std::wstring &s, const SColor &initial_color)
+void EnrichedString::addAtEnd(const std::wstring &s, SColor initial_color)
{
SColor color(initial_color);
bool use_default = (m_default_length == m_string.size() &&
color == m_default_color);
+ m_colors.reserve(m_colors.size() + s.size());
+
size_t i = 0;
while (i < s.length()) {
if (s[i] != L'\x1b') {
@@ -200,12 +202,6 @@ const std::wstring &EnrichedString::getString() const
return m_string;
}
-void EnrichedString::setDefaultColor(const irr::video::SColor &color)
-{
- m_default_color = color;
- updateDefaultColor();
-}
-
void EnrichedString::updateDefaultColor()
{
sanity_check(m_default_length <= m_colors.size());
diff --git a/src/util/enriched_string.h b/src/util/enriched_string.h
index c8a095887..16a0eef74 100644
--- a/src/util/enriched_string.h
+++ b/src/util/enriched_string.h
@@ -23,18 +23,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <vector>
#include <SColor.h>
+using namespace irr;
+
class EnrichedString {
public:
EnrichedString();
EnrichedString(const std::wstring &s,
- const irr::video::SColor &color = irr::video::SColor(255, 255, 255, 255));
+ const video::SColor &color = video::SColor(255, 255, 255, 255));
EnrichedString(const wchar_t *str,
- const irr::video::SColor &color = irr::video::SColor(255, 255, 255, 255));
+ const video::SColor &color = video::SColor(255, 255, 255, 255));
EnrichedString(const std::wstring &string,
- const std::vector<irr::video::SColor> &colors);
- void clear();
+ const std::vector<video::SColor> &colors);
void operator=(const wchar_t *str);
- void addAtEnd(const std::wstring &s, const irr::video::SColor &color);
+
+ void clear();
+
+ void addAtEnd(const std::wstring &s, video::SColor color);
// Adds the character source[i] at the end.
// An EnrichedString should always be able to be copied
@@ -49,12 +53,16 @@ public:
EnrichedString operator+(const EnrichedString &other) const;
void operator+=(const EnrichedString &other);
const wchar_t *c_str() const;
- const std::vector<irr::video::SColor> &getColors() const;
+ const std::vector<video::SColor> &getColors() const;
const std::wstring &getString() const;
- void setDefaultColor(const irr::video::SColor &color);
+ inline void setDefaultColor(video::SColor color)
+ {
+ m_default_color = color;
+ updateDefaultColor();
+ }
void updateDefaultColor();
- inline const irr::video::SColor &getDefaultColor() const
+ inline const video::SColor &getDefaultColor() const
{
return m_default_color;
}
@@ -80,11 +88,11 @@ public:
{
return m_has_background;
}
- inline irr::video::SColor getBackground() const
+ inline video::SColor getBackground() const
{
return m_background;
}
- inline void setBackground(const irr::video::SColor &color)
+ inline void setBackground(video::SColor color)
{
m_background = color;
m_has_background = true;
@@ -92,10 +100,10 @@ public:
private:
std::wstring m_string;
- std::vector<irr::video::SColor> m_colors;
+ std::vector<video::SColor> m_colors;
bool m_has_background;
- irr::video::SColor m_default_color;
- irr::video::SColor m_background;
+ video::SColor m_default_color;
+ video::SColor m_background;
// This variable defines the length of the default-colored text.
// Change this to a std::vector if an "end coloring" tag is wanted.
size_t m_default_length = 0;
diff --git a/src/util/string.cpp b/src/util/string.cpp
index 611ad35cb..eec5ab4cd 100644
--- a/src/util/string.cpp
+++ b/src/util/string.cpp
@@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <array>
#include <sstream>
#include <iomanip>
-#include <map>
+#include <unordered_map>
#ifndef _WIN32
#include <iconv.h>
@@ -44,10 +44,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define BSD_ICONV_USED
#endif
-static bool parseHexColorString(const std::string &value, video::SColor &color,
- unsigned char default_alpha = 0xff);
-static bool parseNamedColorString(const std::string &value, video::SColor &color);
-
#ifndef _WIN32
static bool convert(const char *to, const char *from, char *outbuf,
@@ -324,29 +320,10 @@ u64 read_seed(const char *str)
return num;
}
-bool parseColorString(const std::string &value, video::SColor &color, bool quiet,
- unsigned char default_alpha)
-{
- bool success;
-
- if (value[0] == '#')
- success = parseHexColorString(value, color, default_alpha);
- else
- success = parseNamedColorString(value, color);
-
- if (!success && !quiet)
- errorstream << "Invalid color: \"" << value << "\"" << std::endl;
-
- return success;
-}
-
static bool parseHexColorString(const std::string &value, video::SColor &color,
unsigned char default_alpha)
{
- unsigned char components[] = { 0x00, 0x00, 0x00, default_alpha }; // R,G,B,A
-
- if (value[0] != '#')
- return false;
+ u8 components[] = {0x00, 0x00, 0x00, default_alpha}; // R,G,B,A
size_t len = value.size();
bool short_form;
@@ -358,198 +335,182 @@ static bool parseHexColorString(const std::string &value, video::SColor &color,
else
return false;
- bool success = true;
-
for (size_t pos = 1, cc = 0; pos < len; pos++, cc++) {
- assert(cc < sizeof components / sizeof components[0]);
if (short_form) {
- unsigned char d;
- if (!hex_digit_decode(value[pos], d)) {
- success = false;
- break;
- }
+ u8 d;
+ if (!hex_digit_decode(value[pos], d))
+ return false;
+
components[cc] = (d & 0xf) << 4 | (d & 0xf);
} else {
- unsigned char d1, d2;
+ u8 d1, d2;
if (!hex_digit_decode(value[pos], d1) ||
- !hex_digit_decode(value[pos+1], d2)) {
- success = false;
- break;
- }
+ !hex_digit_decode(value[pos+1], d2))
+ return false;
+
components[cc] = (d1 & 0xf) << 4 | (d2 & 0xf);
- pos++; // skip the second digit -- it's already used
+ pos++; // skip the second digit -- it's already used
}
}
- if (success) {
- color.setRed(components[0]);
- color.setGreen(components[1]);
- color.setBlue(components[2]);
- color.setAlpha(components[3]);
- }
+ color.setRed(components[0]);
+ color.setGreen(components[1]);
+ color.setBlue(components[2]);
+ color.setAlpha(components[3]);
- return success;
+ return true;
}
-struct ColorContainer {
- ColorContainer();
- std::map<const std::string, u32> colors;
+const static std::unordered_map<std::string, u32> s_named_colors = {
+ {"aliceblue", 0xf0f8ff},
+ {"antiquewhite", 0xfaebd7},
+ {"aqua", 0x00ffff},
+ {"aquamarine", 0x7fffd4},
+ {"azure", 0xf0ffff},
+ {"beige", 0xf5f5dc},
+ {"bisque", 0xffe4c4},
+ {"black", 00000000},
+ {"blanchedalmond", 0xffebcd},
+ {"blue", 0x0000ff},
+ {"blueviolet", 0x8a2be2},
+ {"brown", 0xa52a2a},
+ {"burlywood", 0xdeb887},
+ {"cadetblue", 0x5f9ea0},
+ {"chartreuse", 0x7fff00},
+ {"chocolate", 0xd2691e},
+ {"coral", 0xff7f50},
+ {"cornflowerblue", 0x6495ed},
+ {"cornsilk", 0xfff8dc},
+ {"crimson", 0xdc143c},
+ {"cyan", 0x00ffff},
+ {"darkblue", 0x00008b},
+ {"darkcyan", 0x008b8b},
+ {"darkgoldenrod", 0xb8860b},
+ {"darkgray", 0xa9a9a9},
+ {"darkgreen", 0x006400},
+ {"darkgrey", 0xa9a9a9},
+ {"darkkhaki", 0xbdb76b},
+ {"darkmagenta", 0x8b008b},
+ {"darkolivegreen", 0x556b2f},
+ {"darkorange", 0xff8c00},
+ {"darkorchid", 0x9932cc},
+ {"darkred", 0x8b0000},
+ {"darksalmon", 0xe9967a},
+ {"darkseagreen", 0x8fbc8f},
+ {"darkslateblue", 0x483d8b},
+ {"darkslategray", 0x2f4f4f},
+ {"darkslategrey", 0x2f4f4f},
+ {"darkturquoise", 0x00ced1},
+ {"darkviolet", 0x9400d3},
+ {"deeppink", 0xff1493},
+ {"deepskyblue", 0x00bfff},
+ {"dimgray", 0x696969},
+ {"dimgrey", 0x696969},
+ {"dodgerblue", 0x1e90ff},
+ {"firebrick", 0xb22222},
+ {"floralwhite", 0xfffaf0},
+ {"forestgreen", 0x228b22},
+ {"fuchsia", 0xff00ff},
+ {"gainsboro", 0xdcdcdc},
+ {"ghostwhite", 0xf8f8ff},
+ {"gold", 0xffd700},
+ {"goldenrod", 0xdaa520},
+ {"gray", 0x808080},
+ {"green", 0x008000},
+ {"greenyellow", 0xadff2f},
+ {"grey", 0x808080},
+ {"honeydew", 0xf0fff0},
+ {"hotpink", 0xff69b4},
+ {"indianred", 0xcd5c5c},
+ {"indigo", 0x4b0082},
+ {"ivory", 0xfffff0},
+ {"khaki", 0xf0e68c},
+ {"lavender", 0xe6e6fa},
+ {"lavenderblush", 0xfff0f5},
+ {"lawngreen", 0x7cfc00},
+ {"lemonchiffon", 0xfffacd},
+ {"lightblue", 0xadd8e6},
+ {"lightcoral", 0xf08080},
+ {"lightcyan", 0xe0ffff},
+ {"lightgoldenrodyellow", 0xfafad2},
+ {"lightgray", 0xd3d3d3},
+ {"lightgreen", 0x90ee90},
+ {"lightgrey", 0xd3d3d3},
+ {"lightpink", 0xffb6c1},
+ {"lightsalmon", 0xffa07a},
+ {"lightseagreen", 0x20b2aa},
+ {"lightskyblue", 0x87cefa},
+ {"lightslategray", 0x778899},
+ {"lightslategrey", 0x778899},
+ {"lightsteelblue", 0xb0c4de},
+ {"lightyellow", 0xffffe0},
+ {"lime", 0x00ff00},
+ {"limegreen", 0x32cd32},
+ {"linen", 0xfaf0e6},
+ {"magenta", 0xff00ff},
+ {"maroon", 0x800000},
+ {"mediumaquamarine", 0x66cdaa},
+ {"mediumblue", 0x0000cd},
+ {"mediumorchid", 0xba55d3},
+ {"mediumpurple", 0x9370db},
+ {"mediumseagreen", 0x3cb371},
+ {"mediumslateblue", 0x7b68ee},
+ {"mediumspringgreen", 0x00fa9a},
+ {"mediumturquoise", 0x48d1cc},
+ {"mediumvioletred", 0xc71585},
+ {"midnightblue", 0x191970},
+ {"mintcream", 0xf5fffa},
+ {"mistyrose", 0xffe4e1},
+ {"moccasin", 0xffe4b5},
+ {"navajowhite", 0xffdead},
+ {"navy", 0x000080},
+ {"oldlace", 0xfdf5e6},
+ {"olive", 0x808000},
+ {"olivedrab", 0x6b8e23},
+ {"orange", 0xffa500},
+ {"orangered", 0xff4500},
+ {"orchid", 0xda70d6},
+ {"palegoldenrod", 0xeee8aa},
+ {"palegreen", 0x98fb98},
+ {"paleturquoise", 0xafeeee},
+ {"palevioletred", 0xdb7093},
+ {"papayawhip", 0xffefd5},
+ {"peachpuff", 0xffdab9},
+ {"peru", 0xcd853f},
+ {"pink", 0xffc0cb},
+ {"plum", 0xdda0dd},
+ {"powderblue", 0xb0e0e6},
+ {"purple", 0x800080},
+ {"red", 0xff0000},
+ {"rosybrown", 0xbc8f8f},
+ {"royalblue", 0x4169e1},
+ {"saddlebrown", 0x8b4513},
+ {"salmon", 0xfa8072},
+ {"sandybrown", 0xf4a460},
+ {"seagreen", 0x2e8b57},
+ {"seashell", 0xfff5ee},
+ {"sienna", 0xa0522d},
+ {"silver", 0xc0c0c0},
+ {"skyblue", 0x87ceeb},
+ {"slateblue", 0x6a5acd},
+ {"slategray", 0x708090},
+ {"slategrey", 0x708090},
+ {"snow", 0xfffafa},
+ {"springgreen", 0x00ff7f},
+ {"steelblue", 0x4682b4},
+ {"tan", 0xd2b48c},
+ {"teal", 0x008080},
+ {"thistle", 0xd8bfd8},
+ {"tomato", 0xff6347},
+ {"turquoise", 0x40e0d0},
+ {"violet", 0xee82ee},
+ {"wheat", 0xf5deb3},
+ {"white", 0xffffff},
+ {"whitesmoke", 0xf5f5f5},
+ {"yellow", 0xffff00},
+ {"yellowgreen", 0x9acd32}
};
-ColorContainer::ColorContainer()
-{
- colors["aliceblue"] = 0xf0f8ff;
- colors["antiquewhite"] = 0xfaebd7;
- colors["aqua"] = 0x00ffff;
- colors["aquamarine"] = 0x7fffd4;
- colors["azure"] = 0xf0ffff;
- colors["beige"] = 0xf5f5dc;
- colors["bisque"] = 0xffe4c4;
- colors["black"] = 00000000;
- colors["blanchedalmond"] = 0xffebcd;
- colors["blue"] = 0x0000ff;
- colors["blueviolet"] = 0x8a2be2;
- colors["brown"] = 0xa52a2a;
- colors["burlywood"] = 0xdeb887;
- colors["cadetblue"] = 0x5f9ea0;
- colors["chartreuse"] = 0x7fff00;
- colors["chocolate"] = 0xd2691e;
- colors["coral"] = 0xff7f50;
- colors["cornflowerblue"] = 0x6495ed;
- colors["cornsilk"] = 0xfff8dc;
- colors["crimson"] = 0xdc143c;
- colors["cyan"] = 0x00ffff;
- colors["darkblue"] = 0x00008b;
- colors["darkcyan"] = 0x008b8b;
- colors["darkgoldenrod"] = 0xb8860b;
- colors["darkgray"] = 0xa9a9a9;
- colors["darkgreen"] = 0x006400;
- colors["darkgrey"] = 0xa9a9a9;
- colors["darkkhaki"] = 0xbdb76b;
- colors["darkmagenta"] = 0x8b008b;
- colors["darkolivegreen"] = 0x556b2f;
- colors["darkorange"] = 0xff8c00;
- colors["darkorchid"] = 0x9932cc;
- colors["darkred"] = 0x8b0000;
- colors["darksalmon"] = 0xe9967a;
- colors["darkseagreen"] = 0x8fbc8f;
- colors["darkslateblue"] = 0x483d8b;
- colors["darkslategray"] = 0x2f4f4f;
- colors["darkslategrey"] = 0x2f4f4f;
- colors["darkturquoise"] = 0x00ced1;
- colors["darkviolet"] = 0x9400d3;
- colors["deeppink"] = 0xff1493;
- colors["deepskyblue"] = 0x00bfff;
- colors["dimgray"] = 0x696969;
- colors["dimgrey"] = 0x696969;
- colors["dodgerblue"] = 0x1e90ff;
- colors["firebrick"] = 0xb22222;
- colors["floralwhite"] = 0xfffaf0;
- colors["forestgreen"] = 0x228b22;
- colors["fuchsia"] = 0xff00ff;
- colors["gainsboro"] = 0xdcdcdc;
- colors["ghostwhite"] = 0xf8f8ff;
- colors["gold"] = 0xffd700;
- colors["goldenrod"] = 0xdaa520;
- colors["gray"] = 0x808080;
- colors["green"] = 0x008000;
- colors["greenyellow"] = 0xadff2f;
- colors["grey"] = 0x808080;
- colors["honeydew"] = 0xf0fff0;
- colors["hotpink"] = 0xff69b4;
- colors["indianred"] = 0xcd5c5c;
- colors["indigo"] = 0x4b0082;
- colors["ivory"] = 0xfffff0;
- colors["khaki"] = 0xf0e68c;
- colors["lavender"] = 0xe6e6fa;
- colors["lavenderblush"] = 0xfff0f5;
- colors["lawngreen"] = 0x7cfc00;
- colors["lemonchiffon"] = 0xfffacd;
- colors["lightblue"] = 0xadd8e6;
- colors["lightcoral"] = 0xf08080;
- colors["lightcyan"] = 0xe0ffff;
- colors["lightgoldenrodyellow"] = 0xfafad2;
- colors["lightgray"] = 0xd3d3d3;
- colors["lightgreen"] = 0x90ee90;
- colors["lightgrey"] = 0xd3d3d3;
- colors["lightpink"] = 0xffb6c1;
- colors["lightsalmon"] = 0xffa07a;
- colors["lightseagreen"] = 0x20b2aa;
- colors["lightskyblue"] = 0x87cefa;
- colors["lightslategray"] = 0x778899;
- colors["lightslategrey"] = 0x778899;
- colors["lightsteelblue"] = 0xb0c4de;
- colors["lightyellow"] = 0xffffe0;
- colors["lime"] = 0x00ff00;
- colors["limegreen"] = 0x32cd32;
- colors["linen"] = 0xfaf0e6;
- colors["magenta"] = 0xff00ff;
- colors["maroon"] = 0x800000;
- colors["mediumaquamarine"] = 0x66cdaa;
- colors["mediumblue"] = 0x0000cd;
- colors["mediumorchid"] = 0xba55d3;
- colors["mediumpurple"] = 0x9370db;
- colors["mediumseagreen"] = 0x3cb371;
- colors["mediumslateblue"] = 0x7b68ee;
- colors["mediumspringgreen"] = 0x00fa9a;
- colors["mediumturquoise"] = 0x48d1cc;
- colors["mediumvioletred"] = 0xc71585;
- colors["midnightblue"] = 0x191970;
- colors["mintcream"] = 0xf5fffa;
- colors["mistyrose"] = 0xffe4e1;
- colors["moccasin"] = 0xffe4b5;
- colors["navajowhite"] = 0xffdead;
- colors["navy"] = 0x000080;
- colors["oldlace"] = 0xfdf5e6;
- colors["olive"] = 0x808000;
- colors["olivedrab"] = 0x6b8e23;
- colors["orange"] = 0xffa500;
- colors["orangered"] = 0xff4500;
- colors["orchid"] = 0xda70d6;
- colors["palegoldenrod"] = 0xeee8aa;
- colors["palegreen"] = 0x98fb98;
- colors["paleturquoise"] = 0xafeeee;
- colors["palevioletred"] = 0xdb7093;
- colors["papayawhip"] = 0xffefd5;
- colors["peachpuff"] = 0xffdab9;
- colors["peru"] = 0xcd853f;
- colors["pink"] = 0xffc0cb;
- colors["plum"] = 0xdda0dd;
- colors["powderblue"] = 0xb0e0e6;
- colors["purple"] = 0x800080;
- colors["red"] = 0xff0000;
- colors["rosybrown"] = 0xbc8f8f;
- colors["royalblue"] = 0x4169e1;
- colors["saddlebrown"] = 0x8b4513;
- colors["salmon"] = 0xfa8072;
- colors["sandybrown"] = 0xf4a460;
- colors["seagreen"] = 0x2e8b57;
- colors["seashell"] = 0xfff5ee;
- colors["sienna"] = 0xa0522d;
- colors["silver"] = 0xc0c0c0;
- colors["skyblue"] = 0x87ceeb;
- colors["slateblue"] = 0x6a5acd;
- colors["slategray"] = 0x708090;
- colors["slategrey"] = 0x708090;
- colors["snow"] = 0xfffafa;
- colors["springgreen"] = 0x00ff7f;
- colors["steelblue"] = 0x4682b4;
- colors["tan"] = 0xd2b48c;
- colors["teal"] = 0x008080;
- colors["thistle"] = 0xd8bfd8;
- colors["tomato"] = 0xff6347;
- colors["turquoise"] = 0x40e0d0;
- colors["violet"] = 0xee82ee;
- colors["wheat"] = 0xf5deb3;
- colors["white"] = 0xffffff;
- colors["whitesmoke"] = 0xf5f5f5;
- colors["yellow"] = 0xffff00;
- colors["yellowgreen"] = 0x9acd32;
-
-}
-
-static const ColorContainer named_colors;
-
static bool parseNamedColorString(const std::string &value, video::SColor &color)
{
std::string color_name;
@@ -570,9 +531,8 @@ static bool parseNamedColorString(const std::string &value, video::SColor &color
color_name = lowercase(color_name);
- std::map<const std::string, unsigned>::const_iterator it;
- it = named_colors.colors.find(color_name);
- if (it == named_colors.colors.end())
+ auto it = s_named_colors.find(color_name);
+ if (it == s_named_colors.end())
return false;
u32 color_temp = it->second;
@@ -580,21 +540,26 @@ static bool parseNamedColorString(const std::string &value, video::SColor &color
/* An empty string for alpha is ok (none of the color table entries
* have an alpha value either). Color strings without an alpha specified
* are interpreted as fully opaque
- *
- * For named colors the supplied alpha string (representing a hex value)
- * must be exactly two digits. For example: colorname#08
*/
if (!alpha_string.empty()) {
- if (alpha_string.length() != 2)
- return false;
-
- unsigned char d1, d2;
- if (!hex_digit_decode(alpha_string.at(0), d1)
- || !hex_digit_decode(alpha_string.at(1), d2))
+ if (alpha_string.size() == 1) {
+ u8 d;
+ if (!hex_digit_decode(alpha_string[0], d))
+ return false;
+
+ color_temp |= ((d & 0xf) << 4 | (d & 0xf)) << 24;
+ } else if (alpha_string.size() == 2) {
+ u8 d1, d2;
+ if (!hex_digit_decode(alpha_string[0], d1)
+ || !hex_digit_decode(alpha_string[1], d2))
+ return false;
+
+ color_temp |= ((d1 & 0xf) << 4 | (d2 & 0xf)) << 24;
+ } else {
return false;
- color_temp |= ((d1 & 0xf) << 4 | (d2 & 0xf)) << 24;
+ }
} else {
- color_temp |= 0xff << 24; // Fully opaque
+ color_temp |= 0xff << 24; // Fully opaque
}
color = video::SColor(color_temp);
@@ -602,6 +567,22 @@ static bool parseNamedColorString(const std::string &value, video::SColor &color
return true;
}
+bool parseColorString(const std::string &value, video::SColor &color, bool quiet,
+ unsigned char default_alpha)
+{
+ bool success;
+
+ if (value[0] == '#')
+ success = parseHexColorString(value, color, default_alpha);
+ else
+ success = parseNamedColorString(value, color);
+
+ if (!success && !quiet)
+ errorstream << "Invalid color: \"" << value << "\"" << std::endl;
+
+ return success;
+}
+
void str_replace(std::string &str, char from, char to)
{
std::replace(str.begin(), str.end(), from, to);
diff --git a/src/voxelalgorithms.cpp b/src/voxelalgorithms.cpp
index 62fd68890..ffb70aa71 100644
--- a/src/voxelalgorithms.cpp
+++ b/src/voxelalgorithms.cpp
@@ -65,7 +65,7 @@ struct ChangingLight {
ChangingLight() = default;
- ChangingLight(const relative_v3 &rel_pos, const mapblock_v3 &block_pos,
+ ChangingLight(relative_v3 rel_pos, mapblock_v3 block_pos,
MapBlock *b, direction source_dir) :
rel_position(rel_pos),
block_position(block_pos),
@@ -125,8 +125,8 @@ struct LightQueue {
* The parameters are the same as in ChangingLight's constructor.
* \param light light level of the ChangingLight
*/
- inline void push(u8 light, const relative_v3 &rel_pos,
- const mapblock_v3 &block_pos, MapBlock *block,
+ inline void push(u8 light, relative_v3 rel_pos,
+ mapblock_v3 block_pos, MapBlock *block,
direction source_dir)
{
assert(light <= LIGHT_SUN);
@@ -467,7 +467,7 @@ bool is_sunlight_above(Map *map, v3s16 pos, const NodeDefManager *ndef)
static const LightBank banks[] = { LIGHTBANK_DAY, LIGHTBANK_NIGHT };
void update_lighting_nodes(Map *map,
- std::vector<std::pair<v3s16, MapNode> > &oldnodes,
+ const std::vector<std::pair<v3s16, MapNode>> &oldnodes,
std::map<v3s16, MapBlock*> &modified_blocks)
{
const NodeDefManager *ndef = map->getNodeDefManager();
@@ -482,8 +482,7 @@ void update_lighting_nodes(Map *map,
// won't change, since they didn't get their light from a
// modified node.
u8 min_safe_light = 0;
- for (std::vector<std::pair<v3s16, MapNode> >::iterator it =
- oldnodes.begin(); it < oldnodes.end(); ++it) {
+ for (auto it = oldnodes.cbegin(); it < oldnodes.cend(); ++it) {
u8 old_light = it->second.getLight(bank, ndef);
if (old_light > min_safe_light) {
min_safe_light = old_light;
@@ -495,8 +494,7 @@ void update_lighting_nodes(Map *map,
min_safe_light++;
}
// For each changed node process sunlight and initialize
- for (std::vector<std::pair<v3s16, MapNode> >::iterator it =
- oldnodes.begin(); it < oldnodes.end(); ++it) {
+ for (auto it = oldnodes.cbegin(); it < oldnodes.cend(); ++it) {
// Get position and block of the changed node
v3s16 p = it->first;
relative_v3 rel_pos;
diff --git a/src/voxelalgorithms.h b/src/voxelalgorithms.h
index 1452f30f4..bcbd3b586 100644
--- a/src/voxelalgorithms.h
+++ b/src/voxelalgorithms.h
@@ -45,7 +45,7 @@ namespace voxalgo
*/
void update_lighting_nodes(
Map *map,
- std::vector<std::pair<v3s16, MapNode> > &oldnodes,
+ const std::vector<std::pair<v3s16, MapNode>> &oldnodes,
std::map<v3s16, MapBlock*> &modified_blocks);
/*!