aboutsummaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
Diffstat (limited to 'src/client')
-rw-r--r--src/client/camera.cpp46
-rw-r--r--src/client/camera.h49
-rw-r--r--src/client/client.cpp48
-rw-r--r--src/client/client.h9
-rw-r--r--src/client/clientenvironment.cpp143
-rw-r--r--src/client/clientlauncher.cpp220
-rw-r--r--src/client/clientlauncher.h23
-rw-r--r--src/client/clientmap.cpp133
-rw-r--r--src/client/clientmap.h19
-rw-r--r--src/client/clientmedia.cpp3
-rw-r--r--src/client/clouds.cpp60
-rw-r--r--src/client/content_cao.cpp181
-rw-r--r--src/client/content_cao.h12
-rw-r--r--src/client/content_mapblock.cpp11
-rw-r--r--src/client/content_mapblock.h2
-rw-r--r--src/client/event_manager.h2
-rw-r--r--src/client/fontengine.cpp80
-rw-r--r--src/client/fontengine.h12
-rw-r--r--src/client/game.cpp478
-rw-r--r--src/client/game.h13
-rw-r--r--src/client/gameui.cpp33
-rw-r--r--src/client/gameui.h1
-rw-r--r--src/client/guiscalingfilter.cpp5
-rw-r--r--src/client/guiscalingfilter.h3
-rw-r--r--src/client/hud.cpp213
-rw-r--r--src/client/hud.h14
-rw-r--r--src/client/inputhandler.cpp159
-rw-r--r--src/client/inputhandler.h164
-rw-r--r--src/client/joystick_controller.cpp68
-rw-r--r--src/client/joystick_controller.h38
-rw-r--r--src/client/keycode.cpp3
-rw-r--r--src/client/keys.h8
-rw-r--r--src/client/localplayer.cpp2
-rw-r--r--src/client/mapblock_mesh.cpp116
-rw-r--r--src/client/mapblock_mesh.h15
-rw-r--r--src/client/mesh.cpp9
-rw-r--r--src/client/mesh.h7
-rw-r--r--src/client/mesh_generator_thread.cpp6
-rw-r--r--src/client/mesh_generator_thread.h2
-rw-r--r--src/client/minimap.cpp269
-rw-r--r--src/client/minimap.h51
-rw-r--r--src/client/render/core.cpp1
-rw-r--r--src/client/render/factory.cpp7
-rw-r--r--src/client/render/interlaced.cpp2
-rw-r--r--src/client/renderingengine.cpp2
-rw-r--r--src/client/shader.cpp617
-rw-r--r--src/client/shader.h23
-rw-r--r--src/client/sky.cpp225
-rw-r--r--src/client/sky.h17
-rw-r--r--src/client/sound_openal.cpp56
-rw-r--r--src/client/tile.cpp14
-rw-r--r--src/client/tile.h5
-rw-r--r--src/client/wieldmesh.cpp211
53 files changed, 2010 insertions, 1900 deletions
diff --git a/src/client/camera.cpp b/src/client/camera.cpp
index abc55e4b7..350b685e1 100644
--- a/src/client/camera.cpp
+++ b/src/client/camera.cpp
@@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "wieldmesh.h"
#include "noise.h" // easeCurve
#include "sound.h"
-#include "event.h"
+#include "mtevent.h"
#include "nodedef.h"
#include "util/numeric.h"
#include "constants.h"
@@ -79,6 +79,7 @@ Camera::Camera(MapDrawControl &draw_control, Client *client):
m_cache_fov = std::fmax(g_settings->getFloat("fov"), 45.0f);
m_arm_inertia = g_settings->getBool("arm_inertia");
m_nametags.clear();
+ m_show_nametag_backgrounds = g_settings->getBool("show_nametag_backgrounds");
}
Camera::~Camera()
@@ -691,46 +692,47 @@ void Camera::drawNametags()
core::matrix4 trans = m_cameranode->getProjectionMatrix();
trans *= m_cameranode->getViewMatrix();
- for (std::list<Nametag *>::const_iterator
- i = m_nametags.begin();
- i != m_nametags.end(); ++i) {
- Nametag *nametag = *i;
- if (nametag->nametag_color.getAlpha() == 0) {
- // Enforce hiding nametag,
- // because if freetype is enabled, a grey
- // shadow can remain.
- continue;
- }
- v3f pos = nametag->parent_node->getAbsolutePosition() + nametag->nametag_pos * BS;
+ gui::IGUIFont *font = g_fontengine->getFont();
+ video::IVideoDriver *driver = RenderingEngine::get_video_driver();
+ v2u32 screensize = driver->getScreenSize();
+
+ for (const Nametag *nametag : m_nametags) {
+ // Nametags are hidden in GenericCAO::updateNametag()
+
+ v3f pos = nametag->parent_node->getAbsolutePosition() + nametag->pos * BS;
f32 transformed_pos[4] = { pos.X, pos.Y, pos.Z, 1.0f };
trans.multiplyWith1x4Matrix(transformed_pos);
if (transformed_pos[3] > 0) {
std::wstring nametag_colorless =
- unescape_translate(utf8_to_wide(nametag->nametag_text));
- core::dimension2d<u32> textsize =
- g_fontengine->getFont()->getDimension(
+ unescape_translate(utf8_to_wide(nametag->text));
+ core::dimension2d<u32> textsize = font->getDimension(
nametag_colorless.c_str());
f32 zDiv = transformed_pos[3] == 0.0f ? 1.0f :
core::reciprocal(transformed_pos[3]);
- v2u32 screensize = RenderingEngine::get_video_driver()->getScreenSize();
v2s32 screen_pos;
screen_pos.X = screensize.X *
(0.5 * transformed_pos[0] * zDiv + 0.5) - textsize.Width / 2;
screen_pos.Y = screensize.Y *
(0.5 - transformed_pos[1] * zDiv * 0.5) - textsize.Height / 2;
core::rect<s32> size(0, 0, textsize.Width, textsize.Height);
- g_fontengine->getFont()->draw(
- translate_string(utf8_to_wide(nametag->nametag_text)).c_str(),
- size + screen_pos, nametag->nametag_color);
+ core::rect<s32> bg_size(-2, 0, textsize.Width+2, textsize.Height);
+
+ auto bgcolor = nametag->getBgColor(m_show_nametag_backgrounds);
+ if (bgcolor.getAlpha() != 0)
+ driver->draw2DRectangle(bgcolor, bg_size + screen_pos);
+
+ font->draw(
+ translate_string(utf8_to_wide(nametag->text)).c_str(),
+ size + screen_pos, nametag->textcolor);
}
}
}
Nametag *Camera::addNametag(scene::ISceneNode *parent_node,
- const std::string &nametag_text, video::SColor nametag_color,
- const v3f &pos)
+ const std::string &text, video::SColor textcolor,
+ Optional<video::SColor> bgcolor, const v3f &pos)
{
- Nametag *nametag = new Nametag(parent_node, nametag_text, nametag_color, pos);
+ Nametag *nametag = new Nametag(parent_node, text, textcolor, bgcolor, pos);
m_nametags.push_back(nametag);
return nametag;
}
diff --git a/src/client/camera.h b/src/client/camera.h
index 3a59637bc..6fd8d9aa7 100644
--- a/src/client/camera.h
+++ b/src/client/camera.h
@@ -25,27 +25,47 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <ICameraSceneNode.h>
#include <ISceneNode.h>
#include <list>
+#include "util/Optional.h"
class LocalPlayer;
struct MapDrawControl;
class Client;
class WieldMeshSceneNode;
-struct Nametag {
+struct Nametag
+{
+ scene::ISceneNode *parent_node;
+ std::string text;
+ video::SColor textcolor;
+ Optional<video::SColor> bgcolor;
+ v3f pos;
+
Nametag(scene::ISceneNode *a_parent_node,
- const std::string &a_nametag_text,
- const video::SColor &a_nametag_color,
- const v3f &a_nametag_pos):
+ const std::string &text,
+ const video::SColor &textcolor,
+ const Optional<video::SColor> &bgcolor,
+ const v3f &pos):
parent_node(a_parent_node),
- nametag_text(a_nametag_text),
- nametag_color(a_nametag_color),
- nametag_pos(a_nametag_pos)
+ text(text),
+ textcolor(textcolor),
+ bgcolor(bgcolor),
+ pos(pos)
{
}
- scene::ISceneNode *parent_node;
- std::string nametag_text;
- video::SColor nametag_color;
- v3f nametag_pos;
+
+ video::SColor getBgColor(bool use_fallback) const
+ {
+ if (bgcolor)
+ return bgcolor.value();
+ else if (!use_fallback)
+ return video::SColor(0, 0, 0, 0);
+ else if (textcolor.getLuminance() > 186)
+ // Dark background for light text
+ return video::SColor(50, 50, 50, 50);
+ else
+ // Light background for dark text
+ return video::SColor(50, 255, 255, 255);
+ }
};
enum CameraMode {CAMERA_MODE_FIRST, CAMERA_MODE_THIRD, CAMERA_MODE_THIRD_FRONT};
@@ -164,13 +184,11 @@ public:
}
Nametag *addNametag(scene::ISceneNode *parent_node,
- const std::string &nametag_text, video::SColor nametag_color,
- const v3f &pos);
+ const std::string &text, video::SColor textcolor,
+ Optional<video::SColor> bgcolor, const v3f &pos);
void removeNametag(Nametag *nametag);
- const std::list<Nametag *> &getNametags() { return m_nametags; }
-
void drawNametags();
inline void addArmInertia(f32 player_yaw);
@@ -247,4 +265,5 @@ private:
bool m_arm_inertia;
std::list<Nametag *> m_nametags;
+ bool m_show_nametag_backgrounds;
};
diff --git a/src/client/client.cpp b/src/client/client.cpp
index 65e5b3d8c..ef4a3cdfc 100644
--- a/src/client/client.cpp
+++ b/src/client/client.cpp
@@ -129,6 +129,7 @@ Client::Client(
if (g_settings->getBool("enable_minimap")) {
m_minimap = new Minimap(this);
}
+
m_cache_save_interval = g_settings->getU16("server_map_save_interval");
}
@@ -158,20 +159,6 @@ void Client::loadMods()
scanModIntoMemory(BUILTIN_MOD_NAME, getBuiltinLuaPath());
m_script->loadModFromMemory(BUILTIN_MOD_NAME);
- // TODO Uncomment when server-sent CSM and verifying of builtin are complete
- /*
- // Don't load client-provided mods if disabled by server
- if (checkCSMRestrictionFlag(CSMRestrictionFlags::CSM_RF_LOAD_CLIENT_MODS)) {
- warningstream << "Client-provided mod loading is disabled by server." <<
- std::endl;
- // If builtin integrity is wrong, disconnect user
- if (!checkBuiltinIntegrity()) {
- // TODO disconnect user
- }
- return;
- }
- */
-
ClientModConfiguration modconf(getClientModsLuaPath());
m_mods = modconf.getMods();
// complain about mods with unsatisfied dependencies
@@ -215,12 +202,6 @@ void Client::loadMods()
m_script->on_minimap_ready(m_minimap);
}
-bool Client::checkBuiltinIntegrity()
-{
- // TODO
- return true;
-}
-
void Client::scanModSubfolder(const std::string &mod_name, const std::string &mod_path,
std::string mod_subpath)
{
@@ -238,18 +219,13 @@ void Client::scanModSubfolder(const std::string &mod_name, const std::string &mo
infostream << "Client::scanModSubfolder(): Loading \"" << real_path
<< "\" as \"" << vfs_path << "\"." << std::endl;
- std::ifstream is(real_path, std::ios::binary | std::ios::ate);
- if(!is.good()) {
+ std::string contents;
+ if (!fs::ReadFile(real_path, contents)) {
errorstream << "Client::scanModSubfolder(): Can't read file \""
<< real_path << "\"." << std::endl;
continue;
}
- auto size = is.tellg();
- std::string contents(size, '\0');
- is.seekg(0);
- is.read(&contents[0], size);
- infostream << " size: " << size << " bytes" << std::endl;
m_mod_vfs.emplace(vfs_path, contents);
}
}
@@ -330,6 +306,8 @@ Client::~Client()
}
delete m_minimap;
+ m_minimap = nullptr;
+
delete m_media_downloader;
}
@@ -1218,7 +1196,7 @@ void Client::sendChatMessage(const std::wstring &message)
if (canSendChatMessage()) {
u32 now = time(NULL);
float time_passed = now - m_last_chat_message_sent;
- m_last_chat_message_sent = time(NULL);
+ m_last_chat_message_sent = now;
m_chat_message_allowance += time_passed * (CLIENT_CHAT_MESSAGE_LIMIT_PER_10S / 8.0f);
if (m_chat_message_allowance > CLIENT_CHAT_MESSAGE_LIMIT_PER_10S)
@@ -1297,9 +1275,8 @@ void Client::sendPlayerPos()
// Save bandwidth by only updating position when
// player is not dead and something changed
- // FIXME: This part causes breakages in mods like 3d_armor, and has been commented for now
- // if (m_activeobjects_received && player->isDead())
- // return;
+ if (m_activeobjects_received && player->isDead())
+ return;
if (
player->last_position == player->getPosition() &&
@@ -1307,7 +1284,7 @@ void Client::sendPlayerPos()
player->last_pitch == player->getPitch() &&
player->last_yaw == player->getYaw() &&
player->last_keyPressed == player->keyPressed &&
- player->last_camera_fov == camera_fov &&
+ player->last_camera_fov == camera_fov &&
player->last_wanted_range == wanted_range)
return;
@@ -1669,11 +1646,6 @@ ClientEvent *Client::getClientEvent()
return event;
}
-bool Client::connectedToServer()
-{
- return m_con->Connected();
-}
-
const Address Client::getServerAddress()
{
return m_con->GetPeerAddress(PEER_ID_SERVER);
@@ -1860,7 +1832,7 @@ void Client::makeScreenshot()
sstr << "Failed to save screenshot '" << filename << "'";
}
pushToChatQueue(new ChatMessage(CHATMESSAGE_TYPE_SYSTEM,
- narrow_to_wide(sstr.str())));
+ utf8_to_wide(sstr.str())));
infostream << sstr.str() << std::endl;
image->drop();
}
diff --git a/src/client/client.h b/src/client/client.h
index 733634db1..25a1b97ba 100644
--- a/src/client/client.h
+++ b/src/client/client.h
@@ -223,6 +223,7 @@ public:
void handleCommand_CSMRestrictionFlags(NetworkPacket *pkt);
void handleCommand_PlayerSpeed(NetworkPacket *pkt);
void handleCommand_MediaPush(NetworkPacket *pkt);
+ void handleCommand_MinimapModes(NetworkPacket *pkt);
void ProcessData(NetworkPacket *pkt);
@@ -337,7 +338,6 @@ public:
u16 getProtoVersion()
{ return m_proto_ver; }
- bool connectedToServer();
void confirmRegistration();
bool m_is_registration_confirmation_state = false;
bool m_simple_singleplayer_mode;
@@ -415,11 +415,6 @@ public:
return m_csm_restriction_flags & flag;
}
- u32 getCSMNodeRangeLimit() const
- {
- return m_csm_restriction_noderange;
- }
-
inline std::unordered_map<u32, u32> &getHUDTranslationMap()
{
return m_hud_server_to_client;
@@ -437,7 +432,6 @@ public:
}
private:
void loadMods();
- bool checkBuiltinIntegrity();
// Virtual methods from con::PeerHandler
void peerAdded(con::Peer *peer) override;
@@ -587,7 +581,6 @@ private:
// Client modding
ClientScripting *m_script = nullptr;
- bool m_modding_enabled;
std::unordered_map<std::string, ModMetadata *> m_mod_storages;
float m_mod_storage_save_timer = 10.0f;
std::vector<ModSpec> m_mods;
diff --git a/src/client/clientenvironment.cpp b/src/client/clientenvironment.cpp
index 895b0193c..fc7cbe254 100644
--- a/src/client/clientenvironment.cpp
+++ b/src/client/clientenvironment.cpp
@@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "clientmap.h"
#include "scripting_client.h"
#include "mapblock_mesh.h"
-#include "event.h"
+#include "mtevent.h"
#include "collision.h"
#include "nodedef.h"
#include "profiler.h"
@@ -51,12 +51,8 @@ public:
~CAOShaderConstantSetter() override = default;
- void onSetConstants(video::IMaterialRendererServices *services,
- bool is_highlevel) override
+ void onSetConstants(video::IMaterialRendererServices *services) override
{
- if (!is_highlevel)
- return;
-
// Ambient color
video::SColorf emissive_color(m_emissive_color);
@@ -183,84 +179,61 @@ void ClientEnvironment::step(float dtime)
if(dtime > 0.5)
dtime = 0.5;
- f32 dtime_downcount = dtime;
-
/*
Stuff that has a maximum time increment
*/
- u32 loopcount = 0;
- do
- {
- loopcount++;
-
- f32 dtime_part;
- if(dtime_downcount > dtime_max_increment)
- {
- dtime_part = dtime_max_increment;
- dtime_downcount -= dtime_part;
- }
- else
- {
- dtime_part = dtime_downcount;
- /*
- Setting this to 0 (no -=dtime_part) disables an infinite loop
- when dtime_part is so small that dtime_downcount -= dtime_part
- does nothing
- */
- dtime_downcount = 0;
- }
-
+ u32 steps = ceil(dtime / dtime_max_increment);
+ f32 dtime_part = dtime / steps;
+ for (; steps > 0; --steps) {
/*
- Handle local player
+ Local player handling
*/
- {
- // Control local player
- lplayer->applyControl(dtime_part, this);
-
- // Apply physics
- if (!free_move && !is_climbing) {
- // Gravity
- v3f speed = lplayer->getSpeed();
- if (!lplayer->in_liquid)
- speed.Y -= lplayer->movement_gravity *
- lplayer->physics_override_gravity * dtime_part * 2.0f;
-
- // Liquid floating / sinking
- if (lplayer->in_liquid && !lplayer->swimming_vertical &&
- !lplayer->swimming_pitch)
- speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2.0f;
-
- // Liquid resistance
- if (lplayer->in_liquid_stable || lplayer->in_liquid) {
- // How much the node's viscosity blocks movement, ranges
- // between 0 and 1. Should match the scale at which viscosity
- // increase affects other liquid attributes.
- static const f32 viscosity_factor = 0.3f;
-
- v3f d_wanted = -speed / lplayer->movement_liquid_fluidity;
- f32 dl = d_wanted.getLength();
- if (dl > lplayer->movement_liquid_fluidity_smooth)
- dl = lplayer->movement_liquid_fluidity_smooth;
-
- dl *= (lplayer->liquid_viscosity * viscosity_factor) +
- (1 - viscosity_factor);
- v3f d = d_wanted.normalize() * (dl * dtime_part * 100.0f);
- speed += d;
- }
-
- lplayer->setSpeed(speed);
+ // Control local player
+ lplayer->applyControl(dtime_part, this);
+
+ // Apply physics
+ if (!free_move && !is_climbing) {
+ // Gravity
+ v3f speed = lplayer->getSpeed();
+ if (!lplayer->in_liquid)
+ speed.Y -= lplayer->movement_gravity *
+ lplayer->physics_override_gravity * dtime_part * 2.0f;
+
+ // Liquid floating / sinking
+ if (lplayer->in_liquid && !lplayer->swimming_vertical &&
+ !lplayer->swimming_pitch)
+ speed.Y -= lplayer->movement_liquid_sink * dtime_part * 2.0f;
+
+ // Liquid resistance
+ if (lplayer->in_liquid_stable || lplayer->in_liquid) {
+ // How much the node's viscosity blocks movement, ranges
+ // between 0 and 1. Should match the scale at which viscosity
+ // increase affects other liquid attributes.
+ static const f32 viscosity_factor = 0.3f;
+
+ v3f d_wanted = -speed / lplayer->movement_liquid_fluidity;
+ f32 dl = d_wanted.getLength();
+ if (dl > lplayer->movement_liquid_fluidity_smooth)
+ dl = lplayer->movement_liquid_fluidity_smooth;
+
+ dl *= (lplayer->liquid_viscosity * viscosity_factor) +
+ (1 - viscosity_factor);
+ v3f d = d_wanted.normalize() * (dl * dtime_part * 100.0f);
+ speed += d;
}
- /*
- Move the lplayer.
- This also does collision detection.
- */
- lplayer->move(dtime_part, this, position_max_increment,
- &player_collisions);
+ lplayer->setSpeed(speed);
}
- } while (dtime_downcount > 0.001);
+
+ /*
+ Move the lplayer.
+ This also does collision detection.
+ */
+ lplayer->move(dtime_part, this, position_max_increment,
+ &player_collisions);
+ }
bool player_immortal = lplayer->getCAO() && lplayer->getCAO()->isImmortal();
@@ -361,28 +334,6 @@ GenericCAO* ClientEnvironment::getGenericCAO(u16 id)
return NULL;
}
-bool isFreeClientActiveObjectId(const u16 id,
- ClientActiveObjectMap &objects)
-{
- return id != 0 && objects.find(id) == objects.end();
-
-}
-
-u16 getFreeClientActiveObjectId(ClientActiveObjectMap &objects)
-{
- // try to reuse id's as late as possible
- static u16 last_used_id = 0;
- u16 startid = last_used_id;
- for(;;) {
- last_used_id ++;
- if (isFreeClientActiveObjectId(last_used_id, objects))
- return last_used_id;
-
- if (last_used_id == startid)
- return 0;
- }
-}
-
u16 ClientEnvironment::addActiveObject(ClientActiveObject *object)
{
// Register object. If failed return zero id
diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp
index f18915a55..2bb0bc385 100644
--- a/src/client/clientlauncher.cpp
+++ b/src/client/clientlauncher.cpp
@@ -56,6 +56,20 @@ bool isMenuActive()
// Passed to menus to allow disconnecting and exiting
MainGameCallback *g_gamecallback = nullptr;
+#if 0
+// This can be helpful for the next code cleanup
+static void dump_start_data(const GameStartData &data)
+{
+ std::cout <<
+ "\ndedicated " << (int)data.is_dedicated_server <<
+ "\nport " << data.socket_port <<
+ "\nworld_path " << data.world_spec.path <<
+ "\nworld game " << data.world_spec.gameid <<
+ "\ngame path " << data.game_spec.path <<
+ "\nplayer name " << data.name <<
+ "\naddress " << data.address << std::endl;
+}
+#endif
ClientLauncher::~ClientLauncher()
{
@@ -74,9 +88,16 @@ ClientLauncher::~ClientLauncher()
}
-bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
+bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args)
{
- init_args(game_params, cmd_args);
+ /* This function is called when a client must be started.
+ * Covered cases:
+ * - Singleplayer (address but map provided)
+ * - Join server (no map but address provided)
+ * - Local server (for main menu only)
+ */
+
+ init_args(start_data, cmd_args);
// List video modes if requested
if (list_video_modes)
@@ -154,7 +175,7 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
}
}
#endif
- g_fontengine = new FontEngine(g_settings, guienv);
+ 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
@@ -216,7 +237,7 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
core::rect<s32>(0, 0, 10000, 10000));
bool game_has_run = launch_game(error_message, reconnect_requested,
- game_params, cmd_args);
+ start_data, cmd_args);
// Reset the reconnect_requested flag
reconnect_requested = false;
@@ -241,13 +262,6 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
break;
}
- if (current_playername.length() > PLAYERNAME_SIZE-1) {
- error_message = gettext("Player name too long.");
- playername = current_playername.substr(0, PLAYERNAME_SIZE-1);
- g_settings->set("name", playername);
- continue;
- }
-
RenderingEngine::get_video_driver()->setTextureCreationFlag(
video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map"));
@@ -258,18 +272,11 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
the_game(
kill,
- random_input,
input,
- worldspec.path,
- current_playername,
- current_password,
- current_address,
- current_port,
+ start_data,
error_message,
chat_backend,
- &reconnect_requested,
- gamespec,
- simple_singleplayer_mode
+ &reconnect_requested
);
RenderingEngine::get_scene_manager()->clear();
@@ -311,31 +318,27 @@ bool ClientLauncher::run(GameParams &game_params, const Settings &cmd_args)
return retval;
}
-void ClientLauncher::init_args(GameParams &game_params, const Settings &cmd_args)
+void ClientLauncher::init_args(GameStartData &start_data, const Settings &cmd_args)
{
-
skip_main_menu = cmd_args.getFlag("go");
- // FIXME: This is confusing (but correct)
-
- /* If world_path is set then override it unless skipping the main menu using
- * the --go command line param. Else, give preference to the address
- * supplied on the command line
- */
- address = g_settings->get("address");
- if (!game_params.world_path.empty() && !skip_main_menu)
- address = "";
- else if (cmd_args.exists("address"))
- address = cmd_args.get("address");
+ start_data.address = g_settings->get("address");
+ if (cmd_args.exists("address")) {
+ // Join a remote server
+ start_data.address = cmd_args.get("address");
+ start_data.world_path.clear();
+ start_data.name = g_settings->get("name");
+ }
+ if (!start_data.world_path.empty()) {
+ // Start a singleplayer instance
+ start_data.address = "";
+ }
- playername = g_settings->get("name");
if (cmd_args.exists("name"))
- playername = cmd_args.get("name");
+ start_data.name = cmd_args.get("name");
list_video_modes = cmd_args.getFlag("videomodes");
- use_freetype = g_settings->getBool("freetype");
-
random_input = g_settings->getBool("random_input")
|| cmd_args.getFlag("random-input");
}
@@ -375,28 +378,20 @@ void ClientLauncher::init_input()
}
bool ClientLauncher::launch_game(std::string &error_message,
- bool reconnect_requested, GameParams &game_params,
+ bool reconnect_requested, GameStartData &start_data,
const Settings &cmd_args)
{
- // Initialize menu data
- MainMenuData menudata;
- menudata.address = address;
- menudata.name = playername;
- menudata.password = password;
- menudata.port = itos(game_params.socket_port);
- menudata.script_data.errormessage = error_message;
- menudata.script_data.reconnect_requested = reconnect_requested;
-
+ // Prepare and check the start data to launch a game
+ std::string error_message_lua = error_message;
error_message.clear();
if (cmd_args.exists("password"))
- menudata.password = cmd_args.get("password");
-
+ start_data.password = cmd_args.get("password");
if (cmd_args.exists("password-file")) {
std::ifstream passfile(cmd_args.get("password-file"));
if (passfile.good()) {
- getline(passfile, menudata.password);
+ getline(passfile, start_data.password);
} else {
error_message = gettext("Provided password file "
"failed to open: ")
@@ -407,88 +402,106 @@ bool ClientLauncher::launch_game(std::string &error_message,
}
// If a world was commanded, append and select it
- if (!game_params.world_path.empty()) {
- worldspec.gameid = getWorldGameId(game_params.world_path, true);
- worldspec.name = _("[--world parameter]");
+ // This is provieded by "get_world_from_cmdline()", main.cpp
+ if (!start_data.world_path.empty()) {
+ auto &spec = start_data.world_spec;
+
+ spec.path = start_data.world_path;
+ spec.gameid = getWorldGameId(spec.path, true);
+ spec.name = _("[--world parameter]");
- if (worldspec.gameid.empty()) { // Create new
- worldspec.gameid = g_settings->get("default_game");
- worldspec.name += " [new]";
+ if (spec.gameid.empty()) { // Create new
+ spec.gameid = g_settings->get("default_game");
+ spec.name += " [new]";
}
- worldspec.path = game_params.world_path;
}
/* Show the GUI menu
*/
+ std::string server_name, server_description;
if (!skip_main_menu) {
+ // Initialize menu data
+ // TODO: Re-use existing structs (GameStartData)
+ MainMenuData menudata;
+ menudata.address = start_data.address;
+ menudata.name = start_data.name;
+ menudata.password = start_data.password;
+ menudata.port = itos(start_data.socket_port);
+ menudata.script_data.errormessage = error_message_lua;
+ menudata.script_data.reconnect_requested = reconnect_requested;
+
main_menu(&menudata);
// Skip further loading if there was an exit signal.
if (*porting::signal_handler_killstatus())
return false;
- address = menudata.address;
+ if (!menudata.script_data.errormessage.empty()) {
+ /* The calling function will pass this back into this function upon the
+ * next iteration (if any) causing it to be displayed by the GUI
+ */
+ error_message = menudata.script_data.errormessage;
+ return false;
+ }
+
int newport = stoi(menudata.port);
if (newport != 0)
- game_params.socket_port = newport;
-
- simple_singleplayer_mode = menudata.simple_singleplayer_mode;
+ start_data.socket_port = newport;
+ // Update world information using main menu data
std::vector<WorldSpec> worldspecs = getAvailableWorlds();
- if (menudata.selected_world >= 0
- && menudata.selected_world < (int)worldspecs.size()) {
+ int world_index = menudata.selected_world;
+ if (world_index >= 0 && world_index < (int)worldspecs.size()) {
g_settings->set("selected_world_path",
- worldspecs[menudata.selected_world].path);
- worldspec = worldspecs[menudata.selected_world];
+ worldspecs[world_index].path);
+ start_data.world_spec = worldspecs[world_index];
}
+
+ start_data.name = menudata.name;
+ start_data.password = menudata.password;
+ start_data.address = std::move(menudata.address);
+ server_name = menudata.servername;
+ server_description = menudata.serverdescription;
+
+ start_data.local_server = !menudata.simple_singleplayer_mode &&
+ start_data.address.empty();
+ } else {
+ start_data.local_server = !start_data.world_path.empty() &&
+ start_data.address.empty() && !start_data.name.empty();
}
- if (!menudata.script_data.errormessage.empty()) {
- /* The calling function will pass this back into this function upon the
- * next iteration (if any) causing it to be displayed by the GUI
- */
- error_message = menudata.script_data.errormessage;
+ if (!RenderingEngine::run())
return false;
- }
- if (menudata.name.empty() && !simple_singleplayer_mode) {
+ if (!start_data.isSinglePlayer() && start_data.name.empty()) {
error_message = gettext("Please choose a name!");
errorstream << error_message << std::endl;
return false;
}
- playername = menudata.name;
- password = menudata.password;
-
- current_playername = playername;
- current_password = password;
- current_address = address;
- current_port = game_params.socket_port;
-
// If using simple singleplayer mode, override
- if (simple_singleplayer_mode) {
- assert(!skip_main_menu);
- current_playername = "singleplayer";
- current_password = "";
- current_address = "";
- current_port = myrand_range(49152, 65535);
+ if (start_data.isSinglePlayer()) {
+ start_data.name = "singleplayer";
+ start_data.password = "";
+ start_data.socket_port = myrand_range(49152, 65535);
} else {
- g_settings->set("name", playername);
- if (!address.empty()) {
- ServerListSpec server;
- server["name"] = menudata.servername;
- server["address"] = menudata.address;
- server["port"] = menudata.port;
- server["description"] = menudata.serverdescription;
- ServerList::insert(server);
- }
+ g_settings->set("name", start_data.name);
+ }
+
+ if (start_data.name.length() > PLAYERNAME_SIZE - 1) {
+ error_message = gettext("Player name too long.");
+ start_data.name.resize(PLAYERNAME_SIZE);
+ g_settings->set("name", start_data.name);
+ return false;
}
+ auto &worldspec = start_data.world_spec;
infostream << "Selected world: " << worldspec.name
<< " [" << worldspec.path << "]" << std::endl;
- if (current_address.empty()) { // If local game
+ if (start_data.address.empty()) {
+ // For singleplayer and local server
if (worldspec.path.empty()) {
error_message = gettext("No world selected and no address "
"provided. Nothing to do.");
@@ -504,8 +517,8 @@ bool ClientLauncher::launch_game(std::string &error_message,
}
// Load gamespec for required game
- gamespec = findWorldSubgame(worldspec.path);
- if (!gamespec.isValid() && !game_params.game_spec.isValid()) {
+ start_data.game_spec = findWorldSubgame(worldspec.path);
+ if (!start_data.game_spec.isValid()) {
error_message = gettext("Could not find or load game \"")
+ worldspec.gameid + "\"";
errorstream << error_message << std::endl;
@@ -515,15 +528,7 @@ bool ClientLauncher::launch_game(std::string &error_message,
if (porting::signal_handler_killstatus())
return true;
- if (game_params.game_spec.isValid() &&
- game_params.game_spec.id != worldspec.gameid) {
- warningstream << "Overriding gamespec from \""
- << worldspec.gameid << "\" to \""
- << game_params.game_spec.id << "\"" << std::endl;
- gamespec = game_params.game_spec;
- }
-
- if (!gamespec.isValid()) {
+ if (!start_data.game_spec.isValid()) {
error_message = gettext("Invalid gamespec.");
error_message += " (world.gameid=" + worldspec.gameid + ")";
errorstream << error_message << std::endl;
@@ -531,6 +536,7 @@ bool ClientLauncher::launch_game(std::string &error_message,
}
}
+ start_data.world_path = start_data.world_spec.path;
return true;
}
diff --git a/src/client/clientlauncher.h b/src/client/clientlauncher.h
index 2702895d6..b280d8e6b 100644
--- a/src/client/clientlauncher.h
+++ b/src/client/clientlauncher.h
@@ -32,15 +32,15 @@ public:
~ClientLauncher();
- bool run(GameParams &game_params, const Settings &cmd_args);
+ bool run(GameStartData &start_data, const Settings &cmd_args);
-protected:
- void init_args(GameParams &game_params, const Settings &cmd_args);
+private:
+ void init_args(GameStartData &start_data, const Settings &cmd_args);
bool init_engine();
void init_input();
bool launch_game(std::string &error_message, bool reconnect_requested,
- GameParams &game_params, const Settings &cmd_args);
+ GameStartData &start_data, const Settings &cmd_args);
void main_menu(MainMenuData *menudata);
@@ -48,23 +48,8 @@ protected:
bool list_video_modes = false;
bool skip_main_menu = false;
- bool use_freetype = false;
bool random_input = false;
- std::string address = "";
- std::string playername = "";
- std::string password = "";
InputHandler *input = nullptr;
MyEventReceiver *receiver = nullptr;
gui::IGUISkin *skin = nullptr;
- gui::IGUIFont *font = nullptr;
- SubgameSpec gamespec;
- WorldSpec worldspec;
- bool simple_singleplayer_mode = false;
-
- // These are set up based on the menu and other things
- // TODO: Are these required since there's already playername, password, etc
- std::string current_playername = "inv£lid";
- std::string current_password = "";
- std::string current_address = "does-not-exist";
- int current_port = 0;
};
diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp
index 3e4ab2e94..b9e0cc2ce 100644
--- a/src/client/clientmap.cpp
+++ b/src/client/clientmap.cpp
@@ -31,12 +31,43 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <algorithm>
#include "client/renderingengine.h"
+// struct MeshBufListList
+void MeshBufListList::clear()
+{
+ for (auto &list : lists)
+ list.clear();
+}
+
+void MeshBufListList::add(scene::IMeshBuffer *buf, v3s16 position, u8 layer)
+{
+ // Append to the correct layer
+ std::vector<MeshBufList> &list = lists[layer];
+ const video::SMaterial &m = buf->getMaterial();
+ for (MeshBufList &l : list) {
+ // comparing a full material is quite expensive so we don't do it if
+ // not even first texture is equal
+ if (l.m.TextureLayer[0].Texture != m.TextureLayer[0].Texture)
+ continue;
+
+ if (l.m == m) {
+ l.bufs.emplace_back(position, buf);
+ return;
+ }
+ }
+ MeshBufList l;
+ l.m = m;
+ l.bufs.emplace_back(position, buf);
+ list.emplace_back(l);
+}
+
+// ClientMap
+
ClientMap::ClientMap(
Client *client,
MapDrawControl &control,
s32 id
):
- Map(dout_client, client),
+ Map(client),
scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(),
RenderingEngine::get_scene_manager(), id),
m_client(client),
@@ -122,20 +153,20 @@ void ClientMap::updateDrawList()
}
m_drawlist.clear();
- v3f camera_position = m_camera_position;
- v3f camera_direction = m_camera_direction;
- f32 camera_fov = m_camera_fov;
+ const v3f camera_position = m_camera_position;
+ const v3f camera_direction = m_camera_direction;
// Use a higher fov to accomodate faster camera movements.
// Blocks are cropped better when they are drawn.
- // Or maybe they aren't? Well whatever.
- camera_fov *= 1.2;
+ const f32 camera_fov = m_camera_fov * 1.1f;
v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
v3s16 p_blocks_min;
v3s16 p_blocks_max;
getBlocksInViewRange(cam_pos_nodes, &p_blocks_min, &p_blocks_max);
+ // Number of blocks currently loaded by the client
+ u32 blocks_loaded = 0;
// Number of blocks with mesh in rendering range
u32 blocks_in_range_with_mesh = 0;
// Number of blocks occlusion culled
@@ -160,6 +191,7 @@ void ClientMap::updateDrawList()
MapSector *sector = sector_it.second;
v2s16 sp = sector->getPos();
+ blocks_loaded += sector->size();
if (!m_control.range_all) {
if (sp.X < p_blocks_min.X || sp.X > p_blocks_max.X ||
sp.Y < p_blocks_min.Z || sp.Y > p_blocks_max.Z)
@@ -181,8 +213,10 @@ void ClientMap::updateDrawList()
if not seen on display
*/
- if (block->mesh)
- block->mesh->updateCameraOffset(m_camera_offset);
+ if (!block->mesh) {
+ // Ignore if mesh doesn't exist
+ continue;
+ }
float range = 100000 * BS;
if (!m_control.range_all)
@@ -193,13 +227,6 @@ void ClientMap::updateDrawList()
camera_direction, camera_fov, range, &d))
continue;
-
- /*
- Ignore if mesh doesn't exist
- */
- if (!block->mesh)
- continue;
-
blocks_in_range_with_mesh++;
/*
@@ -228,52 +255,9 @@ void ClientMap::updateDrawList()
g_profiler->avg("MapBlock meshes in range [#]", blocks_in_range_with_mesh);
g_profiler->avg("MapBlocks occlusion culled [#]", blocks_occlusion_culled);
g_profiler->avg("MapBlocks drawn [#]", m_drawlist.size());
+ g_profiler->avg("MapBlocks loaded [#]", blocks_loaded);
}
-struct MeshBufList
-{
- video::SMaterial m;
- std::vector<scene::IMeshBuffer*> bufs;
-};
-
-struct MeshBufListList
-{
- /*!
- * Stores the mesh buffers of the world.
- * The array index is the material's layer.
- * The vector part groups vertices by material.
- */
- std::vector<MeshBufList> lists[MAX_TILE_LAYERS];
-
- void clear()
- {
- for (auto &list : lists)
- list.clear();
- }
-
- void add(scene::IMeshBuffer *buf, u8 layer)
- {
- // Append to the correct layer
- std::vector<MeshBufList> &list = lists[layer];
- const video::SMaterial &m = buf->getMaterial();
- for (MeshBufList &l : list) {
- // comparing a full material is quite expensive so we don't do it if
- // not even first texture is equal
- if (l.m.TextureLayer[0].Texture != m.TextureLayer[0].Texture)
- continue;
-
- if (l.m == m) {
- l.bufs.push_back(buf);
- return;
- }
- }
- MeshBufList l;
- l.m = m;
- l.bufs.push_back(buf);
- list.push_back(l);
- }
-};
-
void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
{
bool is_transparent_pass = pass == scene::ESNRP_TRANSPARENT;
@@ -293,19 +277,20 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
/*
Get animation parameters
*/
- float animation_time = m_client->getAnimationTime();
- int crack = m_client->getCrackLevel();
- u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
+ const float animation_time = m_client->getAnimationTime();
+ const int crack = m_client->getCrackLevel();
+ const u32 daynight_ratio = m_client->getEnv().getDayNightRatio();
- v3f camera_position = m_camera_position;
- v3f camera_direction = m_camera_direction;
- f32 camera_fov = m_camera_fov;
+ const v3f camera_position = m_camera_position;
+ const v3f camera_direction = m_camera_direction;
+ const f32 camera_fov = m_camera_fov;
/*
Get all blocks and draw all visible ones
*/
u32 vertex_count = 0;
+ u32 drawcall_count = 0;
// For limiting number of mesh animations per frame
u32 mesh_animate_count = 0;
@@ -318,6 +303,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
MeshBufListList drawbufs;
for (auto &i : m_drawlist) {
+ v3s16 block_pos = i.first;
MapBlock *block = i.second;
// If the mesh of the block happened to get deleted, ignore it
@@ -383,7 +369,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
material.setFlag(video::EMF_WIREFRAME,
m_control.show_wireframe);
- drawbufs.add(buf, layer);
+ drawbufs.add(buf, block_pos, layer);
}
}
}
@@ -392,6 +378,9 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
TimeTaker draw("Drawing mesh buffers");
+ core::matrix4 m; // Model matrix
+ v3f offset = intToFloat(m_camera_offset, BS);
+
// Render all layers in order
for (auto &lists : drawbufs.lists) {
for (MeshBufList &list : lists) {
@@ -403,7 +392,14 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
}
driver->setMaterial(list.m);
- for (scene::IMeshBuffer *buf : list.bufs) {
+ drawcall_count += list.bufs.size();
+ for (auto &pair : list.bufs) {
+ scene::IMeshBuffer *buf = pair.second;
+
+ v3f block_wpos = intToFloat(pair.first * MAP_BLOCKSIZE, BS);
+ m.setTranslation(block_wpos - offset);
+
+ driver->setTransform(video::ETS_WORLD, m);
driver->drawMeshBuffer(buf);
vertex_count += buf->getVertexCount();
}
@@ -417,6 +413,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass)
}
g_profiler->avg(prefix + "vertices drawn [#]", vertex_count);
+ g_profiler->avg(prefix + "drawcalls [#]", drawcall_count);
}
static bool getVisibleBrightness(Map *map, const v3f &p0, v3f dir, float step,
@@ -608,5 +605,3 @@ void ClientMap::PrintInfo(std::ostream &out)
{
out<<"ClientMap: ";
}
-
-
diff --git a/src/client/clientmap.h b/src/client/clientmap.h
index 172e3a1d6..57cc4427e 100644
--- a/src/client/clientmap.h
+++ b/src/client/clientmap.h
@@ -35,6 +35,25 @@ struct MapDrawControl
bool show_wireframe = false;
};
+struct MeshBufList
+{
+ video::SMaterial m;
+ std::vector<std::pair<v3s16,scene::IMeshBuffer*>> bufs;
+};
+
+struct MeshBufListList
+{
+ /*!
+ * Stores the mesh buffers of the world.
+ * The array index is the material's layer.
+ * The vector part groups vertices by material.
+ */
+ std::vector<MeshBufList> lists[MAX_TILE_LAYERS];
+
+ void clear();
+ void add(scene::IMeshBuffer *buf, v3s16 position, u8 layer);
+};
+
class Client;
class ITextureSource;
diff --git a/src/client/clientmedia.cpp b/src/client/clientmedia.cpp
index 8cd3b6bcc..c4c08c05d 100644
--- a/src/client/clientmedia.cpp
+++ b/src/client/clientmedia.cpp
@@ -260,7 +260,8 @@ void ClientMediaDownloader::initialStep(Client *client)
fetch_request.request_id = m_httpfetch_next_id; // == i
fetch_request.timeout = m_httpfetch_timeout;
fetch_request.connect_timeout = m_httpfetch_timeout;
- fetch_request.post_data = required_hash_set;
+ fetch_request.method = HTTP_POST;
+ fetch_request.raw_data = required_hash_set;
fetch_request.extra_headers.emplace_back(
"Content-Type: application/octet-stream");
diff --git a/src/client/clouds.cpp b/src/client/clouds.cpp
index 887a62f25..253dee8b9 100644
--- a/src/client/clouds.cpp
+++ b/src/client/clouds.cpp
@@ -170,8 +170,9 @@ void Clouds::render()
// Read noise
- bool *grid = new bool[m_cloud_radius_i * 2 * m_cloud_radius_i * 2];
-
+ std::vector<char> grid(m_cloud_radius_i * 2 * m_cloud_radius_i * 2); // vector<bool> is broken
+ std::vector<video::S3DVertex> vertices;
+ vertices.reserve(16 * m_cloud_radius_i * m_cloud_radius_i);
for(s16 zi = -m_cloud_radius_i; zi < m_cloud_radius_i; zi++) {
u32 si = (zi + m_cloud_radius_i) * m_cloud_radius_i * 2 + m_cloud_radius_i;
@@ -195,12 +196,7 @@ void Clouds::render()
{
s16 zi = zi0;
s16 xi = xi0;
- // Draw from front to back (needed for transparency)
- /*if(zi <= 0)
- zi = -m_cloud_radius_i - zi;
- if(xi <= 0)
- xi = -m_cloud_radius_i - xi;*/
- // Draw from back to front
+ // Draw from back to front for proper transparency
if(zi >= 0)
zi = m_cloud_radius_i - zi - 1;
if(xi >= 0)
@@ -220,17 +216,10 @@ void Clouds::render()
video::S3DVertex(0,0,0, 0,0,0, c_top, 0, 0)
};
- /*if(zi <= 0 && xi <= 0){
- v[0].Color.setBlue(255);
- v[1].Color.setBlue(255);
- v[2].Color.setBlue(255);
- v[3].Color.setBlue(255);
- }*/
-
- f32 rx = cloud_size / 2.0f;
+ const f32 rx = cloud_size / 2.0f;
// if clouds are flat, the top layer should be at the given height
- f32 ry = m_enable_3d ? m_params.thickness * BS : 0.0f;
- f32 rz = cloud_size / 2;
+ const f32 ry = m_enable_3d ? m_params.thickness * BS : 0.0f;
+ const f32 rz = cloud_size / 2;
for(int i=0; i<num_faces_to_draw; i++)
{
@@ -320,15 +309,25 @@ void Clouds::render()
v3f pos(p0.X, m_params.height * BS, p0.Y);
pos -= intToFloat(m_camera_offset, BS);
- for (video::S3DVertex &vertex : v)
+ for (video::S3DVertex &vertex : v) {
vertex.Pos += pos;
- u16 indices[] = {0,1,2,2,3,0};
- driver->drawVertexPrimitiveList(v, 4, indices, 2,
- video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
+ vertices.push_back(vertex);
+ }
}
}
-
- delete[] grid;
+ int quad_count = vertices.size() / 4;
+ std::vector<u16> indices;
+ indices.reserve(quad_count * 6);
+ for (int k = 0; k < quad_count; k++) {
+ indices.push_back(4 * k + 0);
+ indices.push_back(4 * k + 1);
+ indices.push_back(4 * k + 2);
+ indices.push_back(4 * k + 2);
+ indices.push_back(4 * k + 3);
+ indices.push_back(4 * k + 0);
+ }
+ driver->drawVertexPrimitiveList(vertices.data(), vertices.size(), indices.data(), 2 * quad_count,
+ video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
// Restore fog settings
driver->setFog(fog_color, fog_type, fog_start, fog_end, fog_density,
@@ -342,14 +341,13 @@ void Clouds::step(float dtime)
void Clouds::update(const v3f &camera_p, const video::SColorf &color_diffuse)
{
+ video::SColorf ambient(m_params.color_ambient);
+ video::SColorf bright(m_params.color_bright);
m_camera_pos = camera_p;
- m_color.r = MYMIN(MYMAX(color_diffuse.r * m_params.color_bright.getRed(),
- m_params.color_ambient.getRed()), 255) / 255.0f;
- m_color.g = MYMIN(MYMAX(color_diffuse.g * m_params.color_bright.getGreen(),
- m_params.color_ambient.getGreen()), 255) / 255.0f;
- m_color.b = MYMIN(MYMAX(color_diffuse.b * m_params.color_bright.getBlue(),
- m_params.color_ambient.getBlue()), 255) / 255.0f;
- m_color.a = m_params.color_bright.getAlpha() / 255.0f;
+ m_color.r = core::clamp(color_diffuse.r * bright.r, ambient.r, 1.0f);
+ m_color.g = core::clamp(color_diffuse.g * bright.g, ambient.g, 1.0f);
+ m_color.b = core::clamp(color_diffuse.b * bright.b, ambient.b, 1.0f);
+ m_color.a = bright.a;
// is the camera inside the cloud mesh?
m_camera_inside_cloud = false; // default
diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp
index 4f949f6b0..97ae9afc4 100644
--- a/src/client/content_cao.cpp
+++ b/src/client/content_cao.cpp
@@ -47,6 +47,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <algorithm>
#include <cmath>
#include "client/shader.h"
+#include "client/minimap.h"
class Settings;
struct ToolCapabilities;
@@ -353,6 +354,8 @@ void GenericCAO::initialize(const std::string &data)
m_is_local_player = true;
m_is_visible = false;
player->setCAO(this);
+
+ m_prop.show_on_minimap = false;
}
}
@@ -371,7 +374,7 @@ void GenericCAO::processInitData(const std::string &data)
}
// PROTOCOL_VERSION >= 37
- m_name = deSerializeString(is);
+ m_name = deSerializeString16(is);
m_is_player = readU8(is);
m_id = readU16(is);
m_position = readV3F32(is);
@@ -381,7 +384,7 @@ void GenericCAO::processInitData(const std::string &data)
const u8 num_messages = readU8(is);
for (int i = 0; i < num_messages; i++) {
- std::string message = deSerializeLongString(is);
+ std::string message = deSerializeString32(is);
processMessage(message);
}
@@ -456,18 +459,21 @@ void GenericCAO::setChildrenVisible(bool toset)
for (u16 cao_id : m_attachment_child_ids) {
GenericCAO *obj = m_env->getGenericCAO(cao_id);
if (obj) {
- obj->setVisible(toset);
+ // Check if the entity is forced to appear in first person.
+ obj->setVisible(obj->m_force_visible ? true : toset);
}
}
}
-void GenericCAO::setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation)
+void GenericCAO::setAttachment(int parent_id, const std::string &bone,
+ v3f position, v3f rotation, bool force_visible)
{
int old_parent = m_attachment_parent_id;
m_attachment_parent_id = parent_id;
m_attachment_bone = bone;
m_attachment_position = position;
m_attachment_rotation = rotation;
+ m_force_visible = force_visible;
ClientActiveObject *parent = m_env->getActiveObject(parent_id);
@@ -477,18 +483,31 @@ void GenericCAO::setAttachment(int parent_id, const std::string &bone, v3f posit
if (parent)
parent->addAttachmentChild(m_id);
}
-
-
updateAttachments();
+
+ // Forcibly show attachments if required by set_attach
+ if (m_force_visible) {
+ m_is_visible = true;
+ } else if (!m_is_local_player) {
+ // Objects attached to the local player should be hidden in first person
+ m_is_visible = !m_attached_to_local ||
+ m_client->getCamera()->getCameraMode() != CAMERA_MODE_FIRST;
+ m_force_visible = false;
+ } else {
+ // Local players need to have this set,
+ // otherwise first person attachments fail.
+ m_is_visible = true;
+ }
}
void GenericCAO::getAttachment(int *parent_id, std::string *bone, v3f *position,
- v3f *rotation) const
+ v3f *rotation, bool *force_visible) const
{
*parent_id = m_attachment_parent_id;
*bone = m_attachment_bone;
*position = m_attachment_position;
*rotation = m_attachment_rotation;
+ *force_visible = m_force_visible;
}
void GenericCAO::clearChildAttachments()
@@ -498,7 +517,7 @@ void GenericCAO::clearChildAttachments()
int child_id = *m_attachment_child_ids.begin();
if (ClientActiveObject *child = m_env->getActiveObject(child_id))
- child->setAttachment(0, "", v3f(), v3f());
+ child->setAttachment(0, "", v3f(), v3f(), false);
removeAttachmentChild(child_id);
}
@@ -507,9 +526,9 @@ void GenericCAO::clearChildAttachments()
void GenericCAO::clearParentAttachment()
{
if (m_attachment_parent_id)
- setAttachment(0, "", m_attachment_position, m_attachment_rotation);
+ setAttachment(0, "", m_attachment_position, m_attachment_rotation, false);
else
- setAttachment(0, "", v3f(), v3f());
+ setAttachment(0, "", v3f(), v3f(), false);
}
void GenericCAO::addAttachmentChild(int child_id)
@@ -567,6 +586,9 @@ void GenericCAO::removeFromScene(bool permanent)
m_client->getCamera()->removeNametag(m_nametag);
m_nametag = nullptr;
}
+
+ if (m_marker && m_client->getMinimap())
+ m_client->getMinimap()->removeMarker(&m_marker);
}
void GenericCAO::addToScene(ITextureSource *tsrc)
@@ -795,11 +817,13 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
node->setParent(m_matrixnode);
updateNametag();
+ updateMarker();
updateNodePos();
updateAnimation();
updateBonePosition();
updateAttachments();
setNodeLight(m_last_light);
+ updateMeshCulling();
}
void GenericCAO::updateLight(u32 day_night_ratio)
@@ -885,12 +909,32 @@ u16 GenericCAO::getLightPosition(v3s16 *pos)
return 3;
}
+void GenericCAO::updateMarker()
+{
+ if (!m_client->getMinimap())
+ return;
+
+ if (!m_prop.show_on_minimap) {
+ if (m_marker)
+ m_client->getMinimap()->removeMarker(&m_marker);
+ return;
+ }
+
+ if (m_marker)
+ return;
+
+ scene::ISceneNode *node = getSceneNode();
+ if (!node)
+ return;
+ m_marker = m_client->getMinimap()->addMarker(node);
+}
+
void GenericCAO::updateNametag()
{
if (m_is_local_player) // No nametag for local player
return;
- if (m_prop.nametag.empty()) {
+ if (m_prop.nametag.empty() || m_prop.nametag_color.getAlpha() == 0) {
// Delete nametag
if (m_nametag) {
m_client->getCamera()->removeNametag(m_nametag);
@@ -908,12 +952,14 @@ void GenericCAO::updateNametag()
if (!m_nametag) {
// Add nametag
m_nametag = m_client->getCamera()->addNametag(node,
- m_prop.nametag, m_prop.nametag_color, pos);
+ m_prop.nametag, m_prop.nametag_color,
+ m_prop.nametag_bgcolor, pos);
} else {
// Update nametag
- m_nametag->nametag_text = m_prop.nametag;
- m_nametag->nametag_color = m_prop.nametag_color;
- m_nametag->nametag_pos = pos;
+ m_nametag->text = m_prop.nametag;
+ m_nametag->textcolor = m_prop.nametag_color;
+ m_nametag->bgcolor = m_prop.nametag_bgcolor;
+ m_nametag->pos = pos;
}
}
@@ -975,13 +1021,13 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
if (controls.sneak && walking)
new_speed /= 2;
- if (walking && (controls.LMB || controls.RMB)) {
+ if (walking && (controls.dig || controls.place)) {
new_anim = player->local_animations[3];
player->last_animation = WD_ANIM;
- } else if(walking) {
+ } else if (walking) {
new_anim = player->local_animations[1];
player->last_animation = WALK_ANIM;
- } else if(controls.LMB || controls.RMB) {
+ } else if (controls.dig || controls.place) {
new_anim = player->local_animations[2];
player->last_animation = DIG_ANIM;
}
@@ -1004,9 +1050,9 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
// Update local player animations
if ((player->last_animation != old_anim ||
- m_animation_speed != old_anim_speed) &&
- player->last_animation != NO_ANIM && allow_update)
- updateAnimation();
+ m_animation_speed != old_anim_speed) &&
+ player->last_animation != NO_ANIM && allow_update)
+ updateAnimation();
}
}
@@ -1121,7 +1167,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
}
}
- if (!getParent() && std::fabs(m_prop.automatic_rotate) > 0.001) {
+ if (!getParent() && node && fabs(m_prop.automatic_rotate) > 0.001f) {
// This is the child node's rotation. It is only used for automatic_rotate.
v3f local_rot = node->getRotation();
local_rot.Y = modulo360f(local_rot.Y - dtime * core::RADTODEG *
@@ -1130,7 +1176,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env)
}
if (!getParent() && m_prop.automatic_face_movement_dir &&
- (fabs(m_velocity.Z) > 0.001 || fabs(m_velocity.X) > 0.001)) {
+ (fabs(m_velocity.Z) > 0.001f || fabs(m_velocity.X) > 0.001f)) {
float target_yaw = atan2(m_velocity.Z, m_velocity.X) * 180 / M_PI
+ m_prop.automatic_face_movement_dir_offset;
float max_rotation_per_sec =
@@ -1176,6 +1222,7 @@ void GenericCAO::updateTexturePos()
int row = m_tx_basepos.Y;
int col = m_tx_basepos.X;
+ // Yawpitch goes rightwards
if (m_tx_select_horiz_by_yawpitch) {
if (cam_to_entity.Y > 0.75)
col += 5;
@@ -1206,6 +1253,27 @@ void GenericCAO::updateTexturePos()
float tys = m_tx_size.Y;
setBillboardTextureMatrix(m_spritenode, txs, tys, col, row);
}
+
+ else if (m_meshnode) {
+ if (m_prop.visual == "upright_sprite") {
+ int row = m_tx_basepos.Y;
+ int col = m_tx_basepos.X;
+
+ // Animation goes downwards
+ row += m_anim_frame;
+
+ const auto &tx = m_tx_size;
+ v2f t[4] = { // cf. vertices in GenericCAO::addToScene()
+ tx * v2f(col+1, row+1),
+ tx * v2f(col, row+1),
+ tx * v2f(col, row),
+ tx * v2f(col+1, row),
+ };
+ auto mesh = m_meshnode->getMesh();
+ setMeshBufferTextureCoords(mesh->getMeshBuffer(0), t, 4);
+ setMeshBufferTextureCoords(mesh->getMeshBuffer(1), t, 4);
+ }
+ }
}
// Do not pass by reference, see header.
@@ -1247,7 +1315,7 @@ void GenericCAO::updateTextures(std::string mod)
}
}
- if (m_animated_meshnode) {
+ else if (m_animated_meshnode) {
if (m_prop.visual == "mesh") {
for (u32 i = 0; i < m_prop.textures.size() &&
i < m_animated_meshnode->getMaterialCount(); ++i) {
@@ -1296,8 +1364,8 @@ void GenericCAO::updateTextures(std::string mod)
}
}
}
- if(m_meshnode)
- {
+
+ else if (m_meshnode) {
if(m_prop.visual == "cube")
{
for (u32 i = 0; i < 6; ++i)
@@ -1389,6 +1457,9 @@ void GenericCAO::updateTextures(std::string mod)
setMeshColor(mesh, m_prop.colors[0]);
}
}
+ // Prevent showing the player after changing texture
+ if (m_is_local_player)
+ updateMeshCulling();
}
void GenericCAO::updateAnimation()
@@ -1558,6 +1629,8 @@ void GenericCAO::processMessage(const std::string &data)
u8 cmd = readU8(is);
if (cmd == AO_CMD_SET_PROPERTIES) {
ObjectProperties newprops;
+ newprops.show_on_minimap = m_is_player; // default
+
newprops.deSerialize(is);
// Check what exactly changed
@@ -1591,6 +1664,8 @@ void GenericCAO::processMessage(const std::string &data)
if ((m_is_player && !m_is_local_player) && m_prop.nametag.empty())
m_prop.nametag = m_name;
+ if (m_is_local_player)
+ m_prop.show_on_minimap = false;
if (expire_visuals) {
expireVisuals();
@@ -1603,6 +1678,7 @@ void GenericCAO::processMessage(const std::string &data)
updateTextures(m_current_texture_modifier);
}
updateNametag();
+ updateMarker();
}
} else if (cmd == AO_CMD_UPDATE_POSITION) {
// Not sent by the server if this object is an attachment.
@@ -1635,7 +1711,7 @@ void GenericCAO::processMessage(const std::string &data)
rot_translator.update(m_rotation, false, update_interval);
updateNodePos();
} else if (cmd == AO_CMD_SET_TEXTURE_MOD) {
- std::string mod = deSerializeString(is);
+ std::string mod = deSerializeString16(is);
// immediately reset a engine issued texture modifier if a mod sends a different one
if (m_reset_textures_timer > 0) {
@@ -1713,7 +1789,7 @@ void GenericCAO::processMessage(const std::string &data)
m_animation_speed = readF32(is);
updateAnimationSpeed();
} else if (cmd == AO_CMD_SET_BONE_POSITION) {
- std::string bone = deSerializeString(is);
+ std::string bone = deSerializeString16(is);
v3f position = readV3F32(is);
v3f rotation = readV3F32(is);
m_bone_position[bone] = core::vector2d<v3f>(position, rotation);
@@ -1721,15 +1797,12 @@ void GenericCAO::processMessage(const std::string &data)
// updateBonePosition(); now called every step
} else if (cmd == AO_CMD_ATTACH_TO) {
u16 parent_id = readS16(is);
- std::string bone = deSerializeString(is);
+ std::string bone = deSerializeString16(is);
v3f position = readV3F32(is);
v3f rotation = readV3F32(is);
+ bool force_visible = readU8(is); // Returns false for EOF
- setAttachment(parent_id, bone, position, rotation);
-
- // localplayer itself can't be attached to localplayer
- if (!m_is_local_player)
- m_is_visible = !m_attached_to_local;
+ setAttachment(parent_id, bone, position, rotation, force_visible);
} else if (cmd == AO_CMD_PUNCHED) {
u16 result_hp = readU16(is);
@@ -1771,7 +1844,7 @@ void GenericCAO::processMessage(const std::string &data)
int armor_groups_size = readU16(is);
for(int i=0; i<armor_groups_size; i++)
{
- std::string name = deSerializeString(is);
+ std::string name = deSerializeString16(is);
int rating = readS16(is);
m_armor_groups[name] = rating;
}
@@ -1843,5 +1916,43 @@ std::string GenericCAO::debugInfoText()
return os.str();
}
+void GenericCAO::updateMeshCulling()
+{
+ if (!m_is_local_player)
+ return;
+
+ const bool hidden = m_client->getCamera()->getCameraMode() == CAMERA_MODE_FIRST;
+
+ if (m_meshnode && m_prop.visual == "upright_sprite") {
+ u32 buffers = m_meshnode->getMesh()->getMeshBufferCount();
+ for (u32 i = 0; i < buffers; i++) {
+ video::SMaterial &mat = m_meshnode->getMesh()->getMeshBuffer(i)->getMaterial();
+ // upright sprite has no backface culling
+ mat.setFlag(video::EMF_FRONT_FACE_CULLING, hidden);
+ }
+ return;
+ }
+
+ irr::scene::ISceneNode *node = getSceneNode();
+ if (!node)
+ return;
+
+ if (hidden) {
+ // Hide the mesh by culling both front and
+ // back faces. Serious hackyness but it works for our
+ // purposes. This also preserves the skeletal armature.
+ node->setMaterialFlag(video::EMF_BACK_FACE_CULLING,
+ true);
+ node->setMaterialFlag(video::EMF_FRONT_FACE_CULLING,
+ true);
+ } else {
+ // Restore mesh visibility.
+ node->setMaterialFlag(video::EMF_BACK_FACE_CULLING,
+ m_prop.backface_culling);
+ node->setMaterialFlag(video::EMF_FRONT_FACE_CULLING,
+ false);
+ }
+}
+
// Prototype
GenericCAO proto_GenericCAO(NULL, NULL);
diff --git a/src/client/content_cao.h b/src/client/content_cao.h
index 974ff9a1e..7c134fb48 100644
--- a/src/client/content_cao.h
+++ b/src/client/content_cao.h
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Camera;
class Client;
struct Nametag;
+struct MinimapMarker;
/*
SmoothTranslator
@@ -84,6 +85,7 @@ private:
scene::IBillboardSceneNode *m_spritenode = nullptr;
scene::IDummyTransformationSceneNode *m_matrixnode = nullptr;
Nametag *m_nametag = nullptr;
+ MinimapMarker *m_marker = nullptr;
v3f m_position = v3f(0.0f, 10.0f * BS, 0);
v3f m_velocity;
v3f m_acceleration;
@@ -109,6 +111,7 @@ private:
v3f m_attachment_position;
v3f m_attachment_rotation;
bool m_attached_to_local = false;
+ bool m_force_visible = false;
int m_anim_frame = 0;
int m_anim_num_frames = 1;
@@ -216,9 +219,10 @@ public:
}
void setChildrenVisible(bool toset);
- void setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation);
+ void setAttachment(int parent_id, const std::string &bone, v3f position,
+ v3f rotation, bool force_visible);
void getAttachment(int *parent_id, std::string *bone, v3f *position,
- v3f *rotation) const;
+ v3f *rotation, bool *force_visible) const;
void clearChildAttachments();
void clearParentAttachment();
void addAttachmentChild(int child_id);
@@ -248,6 +252,8 @@ public:
void updateNametag();
+ void updateMarker();
+
void updateNodePos();
void step(float dtime, ClientEnvironment *env);
@@ -275,4 +281,6 @@ public:
{
return m_prop.infotext;
}
+
+ void updateMeshCulling();
};
diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp
index 3d06584c4..90284ecce 100644
--- a/src/client/content_mapblock.cpp
+++ b/src/client/content_mapblock.cpp
@@ -513,10 +513,10 @@ f32 MapblockMeshGenerator::getCornerLevel(int i, int k)
count++;
} else if (content == CONTENT_AIR) {
air_count++;
- if (air_count >= 2)
- return -0.5 * BS + 0.2;
}
}
+ if (air_count >= 2)
+ return -0.5 * BS + 0.2;
if (count > 0)
return sum / count;
return 0;
@@ -723,7 +723,8 @@ void MapblockMeshGenerator::drawGlasslikeFramedNode()
for (auto &glass_tile : glass_tiles)
glass_tile = tiles[4];
- u8 param2 = n.getParam2();
+ // Only respect H/V merge bits when paramtype2 = "glasslikeliquidlevel" (liquid tank)
+ u8 param2 = (f->param_type_2 == CPT2_GLASSLIKE_LIQUID_LEVEL) ? n.getParam2() : 0;
bool H_merge = !(param2 & 128);
bool V_merge = !(param2 & 64);
param2 &= 63;
@@ -1454,10 +1455,10 @@ void MapblockMeshGenerator::generate()
}
}
-void MapblockMeshGenerator::renderSingle(content_t node)
+void MapblockMeshGenerator::renderSingle(content_t node, u8 param2)
{
p = {0, 0, 0};
- n = MapNode(node, 0xff, 0x00);
+ n = MapNode(node, 0xff, param2);
f = &nodedef->get(n);
drawNode();
}
diff --git a/src/client/content_mapblock.h b/src/client/content_mapblock.h
index 97947cdbe..487d84a07 100644
--- a/src/client/content_mapblock.h
+++ b/src/client/content_mapblock.h
@@ -174,5 +174,5 @@ public:
public:
MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output);
void generate();
- void renderSingle(content_t node);
+ void renderSingle(content_t node, u8 param2 = 0x00);
};
diff --git a/src/client/event_manager.h b/src/client/event_manager.h
index 3762e89bf..16f7bcf07 100644
--- a/src/client/event_manager.h
+++ b/src/client/event_manager.h
@@ -19,7 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
-#include "event.h"
+#include "mtevent.h"
#include <list>
#include <map>
diff --git a/src/client/fontengine.cpp b/src/client/fontengine.cpp
index 61d52cc2f..47218c0d9 100644
--- a/src/client/fontengine.cpp
+++ b/src/client/fontengine.cpp
@@ -42,8 +42,7 @@ static void font_setting_changed(const std::string &name, void *userdata)
}
/******************************************************************************/
-FontEngine::FontEngine(Settings* main_settings, gui::IGUIEnvironment* env) :
- m_settings(main_settings),
+FontEngine::FontEngine(gui::IGUIEnvironment* env) :
m_env(env)
{
@@ -51,34 +50,34 @@ FontEngine::FontEngine(Settings* main_settings, gui::IGUIEnvironment* env) :
i = (FontMode) FONT_SIZE_UNSPECIFIED;
}
- assert(m_settings != NULL); // pre-condition
+ assert(g_settings != NULL); // pre-condition
assert(m_env != NULL); // pre-condition
assert(m_env->getSkin() != NULL); // pre-condition
readSettings();
if (m_currentMode == FM_Standard) {
- m_settings->registerChangedCallback("font_size", font_setting_changed, NULL);
- m_settings->registerChangedCallback("font_bold", font_setting_changed, NULL);
- m_settings->registerChangedCallback("font_italic", font_setting_changed, NULL);
- m_settings->registerChangedCallback("font_path", font_setting_changed, NULL);
- m_settings->registerChangedCallback("font_path_bold", font_setting_changed, NULL);
- m_settings->registerChangedCallback("font_path_italic", font_setting_changed, NULL);
- m_settings->registerChangedCallback("font_path_bolditalic", font_setting_changed, NULL);
- m_settings->registerChangedCallback("font_shadow", font_setting_changed, NULL);
- m_settings->registerChangedCallback("font_shadow_alpha", font_setting_changed, NULL);
+ 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);
+ g_settings->registerChangedCallback("font_path", font_setting_changed, NULL);
+ g_settings->registerChangedCallback("font_path_bold", font_setting_changed, NULL);
+ g_settings->registerChangedCallback("font_path_italic", font_setting_changed, NULL);
+ 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) {
- m_settings->registerChangedCallback("fallback_font_size", font_setting_changed, NULL);
- m_settings->registerChangedCallback("fallback_font_path", font_setting_changed, NULL);
- m_settings->registerChangedCallback("fallback_font_shadow", font_setting_changed, NULL);
- m_settings->registerChangedCallback("fallback_font_shadow_alpha", font_setting_changed, NULL);
+ 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);
}
- m_settings->registerChangedCallback("mono_font_path", font_setting_changed, NULL);
- m_settings->registerChangedCallback("mono_font_size", font_setting_changed, NULL);
- m_settings->registerChangedCallback("screen_dpi", font_setting_changed, NULL);
- m_settings->registerChangedCallback("gui_scaling", font_setting_changed, NULL);
+ g_settings->registerChangedCallback("mono_font_path", font_setting_changed, NULL);
+ g_settings->registerChangedCallback("mono_font_size", font_setting_changed, NULL);
+ g_settings->registerChangedCallback("screen_dpi", font_setting_changed, NULL);
+ g_settings->registerChangedCallback("gui_scaling", font_setting_changed, NULL);
}
/******************************************************************************/
@@ -186,13 +185,28 @@ unsigned int FontEngine::getDefaultFontSize()
return m_default_size[m_currentMode];
}
+unsigned int FontEngine::getFontSize(FontMode mode)
+{
+ if (m_currentMode == FM_Simple) {
+ if (mode == FM_Mono || mode == FM_SimpleMono)
+ return m_default_size[FM_SimpleMono];
+ else
+ return m_default_size[FM_Simple];
+ }
+
+ if (mode == FM_Unspecified)
+ return m_default_size[FM_Standard];
+
+ return m_default_size[mode];
+}
+
/******************************************************************************/
void FontEngine::readSettings()
{
if (USE_FREETYPE && g_settings->getBool("freetype")) {
- m_default_size[FM_Standard] = m_settings->getU16("font_size");
- m_default_size[FM_Fallback] = m_settings->getU16("fallback_font_size");
- m_default_size[FM_Mono] = m_settings->getU16("mono_font_size");
+ 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"
@@ -205,15 +219,15 @@ void FontEngine::readSettings()
m_currentMode = is_yes(gettext("needs_fallback_font")) ?
FM_Fallback : FM_Standard;
- m_default_bold = m_settings->getBool("font_bold");
- m_default_italic = m_settings->getBool("font_italic");
+ m_default_bold = g_settings->getBool("font_bold");
+ m_default_italic = g_settings->getBool("font_italic");
} else {
m_currentMode = FM_Simple;
}
- m_default_size[FM_Simple] = m_settings->getU16("font_size");
- m_default_size[FM_SimpleMono] = m_settings->getU16("mono_font_size");
+ m_default_size[FM_Simple] = g_settings->getU16("font_size");
+ m_default_size[FM_SimpleMono] = g_settings->getU16("mono_font_size");
cleanCache();
updateFontCache();
@@ -229,7 +243,7 @@ void FontEngine::updateSkin()
m_env->getSkin()->setFont(font);
else
errorstream << "FontEngine: Default font file: " <<
- "\n\t\"" << m_settings->get("font_path") << "\"" <<
+ "\n\t\"" << g_settings->get("font_path") << "\"" <<
"\n\trequired for current screen configuration was not found" <<
" or was invalid file format." <<
"\n\tUsing irrlicht default font." << std::endl;
@@ -277,7 +291,7 @@ gui::IGUIFont *FontEngine::initFont(const FontSpec &spec)
setting_suffix.append("_italic");
u32 size = std::floor(RenderingEngine::getDisplayDensity() *
- m_settings->getFloat("gui_scaling") * spec.size);
+ g_settings->getFloat("gui_scaling") * spec.size);
if (size == 0) {
errorstream << "FontEngine: attempt to use font size 0" << std::endl;
@@ -296,8 +310,8 @@ gui::IGUIFont *FontEngine::initFont(const FontSpec &spec)
std::string fallback_settings[] = {
wanted_font_path,
- m_settings->get("fallback_font_path"),
- m_settings->getDefault(setting_prefix + "font_path")
+ g_settings->get("fallback_font_path"),
+ Settings::getLayer(SL_DEFAULTS)->get(setting_prefix + "font_path")
};
#if USE_FREETYPE
@@ -331,7 +345,7 @@ gui::IGUIFont *FontEngine::initSimpleFont(const FontSpec &spec)
assert(spec.mode == FM_Simple || spec.mode == FM_SimpleMono);
assert(spec.size != FONT_SIZE_UNSPECIFIED);
- const std::string &font_path = m_settings->get(
+ const std::string &font_path = g_settings->get(
(spec.mode == FM_SimpleMono) ? "mono_font_path" : "font_path");
size_t pos_dot = font_path.find_last_of('.');
@@ -349,7 +363,7 @@ gui::IGUIFont *FontEngine::initSimpleFont(const FontSpec &spec)
u32 size = std::floor(
RenderingEngine::getDisplayDensity() *
- m_settings->getFloat("gui_scaling") *
+ g_settings->getFloat("gui_scaling") *
spec.size);
irr::gui::IGUIFont *font = nullptr;
diff --git a/src/client/fontengine.h b/src/client/fontengine.h
index 53f14c45f..e27ef60e9 100644
--- a/src/client/fontengine.h
+++ b/src/client/fontengine.h
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <map>
#include <vector>
#include "util/basic_macros.h"
+#include "irrlichttypes.h"
#include <IGUIFont.h>
#include <IGUISkin.h>
#include <IGUIEnvironment.h>
@@ -48,7 +49,7 @@ struct FontSpec {
u16 getHash()
{
- return (mode << 2) | (bold << 1) | italic;
+ return (mode << 2) | (static_cast<u8>(bold) << 1) | static_cast<u8>(italic);
}
unsigned int size;
@@ -61,7 +62,7 @@ class FontEngine
{
public:
- FontEngine(Settings* main_settings, gui::IGUIEnvironment* env);
+ FontEngine(gui::IGUIEnvironment* env);
~FontEngine();
@@ -124,8 +125,8 @@ public:
/** get default font size */
unsigned int getDefaultFontSize();
- /** initialize font engine */
- void initialize(Settings* main_settings, gui::IGUIEnvironment* env);
+ /** get font size for a specific mode */
+ unsigned int getFontSize(FontMode mode);
/** update internal parameters from settings */
void readSettings();
@@ -146,9 +147,6 @@ private:
/** clean cache */
void cleanCache();
- /** pointer to settings for registering callbacks or reading config */
- Settings* m_settings = nullptr;
-
/** pointer to irrlicht gui environment */
gui::IGUIEnvironment* m_env = nullptr;
diff --git a/src/client/game.cpp b/src/client/game.cpp
index 069c482ca..3c58fb46f 100644
--- a/src/client/game.cpp
+++ b/src/client/game.cpp
@@ -34,11 +34,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "clouds.h"
#include "config.h"
#include "content_cao.h"
+#include "content/subgames.h"
#include "client/event_manager.h"
#include "fontengine.h"
#include "itemdef.h"
#include "log.h"
#include "filesys.h"
+#include "gameparams.h"
#include "gettext.h"
#include "gui/guiChatConsole.h"
#include "gui/guiConfirmRegistration.h"
@@ -169,13 +171,7 @@ struct LocalFormspecHandler : public TextDest
return;
}
- if (fields.find("quit") != fields.end()) {
- return;
- }
-
- if (fields.find("btn_continue") != fields.end()) {
- return;
- }
+ return;
}
if (m_formname == "MT_DEATH_SCREEN") {
@@ -184,7 +180,7 @@ struct LocalFormspecHandler : public TextDest
return;
}
- if (m_client && m_client->modsLoaded())
+ if (m_client->modsLoaded())
m_client->getScript()->on_formspec_input(m_formname, fields);
}
@@ -422,14 +418,13 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
CachedVertexShaderSetting<float> m_animation_timer_vertex;
CachedPixelShaderSetting<float> m_animation_timer_pixel;
CachedPixelShaderSetting<float, 3> m_day_light;
+ CachedPixelShaderSetting<float, 4> m_star_color;
CachedPixelShaderSetting<float, 3> m_eye_position_pixel;
CachedVertexShaderSetting<float, 3> m_eye_position_vertex;
CachedPixelShaderSetting<float, 3> m_minimap_yaw;
CachedPixelShaderSetting<float, 3> m_camera_offset_pixel;
CachedPixelShaderSetting<float, 3> m_camera_offset_vertex;
CachedPixelShaderSetting<SamplerLayer_t> m_base_texture;
- CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture;
- CachedPixelShaderSetting<SamplerLayer_t> m_texture_flags;
Client *m_client;
public:
@@ -456,14 +451,13 @@ public:
m_animation_timer_vertex("animationTimer"),
m_animation_timer_pixel("animationTimer"),
m_day_light("dayLight"),
+ m_star_color("starColor"),
m_eye_position_pixel("eyePosition"),
m_eye_position_vertex("eyePosition"),
m_minimap_yaw("yawVec"),
m_camera_offset_pixel("cameraOffset"),
m_camera_offset_vertex("cameraOffset"),
m_base_texture("baseTexture"),
- m_normal_texture("normalTexture"),
- m_texture_flags("textureFlags"),
m_client(client)
{
g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
@@ -475,12 +469,8 @@ public:
g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this);
}
- virtual void onSetConstants(video::IMaterialRendererServices *services,
- bool is_highlevel)
+ void onSetConstants(video::IMaterialRendererServices *services) override
{
- if (!is_highlevel)
- return;
-
// Background color
video::SColor bgcolor = m_sky->getBgColor();
video::SColorf bgcolorf(bgcolor);
@@ -509,6 +499,10 @@ public:
sunlight.b };
m_day_light.set(dnc, services);
+ video::SColorf star_color = m_sky->getCurrentStarColor();
+ float clr[4] = {star_color.r, star_color.g, star_color.b, star_color.a};
+ m_star_color.set(clr, services);
+
u32 animation_timer = porting::getTimeMs() % 1000000;
float animation_timer_f = (float)animation_timer / 100000.f;
m_animation_timer_vertex.set(&animation_timer_f, services);
@@ -551,12 +545,8 @@ public:
m_camera_offset_pixel.set(camera_offset_array, services);
m_camera_offset_vertex.set(camera_offset_array, services);
- SamplerLayer_t base_tex = 0,
- normal_tex = 1,
- flags_tex = 2;
+ SamplerLayer_t base_tex = 0;
m_base_texture.set(&base_tex, services);
- m_normal_texture.set(&normal_tex, services);
- m_texture_flags.set(&flags_tex, services);
}
};
@@ -587,7 +577,7 @@ public:
virtual IShaderConstantSetter* create()
{
- GameGlobalShaderConstantSetter *scs = new GameGlobalShaderConstantSetter(
+ auto *scs = new GameGlobalShaderConstantSetter(
m_sky, m_force_fog_off, m_fog_range, m_client);
if (!m_sky)
created_nosky.push_back(scs);
@@ -602,7 +592,6 @@ public:
#endif
/****************************************************************************
-
****************************************************************************/
const float object_hit_delay = 0.2;
@@ -623,15 +612,15 @@ struct GameRunData {
u16 new_playeritem;
PointedThing pointed_old;
bool digging;
- bool ldown_for_dig;
+ bool punching;
+ bool btn_down_for_dig;
bool dig_instantly;
bool digging_blocked;
- bool left_punch;
bool reset_jump_timer;
float nodig_delay_timer;
float dig_time;
float dig_time_complete;
- float repeat_rightclick_timer;
+ float repeat_place_timer;
float object_hit_delay_timer;
float time_from_last_punch;
ClientActiveObject *selected_object;
@@ -669,19 +658,11 @@ public:
~Game();
bool startup(bool *kill,
- bool random_input,
InputHandler *input,
- const std::string &map_dir,
- const std::string &playername,
- const std::string &password,
- // If address is "", local server is used and address is updated
- std::string *address,
- u16 port,
+ const GameStartData &game_params,
std::string &error_message,
bool *reconnect,
- ChatBackend *chat_backend,
- const SubgameSpec &gamespec, // Used for local game
- bool simple_singleplayer_mode);
+ ChatBackend *chat_backend);
void run();
void shutdown();
@@ -691,21 +672,18 @@ protected:
void extendedResourceCleanup();
// Basic initialisation
- bool init(const std::string &map_dir, std::string *address,
- u16 port,
- const SubgameSpec &gamespec);
+ bool init(const std::string &map_dir, const std::string &address,
+ u16 port, const SubgameSpec &gamespec);
bool initSound();
bool createSingleplayerServer(const std::string &map_dir,
- const SubgameSpec &gamespec, u16 port, std::string *address);
+ const SubgameSpec &gamespec, u16 port);
// Client creation
- bool createClient(const std::string &playername,
- const std::string &password, std::string *address, u16 port);
+ bool createClient(const GameStartData &start_data);
bool initGui();
// Client connection
- bool connectToServer(const std::string &playername,
- const std::string &password, std::string *address, u16 port,
+ bool connectToServer(const GameStartData &start_data,
bool *connect_ok, bool *aborted);
bool getServerContent(bool *aborted);
@@ -796,6 +774,14 @@ protected:
{
return input->wasKeyDown(k);
}
+ inline bool wasKeyPressed(GameKeyType k)
+ {
+ return input->wasKeyPressed(k);
+ }
+ inline bool wasKeyReleased(GameKeyType k)
+ {
+ return input->wasKeyReleased(k);
+ }
#ifdef __ANDROID__
void handleAndroidChatInput();
@@ -885,7 +871,6 @@ private:
bool *reconnect_requested;
scene::ISceneNode *skybox;
- bool random_input;
bool simple_singleplayer_mode;
/* End 'cache' */
@@ -910,7 +895,7 @@ private:
bool m_cache_enable_free_move;
f32 m_cache_mouse_sensitivity;
f32 m_cache_joystick_frustum_sensitivity;
- f32 m_repeat_right_click_time;
+ f32 m_repeat_place_time;
f32 m_cache_cam_smoothing;
f32 m_cache_fog_start;
@@ -920,6 +905,7 @@ private:
bool m_does_lost_focus_pause_game = false;
+ int m_reset_HW_buffer_counter = 0;
#ifdef __ANDROID__
bool m_cache_hold_aux1;
bool m_android_chat_open;
@@ -944,7 +930,7 @@ Game::Game() :
&settingChangedCallback, this);
g_settings->registerChangedCallback("joystick_frustum_sensitivity",
&settingChangedCallback, this);
- g_settings->registerChangedCallback("repeat_rightclick_time",
+ g_settings->registerChangedCallback("repeat_place_time",
&settingChangedCallback, this);
g_settings->registerChangedCallback("noclip",
&settingChangedCallback, this);
@@ -1002,7 +988,7 @@ Game::~Game()
&settingChangedCallback, this);
g_settings->deregisterChangedCallback("mouse_sensitivity",
&settingChangedCallback, this);
- g_settings->deregisterChangedCallback("repeat_rightclick_time",
+ g_settings->deregisterChangedCallback("repeat_place_time",
&settingChangedCallback, this);
g_settings->deregisterChangedCallback("noclip",
&settingChangedCallback, this);
@@ -1017,28 +1003,21 @@ Game::~Game()
}
bool Game::startup(bool *kill,
- bool random_input,
InputHandler *input,
- const std::string &map_dir,
- const std::string &playername,
- const std::string &password,
- std::string *address, // can change if simple_singleplayer_mode
- u16 port,
+ const GameStartData &start_data,
std::string &error_message,
bool *reconnect,
- ChatBackend *chat_backend,
- const SubgameSpec &gamespec,
- bool simple_singleplayer_mode)
+ ChatBackend *chat_backend)
{
+
// "cache"
this->device = RenderingEngine::get_raw_device();
this->kill = kill;
this->error_message = &error_message;
this->reconnect_requested = reconnect;
- this->random_input = random_input;
this->input = input;
this->chat_backend = chat_backend;
- this->simple_singleplayer_mode = simple_singleplayer_mode;
+ this->simple_singleplayer_mode = start_data.isSinglePlayer();
input->keycache.populate();
@@ -1059,10 +1038,12 @@ bool Game::startup(bool *kill,
g_client_translations->clear();
- if (!init(map_dir, address, port, gamespec))
+ // address can change if simple_singleplayer_mode
+ if (!init(start_data.world_spec.path, start_data.address,
+ start_data.socket_port, start_data.game_spec))
return false;
- if (!createClient(playername, password, address, port))
+ if (!createClient(start_data))
return false;
RenderingEngine::initialize(client, hud);
@@ -1221,7 +1202,7 @@ void Game::shutdown()
bool Game::init(
const std::string &map_dir,
- std::string *address,
+ const std::string &address,
u16 port,
const SubgameSpec &gamespec)
{
@@ -1245,8 +1226,8 @@ bool Game::init(
return false;
// Create a server if not connecting to an existing one
- if (address->empty()) {
- if (!createSingleplayerServer(map_dir, gamespec, port, address))
+ if (address.empty()) {
+ if (!createSingleplayerServer(map_dir, gamespec, port))
return false;
}
@@ -1281,7 +1262,7 @@ bool Game::initSound()
}
bool Game::createSingleplayerServer(const std::string &map_dir,
- const SubgameSpec &gamespec, u16 port, std::string *address)
+ const SubgameSpec &gamespec, u16 port)
{
showOverlayMessage(N_("Creating server..."), 0, 5);
@@ -1308,14 +1289,14 @@ bool Game::createSingleplayerServer(const std::string &map_dir,
return false;
}
- server = new Server(map_dir, gamespec, simple_singleplayer_mode, bind_addr, false);
+ server = new Server(map_dir, gamespec, simple_singleplayer_mode, bind_addr,
+ false, nullptr, error_message);
server->start();
return true;
}
-bool Game::createClient(const std::string &playername,
- const std::string &password, std::string *address, u16 port)
+bool Game::createClient(const GameStartData &start_data)
{
showOverlayMessage(N_("Creating client..."), 0, 10);
@@ -1330,8 +1311,7 @@ bool Game::createClient(const std::string &playername,
g_touchscreengui->hide();
}
#endif
- if (!connectToServer(playername, password, address, port,
- &could_connect, &connect_aborted))
+ if (!connectToServer(start_data, &could_connect, &connect_aborted))
return false;
if (!could_connect) {
@@ -1352,7 +1332,7 @@ bool Game::createClient(const std::string &playername,
return false;
}
- GameGlobalShaderConstantSetterFactory *scsf = new GameGlobalShaderConstantSetterFactory(
+ auto *scsf = new GameGlobalShaderConstantSetterFactory(
&m_flags.force_fog_off, &runData.fog_range, client);
shader_src->addShaderConstantSetterFactory(scsf);
@@ -1362,33 +1342,21 @@ bool Game::createClient(const std::string &playername,
/* Camera
*/
camera = new Camera(*draw_control, client);
- if (!camera || !camera->successfullyCreated(*error_message))
+ if (!camera->successfullyCreated(*error_message))
return false;
client->setCamera(camera);
/* Clouds
*/
- if (m_cache_enable_clouds) {
+ if (m_cache_enable_clouds)
clouds = new Clouds(smgr, -1, time(0));
- if (!clouds) {
- *error_message = "Memory allocation error (clouds)";
- errorstream << *error_message << std::endl;
- return false;
- }
- }
/* Skybox
*/
- sky = new Sky(-1, texture_src);
+ sky = new Sky(-1, texture_src, shader_src);
scsf->setSky(sky);
skybox = NULL; // This is used/set later on in the main run loop
- if (!sky) {
- *error_message = "Memory allocation error sky";
- errorstream << *error_message << std::endl;
- return false;
- }
-
/* Pre-calculated values
*/
video::ITexture *t = texture_src->getTexture("crack_anylength.png");
@@ -1418,18 +1386,10 @@ bool Game::createClient(const std::string &playername,
hud = new Hud(guienv, client, player, &player->inventory);
- if (!hud) {
- *error_message = "Memory error: could not create HUD";
- errorstream << *error_message << std::endl;
- return false;
- }
-
mapper = client->getMinimap();
- if (mapper) {
- mapper->setMinimapMode(MINIMAP_MODE_OFF);
- if (client->modsLoaded())
- client->getScript()->on_minimap_ready(mapper);
- }
+
+ if (mapper && client->modsLoaded())
+ client->getScript()->on_minimap_ready(mapper);
return true;
}
@@ -1447,11 +1407,6 @@ bool Game::initGui()
// Chat backend and console
gui_chat_console = new GUIChatConsole(guienv, guienv->getRootGUIElement(),
-1, chat_backend, client, &g_menumgr);
- if (!gui_chat_console) {
- *error_message = "Could not allocate memory for chat console";
- errorstream << *error_message << std::endl;
- return false;
- }
#ifdef HAVE_TOUCHSCREENGUI
@@ -1463,8 +1418,7 @@ bool Game::initGui()
return true;
}
-bool Game::connectToServer(const std::string &playername,
- const std::string &password, std::string *address, u16 port,
+bool Game::connectToServer(const GameStartData &start_data,
bool *connect_ok, bool *connection_aborted)
{
*connect_ok = false; // Let's not be overly optimistic
@@ -1473,10 +1427,10 @@ bool Game::connectToServer(const std::string &playername,
showOverlayMessage(N_("Resolving address..."), 0, 15);
- Address connect_address(0, 0, 0, 0, port);
+ Address connect_address(0, 0, 0, 0, start_data.socket_port);
try {
- connect_address.Resolve(address->c_str());
+ connect_address.Resolve(start_data.address.c_str());
if (connect_address.isZero()) { // i.e. INADDR_ANY, IN6ADDR_ANY
//connect_address.Resolve("localhost");
@@ -1503,14 +1457,12 @@ bool Game::connectToServer(const std::string &playername,
return false;
}
- client = new Client(playername.c_str(), password, *address,
+ client = new Client(start_data.name.c_str(),
+ 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());
- if (!client)
- return false;
-
client->m_simple_singleplayer_mode = simple_singleplayer_mode;
infostream << "Connecting to server at ";
@@ -1574,13 +1526,13 @@ bool Game::connectToServer(const std::string &playername,
} else {
registration_confirmation_shown = true;
(new GUIConfirmRegistration(guienv, guienv->getRootGUIElement(), -1,
- &g_menumgr, client, playername, password,
+ &g_menumgr, client, start_data.name, start_data.password,
connection_aborted, texture_src))->drop();
}
} else {
wait_time += dtime;
// Only time out if we aren't waiting for the server we started
- if (!address->empty() && wait_time > 10) {
+ if (!start_data.isSinglePlayer() && wait_time > 10) {
*error_message = "Connection timed out.";
errorstream << *error_message << std::endl;
break;
@@ -1659,7 +1611,10 @@ bool Game::getServerContent(bool *aborted)
std::stringstream message;
std::fixed(message);
message.precision(0);
- message << gettext("Media...") << " " << (client->mediaReceiveProgress()*100) << "%";
+ float receive = client->mediaReceiveProgress() * 100;
+ message << gettext("Media...");
+ if (receive > 0)
+ message << " " << receive << "%";
message.precision(2);
if ((USE_CURL == 0) ||
@@ -2029,15 +1984,11 @@ void Game::processItemSelection(u16 *new_playeritem)
s32 dir = wheel;
- if (input->joystick.wasKeyDown(KeyType::SCROLL_DOWN) ||
- wasKeyDown(KeyType::HOTBAR_NEXT)) {
+ if (wasKeyDown(KeyType::HOTBAR_NEXT))
dir = -1;
- }
- if (input->joystick.wasKeyDown(KeyType::SCROLL_UP) ||
- wasKeyDown(KeyType::HOTBAR_PREV)) {
+ if (wasKeyDown(KeyType::HOTBAR_PREV))
dir = 1;
- }
if (dir < 0)
*new_playeritem = *new_playeritem < max_item ? *new_playeritem + 1 : 0;
@@ -2090,7 +2041,7 @@ void Game::openInventory()
TextDest *txt_dst = new TextDestPlayerInventory(client);
auto *&formspec = m_game_ui->updateFormspec("");
GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src,
- txt_dst, client->getFormspecPrepend());
+ txt_dst, client->getFormspecPrepend(), sound);
formspec->setFormSpec(fs_src->getForm(), inventoryloc);
}
@@ -2231,52 +2182,37 @@ void Game::toggleMinimap(bool shift_pressed)
if (!mapper || !m_game_ui->m_flags.show_hud || !g_settings->getBool("enable_minimap"))
return;
- if (shift_pressed) {
+ if (shift_pressed)
mapper->toggleMinimapShape();
- return;
- }
+ else
+ mapper->nextMode();
+
+ // TODO: When legacy minimap is deprecated, keep only HUD minimap stuff here
+ // Not so satisying code to keep compatibility with old fixed mode system
+ // -->
u32 hud_flags = client->getEnv().getLocalPlayer()->hud_flags;
- MinimapMode mode = MINIMAP_MODE_OFF;
- if (hud_flags & HUD_FLAG_MINIMAP_VISIBLE) {
- mode = mapper->getMinimapMode();
- mode = (MinimapMode)((int)mode + 1);
- // If radar is disabled and in, or switching to, radar mode
- if (!(hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE) && mode > 3)
- mode = MINIMAP_MODE_OFF;
- }
+ if (!(hud_flags & HUD_FLAG_MINIMAP_VISIBLE)) {
+ m_game_ui->m_flags.show_minimap = false;
+ } else {
- m_game_ui->m_flags.show_minimap = true;
- switch (mode) {
- case MINIMAP_MODE_SURFACEx1:
- m_game_ui->showTranslatedStatusText("Minimap in surface mode, Zoom x1");
- break;
- case MINIMAP_MODE_SURFACEx2:
- m_game_ui->showTranslatedStatusText("Minimap in surface mode, Zoom x2");
- break;
- case MINIMAP_MODE_SURFACEx4:
- m_game_ui->showTranslatedStatusText("Minimap in surface mode, Zoom x4");
- break;
- case MINIMAP_MODE_RADARx1:
- m_game_ui->showTranslatedStatusText("Minimap in radar mode, Zoom x1");
- break;
- case MINIMAP_MODE_RADARx2:
- m_game_ui->showTranslatedStatusText("Minimap in radar mode, Zoom x2");
- break;
- case MINIMAP_MODE_RADARx4:
- m_game_ui->showTranslatedStatusText("Minimap in radar mode, Zoom x4");
- break;
- default:
- mode = MINIMAP_MODE_OFF;
- m_game_ui->m_flags.show_minimap = false;
- if (hud_flags & HUD_FLAG_MINIMAP_VISIBLE)
- m_game_ui->showTranslatedStatusText("Minimap hidden");
- else
- m_game_ui->showTranslatedStatusText("Minimap currently disabled by game or mod");
- }
+ // If radar is disabled, try to find a non radar mode or fall back to 0
+ if (!(hud_flags & HUD_FLAG_MINIMAP_RADAR_VISIBLE))
+ while (mapper->getModeIndex() &&
+ mapper->getModeDef().type == MINIMAP_TYPE_RADAR)
+ mapper->nextMode();
- mapper->setMinimapMode(mode);
+ m_game_ui->m_flags.show_minimap = mapper->getModeDef().type !=
+ MINIMAP_TYPE_OFF;
+ }
+ // <--
+ // End of 'not so satifying code'
+ if ((hud_flags & HUD_FLAG_MINIMAP_VISIBLE) ||
+ (hud && hud->hasElementOfType(HUD_ELEM_MINIMAP)))
+ m_game_ui->showStatusText(utf8_to_wide(mapper->getModeDef().label));
+ else
+ m_game_ui->showTranslatedStatusText("Minimap currently disabled by game or mod");
}
void Game::toggleFog()
@@ -2399,10 +2335,10 @@ void Game::checkZoomEnabled()
void Game::updateCameraDirection(CameraOrientation *cam, float dtime)
{
if ((device->isWindowActive() && device->isWindowFocused()
- && !isMenuActive()) || random_input) {
+ && !isMenuActive()) || input->isRandom()) {
#ifndef __ANDROID__
- if (!random_input) {
+ if (!input->isRandom()) {
// Mac OSX gets upset if this is set every frame
if (device->getCursorControl()->isVisible())
device->getCursorControl()->setVisible(false);
@@ -2482,8 +2418,8 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
isKeyDown(KeyType::SPECIAL1),
isKeyDown(KeyType::SNEAK),
isKeyDown(KeyType::ZOOM),
- input->getLeftState(),
- input->getRightState(),
+ isKeyDown(KeyType::DIG),
+ isKeyDown(KeyType::PLACE),
cam.camera_pitch,
cam.camera_yaw,
input->joystick.getAxisWithoutDead(JA_SIDEWARD_MOVE),
@@ -2498,8 +2434,8 @@ void Game::updatePlayerControl(const CameraOrientation &cam)
( (u32)(isKeyDown(KeyType::JUMP) & 0x1) << 4) |
( (u32)(isKeyDown(KeyType::SPECIAL1) & 0x1) << 5) |
( (u32)(isKeyDown(KeyType::SNEAK) & 0x1) << 6) |
- ( (u32)(input->getLeftState() & 0x1) << 7) |
- ( (u32)(input->getRightState() & 0x1) << 8) |
+ ( (u32)(isKeyDown(KeyType::DIG) & 0x1) << 7) |
+ ( (u32)(isKeyDown(KeyType::PLACE) & 0x1) << 8) |
( (u32)(isKeyDown(KeyType::ZOOM) & 0x1) << 9)
);
@@ -2637,7 +2573,7 @@ void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation
auto *&formspec = m_game_ui->updateFormspec(*(event->show_formspec.formname));
GUIFormSpecMenu::create(formspec, client, &input->joystick,
- fs_src, txt_dst, client->getFormspecPrepend());
+ fs_src, txt_dst, client->getFormspecPrepend(), sound);
}
delete event->show_formspec.formspec;
@@ -2650,7 +2586,7 @@ void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrienta
LocalFormspecHandler *txt_dst =
new LocalFormspecHandler(*event->show_formspec.formname, client);
GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, &input->joystick,
- fs_src, txt_dst, client->getFormspecPrepend());
+ fs_src, txt_dst, client->getFormspecPrepend(), sound);
delete event->show_formspec.formspec;
delete event->show_formspec.formname;
@@ -2959,7 +2895,8 @@ void Game::updateCamera(u32 busy_time, f32 dtime)
camera->toggleCameraMode();
- playercao->setVisible(camera->getCameraMode() > CAMERA_MODE_FIRST);
+ // Make the player visible depending on camera mode.
+ playercao->updateMeshCulling();
playercao->setChildrenVisible(camera->getCameraMode() > CAMERA_MODE_FIRST);
}
@@ -3081,7 +3018,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
PointedThing pointed = updatePointedThing(shootline,
selected_def.liquids_pointable,
- !runData.ldown_for_dig,
+ !runData.btn_down_for_dig,
camera_offset);
if (pointed != runData.pointed_old) {
@@ -3089,20 +3026,18 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
hud->updateSelectionMesh(camera_offset);
}
- if (runData.digging_blocked && !input->getLeftState()) {
- // allow digging again if button is not pressed
+ // Allow digging again if button is not pressed
+ if (runData.digging_blocked && !isKeyDown(KeyType::DIG))
runData.digging_blocked = false;
- }
/*
Stop digging when
- - releasing left mouse button
+ - releasing dig button
- pointing away from node
*/
if (runData.digging) {
- if (input->getLeftReleased()) {
- infostream << "Left button released"
- << " (stopped digging)" << std::endl;
+ if (wasKeyReleased(KeyType::DIG)) {
+ infostream << "Dig button released (stopped digging)" << std::endl;
runData.digging = false;
} else if (pointed != runData.pointed_old) {
if (pointed.type == POINTEDTHING_NODE
@@ -3112,8 +3047,7 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
// Still pointing to the same node, but a different face.
// Don't reset.
} else {
- infostream << "Pointing away from node"
- << " (stopped digging)" << std::endl;
+ infostream << "Pointing away from node (stopped digging)" << std::endl;
runData.digging = false;
hud->updateSelectionMesh(camera_offset);
}
@@ -3124,55 +3058,60 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug)
client->setCrack(-1, v3s16(0, 0, 0));
runData.dig_time = 0.0;
}
- } else if (runData.dig_instantly && input->getLeftReleased()) {
- // Remove e.g. torches faster when clicking instead of holding LMB
+ } else if (runData.dig_instantly && wasKeyReleased(KeyType::DIG)) {
+ // Remove e.g. torches faster when clicking instead of holding dig button
runData.nodig_delay_timer = 0;
runData.dig_instantly = false;
}
- if (!runData.digging && runData.ldown_for_dig && !input->getLeftState()) {
- runData.ldown_for_dig = false;
- }
+ if (!runData.digging && runData.btn_down_for_dig && !isKeyDown(KeyType::DIG))
+ runData.btn_down_for_dig = false;
- runData.left_punch = false;
+ runData.punching = false;
soundmaker->m_player_leftpunch_sound.name = "";
// Prepare for repeating, unless we're not supposed to
- if (input->getRightState() && !g_settings->getBool("safe_dig_and_place"))
- runData.repeat_rightclick_timer += dtime;
+ if (isKeyDown(KeyType::PLACE) && !g_settings->getBool("safe_dig_and_place"))
+ runData.repeat_place_timer += dtime;
else
- runData.repeat_rightclick_timer = 0;
+ runData.repeat_place_timer = 0;
- if (selected_def.usable && input->getLeftState()) {
- if (input->getLeftClicked() && (!client->modsLoaded()
- || !client->getScript()->on_item_use(selected_item, pointed)))
+ if (selected_def.usable && isKeyDown(KeyType::DIG)) {
+ if (wasKeyPressed(KeyType::DIG) && (!client->modsLoaded() ||
+ !client->getScript()->on_item_use(selected_item, pointed)))
client->interact(INTERACT_USE, pointed);
} else if (pointed.type == POINTEDTHING_NODE) {
handlePointingAtNode(pointed, selected_item, hand_item, dtime);
} else if (pointed.type == POINTEDTHING_OBJECT) {
v3f player_position = player->getPosition();
handlePointingAtObject(pointed, tool_item, player_position, show_debug);
- } else if (input->getLeftState()) {
+ } else if (isKeyDown(KeyType::DIG)) {
// When button is held down in air, show continuous animation
- runData.left_punch = true;
+ runData.punching = true;
// Run callback even though item is not usable
- if (input->getLeftClicked() && client->modsLoaded())
+ if (wasKeyPressed(KeyType::DIG) && client->modsLoaded())
client->getScript()->on_item_use(selected_item, pointed);
- } else if (input->getRightClicked()) {
+ } else if (wasKeyPressed(KeyType::PLACE)) {
handlePointingAtNothing(selected_item);
}
runData.pointed_old = pointed;
- if (runData.left_punch || input->getLeftClicked())
- camera->setDigging(0); // left click animation
+ if (runData.punching || wasKeyPressed(KeyType::DIG))
+ camera->setDigging(0); // dig animation
- input->resetLeftClicked();
- input->resetRightClicked();
+ input->clearWasKeyPressed();
+ input->clearWasKeyReleased();
+ // Ensure DIG & PLACE are marked as handled
+ wasKeyDown(KeyType::DIG);
+ wasKeyDown(KeyType::PLACE);
- input->resetLeftReleased();
- input->resetRightReleased();
+ input->joystick.clearWasKeyPressed(KeyType::DIG);
+ input->joystick.clearWasKeyPressed(KeyType::PLACE);
+
+ input->joystick.clearWasKeyReleased(KeyType::DIG);
+ input->joystick.clearWasKeyReleased(KeyType::PLACE);
}
@@ -3193,11 +3132,14 @@ PointedThing Game::updatePointedThing(
const NodeDefManager *nodedef = map.getNodeDefManager();
runData.selected_object = NULL;
+ hud->pointing_at_object = false;
RaycastState s(shootline, look_for_object, liquids_pointable);
PointedThing result;
env.continueRaycast(&s, &result);
if (result.type == POINTEDTHING_OBJECT) {
+ hud->pointing_at_object = true;
+
runData.selected_object = client->getEnv().getActiveObject(result.object_id);
aabb3f selection_box;
if (show_entity_selectionbox && runData.selected_object->doShowSelectionBox() &&
@@ -3269,7 +3211,7 @@ PointedThing Game::updatePointedThing(
void Game::handlePointingAtNothing(const ItemStack &playerItem)
{
- infostream << "Right Clicked in Air" << std::endl;
+ infostream << "Attempted to place item while pointing at nothing" << std::endl;
PointedThing fauxPointed;
fauxPointed.type = POINTEDTHING_NOTHING;
client->interact(INTERACT_ACTIVATE, fauxPointed);
@@ -3288,7 +3230,7 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
ClientMap &map = client->getEnv().getClientMap();
- if (runData.nodig_delay_timer <= 0.0 && input->getLeftState()
+ if (runData.nodig_delay_timer <= 0.0 && isKeyDown(KeyType::DIG)
&& !runData.digging_blocked
&& client->checkPrivilege("interact")) {
handleDigging(pointed, nodepos, selected_item, hand_item, dtime);
@@ -3309,13 +3251,14 @@ void Game::handlePointingAtNode(const PointedThing &pointed,
}
}
- if ((input->getRightClicked() ||
- runData.repeat_rightclick_timer >= m_repeat_right_click_time) &&
+ if ((wasKeyPressed(KeyType::PLACE) ||
+ runData.repeat_place_timer >= m_repeat_place_time) &&
client->checkPrivilege("interact")) {
- runData.repeat_rightclick_timer = 0;
- infostream << "Ground right-clicked" << std::endl;
+ runData.repeat_place_timer = 0;
+ infostream << "Place button pressed while looking at ground" << std::endl;
- camera->setDigging(1); // right click animation (always shown for feedback)
+ // Placing animation (always shown for feedback)
+ camera->setDigging(1);
soundmaker->m_player_rightpunch_sound = SimpleSoundSpec();
@@ -3349,7 +3292,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
}
// formspec in meta
- if (meta && !meta->getString("formspec").empty() && !random_input
+ if (meta && !meta->getString("formspec").empty() && !input->isRandom()
&& !isKeyDown(KeyType::SNEAK)) {
// on_rightclick callbacks are called anyway
if (nodedef_manager->get(map.getNode(nodepos)).rightclickable)
@@ -3366,7 +3309,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
auto *&formspec = m_game_ui->updateFormspec("");
GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src,
- txt_dst, client->getFormspecPrepend());
+ txt_dst, client->getFormspecPrepend(), sound);
formspec->setFormSpec(meta->getString("formspec"), inventoryloc);
return false;
@@ -3381,8 +3324,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
}
verbosestream << "Node placement prediction for "
- << selected_def.name << " is "
- << prediction << std::endl;
+ << selected_def.name << " is " << prediction << std::endl;
v3s16 p = neighbourpos;
// Place inside node itself if buildable_to
@@ -3393,6 +3335,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
} else {
node = map.getNode(p, &is_valid_position);
if (is_valid_position && !nodedef->get(node).buildable_to) {
+ soundmaker->m_player_rightpunch_sound = selected_def.sound_place_failed;
// Report to server
client->interact(INTERACT_PLACE, pointed);
return false;
@@ -3465,6 +3408,7 @@ bool Game::nodePlacement(const ItemDefinition &selected_def,
pp = p + v3s16(0, -1, 0);
if (!nodedef->get(map.getNode(pp)).walkable) {
+ soundmaker->m_player_rightpunch_sound = selected_def.sound_place_failed;
// Report to server
client->interact(INTERACT_PLACE, pointed);
return false;
@@ -3541,7 +3485,7 @@ void Game::handlePointingAtObject(const PointedThing &pointed,
m_game_ui->setInfoText(infotext);
- if (input->getLeftState()) {
+ if (isKeyDown(KeyType::DIG)) {
bool do_punch = false;
bool do_punch_damage = false;
@@ -3551,12 +3495,12 @@ void Game::handlePointingAtObject(const PointedThing &pointed,
runData.object_hit_delay_timer = object_hit_delay;
}
- if (input->getLeftClicked())
+ if (wasKeyPressed(KeyType::DIG))
do_punch = true;
if (do_punch) {
- infostream << "Left-clicked object" << std::endl;
- runData.left_punch = true;
+ infostream << "Punched object" << std::endl;
+ runData.punching = true;
}
if (do_punch_damage) {
@@ -3571,8 +3515,8 @@ void Game::handlePointingAtObject(const PointedThing &pointed,
if (!disable_send)
client->interact(INTERACT_START_DIGGING, pointed);
}
- } else if (input->getRightClicked()) {
- infostream << "Right-clicked object" << std::endl;
+ } else if (wasKeyDown(KeyType::PLACE)) {
+ infostream << "Pressed place button while pointing at object" << std::endl;
client->interact(INTERACT_PLACE, pointed); // place
}
}
@@ -3618,7 +3562,7 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
return;
client->interact(INTERACT_START_DIGGING, pointed);
runData.digging = true;
- runData.ldown_for_dig = true;
+ runData.btn_down_for_dig = true;
}
if (!runData.dig_instantly) {
@@ -3712,10 +3656,9 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos,
client->setCrack(-1, nodepos);
}
- camera->setDigging(0); // left click animation
+ camera->setDigging(0); // Dig animation
}
-
void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
const CameraOrientation &cam)
{
@@ -3958,7 +3901,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
/*
Update minimap pos and rotation
*/
- if (mapper && m_game_ui->m_flags.show_minimap && m_game_ui->m_flags.show_hud) {
+ if (mapper && m_game_ui->m_flags.show_hud) {
mapper->setPos(floatToInt(player->getPosition(), BS));
mapper->setAngle(player->getYaw());
}
@@ -3966,6 +3909,27 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime,
/*
End scene
*/
+ if (++m_reset_HW_buffer_counter > 500) {
+ /*
+ Periodically remove all mesh HW buffers.
+
+ Work around for a quirk in Irrlicht where a HW buffer is only
+ released after 20000 iterations (triggered from endScene()).
+
+ Without this, all loaded but unused meshes will retain their HW
+ buffers for at least 5 minutes, at which point looking up the HW buffers
+ becomes a bottleneck and the framerate drops (as much as 30%).
+
+ Tests showed that numbers between 50 and 1000 are good, so picked 500.
+ There are no other public Irrlicht APIs that allow interacting with the
+ HW buffers without tracking the status of every individual mesh.
+
+ The HW buffers for _visible_ meshes will be reinitialized in the next frame.
+ */
+ infostream << "Game::updateFrame(): Removing all HW buffers." << std::endl;
+ driver->removeAllHardwareBuffers();
+ m_reset_HW_buffer_counter = 0;
+ }
driver->endScene();
stats->drawtime = tt_draw.stop(true);
@@ -4001,9 +3965,10 @@ inline void Game::limitFps(FpsControl *fps_timings, f32 *dtime)
else
fps_timings->busy_time = 0;
- u32 frametime_min = 1000 / (g_menumgr.pausesGame()
- ? g_settings->getFloat("pause_fps_max")
- : g_settings->getFloat("fps_max"));
+ u32 frametime_min = 1000 / (
+ device->isWindowFocused() && !g_menumgr.pausesGame()
+ ? g_settings->getFloat("fps_max")
+ : g_settings->getFloat("fps_max_unfocused"));
if (fps_timings->busy_time < frametime_min) {
fps_timings->sleep_time = frametime_min - fps_timings->busy_time;
@@ -4051,7 +4016,7 @@ void Game::readSettings()
m_cache_enable_fog = g_settings->getBool("enable_fog");
m_cache_mouse_sensitivity = g_settings->getFloat("mouse_sensitivity");
m_cache_joystick_frustum_sensitivity = g_settings->getFloat("joystick_frustum_sensitivity");
- m_repeat_right_click_time = g_settings->getFloat("repeat_rightclick_time");
+ m_repeat_place_time = g_settings->getFloat("repeat_place_time");
m_cache_enable_noclip = g_settings->getBool("noclip");
m_cache_enable_free_move = g_settings->getBool("free_move");
@@ -4116,7 +4081,7 @@ void Game::showDeathFormspec()
auto *&formspec = m_game_ui->getFormspecGUI();
GUIFormSpecMenu::create(formspec, client, &input->joystick,
- fs_src, txt_dst, client->getFormspecPrepend());
+ fs_src, txt_dst, client->getFormspecPrepend(), sound);
formspec->setFocus("btn_respawn");
}
@@ -4143,30 +4108,32 @@ void Game::showPauseMenu()
"- %s: move backwards\n"
"- %s: move left\n"
"- %s: move right\n"
- "- %s: jump/climb\n"
- "- %s: sneak/go down\n"
+ "- %s: jump/climb up\n"
+ "- %s: dig/punch\n"
+ "- %s: place/use\n"
+ "- %s: sneak/climb down\n"
"- %s: drop item\n"
"- %s: inventory\n"
"- Mouse: turn/look\n"
- "- Mouse left: dig/punch\n"
- "- Mouse right: place/use\n"
"- Mouse wheel: select item\n"
"- %s: chat\n"
);
- char control_text_buf[600];
-
- porting::mt_snprintf(control_text_buf, sizeof(control_text_buf), control_text_template.c_str(),
- GET_KEY_NAME(keymap_forward),
- GET_KEY_NAME(keymap_backward),
- GET_KEY_NAME(keymap_left),
- GET_KEY_NAME(keymap_right),
- GET_KEY_NAME(keymap_jump),
- GET_KEY_NAME(keymap_sneak),
- GET_KEY_NAME(keymap_drop),
- GET_KEY_NAME(keymap_inventory),
- GET_KEY_NAME(keymap_chat)
- );
+ char control_text_buf[600];
+
+ porting::mt_snprintf(control_text_buf, sizeof(control_text_buf), control_text_template.c_str(),
+ GET_KEY_NAME(keymap_forward),
+ GET_KEY_NAME(keymap_backward),
+ GET_KEY_NAME(keymap_left),
+ GET_KEY_NAME(keymap_right),
+ GET_KEY_NAME(keymap_jump),
+ GET_KEY_NAME(keymap_dig),
+ GET_KEY_NAME(keymap_place),
+ GET_KEY_NAME(keymap_sneak),
+ GET_KEY_NAME(keymap_drop),
+ GET_KEY_NAME(keymap_inventory),
+ GET_KEY_NAME(keymap_chat)
+ );
std::string control_text = std::string(control_text_buf);
str_formspec_escape(control_text);
@@ -4248,7 +4215,7 @@ void Game::showPauseMenu()
auto *&formspec = m_game_ui->getFormspecGUI();
GUIFormSpecMenu::create(formspec, client, &input->joystick,
- fs_src, txt_dst, client->getFormspecPrepend());
+ fs_src, txt_dst, client->getFormspecPrepend(), sound);
formspec->setFocus("btn_continue");
formspec->doPause = true;
}
@@ -4260,19 +4227,11 @@ void Game::showPauseMenu()
/****************************************************************************/
void the_game(bool *kill,
- bool random_input,
InputHandler *input,
- const std::string &map_dir,
- const std::string &playername,
- const std::string &password,
- const std::string &address, // If empty local server is created
- u16 port,
-
+ const GameStartData &start_data,
std::string &error_message,
ChatBackend &chat_backend,
- bool *reconnect_requested,
- const SubgameSpec &gamespec, // Used for local game
- bool simple_singleplayer_mode)
+ bool *reconnect_requested) // Used for local game
{
Game game;
@@ -4280,14 +4239,11 @@ void the_game(bool *kill,
* is created then this is updated and we don't want to change the value
* passed to us by the calling function
*/
- std::string server_address = address;
try {
- if (game.startup(kill, random_input, input, map_dir,
- playername, password, &server_address, port, error_message,
- reconnect_requested, &chat_backend, gamespec,
- simple_singleplayer_mode)) {
+ if (game.startup(kill, input, start_data, error_message,
+ reconnect_requested, &chat_backend)) {
game.run();
}
diff --git a/src/client/game.h b/src/client/game.h
index 69e6eed0b..d04153271 100644
--- a/src/client/game.h
+++ b/src/client/game.h
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class InputHandler;
class ChatBackend; /* to avoid having to include chat.h */
struct SubgameSpec;
+struct GameStartData;
struct Jitter {
f32 max, min, avg, counter, max_sample, min_sample, max_fraction;
@@ -41,16 +42,10 @@ struct CameraOrientation {
f32 camera_pitch; // "up/down"
};
+
void the_game(bool *kill,
- bool random_input,
InputHandler *input,
- const std::string &map_dir,
- const std::string &playername,
- const std::string &password,
- const std::string &address, // If "", local server is used
- u16 port,
+ const GameStartData &start_data,
std::string &error_message,
ChatBackend &chat_backend,
- bool *reconnect_requested,
- const SubgameSpec &gamespec, // Used for local game
- bool simple_singleplayer_mode);
+ bool *reconnect_requested);
diff --git a/src/client/gameui.cpp b/src/client/gameui.cpp
index c216f405d..0c08efeb5 100644
--- a/src/client/gameui.cpp
+++ b/src/client/gameui.cpp
@@ -61,17 +61,6 @@ void GameUI::init()
m_guitext2 = gui::StaticText::add(guienv, L"", core::rect<s32>(0, 0, 0, 0), false,
false, guiroot);
- // At the middle of the screen
- // Object infos are shown in this
- m_guitext_info = gui::StaticText::add(guienv, L"",
- core::rect<s32>(0, 0, 400, g_fontengine->getTextHeight() * 5 + 5)
- + v2s32(100, 200), false, true, guiroot);
-
- // Status text (displays info when showing and hiding GUI stuff, etc.)
- m_guitext_status = gui::StaticText::add(guienv, L"<Status>",
- core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
- m_guitext_status->setVisible(false);
-
// Chat text
m_guitext_chat = gui::StaticText::add(guienv, L"", core::rect<s32>(0, 0, 0, 0),
//false, false); // Disable word wrap as of now
@@ -82,6 +71,20 @@ void GameUI::init()
chat_font_size, FM_Unspecified));
}
+ // At the middle of the screen
+ // Object infos are shown in this
+ u32 chat_font_height = m_guitext_chat->getActiveFont()->getDimension(L"Ay").Height;
+ m_guitext_info = gui::StaticText::add(guienv, L"",
+ core::rect<s32>(0, 0, 400, g_fontengine->getTextHeight() * 5 + 5) +
+ v2s32(100, chat_font_height *
+ (g_settings->getU16("recent_chat_messages") + 3)),
+ false, true, guiroot);
+
+ // Status text (displays info when showing and hiding GUI stuff, etc.)
+ m_guitext_status = gui::StaticText::add(guienv, L"<Status>",
+ core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
+ m_guitext_status->setVisible(false);
+
// Profiler text (size is updated when text is updated)
m_guitext_profiler = gui::StaticText::add(guienv, L"<Profiler>",
core::rect<s32>(0, 0, 0, 0), false, false, guiroot);
@@ -113,8 +116,8 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
<< std::setprecision(1)
<< " | view range: "
<< (draw_control->range_all ? "All" : itos(draw_control->wanted_range))
- << std::setprecision(3)
- << " | RTT: " << client->getRTT() << "s";
+ << std::setprecision(2)
+ << " | RTT: " << (client->getRTT() * 1000.0f) << "ms";
setStaticText(m_guitext, utf8_to_wide(os.str()).c_str());
m_guitext->setRelativePosition(core::rect<s32>(5, 5, screensize.X,
@@ -133,9 +136,9 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_
<< "pos: (" << (player_position.X / BS)
<< ", " << (player_position.Y / BS)
<< ", " << (player_position.Z / BS)
- << ") | yaw: " << (wrapDegrees_0_360(cam.camera_yaw)) << "\xC2\xB0 "
+ << ") | yaw: " << (wrapDegrees_0_360(cam.camera_yaw)) << "° "
<< yawToDirectionString(cam.camera_yaw)
- << " | pitch: " << (-wrapDegrees_180(cam.camera_pitch)) << "\xC2\xB0"
+ << " | pitch: " << (-wrapDegrees_180(cam.camera_pitch)) << "°"
<< " | seed: " << ((u64)client->getMapSeed());
if (pointed_old.type == POINTEDTHING_NODE) {
diff --git a/src/client/gameui.h b/src/client/gameui.h
index 67c6a9921..b6c8a224d 100644
--- a/src/client/gameui.h
+++ b/src/client/gameui.h
@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
+#include "irrlichttypes.h"
#include <IGUIEnvironment.h>
#include "gui/guiFormSpecMenu.h"
#include "util/enriched_string.h"
diff --git a/src/client/guiscalingfilter.cpp b/src/client/guiscalingfilter.cpp
index 4262331bd..406c096e6 100644
--- a/src/client/guiscalingfilter.cpp
+++ b/src/client/guiscalingfilter.cpp
@@ -172,11 +172,8 @@ void draw2DImageFilterScaled(video::IVideoDriver *driver, video::ITexture *txr,
void draw2DImage9Slice(video::IVideoDriver *driver, video::ITexture *texture,
const core::rect<s32> &rect, const core::rect<s32> &middle,
- const core::rect<s32> *cliprect)
+ const core::rect<s32> *cliprect, const video::SColor *const colors)
{
- const video::SColor color(255,255,255,255);
- const video::SColor colors[] = {color,color,color,color};
-
auto originalSize = texture->getOriginalSize();
core::vector2di lowerRightOffset = core::vector2di(originalSize.Width, originalSize.Height) - middle.LowerRightCorner;
diff --git a/src/client/guiscalingfilter.h b/src/client/guiscalingfilter.h
index b703d91f0..379a4bdb0 100644
--- a/src/client/guiscalingfilter.h
+++ b/src/client/guiscalingfilter.h
@@ -54,4 +54,5 @@ void draw2DImageFilterScaled(video::IVideoDriver *driver, video::ITexture *txr,
*/
void draw2DImage9Slice(video::IVideoDriver *driver, video::ITexture *texture,
const core::rect<s32> &rect, const core::rect<s32> &middle,
- const core::rect<s32> *cliprect = nullptr);
+ const core::rect<s32> *cliprect = nullptr,
+ const video::SColor *const colors = nullptr);
diff --git a/src/client/hud.cpp b/src/client/hud.cpp
index 31e633bc2..46736b325 100644
--- a/src/client/hud.cpp
+++ b/src/client/hud.cpp
@@ -36,11 +36,15 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "mesh.h"
#include "wieldmesh.h"
#include "client/renderingengine.h"
+#include "client/minimap.h"
#ifdef HAVE_TOUCHSCREENGUI
#include "gui/touchscreengui.h"
#endif
+#define OBJECT_CROSSHAIR_LINE_SIZE 8
+#define CROSSHAIR_LINE_SIZE 10
+
Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player,
Inventory *inventory)
{
@@ -76,6 +80,7 @@ Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player,
selectionbox_argb = video::SColor(255, sbox_r, sbox_g, sbox_b);
use_crosshair_image = tsrc->isKnownSourceImage("crosshair.png");
+ use_object_crosshair_image = tsrc->isKnownSourceImage("object_crosshair.png");
m_selection_boxes.clear();
m_halo_boxes.clear();
@@ -95,7 +100,7 @@ Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player,
if (g_settings->getBool("enable_shaders")) {
IShaderSource *shdrsrc = client->getShaderSource();
u16 shader_id = shdrsrc->getShader(
- m_mode == HIGHLIGHT_HALO ? "selection_shader" : "default_shader", 1, 1);
+ m_mode == HIGHLIGHT_HALO ? "selection_shader" : "default_shader", TILE_MATERIAL_ALPHA);
m_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material;
} else {
m_selection_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
@@ -110,6 +115,28 @@ Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player,
} else {
m_selection_material.MaterialType = video::EMT_SOLID;
}
+
+ // Prepare mesh for compass drawing
+ m_rotation_mesh_buffer.Vertices.set_used(4);
+ m_rotation_mesh_buffer.Indices.set_used(6);
+
+ video::SColor white(255, 255, 255, 255);
+ v3f normal(0.f, 0.f, 1.f);
+
+ m_rotation_mesh_buffer.Vertices[0] = video::S3DVertex(v3f(-1.f, -1.f, 0.f), normal, white, v2f(0.f, 1.f));
+ m_rotation_mesh_buffer.Vertices[1] = video::S3DVertex(v3f(-1.f, 1.f, 0.f), normal, white, v2f(0.f, 0.f));
+ m_rotation_mesh_buffer.Vertices[2] = video::S3DVertex(v3f( 1.f, 1.f, 0.f), normal, white, v2f(1.f, 0.f));
+ m_rotation_mesh_buffer.Vertices[3] = video::S3DVertex(v3f( 1.f, -1.f, 0.f), normal, white, v2f(1.f, 1.f));
+
+ m_rotation_mesh_buffer.Indices[0] = 0;
+ m_rotation_mesh_buffer.Indices[1] = 1;
+ m_rotation_mesh_buffer.Indices[2] = 2;
+ m_rotation_mesh_buffer.Indices[3] = 2;
+ m_rotation_mesh_buffer.Indices[4] = 3;
+ m_rotation_mesh_buffer.Indices[5] = 0;
+
+ m_rotation_mesh_buffer.getMaterial().Lighting = false;
+ m_rotation_mesh_buffer.getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
}
Hud::~Hud()
@@ -271,6 +298,18 @@ void Hud::drawItems(v2s32 upperleftpos, v2s32 screen_offset, s32 itemcount,
}
}
+bool Hud::hasElementOfType(HudElementType type)
+{
+ for (size_t i = 0; i != player->maxHudId(); i++) {
+ HudElement *e = player->getHud(i);
+ if (!e)
+ continue;
+ if (e->type == type)
+ return true;
+ }
+ return false;
+}
+
// Calculates screen position of waypoint. Returns true if waypoint is visible (in front of the player), else false.
bool Hud::calculateScreenPos(const v3s16 &camera_offset, HudElement *e, v2s32 *pos)
{
@@ -419,6 +458,69 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
core::rect<s32>(core::position2d<s32>(0,0), imgsize),
NULL, colors, true);
break; }
+ case HUD_ELEM_COMPASS: {
+ video::ITexture *texture = tsrc->getTexture(e->text);
+ if (!texture)
+ continue;
+
+ // Positionning :
+ v2s32 dstsize(e->size.X, e->size.Y);
+ if (e->size.X < 0)
+ dstsize.X = m_screensize.X * (e->size.X * -0.01);
+ if (e->size.Y < 0)
+ dstsize.Y = m_screensize.Y * (e->size.Y * -0.01);
+
+ if (dstsize.X <= 0 || dstsize.Y <= 0)
+ return; // Avoid zero divides
+
+ // Angle according to camera view
+ v3f fore(0.f, 0.f, 1.f);
+ scene::ICameraSceneNode *cam = RenderingEngine::get_scene_manager()->getActiveCamera();
+ cam->getAbsoluteTransformation().rotateVect(fore);
+ int angle = - fore.getHorizontalAngle().Y;
+
+ // Limit angle and ajust with given offset
+ angle = (angle + (int)e->number) % 360;
+
+ core::rect<s32> dstrect(0, 0, dstsize.X, dstsize.Y);
+ dstrect += pos + v2s32(
+ (e->align.X - 1.0) * dstsize.X / 2,
+ (e->align.Y - 1.0) * dstsize.Y / 2) +
+ v2s32(e->offset.X * m_hud_scaling, e->offset.Y * m_hud_scaling);
+
+ switch (e->dir) {
+ case HUD_COMPASS_ROTATE:
+ drawCompassRotate(e, texture, dstrect, angle);
+ break;
+ case HUD_COMPASS_ROTATE_REVERSE:
+ drawCompassRotate(e, texture, dstrect, -angle);
+ break;
+ case HUD_COMPASS_TRANSLATE:
+ drawCompassTranslate(e, texture, dstrect, angle);
+ break;
+ case HUD_COMPASS_TRANSLATE_REVERSE:
+ drawCompassTranslate(e, texture, dstrect, -angle);
+ break;
+ default:
+ break;
+ }
+ break; }
+ case HUD_ELEM_MINIMAP: {
+ if (e->size.X <= 0 || e->size.Y <= 0)
+ break;
+ if (!client->getMinimap())
+ break;
+ // Draw a minimap of size "size"
+ v2s32 dstsize(e->size.X * m_scale_factor,
+ e->size.Y * m_scale_factor);
+ // (no percent size as minimap would likely be anamorphosed)
+ v2s32 offset((e->align.X - 1.0) * dstsize.X / 2,
+ (e->align.Y - 1.0) * dstsize.Y / 2);
+ core::rect<s32> rect(0, 0, dstsize.X, dstsize.Y);
+ rect += pos + offset + v2s32(e->offset.X * m_scale_factor,
+ e->offset.Y * m_scale_factor);
+ client->getMinimap()->drawMinimap(rect);
+ break; }
default:
infostream << "Hud::drawLuaElements: ignoring drawform " << e->type <<
" of hud element ID " << i << " due to unrecognized type" << std::endl;
@@ -426,6 +528,74 @@ void Hud::drawLuaElements(const v3s16 &camera_offset)
}
}
+void Hud::drawCompassTranslate(HudElement *e, video::ITexture *texture,
+ const core::rect<s32> &rect, int angle)
+{
+ const video::SColor color(255, 255, 255, 255);
+ const video::SColor colors[] = {color, color, color, color};
+
+ // Compute source image scaling
+ core::dimension2di imgsize(texture->getOriginalSize());
+ core::rect<s32> srcrect(0, 0, imgsize.Width, imgsize.Height);
+
+ v2s32 dstsize(rect.getHeight() * e->scale.X * imgsize.Width / imgsize.Height,
+ rect.getHeight() * e->scale.Y);
+
+ // Avoid infinite loop
+ if (dstsize.X <= 0 || dstsize.Y <= 0)
+ return;
+
+ core::rect<s32> tgtrect(0, 0, dstsize.X, dstsize.Y);
+ tgtrect += v2s32(
+ (rect.getWidth() - dstsize.X) / 2,
+ (rect.getHeight() - dstsize.Y) / 2) +
+ rect.UpperLeftCorner;
+
+ int offset = angle * dstsize.X / 360;
+
+ tgtrect += v2s32(offset, 0);
+
+ // Repeat image as much as needed
+ while (tgtrect.UpperLeftCorner.X > rect.UpperLeftCorner.X)
+ tgtrect -= v2s32(dstsize.X, 0);
+
+ draw2DImageFilterScaled(driver, texture, tgtrect, srcrect, &rect, colors, true);
+ tgtrect += v2s32(dstsize.X, 0);
+
+ while (tgtrect.UpperLeftCorner.X < rect.LowerRightCorner.X) {
+ draw2DImageFilterScaled(driver, texture, tgtrect, srcrect, &rect, colors, true);
+ tgtrect += v2s32(dstsize.X, 0);
+ }
+}
+
+void Hud::drawCompassRotate(HudElement *e, video::ITexture *texture,
+ const core::rect<s32> &rect, int angle)
+{
+ core::rect<s32> oldViewPort = driver->getViewPort();
+ core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION);
+ core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW);
+
+ core::matrix4 Matrix;
+ Matrix.makeIdentity();
+ Matrix.setRotationDegrees(v3f(0.f, 0.f, angle));
+
+ driver->setViewPort(rect);
+ driver->setTransform(video::ETS_PROJECTION, core::matrix4());
+ driver->setTransform(video::ETS_VIEW, core::matrix4());
+ driver->setTransform(video::ETS_WORLD, Matrix);
+
+ video::SMaterial &material = m_rotation_mesh_buffer.getMaterial();
+ material.TextureLayer[0].Texture = texture;
+ driver->setMaterial(material);
+ driver->drawMeshBuffer(&m_rotation_mesh_buffer);
+
+ driver->setTransform(video::ETS_WORLD, core::matrix4());
+ driver->setTransform(video::ETS_VIEW, oldViewMat);
+ driver->setTransform(video::ETS_PROJECTION, oldProjMat);
+
+ // restore the view area
+ driver->setViewPort(oldViewPort);
+}
void Hud::drawStatbar(v2s32 pos, u16 corner, u16 drawdir,
const std::string &texture, const std::string &bgtexture,
@@ -601,6 +771,31 @@ void Hud::drawHotbar(u16 playeritem) {
void Hud::drawCrosshair()
{
+ if (pointing_at_object) {
+ if (use_object_crosshair_image) {
+ video::ITexture *object_crosshair = tsrc->getTexture("object_crosshair.png");
+ v2u32 size = object_crosshair->getOriginalSize();
+ v2s32 lsize = v2s32(m_displaycenter.X - (size.X / 2),
+ m_displaycenter.Y - (size.Y / 2));
+ driver->draw2DImage(object_crosshair, lsize,
+ core::rect<s32>(0, 0, size.X, size.Y),
+ nullptr, crosshair_argb, true);
+ } else {
+ driver->draw2DLine(
+ m_displaycenter - v2s32(OBJECT_CROSSHAIR_LINE_SIZE,
+ OBJECT_CROSSHAIR_LINE_SIZE),
+ m_displaycenter + v2s32(OBJECT_CROSSHAIR_LINE_SIZE,
+ OBJECT_CROSSHAIR_LINE_SIZE), crosshair_argb);
+ driver->draw2DLine(
+ m_displaycenter + v2s32(OBJECT_CROSSHAIR_LINE_SIZE,
+ -OBJECT_CROSSHAIR_LINE_SIZE),
+ m_displaycenter + v2s32(-OBJECT_CROSSHAIR_LINE_SIZE,
+ OBJECT_CROSSHAIR_LINE_SIZE), crosshair_argb);
+ }
+
+ return;
+ }
+
if (use_crosshair_image) {
video::ITexture *crosshair = tsrc->getTexture("crosshair.png");
v2u32 size = crosshair->getOriginalSize();
@@ -608,12 +803,12 @@ void Hud::drawCrosshair()
m_displaycenter.Y - (size.Y / 2));
driver->draw2DImage(crosshair, lsize,
core::rect<s32>(0, 0, size.X, size.Y),
- 0, crosshair_argb, true);
+ nullptr, crosshair_argb, true);
} else {
- driver->draw2DLine(m_displaycenter - v2s32(10, 0),
- m_displaycenter + v2s32(10, 0), crosshair_argb);
- driver->draw2DLine(m_displaycenter - v2s32(0, 10),
- m_displaycenter + v2s32(0, 10), crosshair_argb);
+ driver->draw2DLine(m_displaycenter - v2s32(CROSSHAIR_LINE_SIZE, 0),
+ m_displaycenter + v2s32(CROSSHAIR_LINE_SIZE, 0), crosshair_argb);
+ driver->draw2DLine(m_displaycenter - v2s32(0, CROSSHAIR_LINE_SIZE),
+ m_displaycenter + v2s32(0, CROSSHAIR_LINE_SIZE), crosshair_argb);
}
}
@@ -858,9 +1053,9 @@ void drawItemStack(
if (def.type == ITEM_TOOL && item.wear != 0) {
// Draw a progressbar
- float barheight = rect.getHeight() / 16;
- float barpad_x = rect.getWidth() / 16;
- float barpad_y = rect.getHeight() / 16;
+ float barheight = static_cast<float>(rect.getHeight()) / 16;
+ float barpad_x = static_cast<float>(rect.getWidth()) / 16;
+ float barpad_y = static_cast<float>(rect.getHeight()) / 16;
core::rect<s32> progressrect(
rect.UpperLeftCorner.X + barpad_x,
diff --git a/src/client/hud.h b/src/client/hud.h
index 6f4c54626..d46545d71 100644
--- a/src/client/hud.h
+++ b/src/client/hud.h
@@ -45,12 +45,16 @@ public:
video::SColor crosshair_argb;
video::SColor selectionbox_argb;
+
bool use_crosshair_image = false;
+ bool use_object_crosshair_image = false;
std::string hotbar_image = "";
bool use_hotbar_image = false;
std::string hotbar_selected_image = "";
bool use_hotbar_selected_image = false;
+ bool pointing_at_object = false;
+
Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player,
Inventory *inventory);
~Hud();
@@ -77,6 +81,8 @@ public:
m_selected_face_normal = face_normal;
}
+ bool hasElementOfType(HudElementType type);
+
void drawLuaElements(const v3s16 &camera_offset);
private:
@@ -91,6 +97,12 @@ private:
void drawItem(const ItemStack &item, const core::rect<s32> &rect, bool selected);
+ void drawCompassTranslate(HudElement *e, video::ITexture *texture,
+ const core::rect<s32> &rect, int way);
+
+ void drawCompassRotate(HudElement *e, video::ITexture *texture,
+ const core::rect<s32> &rect, int way);
+
float m_hud_scaling; // cached minetest setting
float m_scale_factor;
v3s16 m_camera_offset;
@@ -111,6 +123,8 @@ private:
video::SMaterial m_selection_material;
+ scene::SMeshBuffer m_rotation_mesh_buffer;
+
enum
{
HIGHLIGHT_BOX,
diff --git a/src/client/inputhandler.cpp b/src/client/inputhandler.cpp
index a79b04a90..978baa320 100644
--- a/src/client/inputhandler.cpp
+++ b/src/client/inputhandler.cpp
@@ -37,6 +37,8 @@ void KeyCache::populate()
key[KeyType::JUMP] = getKeySetting("keymap_jump");
key[KeyType::SPECIAL1] = getKeySetting("keymap_special1");
key[KeyType::SNEAK] = getKeySetting("keymap_sneak");
+ key[KeyType::DIG] = getKeySetting("keymap_dig");
+ key[KeyType::PLACE] = getKeySetting("keymap_place");
key[KeyType::AUTOFORWARD] = getKeySetting("keymap_autoforward");
@@ -112,56 +114,75 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
const KeyPress &keyCode = event.KeyInput;
if (keysListenedFor[keyCode]) {
if (event.KeyInput.PressedDown) {
+ if (!IsKeyDown(keyCode))
+ keyWasPressed.set(keyCode);
+
keyIsDown.set(keyCode);
keyWasDown.set(keyCode);
} else {
+ if (IsKeyDown(keyCode))
+ keyWasReleased.set(keyCode);
+
keyIsDown.unset(keyCode);
}
+
return true;
}
- }
#ifdef HAVE_TOUCHSCREENGUI
- // case of touchscreengui we have to handle different events
- if (m_touchscreengui && event.EventType == irr::EET_TOUCH_INPUT_EVENT) {
+ } else if (m_touchscreengui && event.EventType == irr::EET_TOUCH_INPUT_EVENT) {
+ // In case of touchscreengui, we have to handle different events
m_touchscreengui->translateEvent(event);
return true;
- }
#endif
- if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) {
+ } else if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) {
/* TODO add a check like:
if (event.JoystickEvent != joystick_we_listen_for)
return false;
*/
return joystick->handleEvent(event.JoystickEvent);
- }
- // handle mouse events
- if (event.EventType == irr::EET_MOUSE_INPUT_EVENT) {
- if (isMenuActive()) {
- left_active = false;
- middle_active = false;
- right_active = false;
- } else {
- left_active = event.MouseInput.isLeftPressed();
- middle_active = event.MouseInput.isMiddlePressed();
- right_active = event.MouseInput.isRightPressed();
-
- if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) {
- leftclicked = true;
- }
- if (event.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN) {
- rightclicked = true;
- }
- if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) {
- leftreleased = true;
- }
- if (event.MouseInput.Event == EMIE_RMOUSE_LEFT_UP) {
- rightreleased = true;
- }
- if (event.MouseInput.Event == EMIE_MOUSE_WHEEL) {
- mouse_wheel += event.MouseInput.Wheel;
- }
+ } else if (event.EventType == irr::EET_MOUSE_INPUT_EVENT) {
+ // Handle mouse events
+ KeyPress key;
+ switch (event.MouseInput.Event) {
+ case EMIE_LMOUSE_PRESSED_DOWN:
+ key = "KEY_LBUTTON";
+ keyIsDown.set(key);
+ keyWasDown.set(key);
+ keyWasPressed.set(key);
+ break;
+ case EMIE_MMOUSE_PRESSED_DOWN:
+ key = "KEY_MBUTTON";
+ keyIsDown.set(key);
+ keyWasDown.set(key);
+ keyWasPressed.set(key);
+ break;
+ case EMIE_RMOUSE_PRESSED_DOWN:
+ key = "KEY_RBUTTON";
+ keyIsDown.set(key);
+ keyWasDown.set(key);
+ keyWasPressed.set(key);
+ break;
+ case EMIE_LMOUSE_LEFT_UP:
+ key = "KEY_LBUTTON";
+ keyIsDown.unset(key);
+ keyWasReleased.set(key);
+ break;
+ case EMIE_MMOUSE_LEFT_UP:
+ key = "KEY_MBUTTON";
+ keyIsDown.unset(key);
+ keyWasReleased.set(key);
+ break;
+ case EMIE_RMOUSE_LEFT_UP:
+ key = "KEY_RBUTTON";
+ keyIsDown.unset(key);
+ keyWasReleased.set(key);
+ break;
+ case EMIE_MOUSE_WHEEL:
+ mouse_wheel += event.MouseInput.Wheel;
+ break;
+ default: break;
}
} else if (event.EventType == irr::EET_LOG_TEXT_EVENT) {
static const LogLevel irr_loglev_conv[] = {
@@ -188,38 +209,28 @@ s32 RandomInputHandler::Rand(s32 min, s32 max)
return (myrand() % (max - min + 1)) + min;
}
+struct RandomInputHandlerSimData {
+ std::string key;
+ float counter;
+ int time_max;
+};
+
void RandomInputHandler::step(float dtime)
{
- {
- static float counter1 = 0;
- counter1 -= dtime;
- if (counter1 < 0.0) {
- counter1 = 0.1 * Rand(1, 40);
- keydown.toggle(getKeySetting("keymap_jump"));
- }
- }
- {
- static float counter1 = 0;
- counter1 -= dtime;
- if (counter1 < 0.0) {
- counter1 = 0.1 * Rand(1, 40);
- keydown.toggle(getKeySetting("keymap_special1"));
- }
- }
- {
- static float counter1 = 0;
- counter1 -= dtime;
- if (counter1 < 0.0) {
- counter1 = 0.1 * Rand(1, 40);
- keydown.toggle(getKeySetting("keymap_forward"));
- }
- }
- {
- static float counter1 = 0;
- counter1 -= dtime;
- if (counter1 < 0.0) {
- counter1 = 0.1 * Rand(1, 40);
- keydown.toggle(getKeySetting("keymap_left"));
+ static RandomInputHandlerSimData rnd_data[] = {
+ { "keymap_jump", 0.0f, 40 },
+ { "keymap_special1", 0.0f, 40 },
+ { "keymap_forward", 0.0f, 40 },
+ { "keymap_left", 0.0f, 40 },
+ { "keymap_dig", 0.0f, 30 },
+ { "keymap_place", 0.0f, 15 }
+ };
+
+ for (auto &i : rnd_data) {
+ i.counter -= dtime;
+ if (i.counter < 0.0) {
+ i.counter = 0.1 * Rand(1, i.time_max);
+ keydown.toggle(getKeySetting(i.key.c_str()));
}
}
{
@@ -230,29 +241,5 @@ void RandomInputHandler::step(float dtime)
mousespeed = v2s32(Rand(-20, 20), Rand(-15, 20));
}
}
- {
- static float counter1 = 0;
- counter1 -= dtime;
- if (counter1 < 0.0) {
- counter1 = 0.1 * Rand(1, 30);
- leftdown = !leftdown;
- if (leftdown)
- leftclicked = true;
- if (!leftdown)
- leftreleased = true;
- }
- }
- {
- static float counter1 = 0;
- counter1 -= dtime;
- if (counter1 < 0.0) {
- counter1 = 0.1 * Rand(1, 15);
- rightdown = !rightdown;
- if (rightdown)
- rightclicked = true;
- if (!rightdown)
- rightreleased = true;
- }
- }
mousepos += mousespeed;
}
diff --git a/src/client/inputhandler.h b/src/client/inputhandler.h
index 9be2a2ed4..1fb4cf0ec 100644
--- a/src/client/inputhandler.h
+++ b/src/client/inputhandler.h
@@ -144,6 +144,14 @@ public:
return b;
}
+ // Checks whether a key was just pressed. State will be cleared
+ // in the subsequent iteration of Game::processPlayerInteraction
+ bool WasKeyPressed(const KeyPress &keycode) const { return keyWasPressed[keycode]; }
+
+ // Checks whether a key was just released. State will be cleared
+ // in the subsequent iteration of Game::processPlayerInteraction
+ bool WasKeyReleased(const KeyPress &keycode) const { return keyWasReleased[keycode]; }
+
void listenForKey(const KeyPress &keyCode) { keysListenedFor.set(keyCode); }
void dontListenForKeys() { keysListenedFor.clear(); }
@@ -158,17 +166,20 @@ public:
{
keyIsDown.clear();
keyWasDown.clear();
+ keyWasPressed.clear();
+ keyWasReleased.clear();
- leftclicked = false;
- rightclicked = false;
- leftreleased = false;
- rightreleased = false;
+ mouse_wheel = 0;
+ }
- left_active = false;
- middle_active = false;
- right_active = false;
+ void clearWasKeyPressed()
+ {
+ keyWasPressed.clear();
+ }
- mouse_wheel = 0;
+ void clearWasKeyReleased()
+ {
+ keyWasReleased.clear();
}
MyEventReceiver()
@@ -178,15 +189,6 @@ public:
#endif
}
- bool leftclicked = false;
- bool rightclicked = false;
- bool leftreleased = false;
- bool rightreleased = false;
-
- bool left_active = false;
- bool middle_active = false;
- bool right_active = false;
-
s32 mouse_wheel = 0;
JoystickController *joystick = nullptr;
@@ -198,8 +200,16 @@ public:
private:
// The current state of keys
KeyList keyIsDown;
- // Whether a key has been pressed or not
+
+ // Like keyIsDown but only reset when that key is read
KeyList keyWasDown;
+
+ // Whether a key has just been pressed
+ KeyList keyWasPressed;
+
+ // Whether a key has just been released
+ KeyList keyWasReleased;
+
// List of keys we listen for
// TODO perhaps the type of this is not really
// performant as KeyList is designed for few but
@@ -219,29 +229,26 @@ public:
virtual ~InputHandler() = default;
+ virtual bool isRandom() const
+ {
+ return false;
+ }
+
virtual bool isKeyDown(GameKeyType k) = 0;
virtual bool wasKeyDown(GameKeyType k) = 0;
+ virtual bool wasKeyPressed(GameKeyType k) = 0;
+ virtual bool wasKeyReleased(GameKeyType k) = 0;
virtual bool cancelPressed() = 0;
+ virtual void clearWasKeyPressed() {}
+ virtual void clearWasKeyReleased() {}
+
virtual void listenForKey(const KeyPress &keyCode) {}
virtual void dontListenForKeys() {}
virtual v2s32 getMousePos() = 0;
virtual void setMousePos(s32 x, s32 y) = 0;
- virtual bool getLeftState() = 0;
- virtual bool getRightState() = 0;
-
- virtual bool getLeftClicked() = 0;
- virtual bool getRightClicked() = 0;
- virtual void resetLeftClicked() = 0;
- virtual void resetRightClicked() = 0;
-
- virtual bool getLeftReleased() = 0;
- virtual bool getRightReleased() = 0;
- virtual void resetLeftReleased() = 0;
- virtual void resetRightReleased() = 0;
-
virtual s32 getMouseWheel() = 0;
virtual void step(float dtime) {}
@@ -270,10 +277,26 @@ public:
{
return m_receiver->WasKeyDown(keycache.key[k]) || joystick.wasKeyDown(k);
}
+ virtual bool wasKeyPressed(GameKeyType k)
+ {
+ return m_receiver->WasKeyPressed(keycache.key[k]) || joystick.wasKeyPressed(k);
+ }
+ virtual bool wasKeyReleased(GameKeyType k)
+ {
+ return m_receiver->WasKeyReleased(keycache.key[k]) || joystick.wasKeyReleased(k);
+ }
virtual bool cancelPressed()
{
return wasKeyDown(KeyType::ESC) || m_receiver->WasKeyDown(CancelKey);
}
+ virtual void clearWasKeyPressed()
+ {
+ m_receiver->clearWasKeyPressed();
+ }
+ virtual void clearWasKeyReleased()
+ {
+ m_receiver->clearWasKeyReleased();
+ }
virtual void listenForKey(const KeyPress &keyCode)
{
m_receiver->listenForKey(keyCode);
@@ -301,59 +324,6 @@ public:
}
}
- virtual bool getLeftState()
- {
- return m_receiver->left_active || joystick.isKeyDown(KeyType::MOUSE_L);
- }
- virtual bool getRightState()
- {
- return m_receiver->right_active || joystick.isKeyDown(KeyType::MOUSE_R);
- }
-
- virtual bool getLeftClicked()
- {
- return m_receiver->leftclicked ||
- joystick.getWasKeyDown(KeyType::MOUSE_L);
- }
- virtual bool getRightClicked()
- {
- return m_receiver->rightclicked ||
- joystick.getWasKeyDown(KeyType::MOUSE_R);
- }
-
- virtual void resetLeftClicked()
- {
- m_receiver->leftclicked = false;
- joystick.clearWasKeyDown(KeyType::MOUSE_L);
- }
- virtual void resetRightClicked()
- {
- m_receiver->rightclicked = false;
- joystick.clearWasKeyDown(KeyType::MOUSE_R);
- }
-
- virtual bool getLeftReleased()
- {
- return m_receiver->leftreleased ||
- joystick.wasKeyReleased(KeyType::MOUSE_L);
- }
- virtual bool getRightReleased()
- {
- return m_receiver->rightreleased ||
- joystick.wasKeyReleased(KeyType::MOUSE_R);
- }
-
- virtual void resetLeftReleased()
- {
- m_receiver->leftreleased = false;
- joystick.clearWasKeyReleased(KeyType::MOUSE_L);
- }
- virtual void resetRightReleased()
- {
- m_receiver->rightreleased = false;
- joystick.clearWasKeyReleased(KeyType::MOUSE_R);
- }
-
virtual s32 getMouseWheel() { return m_receiver->getMouseWheel(); }
void clear()
@@ -372,25 +342,19 @@ class RandomInputHandler : public InputHandler
public:
RandomInputHandler() = default;
+ bool isRandom() const
+ {
+ return true;
+ }
+
virtual bool isKeyDown(GameKeyType k) { return keydown[keycache.key[k]]; }
virtual bool wasKeyDown(GameKeyType k) { return false; }
+ virtual bool wasKeyPressed(GameKeyType k) { return false; }
+ virtual bool wasKeyReleased(GameKeyType k) { return false; }
virtual bool cancelPressed() { return false; }
virtual v2s32 getMousePos() { return mousepos; }
virtual void setMousePos(s32 x, s32 y) { mousepos = v2s32(x, y); }
- virtual bool getLeftState() { return leftdown; }
- virtual bool getRightState() { return rightdown; }
-
- virtual bool getLeftClicked() { return leftclicked; }
- virtual bool getRightClicked() { return rightclicked; }
- virtual void resetLeftClicked() { leftclicked = false; }
- virtual void resetRightClicked() { rightclicked = false; }
-
- virtual bool getLeftReleased() { return leftreleased; }
- virtual bool getRightReleased() { return rightreleased; }
- virtual void resetLeftReleased() { leftreleased = false; }
- virtual void resetRightReleased() { rightreleased = false; }
-
virtual s32 getMouseWheel() { return 0; }
virtual void step(float dtime);
@@ -401,10 +365,4 @@ private:
KeyList keydown;
v2s32 mousepos;
v2s32 mousespeed;
- bool leftdown = false;
- bool rightdown = false;
- bool leftclicked = false;
- bool rightclicked = false;
- bool leftreleased = false;
- bool rightreleased = false;
};
diff --git a/src/client/joystick_controller.cpp b/src/client/joystick_controller.cpp
index c29e8b639..f61ae4ae6 100644
--- a/src/client/joystick_controller.cpp
+++ b/src/client/joystick_controller.cpp
@@ -37,7 +37,7 @@ bool JoystickAxisCmb::isTriggered(const irr::SEvent::SJoystickEvent &ev) const
{
s16 ax_val = ev.Axis[axis_to_compare];
- return (ax_val * direction < 0) && (thresh * direction > ax_val * direction);
+ return (ax_val * direction < -thresh);
}
// spares many characters
@@ -48,7 +48,7 @@ JoystickLayout create_default_layout()
{
JoystickLayout jlo;
- jlo.axes_dead_border = 1024;
+ jlo.axes_deadzone = g_settings->getU16("joystick_deadzone");
const JoystickAxisLayout axes[JA_COUNT] = {
{0, 1}, // JA_SIDEWARD_MOVE
@@ -74,8 +74,8 @@ JoystickLayout create_default_layout()
// Accessible without four modifier button pressed
// regardless whether start is pressed or not
- JLO_B_PB(KeyType::MOUSE_L, fb | 1 << 4, 1 << 4);
- JLO_B_PB(KeyType::MOUSE_R, fb | 1 << 5, 1 << 5);
+ JLO_B_PB(KeyType::DIG, fb | 1 << 4, 1 << 4);
+ JLO_B_PB(KeyType::PLACE, fb | 1 << 5, 1 << 5);
// Accessible without any modifier pressed
JLO_B_PB(KeyType::JUMP, bm | 1 << 0, 1 << 0);
@@ -83,9 +83,9 @@ JoystickLayout create_default_layout()
// Accessible with start button not pressed, but four pressed
// TODO find usage for button 0
- JLO_B_PB(KeyType::DROP, bm | 1 << 1, fb | 1 << 1);
- JLO_B_PB(KeyType::SCROLL_UP, bm | 1 << 4, fb | 1 << 4);
- JLO_B_PB(KeyType::SCROLL_DOWN,bm | 1 << 5, fb | 1 << 5);
+ JLO_B_PB(KeyType::DROP, bm | 1 << 1, fb | 1 << 1);
+ JLO_B_PB(KeyType::HOTBAR_PREV, bm | 1 << 4, fb | 1 << 4);
+ JLO_B_PB(KeyType::HOTBAR_NEXT, bm | 1 << 5, fb | 1 << 5);
// Accessible with start button and four pressed
// TODO find usage for buttons 0, 1 and 4, 5
@@ -93,14 +93,14 @@ JoystickLayout create_default_layout()
// Now about the buttons simulated by the axes
// Movement buttons, important for vessels
- JLO_A_PB(KeyType::FORWARD, 1, 1, 1024);
- JLO_A_PB(KeyType::BACKWARD, 1, -1, 1024);
- JLO_A_PB(KeyType::LEFT, 0, 1, 1024);
- JLO_A_PB(KeyType::RIGHT, 0, -1, 1024);
+ JLO_A_PB(KeyType::FORWARD, 1, 1, jlo.axes_deadzone);
+ JLO_A_PB(KeyType::BACKWARD, 1, -1, jlo.axes_deadzone);
+ JLO_A_PB(KeyType::LEFT, 0, 1, jlo.axes_deadzone);
+ JLO_A_PB(KeyType::RIGHT, 0, -1, jlo.axes_deadzone);
// Scroll buttons
- JLO_A_PB(KeyType::SCROLL_UP, 2, -1, 1024);
- JLO_A_PB(KeyType::SCROLL_DOWN, 5, -1, 1024);
+ JLO_A_PB(KeyType::HOTBAR_PREV, 2, -1, jlo.axes_deadzone);
+ JLO_A_PB(KeyType::HOTBAR_NEXT, 5, -1, jlo.axes_deadzone);
return jlo;
}
@@ -109,7 +109,7 @@ JoystickLayout create_xbox_layout()
{
JoystickLayout jlo;
- jlo.axes_dead_border = 7000;
+ jlo.axes_deadzone = 7000;
const JoystickAxisLayout axes[JA_COUNT] = {
{0, 1}, // JA_SIDEWARD_MOVE
@@ -134,10 +134,10 @@ JoystickLayout create_xbox_layout()
JLO_B_PB(KeyType::SNEAK, 1 << 12, 1 << 12); // right
// Triggers
- JLO_B_PB(KeyType::MOUSE_L, 1 << 6, 1 << 6); // lt
- JLO_B_PB(KeyType::MOUSE_R, 1 << 7, 1 << 7); // rt
- JLO_B_PB(KeyType::SCROLL_UP, 1 << 4, 1 << 4); // lb
- JLO_B_PB(KeyType::SCROLL_DOWN, 1 << 5, 1 << 5); // rb
+ JLO_B_PB(KeyType::DIG, 1 << 6, 1 << 6); // lt
+ JLO_B_PB(KeyType::PLACE, 1 << 7, 1 << 7); // rt
+ JLO_B_PB(KeyType::HOTBAR_PREV, 1 << 4, 1 << 4); // lb
+ JLO_B_PB(KeyType::HOTBAR_NEXT, 1 << 5, 1 << 5); // rb
// D-PAD
JLO_B_PB(KeyType::ZOOM, 1 << 15, 1 << 15); // up
@@ -146,10 +146,10 @@ JoystickLayout create_xbox_layout()
JLO_B_PB(KeyType::FREEMOVE, 1 << 16, 1 << 16); // down
// Movement buttons, important for vessels
- JLO_A_PB(KeyType::FORWARD, 1, 1, 1024);
- JLO_A_PB(KeyType::BACKWARD, 1, -1, 1024);
- JLO_A_PB(KeyType::LEFT, 0, 1, 1024);
- JLO_A_PB(KeyType::RIGHT, 0, -1, 1024);
+ JLO_A_PB(KeyType::FORWARD, 1, 1, jlo.axes_deadzone);
+ JLO_A_PB(KeyType::BACKWARD, 1, -1, jlo.axes_deadzone);
+ JLO_A_PB(KeyType::LEFT, 0, 1, jlo.axes_deadzone);
+ JLO_A_PB(KeyType::RIGHT, 0, -1, jlo.axes_deadzone);
return jlo;
}
@@ -219,16 +219,19 @@ bool JoystickController::handleEvent(const irr::SEvent::SJoystickEvent &ev)
for (size_t i = 0; i < KeyType::INTERNAL_ENUM_COUNT; i++) {
if (keys_pressed[i]) {
- if (!m_past_pressed_keys[i] &&
+ if (!m_past_keys_pressed[i] &&
m_past_pressed_time[i] < m_internal_time - doubling_dtime) {
- m_past_pressed_keys[i] = true;
+ m_past_keys_pressed[i] = true;
m_past_pressed_time[i] = m_internal_time;
}
- } else if (m_pressed_keys[i]) {
- m_past_released_keys[i] = true;
+ } else if (m_keys_down[i]) {
+ m_keys_released[i] = true;
}
- m_pressed_keys[i] = keys_pressed[i];
+ if (keys_pressed[i] && !(m_keys_down[i]))
+ m_keys_pressed[i] = true;
+
+ m_keys_down[i] = keys_pressed[i];
}
for (size_t i = 0; i < JA_COUNT; i++) {
@@ -236,23 +239,22 @@ bool JoystickController::handleEvent(const irr::SEvent::SJoystickEvent &ev)
m_axes_vals[i] = ax_la.invert * ev.Axis[ax_la.axis_id];
}
-
return true;
}
void JoystickController::clear()
{
- m_pressed_keys.reset();
- m_past_pressed_keys.reset();
- m_past_released_keys.reset();
+ m_keys_pressed.reset();
+ m_keys_down.reset();
+ m_past_keys_pressed.reset();
+ m_keys_released.reset();
memset(m_axes_vals, 0, sizeof(m_axes_vals));
}
s16 JoystickController::getAxisWithoutDead(JoystickAxis axis)
{
s16 v = m_axes_vals[axis];
- if (((v > 0) && (v < m_layout.axes_dead_border)) ||
- ((v < 0) && (v > -m_layout.axes_dead_border)))
+ if (abs(v) < m_layout.axes_deadzone)
return 0;
return v;
}
diff --git a/src/client/joystick_controller.h b/src/client/joystick_controller.h
index 7baacd81b..3f361e4ef 100644
--- a/src/client/joystick_controller.h
+++ b/src/client/joystick_controller.h
@@ -96,7 +96,7 @@ struct JoystickLayout {
std::vector<JoystickButtonCmb> button_keys;
std::vector<JoystickAxisCmb> axis_keys;
JoystickAxisLayout axes[JA_COUNT];
- s16 axes_dead_border;
+ s16 axes_deadzone;
};
class JoystickController {
@@ -111,37 +111,32 @@ public:
bool wasKeyDown(GameKeyType b)
{
- bool r = m_past_pressed_keys[b];
- m_past_pressed_keys[b] = false;
+ bool r = m_past_keys_pressed[b];
+ m_past_keys_pressed[b] = false;
return r;
}
- bool getWasKeyDown(GameKeyType b)
+
+ bool wasKeyReleased(GameKeyType b)
{
- return m_past_pressed_keys[b];
+ return m_keys_released[b];
}
- void clearWasKeyDown(GameKeyType b)
+ void clearWasKeyReleased(GameKeyType b)
{
- m_past_pressed_keys[b] = false;
+ m_keys_released[b] = false;
}
- bool wasKeyReleased(GameKeyType b)
+ bool wasKeyPressed(GameKeyType b)
{
- bool r = m_past_released_keys[b];
- m_past_released_keys[b] = false;
- return r;
- }
- bool getWasKeyReleased(GameKeyType b)
- {
- return m_past_pressed_keys[b];
+ return m_keys_pressed[b];
}
- void clearWasKeyReleased(GameKeyType b)
+ void clearWasKeyPressed(GameKeyType b)
{
- m_past_pressed_keys[b] = false;
+ m_keys_pressed[b] = false;
}
bool isKeyDown(GameKeyType b)
{
- return m_pressed_keys[b];
+ return m_keys_down[b];
}
s16 getAxis(JoystickAxis axis)
@@ -162,12 +157,13 @@ private:
u8 m_joystick_id = 0;
- std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_pressed_keys;
+ std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_keys_down;
+ std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_keys_pressed;
f32 m_internal_time;
f32 m_past_pressed_time[KeyType::INTERNAL_ENUM_COUNT];
- std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_past_pressed_keys;
- std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_past_released_keys;
+ std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_past_keys_pressed;
+ std::bitset<KeyType::INTERNAL_ENUM_COUNT> m_keys_released;
};
diff --git a/src/client/keycode.cpp b/src/client/keycode.cpp
index 6a0e9f569..ce5214f54 100644
--- a/src/client/keycode.cpp
+++ b/src/client/keycode.cpp
@@ -316,7 +316,8 @@ KeyPress::KeyPress(const char *name)
int chars_read = mbtowc(&Char, name, 1);
FATAL_ERROR_IF(chars_read != 1, "Unexpected multibyte character");
m_name = "";
- warningstream << "KeyPress: Unknown key '" << name << "', falling back to first char.";
+ warningstream << "KeyPress: Unknown key '" << name
+ << "', falling back to first char." << std::endl;
}
KeyPress::KeyPress(const irr::SEvent::SKeyInput &in, bool prefer_character)
diff --git a/src/client/keys.h b/src/client/keys.h
index 50d3d194b..60a7a3c45 100644
--- a/src/client/keys.h
+++ b/src/client/keys.h
@@ -35,6 +35,8 @@ public:
SPECIAL1,
SNEAK,
AUTOFORWARD,
+ DIG,
+ PLACE,
ESC,
@@ -108,12 +110,6 @@ public:
SLOT_31,
SLOT_32,
- // joystick specific keys
- MOUSE_L,
- MOUSE_R,
- SCROLL_UP,
- SCROLL_DOWN,
-
// Fake keycode for array size and internal checks
INTERNAL_ENUM_COUNT
diff --git a/src/client/localplayer.cpp b/src/client/localplayer.cpp
index 1e7040d57..f3eb1a2dd 100644
--- a/src/client/localplayer.cpp
+++ b/src/client/localplayer.cpp
@@ -19,7 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "localplayer.h"
#include <cmath>
-#include "event.h"
+#include "mtevent.h"
#include "collision.h"
#include "nodedef.h"
#include "settings.h"
diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp
index 1020e35f5..167e1e3ec 100644
--- a/src/client/mapblock_mesh.cpp
+++ b/src/client/mapblock_mesh.cpp
@@ -35,11 +35,9 @@ with this program; if not, write to the Free Software Foundation, Inc.,
MeshMakeData
*/
-MeshMakeData::MeshMakeData(Client *client, bool use_shaders,
- bool use_tangent_vertices):
+MeshMakeData::MeshMakeData(Client *client, bool use_shaders):
m_client(client),
- m_use_shaders(use_shaders),
- m_use_tangent_vertices(use_tangent_vertices)
+ m_use_shaders(use_shaders)
{}
void MeshMakeData::fillBlockDataBegin(const v3s16 &blockpos)
@@ -81,33 +79,6 @@ void MeshMakeData::fill(MapBlock *block)
}
}
-void MeshMakeData::fillSingleNode(MapNode *node)
-{
- m_blockpos = v3s16(0,0,0);
-
- v3s16 blockpos_nodes = v3s16(0,0,0);
- VoxelArea area(blockpos_nodes-v3s16(1,1,1)*MAP_BLOCKSIZE,
- blockpos_nodes+v3s16(1,1,1)*MAP_BLOCKSIZE*2-v3s16(1,1,1));
- s32 volume = area.getVolume();
- s32 our_node_index = area.index(1,1,1);
-
- // Allocate this block + neighbors
- m_vmanip.clear();
- m_vmanip.addArea(area);
-
- // Fill in data
- MapNode *data = new MapNode[volume];
- for(s32 i = 0; i < volume; i++)
- {
- if (i == our_node_index)
- data[i] = *node;
- else
- data[i] = MapNode(CONTENT_AIR, LIGHT_MAX, 0);
- }
- m_vmanip.copyFrom(data, area, area.MinEdge, area.MinEdge, area.getExtent());
- delete[] data;
-}
-
void MeshMakeData::setCrack(int crack_level, v3s16 crack_pos)
{
if (crack_level >= 0)
@@ -419,12 +390,21 @@ static void getNodeVertexDirs(const v3s16 &dir, v3s16 *vertex_dirs)
u8 idx = (dir.X + 2 * dir.Y + 3 * dir.Z) & 7;
idx = (idx - 1) * 4;
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#if __GNUC__ > 7
+#pragma GCC diagnostic ignored "-Wclass-memaccess"
+#endif
+#endif
memcpy(vertex_dirs, &vertex_dirs_table[idx], 4 * sizeof(v3s16));
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
}
static void getNodeTextureCoords(v3f base, const v3f &scale, const v3s16 &dir, float *u, float *v)
{
- if (dir.X > 0 || dir.Y > 0 || dir.Z < 0)
+ if (dir.X > 0 || dir.Y != 0 || dir.Z < 0)
base -= scale;
if (dir == v3s16(0,0,1)) {
*u = -base.X - 1;
@@ -442,8 +422,8 @@ static void getNodeTextureCoords(v3f base, const v3f &scale, const v3s16 &dir, f
*u = base.X + 1;
*v = -base.Z - 2;
} else if (dir == v3s16(0,-1,0)) {
- *u = base.X;
- *v = base.Z;
+ *u = base.X + 1;
+ *v = base.Z + 1;
}
}
@@ -1034,10 +1014,9 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
for (auto &m : m_mesh)
m = new scene::SMesh();
m_enable_shaders = data->m_use_shaders;
- m_use_tangent_vertices = data->m_use_tangent_vertices;
m_enable_vbo = g_settings->getBool("enable_vbo");
- if (g_settings->getBool("enable_minimap")) {
+ if (data->m_client->getMinimap()) {
m_minimap_mapblock = new MinimapMapblock;
m_minimap_mapblock->getMinimapNodes(
&data->m_vmanip, data->m_blockpos * MAP_BLOCKSIZE);
@@ -1188,51 +1167,15 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
scene::SMesh *mesh = (scene::SMesh *)m_mesh[layer];
- // Create meshbuffer, add to mesh
- if (m_use_tangent_vertices) {
- scene::SMeshBufferTangents *buf =
- new scene::SMeshBufferTangents();
- buf->Material = material;
- buf->Vertices.reallocate(p.vertices.size());
- buf->Indices.reallocate(p.indices.size());
- for (const video::S3DVertex &v: p.vertices)
- buf->Vertices.push_back(video::S3DVertexTangents(v.Pos, v.Color, v.TCoords));
- for (u16 i: p.indices)
- buf->Indices.push_back(i);
- buf->recalculateBoundingBox();
- mesh->addMeshBuffer(buf);
- buf->drop();
- } else {
- scene::SMeshBuffer *buf = new scene::SMeshBuffer();
- buf->Material = material;
- buf->append(&p.vertices[0], p.vertices.size(),
- &p.indices[0], p.indices.size());
- mesh->addMeshBuffer(buf);
- buf->drop();
- }
- }
-
- /*
- Do some stuff to the mesh
- */
- m_camera_offset = camera_offset;
- translateMesh(m_mesh[layer],
- intToFloat(data->m_blockpos * MAP_BLOCKSIZE - camera_offset, BS));
-
- if (m_use_tangent_vertices) {
- scene::IMeshManipulator* meshmanip =
- RenderingEngine::get_scene_manager()->getMeshManipulator();
- meshmanip->recalculateTangents(m_mesh[layer], true, false, false);
+ scene::SMeshBuffer *buf = new scene::SMeshBuffer();
+ buf->Material = material;
+ buf->append(&p.vertices[0], p.vertices.size(),
+ &p.indices[0], p.indices.size());
+ mesh->addMeshBuffer(buf);
+ buf->drop();
}
if (m_mesh[layer]) {
-#if 0
- // Usually 1-700 faces and 1-7 materials
- std::cout << "Updated MapBlock has " << fastfaces_new.size()
- << " faces and uses " << m_mesh[layer]->getMeshBufferCount()
- << " materials (meshbuffers)" << std::endl;
-#endif
-
// Use VBO for mesh (this just would set this for ever buffer)
if (m_enable_vbo)
m_mesh[layer]->setHardwareMappingHint(scene::EHM_STATIC);
@@ -1251,13 +1194,13 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset):
MapBlockMesh::~MapBlockMesh()
{
for (scene::IMesh *m : m_mesh) {
- if (m_enable_vbo && m)
+ if (m_enable_vbo) {
for (u32 i = 0; i < m->getMeshBufferCount(); i++) {
scene::IMeshBuffer *buf = m->getMeshBuffer(i);
RenderingEngine::get_video_driver()->removeHardwareBuffer(buf);
}
+ }
m->drop();
- m = NULL;
}
delete m_minimap_mapblock;
}
@@ -1351,19 +1294,6 @@ bool MapBlockMesh::animate(bool faraway, float time, int crack,
return true;
}
-void MapBlockMesh::updateCameraOffset(v3s16 camera_offset)
-{
- if (camera_offset != m_camera_offset) {
- for (scene::IMesh *layer : m_mesh) {
- translateMesh(layer,
- intToFloat(m_camera_offset - camera_offset, BS));
- if (m_enable_vbo)
- layer->setDirty();
- }
- m_camera_offset = camera_offset;
- }
-}
-
video::SColor encode_light(u16 light, u8 emissive_light)
{
// Get components
diff --git a/src/client/mapblock_mesh.h b/src/client/mapblock_mesh.h
index 6af23a656..3b17c4af9 100644
--- a/src/client/mapblock_mesh.h
+++ b/src/client/mapblock_mesh.h
@@ -45,10 +45,8 @@ struct MeshMakeData
Client *m_client;
bool m_use_shaders;
- bool m_use_tangent_vertices;
- MeshMakeData(Client *client, bool use_shaders,
- bool use_tangent_vertices = false);
+ MeshMakeData(Client *client, bool use_shaders);
/*
Copy block data manually (to allow optimizations by the caller)
@@ -63,11 +61,6 @@ struct MeshMakeData
void fill(MapBlock *block);
/*
- Set up with only a single node at (1,1,1)
- */
- void fillSingleNode(MapNode *node);
-
- /*
Set the (node) position of a crack
*/
void setCrack(int crack_level, v3s16 crack_pos);
@@ -132,8 +125,6 @@ public:
m_animation_force_timer--;
}
- void updateCameraOffset(v3s16 camera_offset);
-
private:
scene::IMesh *m_mesh[MAX_TILE_LAYERS];
MinimapMapblock *m_minimap_mapblock;
@@ -141,7 +132,6 @@ private:
IShaderSource *m_shdrsrc;
bool m_enable_shaders;
- bool m_use_tangent_vertices;
bool m_enable_vbo;
// Must animate() be called before rendering?
@@ -168,9 +158,6 @@ private:
// of sunlit vertices
// Keys are pairs of (mesh index, buffer index in the mesh)
std::map<std::pair<u8, u32>, std::map<u32, video::SColor > > m_daynight_diffs;
-
- // Camera offset info -> do we have to translate the mesh?
- v3s16 m_camera_offset;
};
/*!
diff --git a/src/client/mesh.cpp b/src/client/mesh.cpp
index e1ec22068..2400a374c 100644
--- a/src/client/mesh.cpp
+++ b/src/client/mesh.cpp
@@ -203,6 +203,15 @@ void setMeshColor(scene::IMesh *mesh, const video::SColor &color)
setMeshBufferColor(mesh->getMeshBuffer(j), color);
}
+void setMeshBufferTextureCoords(scene::IMeshBuffer *buf, const v2f *uv, u32 count)
+{
+ const u32 stride = getVertexPitchFromType(buf->getVertexType());
+ assert(buf->getVertexCount() >= count);
+ u8 *vertices = (u8 *) buf->getVertices();
+ for (u32 i = 0; i < count; i++)
+ ((video::S3DVertex*) (vertices + i * stride))->TCoords = uv[i];
+}
+
template <typename F>
static void applyToMesh(scene::IMesh *mesh, const F &fn)
{
diff --git a/src/client/mesh.h b/src/client/mesh.h
index 103c61e45..dbc091a06 100644
--- a/src/client/mesh.h
+++ b/src/client/mesh.h
@@ -58,6 +58,13 @@ void setMeshBufferColor(scene::IMeshBuffer *buf, const video::SColor &color);
*/
void setMeshColor(scene::IMesh *mesh, const video::SColor &color);
+
+/*
+ Sets texture coords for vertices in the mesh buffer.
+ `uv[]` must have `count` elements
+*/
+void setMeshBufferTextureCoords(scene::IMeshBuffer *buf, const v2f *uv, u32 count);
+
/*
Set a constant color for an animated mesh
*/
diff --git a/src/client/mesh_generator_thread.cpp b/src/client/mesh_generator_thread.cpp
index 53b980eeb..c8d1cba26 100644
--- a/src/client/mesh_generator_thread.cpp
+++ b/src/client/mesh_generator_thread.cpp
@@ -52,9 +52,6 @@ MeshUpdateQueue::MeshUpdateQueue(Client *client):
m_client(client)
{
m_cache_enable_shaders = g_settings->getBool("enable_shaders");
- m_cache_use_tangent_vertices = m_cache_enable_shaders && (
- g_settings->getBool("enable_bumpmapping") ||
- g_settings->getBool("enable_parallax_occlusion"));
m_cache_smooth_lighting = g_settings->getBool("smooth_lighting");
m_meshgen_block_cache_size = g_settings->getS32("meshgen_block_cache_size");
}
@@ -207,8 +204,7 @@ CachedMapBlockData* MeshUpdateQueue::getCachedBlock(const v3s16 &p)
void MeshUpdateQueue::fillDataFromMapBlockCache(QueuedMeshUpdate *q)
{
- MeshMakeData *data = new MeshMakeData(m_client, m_cache_enable_shaders,
- m_cache_use_tangent_vertices);
+ MeshMakeData *data = new MeshMakeData(m_client, m_cache_enable_shaders);
q->data = data;
data->fillBlockDataBegin(q->p);
diff --git a/src/client/mesh_generator_thread.h b/src/client/mesh_generator_thread.h
index 9a42852a3..4371b8390 100644
--- a/src/client/mesh_generator_thread.h
+++ b/src/client/mesh_generator_thread.h
@@ -40,7 +40,6 @@ struct QueuedMeshUpdate
{
v3s16 p = v3s16(-1337, -1337, -1337);
bool ack_block_to_server = false;
- bool urgent = false;
int crack_level = -1;
v3s16 crack_pos;
MeshMakeData *data = nullptr; // This is generated in MeshUpdateQueue::pop()
@@ -88,7 +87,6 @@ private:
// TODO: Add callback to update these when g_settings changes
bool m_cache_enable_shaders;
- bool m_cache_use_tangent_vertices;
bool m_cache_smooth_lighting;
int m_meshgen_block_cache_size;
diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp
index 68770ec19..dd810ee0a 100644
--- a/src/client/minimap.cpp
+++ b/src/client/minimap.cpp
@@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "shader.h"
#include "mapblock.h"
#include "client/renderingengine.h"
-
+#include "gettext.h"
////
//// MinimapUpdateThread
@@ -108,8 +108,11 @@ void MinimapUpdateThread::doUpdate()
}
}
- if (data->map_invalidated && data->mode != MINIMAP_MODE_OFF) {
- getMap(data->pos, data->map_size, data->scan_height);
+
+ if (data->map_invalidated && (
+ data->mode.type == MINIMAP_TYPE_RADAR ||
+ data->mode.type == MINIMAP_TYPE_SURFACE)) {
+ getMap(data->pos, data->mode.map_size, data->mode.scan_height);
data->map_invalidated = false;
}
}
@@ -181,19 +184,26 @@ Minimap::Minimap(Client *client)
this->m_ndef = client->getNodeDefManager();
m_angle = 0.f;
+ m_current_mode_index = 0;
// Initialize static settings
m_enable_shaders = g_settings->getBool("enable_shaders");
m_surface_mode_scan_height =
g_settings->getBool("minimap_double_scan_height") ? 256 : 128;
+ // Initialize minimap modes
+ addMode(MINIMAP_TYPE_OFF);
+ addMode(MINIMAP_TYPE_SURFACE, 256);
+ addMode(MINIMAP_TYPE_SURFACE, 128);
+ addMode(MINIMAP_TYPE_SURFACE, 64);
+ addMode(MINIMAP_TYPE_RADAR, 512);
+ addMode(MINIMAP_TYPE_RADAR, 256);
+ addMode(MINIMAP_TYPE_RADAR, 128);
+
// Initialize minimap data
data = new MinimapData;
- data->mode = MINIMAP_MODE_OFF;
- data->is_radar = false;
- data->map_invalidated = true;
- data->texture = NULL;
- data->heightmap_texture = NULL;
+ data->map_invalidated = true;
+
data->minimap_shape_round = g_settings->getBool("minimap_shape_round");
// Get round minimap textures
@@ -215,6 +225,8 @@ Minimap::Minimap(Client *client)
// Create object marker texture
data->object_marker_red = m_tsrc->getTexture("object_marker_red.png");
+ setModeIndex(0);
+
// Create mesh buffer for minimap
m_meshbuffer = getMinimapMeshBuffer();
@@ -240,6 +252,10 @@ Minimap::~Minimap()
driver->removeTexture(data->minimap_overlay_square);
driver->removeTexture(data->object_marker_red);
+ for (MinimapMarker *m : m_markers)
+ delete m;
+ m_markers.clear();
+
delete data;
delete m_minimap_update_thread;
}
@@ -280,29 +296,102 @@ MinimapShape Minimap::getMinimapShape()
return MINIMAP_SHAPE_SQUARE;
}
-void Minimap::setMinimapMode(MinimapMode mode)
+void Minimap::setModeIndex(size_t index)
{
- static const MinimapModeDef modedefs[MINIMAP_MODE_COUNT] = {
- {false, 0, 0},
- {false, m_surface_mode_scan_height, 256},
- {false, m_surface_mode_scan_height, 128},
- {false, m_surface_mode_scan_height, 64},
- {true, 32, 128},
- {true, 32, 64},
- {true, 32, 32}
- };
-
- if (mode >= MINIMAP_MODE_COUNT)
- return;
-
MutexAutoLock lock(m_mutex);
- data->is_radar = modedefs[mode].is_radar;
- data->scan_height = modedefs[mode].scan_height;
- data->map_size = modedefs[mode].map_size;
- data->mode = mode;
+ if (index < m_modes.size()) {
+ data->mode = m_modes[index];
+ m_current_mode_index = index;
+ } else {
+ data->mode = MinimapModeDef{MINIMAP_TYPE_OFF, gettext("Minimap hidden"), 0, 0, ""};
+ m_current_mode_index = 0;
+ }
- m_minimap_update_thread->deferUpdate();
+ data->map_invalidated = true;
+
+ if (m_minimap_update_thread)
+ m_minimap_update_thread->deferUpdate();
+}
+
+void Minimap::addMode(MinimapModeDef mode)
+{
+ // Check validity
+ if (mode.type == MINIMAP_TYPE_TEXTURE) {
+ if (mode.texture.empty())
+ return;
+ if (mode.scale < 1)
+ mode.scale = 1;
+ }
+
+ int zoom = -1;
+
+ // Build a default standard label
+ if (mode.label == "") {
+ switch (mode.type) {
+ case MINIMAP_TYPE_OFF:
+ mode.label = gettext("Minimap hidden");
+ break;
+ case MINIMAP_TYPE_SURFACE:
+ mode.label = gettext("Minimap in surface mode, Zoom x%d");
+ if (mode.map_size > 0)
+ zoom = 256 / mode.map_size;
+ break;
+ case MINIMAP_TYPE_RADAR:
+ mode.label = gettext("Minimap in radar mode, Zoom x%d");
+ if (mode.map_size > 0)
+ zoom = 512 / mode.map_size;
+ break;
+ case MINIMAP_TYPE_TEXTURE:
+ mode.label = gettext("Minimap in texture mode");
+ break;
+ default:
+ break;
+ }
+ }
+ // else: Custom labels need mod-provided client-side translation
+
+ if (zoom >= 0) {
+ char label_buf[1024];
+ porting::mt_snprintf(label_buf, sizeof(label_buf),
+ mode.label.c_str(), zoom);
+ mode.label = label_buf;
+ }
+
+ m_modes.push_back(mode);
+}
+
+void Minimap::addMode(MinimapType type, u16 size, std::string label,
+ std::string texture, u16 scale)
+{
+ MinimapModeDef mode;
+ mode.type = type;
+ mode.label = label;
+ mode.map_size = size;
+ mode.texture = texture;
+ mode.scale = scale;
+ switch (type) {
+ case MINIMAP_TYPE_SURFACE:
+ mode.scan_height = m_surface_mode_scan_height;
+ break;
+ case MINIMAP_TYPE_RADAR:
+ mode.scan_height = 32;
+ break;
+ default:
+ mode.scan_height = 0;
+ }
+ addMode(mode);
+}
+
+void Minimap::nextMode()
+{
+ if (m_modes.empty())
+ return;
+ m_current_mode_index++;
+ if (m_current_mode_index >= m_modes.size())
+ m_current_mode_index = 0;
+
+ setModeIndex(m_current_mode_index);
}
void Minimap::setPos(v3s16 pos)
@@ -331,16 +420,16 @@ void Minimap::setAngle(f32 angle)
void Minimap::blitMinimapPixelsToImageRadar(video::IImage *map_image)
{
video::SColor c(240, 0, 0, 0);
- for (s16 x = 0; x < data->map_size; x++)
- for (s16 z = 0; z < data->map_size; z++) {
- MinimapPixel *mmpixel = &data->minimap_scan[x + z * data->map_size];
+ for (s16 x = 0; x < data->mode.map_size; x++)
+ for (s16 z = 0; z < data->mode.map_size; z++) {
+ MinimapPixel *mmpixel = &data->minimap_scan[x + z * data->mode.map_size];
if (mmpixel->air_count > 0)
c.setGreen(core::clamp(core::round32(32 + mmpixel->air_count * 8), 0, 255));
else
c.setGreen(0);
- map_image->setPixel(x, data->map_size - z - 1, c);
+ map_image->setPixel(x, data->mode.map_size - z - 1, c);
}
}
@@ -349,9 +438,9 @@ void Minimap::blitMinimapPixelsToImageSurface(
{
// This variable creation/destruction has a 1% cost on rendering minimap
video::SColor tilecolor;
- for (s16 x = 0; x < data->map_size; x++)
- for (s16 z = 0; z < data->map_size; z++) {
- MinimapPixel *mmpixel = &data->minimap_scan[x + z * data->map_size];
+ for (s16 x = 0; x < data->mode.map_size; x++)
+ for (s16 z = 0; z < data->mode.map_size; z++) {
+ MinimapPixel *mmpixel = &data->minimap_scan[x + z * data->mode.map_size];
const ContentFeatures &f = m_ndef->get(mmpixel->n);
const TileDef *tile = &f.tiledef[0];
@@ -367,10 +456,10 @@ void Minimap::blitMinimapPixelsToImageSurface(
tilecolor.setBlue(tilecolor.getBlue() * f.minimap_color.getBlue() / 255);
tilecolor.setAlpha(240);
- map_image->setPixel(x, data->map_size - z - 1, tilecolor);
+ map_image->setPixel(x, data->mode.map_size - z - 1, tilecolor);
u32 h = mmpixel->height;
- heightmap_image->setPixel(x,data->map_size - z - 1,
+ heightmap_image->setPixel(x,data->mode.map_size - z - 1,
video::SColor(255, h, h, h));
}
}
@@ -378,21 +467,46 @@ void Minimap::blitMinimapPixelsToImageSurface(
video::ITexture *Minimap::getMinimapTexture()
{
// update minimap textures when new scan is ready
- if (data->map_invalidated)
+ if (data->map_invalidated && data->mode.type != MINIMAP_TYPE_TEXTURE)
return data->texture;
// create minimap and heightmap images in memory
- core::dimension2d<u32> dim(data->map_size, data->map_size);
+ core::dimension2d<u32> dim(data->mode.map_size, data->mode.map_size);
video::IImage *map_image = driver->createImage(video::ECF_A8R8G8B8, dim);
video::IImage *heightmap_image = driver->createImage(video::ECF_A8R8G8B8, dim);
video::IImage *minimap_image = driver->createImage(video::ECF_A8R8G8B8,
core::dimension2d<u32>(MINIMAP_MAX_SX, MINIMAP_MAX_SY));
// Blit MinimapPixels to images
- if (data->is_radar)
- blitMinimapPixelsToImageRadar(map_image);
- else
+ switch(data->mode.type) {
+ case MINIMAP_TYPE_OFF:
+ break;
+ case MINIMAP_TYPE_SURFACE:
blitMinimapPixelsToImageSurface(map_image, heightmap_image);
+ break;
+ case MINIMAP_TYPE_RADAR:
+ blitMinimapPixelsToImageRadar(map_image);
+ break;
+ case MINIMAP_TYPE_TEXTURE:
+ // 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->unlock();
+
+ auto dim = image->getDimension();
+
+ map_image->fill(video::SColor(255, 0, 0, 0));
+
+ image->copyTo(map_image,
+ irr::core::vector2d<int> {
+ ((data->mode.map_size - (static_cast<int>(dim.Width))) >> 1)
+ - data->pos.X / data->mode.scale,
+ ((data->mode.map_size - (static_cast<int>(dim.Height))) >> 1)
+ + data->pos.Z / data->mode.scale
+ });
+ image->drop();
+ }
map_image->copyToScaling(minimap_image);
map_image->drop();
@@ -461,21 +575,31 @@ scene::SMeshBuffer *Minimap::getMinimapMeshBuffer()
void Minimap::drawMinimap()
{
+ // Non hud managed minimap drawing (legacy minimap)
+ v2u32 screensize = RenderingEngine::get_instance()->getWindowSize();
+ const u32 size = 0.25 * screensize.Y;
+
+ drawMinimap(core::rect<s32>(
+ screensize.X - size - 10, 10,
+ screensize.X - 10, size + 10));
+}
+
+void Minimap::drawMinimap(core::rect<s32> rect) {
+
video::ITexture *minimap_texture = getMinimapTexture();
if (!minimap_texture)
return;
+ if (data->mode.type == MINIMAP_TYPE_OFF)
+ return;
+
updateActiveMarkers();
- v2u32 screensize = RenderingEngine::get_instance()->getWindowSize();
- const u32 size = 0.25 * screensize.Y;
core::rect<s32> oldViewPort = driver->getViewPort();
core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION);
core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW);
- driver->setViewPort(core::rect<s32>(
- screensize.X - size - 10, 10,
- screensize.X - 10, size + 10));
+ driver->setViewPort(rect);
driver->setTransform(video::ETS_PROJECTION, core::matrix4());
driver->setTransform(video::ETS_VIEW, core::matrix4());
@@ -488,8 +612,8 @@ void Minimap::drawMinimap()
material.TextureLayer[0].Texture = minimap_texture;
material.TextureLayer[1].Texture = data->heightmap_texture;
- if (m_enable_shaders && !data->is_radar) {
- u16 sid = m_shdrsrc->getShader("minimap_shader", 1, 1);
+ if (m_enable_shaders && data->mode.type == MINIMAP_TYPE_SURFACE) {
+ u16 sid = m_shdrsrc->getShader("minimap_shader", TILE_MATERIAL_ALPHA);
material.MaterialType = m_shdrsrc->getShaderInfo(sid).material;
} else {
material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
@@ -529,14 +653,14 @@ void Minimap::drawMinimap()
driver->setViewPort(oldViewPort);
// Draw player markers
- v2s32 s_pos(screensize.X - size - 10, 10);
+ v2s32 s_pos(rect.UpperLeftCorner.X, rect.UpperLeftCorner.Y);
core::dimension2di imgsize(data->object_marker_red->getOriginalSize());
core::rect<s32> img_rect(0, 0, imgsize.Width, imgsize.Height);
static const video::SColor col(255, 255, 255, 255);
static const video::SColor c[4] = {col, col, col, col};
f32 sin_angle = std::sin(m_angle * core::DEGTORAD);
f32 cos_angle = std::cos(m_angle * core::DEGTORAD);
- s32 marker_size2 = 0.025 * (float)size;
+ s32 marker_size2 = 0.025 * (float)rect.getWidth();;
for (std::list<v2f>::const_iterator
i = m_active_markers.begin();
i != m_active_markers.end(); ++i) {
@@ -547,8 +671,8 @@ void Minimap::drawMinimap()
posf.X = t1;
posf.Y = t2;
}
- posf.X = (posf.X + 0.5) * (float)size;
- posf.Y = (posf.Y + 0.5) * (float)size;
+ posf.X = (posf.X + 0.5) * (float)rect.getWidth();
+ posf.Y = (posf.Y + 0.5) * (float)rect.getHeight();
core::rect<s32> dest_rect(
s_pos.X + posf.X - marker_size2,
s_pos.Y + posf.Y - marker_size2,
@@ -559,28 +683,41 @@ void Minimap::drawMinimap()
}
}
+MinimapMarker* Minimap::addMarker(scene::ISceneNode *parent_node)
+{
+ MinimapMarker *m = new MinimapMarker(parent_node);
+ m_markers.push_back(m);
+ return m;
+}
+
+void Minimap::removeMarker(MinimapMarker **m)
+{
+ m_markers.remove(*m);
+ delete *m;
+ *m = nullptr;
+}
+
void Minimap::updateActiveMarkers()
{
video::IImage *minimap_mask = data->minimap_shape_round ?
data->minimap_mask_round : data->minimap_mask_square;
- const std::list<Nametag *> &nametags = client->getCamera()->getNametags();
-
m_active_markers.clear();
-
- for (Nametag *nametag : nametags) {
- v3s16 pos = floatToInt(nametag->parent_node->getAbsolutePosition() +
- intToFloat(client->getCamera()->getOffset(), BS), BS);
- pos -= data->pos - v3s16(data->map_size / 2,
- data->scan_height / 2,
- data->map_size / 2);
- if (pos.X < 0 || pos.X > data->map_size ||
- pos.Y < 0 || pos.Y > data->scan_height ||
- pos.Z < 0 || pos.Z > data->map_size) {
+ v3f cam_offset = intToFloat(client->getCamera()->getOffset(), BS);
+ v3s16 pos_offset = data->pos - v3s16(data->mode.map_size / 2,
+ data->mode.scan_height / 2,
+ data->mode.map_size / 2);
+
+ for (MinimapMarker *marker : m_markers) {
+ v3s16 pos = floatToInt(marker->parent_node->getAbsolutePosition() +
+ cam_offset, BS) - pos_offset;
+ if (pos.X < 0 || pos.X > data->mode.map_size ||
+ pos.Y < 0 || pos.Y > data->mode.scan_height ||
+ pos.Z < 0 || pos.Z > data->mode.map_size) {
continue;
}
- pos.X = ((float)pos.X / data->map_size) * MINIMAP_MAX_SX;
- pos.Z = ((float)pos.Z / data->map_size) * MINIMAP_MAX_SY;
+ pos.X = ((float)pos.X / data->mode.map_size) * MINIMAP_MAX_SX;
+ pos.Z = ((float)pos.Z / data->mode.map_size) * MINIMAP_MAX_SY;
const video::SColor &mask_col = minimap_mask->getPixel(pos.X, pos.Z);
if (!mask_col.getAlpha()) {
continue;
diff --git a/src/client/minimap.h b/src/client/minimap.h
index 258d5330d..87c9668ee 100644
--- a/src/client/minimap.h
+++ b/src/client/minimap.h
@@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
+#include "../hud.h"
#include "irrlichttypes_extrabloated.h"
#include "util/thread.h"
#include "voxel.h"
@@ -33,28 +34,27 @@ class IShaderSource;
#define MINIMAP_MAX_SX 512
#define MINIMAP_MAX_SY 512
-enum MinimapMode {
- MINIMAP_MODE_OFF,
- MINIMAP_MODE_SURFACEx1,
- MINIMAP_MODE_SURFACEx2,
- MINIMAP_MODE_SURFACEx4,
- MINIMAP_MODE_RADARx1,
- MINIMAP_MODE_RADARx2,
- MINIMAP_MODE_RADARx4,
- MINIMAP_MODE_COUNT,
-};
-
enum MinimapShape {
MINIMAP_SHAPE_SQUARE,
MINIMAP_SHAPE_ROUND,
};
struct MinimapModeDef {
- bool is_radar;
+ MinimapType type;
+ std::string label;
u16 scan_height;
u16 map_size;
+ std::string texture;
+ u16 scale;
};
+struct MinimapMarker {
+ MinimapMarker(scene::ISceneNode *parent_node):
+ parent_node(parent_node)
+ {
+ }
+ scene::ISceneNode *parent_node;
+};
struct MinimapPixel {
//! The topmost node that the minimap displays.
MapNode n;
@@ -69,12 +69,9 @@ struct MinimapMapblock {
};
struct MinimapData {
- bool is_radar;
- MinimapMode mode;
+ MinimapModeDef mode;
v3s16 pos;
v3s16 old_pos;
- u16 scan_height;
- u16 map_size;
MinimapPixel minimap_scan[MINIMAP_MAX_SX * MINIMAP_MAX_SY];
bool map_invalidated;
bool minimap_shape_round;
@@ -127,12 +124,21 @@ public:
v3s16 getPos() const { return data->pos; }
void setAngle(f32 angle);
f32 getAngle() const { return m_angle; }
- void setMinimapMode(MinimapMode mode);
- MinimapMode getMinimapMode() const { return data->mode; }
void toggleMinimapShape();
void setMinimapShape(MinimapShape shape);
MinimapShape getMinimapShape();
+ void clearModes() { m_modes.clear(); };
+ void addMode(MinimapModeDef mode);
+ void addMode(MinimapType type, u16 size = 0, std::string label = "",
+ std::string texture = "", u16 scale = 1);
+
+ void setModeIndex(size_t index);
+ size_t getModeIndex() const { return m_current_mode_index; };
+ size_t getMaxModeIndex() const { return m_modes.size() - 1; };
+ void nextMode();
+
+ MinimapModeDef getModeDef() const { return data->mode; }
video::ITexture *getMinimapTexture();
@@ -142,8 +148,12 @@ public:
scene::SMeshBuffer *getMinimapMeshBuffer();
+ MinimapMarker* addMarker(scene::ISceneNode *parent_node);
+ void removeMarker(MinimapMarker **marker);
+
void updateActiveMarkers();
void drawMinimap();
+ void drawMinimap(core::rect<s32> rect);
video::IVideoDriver *driver;
Client* client;
@@ -153,11 +163,14 @@ private:
ITextureSource *m_tsrc;
IShaderSource *m_shdrsrc;
const NodeDefManager *m_ndef;
- MinimapUpdateThread *m_minimap_update_thread;
+ MinimapUpdateThread *m_minimap_update_thread = nullptr;
scene::SMeshBuffer *m_meshbuffer;
bool m_enable_shaders;
+ std::vector<MinimapModeDef> m_modes;
+ size_t m_current_mode_index;
u16 m_surface_mode_scan_height;
f32 m_angle;
std::mutex m_mutex;
+ std::list<MinimapMarker*> m_markers;
std::list<v2f> m_active_markers;
};
diff --git a/src/client/render/core.cpp b/src/client/render/core.cpp
index bf5aa6c2c..92a7137ea 100644
--- a/src/client/render/core.cpp
+++ b/src/client/render/core.cpp
@@ -86,6 +86,7 @@ void RenderingCore::drawHUD()
if (show_hud) {
if (draw_crosshair)
hud->drawCrosshair();
+
hud->drawHotbar(client->getEnv().getLocalPlayer()->getWieldIndex());
hud->drawLuaElements(camera->getOffset());
camera->drawNametags();
diff --git a/src/client/render/factory.cpp b/src/client/render/factory.cpp
index 30f9480fc..7fcec40dd 100644
--- a/src/client/render/factory.cpp
+++ b/src/client/render/factory.cpp
@@ -19,7 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "factory.h"
-#include <stdexcept>
+#include "log.h"
#include "plain.h"
#include "anaglyph.h"
#include "interlaced.h"
@@ -45,5 +45,8 @@ RenderingCore *createRenderingCore(const std::string &stereo_mode, IrrlichtDevic
return new RenderingCoreSideBySide(device, client, hud, true);
if (stereo_mode == "crossview")
return new RenderingCoreSideBySide(device, client, hud, false, true);
- throw std::invalid_argument("Invalid rendering mode: " + stereo_mode);
+
+ // fallback to plain renderer
+ errorstream << "Invalid rendering mode: " << stereo_mode << std::endl;
+ return new RenderingCorePlain(device, client, hud);
}
diff --git a/src/client/render/interlaced.cpp b/src/client/render/interlaced.cpp
index 2aadadc17..ce8e92f21 100644
--- a/src/client/render/interlaced.cpp
+++ b/src/client/render/interlaced.cpp
@@ -36,7 +36,7 @@ void RenderingCoreInterlaced::initMaterial()
mat.UseMipMaps = false;
mat.ZBuffer = false;
mat.ZWriteEnable = false;
- u32 shader = s->getShader("3d_interlaced_merge", TILE_MATERIAL_BASIC, 0);
+ u32 shader = s->getShader("3d_interlaced_merge", TILE_MATERIAL_BASIC);
mat.MaterialType = s->getShaderInfo(shader).material;
for (int k = 0; k < 3; ++k) {
mat.TextureLayer[k].AnisotropicFilter = false;
diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp
index f5aca8f58..99ff8c1ee 100644
--- a/src/client/renderingengine.cpp
+++ b/src/client/renderingengine.cpp
@@ -153,7 +153,7 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver)
RenderingEngine::~RenderingEngine()
{
core.reset();
- m_device->drop();
+ m_device->closeDevice();
s_singleton = nullptr;
}
diff --git a/src/client/shader.cpp b/src/client/shader.cpp
index ee6079f7a..b3e4911f4 100644
--- a/src/client/shader.cpp
+++ b/src/client/shader.cpp
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <iterator>
#include "shader.h"
#include "irrlichttypes_extrabloated.h"
+#include "irr_ptr.h"
#include "debug.h"
#include "filesys.h"
#include "util/container.h"
@@ -37,6 +38,22 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "log.h"
#include "gamedef.h"
#include "client/tile.h"
+#include "config.h"
+
+#if ENABLE_GLES
+#ifdef _IRR_COMPILE_WITH_OGLES1_
+#include <GLES/gl.h>
+#else
+#include <GLES2/gl2.h>
+#endif
+#else
+#ifndef __APPLE__
+#include <GL/gl.h>
+#else
+#define GL_SILENCE_DEPRECATION
+#include <OpenGL/gl.h>
+#endif
+#endif
/*
A cache from shader name to shader path
@@ -173,19 +190,14 @@ private:
class ShaderCallback : public video::IShaderConstantSetCallBack
{
- std::vector<IShaderConstantSetter*> m_setters;
+ std::vector<std::unique_ptr<IShaderConstantSetter>> m_setters;
public:
- ShaderCallback(const std::vector<IShaderConstantSetterFactory *> &factories)
+ template <typename Factories>
+ ShaderCallback(const Factories &factories)
{
- for (IShaderConstantSetterFactory *factory : factories)
- m_setters.push_back(factory->create());
- }
-
- ~ShaderCallback()
- {
- for (IShaderConstantSetter *setter : m_setters)
- delete setter;
+ for (auto &&factory : factories)
+ m_setters.push_back(std::unique_ptr<IShaderConstantSetter>(factory->create()));
}
virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override
@@ -193,15 +205,13 @@ public:
video::IVideoDriver *driver = services->getVideoDriver();
sanity_check(driver != NULL);
- bool is_highlevel = userData;
-
- for (IShaderConstantSetter *setter : m_setters)
- setter->onSetConstants(services, is_highlevel);
+ for (auto &&setter : m_setters)
+ setter->onSetConstants(services);
}
virtual void OnSetMaterial(const video::SMaterial& material) override
{
- for (IShaderConstantSetter *setter : m_setters)
+ for (auto &&setter : m_setters)
setter->onSetMaterial(material);
}
};
@@ -215,37 +225,61 @@ class MainShaderConstantSetter : public IShaderConstantSetter
{
CachedVertexShaderSetting<float, 16> m_world_view_proj;
CachedVertexShaderSetting<float, 16> m_world;
+#if ENABLE_GLES
+ // Modelview matrix
+ CachedVertexShaderSetting<float, 16> m_world_view;
+ // Texture matrix
+ CachedVertexShaderSetting<float, 16> m_texture;
+ // Normal matrix
+ CachedVertexShaderSetting<float, 9> m_normal;
+#endif
public:
MainShaderConstantSetter() :
- m_world_view_proj("mWorldViewProj"),
- m_world("mWorld")
+ m_world_view_proj("mWorldViewProj")
+ , m_world("mWorld")
+#if ENABLE_GLES
+ , m_world_view("mWorldView")
+ , m_texture("mTexture")
+ , m_normal("mNormal")
+#endif
{}
~MainShaderConstantSetter() = default;
- virtual void onSetConstants(video::IMaterialRendererServices *services,
- bool is_highlevel)
+ virtual void onSetConstants(video::IMaterialRendererServices *services) override
{
video::IVideoDriver *driver = services->getVideoDriver();
sanity_check(driver);
- // Set clip matrix
- core::matrix4 worldViewProj;
- worldViewProj = driver->getTransform(video::ETS_PROJECTION);
- worldViewProj *= driver->getTransform(video::ETS_VIEW);
- worldViewProj *= driver->getTransform(video::ETS_WORLD);
- if (is_highlevel)
- m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
- else
- services->setVertexShaderConstant(worldViewProj.pointer(), 0, 4);
-
// Set world matrix
core::matrix4 world = driver->getTransform(video::ETS_WORLD);
- if (is_highlevel)
- m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
- else
- services->setVertexShaderConstant(world.pointer(), 4, 4);
+ m_world.set(*reinterpret_cast<float(*)[16]>(world.pointer()), services);
+
+ // Set clip matrix
+ core::matrix4 worldView;
+ worldView = driver->getTransform(video::ETS_VIEW);
+ worldView *= world;
+ core::matrix4 worldViewProj;
+ worldViewProj = driver->getTransform(video::ETS_PROJECTION);
+ worldViewProj *= worldView;
+ m_world_view_proj.set(*reinterpret_cast<float(*)[16]>(worldViewProj.pointer()), services);
+
+#if ENABLE_GLES
+ core::matrix4 texture = driver->getTransform(video::ETS_TEXTURE_0);
+ m_world_view.set(*reinterpret_cast<float(*)[16]>(worldView.pointer()), services);
+ m_texture.set(*reinterpret_cast<float(*)[16]>(texture.pointer()), services);
+
+ core::matrix4 normal;
+ worldView.getTransposed(normal);
+ sanity_check(normal.makeInverse());
+ float m[9] = {
+ normal[0], normal[1], normal[2],
+ normal[4], normal[5], normal[6],
+ normal[8], normal[9], normal[10],
+ };
+ m_normal.set(m, services);
+#endif
}
};
@@ -266,7 +300,6 @@ class ShaderSource : public IWritableShaderSource
{
public:
ShaderSource();
- ~ShaderSource();
/*
- If shader material specified by name is found from cache,
@@ -276,7 +309,7 @@ public:
The id 0 points to a null shader. Its material is EMT_SOLID.
*/
u32 getShaderIdDirect(const std::string &name,
- const u8 material_type, const u8 drawtype);
+ MaterialType material_type, NodeDrawType drawtype) override;
/*
If shader specified by the name pointed by the id doesn't
@@ -288,26 +321,26 @@ public:
*/
u32 getShader(const std::string &name,
- const u8 material_type, const u8 drawtype);
+ MaterialType material_type, NodeDrawType drawtype) override;
- ShaderInfo getShaderInfo(u32 id);
+ ShaderInfo getShaderInfo(u32 id) override;
// Processes queued shader requests from other threads.
// Shall be called from the main thread.
- void processQueue();
+ void processQueue() override;
// Insert a shader program into the cache without touching the
// filesystem. Shall be called from the main thread.
void insertSourceShader(const std::string &name_of_shader,
- const std::string &filename, const std::string &program);
+ const std::string &filename, const std::string &program) override;
// Rebuild shaders from the current set of source shaders
// Shall be called from the main thread.
- void rebuildShaders();
+ void rebuildShaders() override;
- void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter)
+ void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter) override
{
- m_setter_factories.push_back(setter);
+ m_setter_factories.push_back(std::unique_ptr<IShaderConstantSetterFactory>(setter));
}
private:
@@ -329,10 +362,11 @@ private:
RequestQueue<std::string, u32, u8, u8> m_get_shader_queue;
// Global constant setter factories
- std::vector<IShaderConstantSetterFactory *> m_setter_factories;
+ std::vector<std::unique_ptr<IShaderConstantSetterFactory>> m_setter_factories;
- // Shader callbacks
- std::vector<ShaderCallback *> m_callbacks;
+ // Generate shader given the shader name.
+ ShaderInfo generateShader(const std::string &name,
+ MaterialType material_type, NodeDrawType drawtype);
};
IWritableShaderSource *createShaderSource()
@@ -340,22 +374,6 @@ IWritableShaderSource *createShaderSource()
return new ShaderSource();
}
-/*
- Generate shader given the shader name.
-*/
-ShaderInfo generate_shader(const std::string &name,
- u8 material_type, u8 drawtype, std::vector<ShaderCallback *> &callbacks,
- const std::vector<IShaderConstantSetterFactory *> &setter_factories,
- SourceShaderCache *sourcecache);
-
-/*
- Load shader programs
-*/
-void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
- video::E_DRIVER_TYPE drivertype, bool enable_shaders,
- std::string &vertex_program, std::string &pixel_program,
- std::string &geometry_program, bool &is_highlevel);
-
ShaderSource::ShaderSource()
{
m_main_thread = std::this_thread::get_id();
@@ -367,18 +385,8 @@ ShaderSource::ShaderSource()
addShaderConstantSetterFactory(new MainShaderConstantSetterFactory());
}
-ShaderSource::~ShaderSource()
-{
- for (ShaderCallback *callback : m_callbacks) {
- delete callback;
- }
- for (IShaderConstantSetterFactory *setter_factorie : m_setter_factories) {
- delete setter_factorie;
- }
-}
-
u32 ShaderSource::getShader(const std::string &name,
- const u8 material_type, const u8 drawtype)
+ MaterialType material_type, NodeDrawType drawtype)
{
/*
Get shader
@@ -420,7 +428,7 @@ u32 ShaderSource::getShader(const std::string &name,
This method generates all the shaders
*/
u32 ShaderSource::getShaderIdDirect(const std::string &name,
- const u8 material_type, const u8 drawtype)
+ MaterialType material_type, NodeDrawType drawtype)
{
//infostream<<"getShaderIdDirect(): name=\""<<name<<"\""<<std::endl;
@@ -447,8 +455,7 @@ u32 ShaderSource::getShaderIdDirect(const std::string &name,
return 0;
}
- ShaderInfo info = generate_shader(name, material_type, drawtype,
- m_callbacks, m_setter_factories, &m_sourcecache);
+ ShaderInfo info = generateShader(name, material_type, drawtype);
/*
Add shader to caches (add dummy shaders too)
@@ -512,24 +519,19 @@ void ShaderSource::rebuildShaders()
for (ShaderInfo &i : m_shaderinfo_cache) {
ShaderInfo *info = &i;
if (!info->name.empty()) {
- *info = generate_shader(info->name, info->material_type,
- info->drawtype, m_callbacks,
- m_setter_factories, &m_sourcecache);
+ *info = generateShader(info->name, info->material_type, info->drawtype);
}
}
}
-ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtype,
- std::vector<ShaderCallback *> &callbacks,
- const std::vector<IShaderConstantSetterFactory *> &setter_factories,
- SourceShaderCache *sourcecache)
+ShaderInfo ShaderSource::generateShader(const std::string &name,
+ MaterialType material_type, NodeDrawType drawtype)
{
ShaderInfo shaderinfo;
shaderinfo.name = name;
shaderinfo.material_type = material_type;
shaderinfo.drawtype = drawtype;
- shaderinfo.material = video::EMT_SOLID;
switch (material_type) {
case TILE_MATERIAL_OPAQUE:
case TILE_MATERIAL_LIQUID_OPAQUE:
@@ -550,326 +552,171 @@ ShaderInfo generate_shader(const std::string &name, u8 material_type, u8 drawtyp
shaderinfo.base_material = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
break;
}
+ shaderinfo.material = shaderinfo.base_material;
bool enable_shaders = g_settings->getBool("enable_shaders");
if (!enable_shaders)
return shaderinfo;
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
-
- video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
- if(!gpu){
- errorstream<<"generate_shader(): "
- "failed to generate \""<<name<<"\", "
- "GPU programming not supported."
- <<std::endl;
+ if (!driver->queryFeature(video::EVDF_ARB_GLSL)) {
+ errorstream << "Shaders are enabled but GLSL is not supported by the driver\n";
return shaderinfo;
}
-
- // Choose shader language depending on driver type and settings
- // Then load shaders
- std::string vertex_program;
- std::string pixel_program;
- std::string geometry_program;
- bool is_highlevel;
- load_shaders(name, sourcecache, driver->getDriverType(),
- enable_shaders, vertex_program, pixel_program,
- geometry_program, is_highlevel);
- // Check hardware/driver support
- if (!vertex_program.empty() &&
- !driver->queryFeature(video::EVDF_VERTEX_SHADER_1_1) &&
- !driver->queryFeature(video::EVDF_ARB_VERTEX_PROGRAM_1)){
- infostream<<"generate_shader(): vertex shaders disabled "
- "because of missing driver/hardware support."
- <<std::endl;
- vertex_program = "";
- }
- if (!pixel_program.empty() &&
- !driver->queryFeature(video::EVDF_PIXEL_SHADER_1_1) &&
- !driver->queryFeature(video::EVDF_ARB_FRAGMENT_PROGRAM_1)){
- infostream<<"generate_shader(): pixel shaders disabled "
- "because of missing driver/hardware support."
- <<std::endl;
- pixel_program = "";
- }
- if (!geometry_program.empty() &&
- !driver->queryFeature(video::EVDF_GEOMETRY_SHADER)){
- infostream<<"generate_shader(): geometry shaders disabled "
- "because of missing driver/hardware support."
- <<std::endl;
- geometry_program = "";
- }
-
- // If no shaders are used, don't make a separate material type
- if (vertex_program.empty() && pixel_program.empty() && geometry_program.empty())
- return shaderinfo;
+ video::IGPUProgrammingServices *gpu = driver->getGPUProgrammingServices();
// Create shaders header
- std::string shaders_header = "#version 120\n";
-
- static const char* drawTypes[] = {
- "NDT_NORMAL",
- "NDT_AIRLIKE",
- "NDT_LIQUID",
- "NDT_FLOWINGLIQUID",
- "NDT_GLASSLIKE",
- "NDT_ALLFACES",
- "NDT_ALLFACES_OPTIONAL",
- "NDT_TORCHLIKE",
- "NDT_SIGNLIKE",
- "NDT_PLANTLIKE",
- "NDT_FENCELIKE",
- "NDT_RAILLIKE",
- "NDT_NODEBOX",
- "NDT_GLASSLIKE_FRAMED",
- "NDT_FIRELIKE",
- "NDT_GLASSLIKE_FRAMED_OPTIONAL",
- "NDT_PLANTLIKE_ROOTED",
- };
-
- for (int i = 0; i < 14; i++){
- shaders_header += "#define ";
- shaders_header += drawTypes[i];
- shaders_header += " ";
- shaders_header += itos(i);
- shaders_header += "\n";
- }
-
- static const char* materialTypes[] = {
- "TILE_MATERIAL_BASIC",
- "TILE_MATERIAL_ALPHA",
- "TILE_MATERIAL_LIQUID_TRANSPARENT",
- "TILE_MATERIAL_LIQUID_OPAQUE",
- "TILE_MATERIAL_WAVING_LEAVES",
- "TILE_MATERIAL_WAVING_PLANTS",
- "TILE_MATERIAL_OPAQUE",
- "TILE_MATERIAL_WAVING_LIQUID_BASIC",
- "TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT",
- "TILE_MATERIAL_WAVING_LIQUID_OPAQUE",
- "TILE_MATERIAL_PLAIN",
- "TILE_MATERIAL_PLAIN_ALPHA",
- };
-
- for (int i = 0; i < 12; i++){
- shaders_header += "#define ";
- shaders_header += materialTypes[i];
- shaders_header += " ";
- shaders_header += itos(i);
- shaders_header += "\n";
- }
-
- shaders_header += "#define MATERIAL_TYPE ";
- shaders_header += itos(material_type);
- shaders_header += "\n";
- shaders_header += "#define DRAW_TYPE ";
- shaders_header += itos(drawtype);
- shaders_header += "\n";
-
- if (g_settings->getBool("generate_normalmaps")) {
- shaders_header += "#define GENERATE_NORMALMAPS 1\n";
+ bool use_gles = false;
+#if ENABLE_GLES
+ use_gles = driver->getDriverType() == video::EDT_OGLES2;
+#endif
+ std::stringstream shaders_header;
+ shaders_header
+ << std::noboolalpha
+ << std::showpoint // for GLSL ES
+ ;
+ std::string vertex_header, fragment_header, geometry_header;
+ if (use_gles) {
+ shaders_header << R"(
+ #version 100
+ )";
+ vertex_header = R"(
+ uniform highp mat4 mWorldView;
+ uniform highp mat4 mWorldViewProj;
+ uniform mediump mat4 mTexture;
+ uniform mediump mat3 mNormal;
+
+ attribute highp vec4 inVertexPosition;
+ attribute lowp vec4 inVertexColor;
+ attribute mediump vec4 inTexCoord0;
+ attribute mediump vec3 inVertexNormal;
+ attribute mediump vec4 inVertexTangent;
+ attribute mediump vec4 inVertexBinormal;
+ )";
+ fragment_header = R"(
+ precision mediump float;
+ )";
} else {
- shaders_header += "#define GENERATE_NORMALMAPS 0\n";
- }
- shaders_header += "#define NORMALMAPS_STRENGTH ";
- shaders_header += ftos(g_settings->getFloat("normalmaps_strength"));
- shaders_header += "\n";
- float sample_step;
- int smooth = (int)g_settings->getFloat("normalmaps_smooth");
- switch (smooth){
- case 0:
- sample_step = 0.0078125; // 1.0 / 128.0
- break;
- case 1:
- sample_step = 0.00390625; // 1.0 / 256.0
- break;
- case 2:
- sample_step = 0.001953125; // 1.0 / 512.0
- break;
- default:
- sample_step = 0.0078125;
- break;
- }
- shaders_header += "#define SAMPLE_STEP ";
- shaders_header += ftos(sample_step);
- shaders_header += "\n";
-
- if (g_settings->getBool("enable_bumpmapping"))
- shaders_header += "#define ENABLE_BUMPMAPPING\n";
-
- if (g_settings->getBool("enable_parallax_occlusion")){
- int mode = g_settings->getFloat("parallax_occlusion_mode");
- float scale = g_settings->getFloat("parallax_occlusion_scale");
- float bias = g_settings->getFloat("parallax_occlusion_bias");
- int iterations = g_settings->getFloat("parallax_occlusion_iterations");
- shaders_header += "#define ENABLE_PARALLAX_OCCLUSION\n";
- shaders_header += "#define PARALLAX_OCCLUSION_MODE ";
- shaders_header += itos(mode);
- shaders_header += "\n";
- shaders_header += "#define PARALLAX_OCCLUSION_SCALE ";
- shaders_header += ftos(scale);
- shaders_header += "\n";
- shaders_header += "#define PARALLAX_OCCLUSION_BIAS ";
- shaders_header += ftos(bias);
- shaders_header += "\n";
- shaders_header += "#define PARALLAX_OCCLUSION_ITERATIONS ";
- shaders_header += itos(iterations);
- shaders_header += "\n";
- }
-
- shaders_header += "#define USE_NORMALMAPS ";
- if (g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion"))
- shaders_header += "1\n";
- else
- shaders_header += "0\n";
-
- if (g_settings->getBool("enable_waving_water")){
- shaders_header += "#define ENABLE_WAVING_WATER 1\n";
- shaders_header += "#define WATER_WAVE_HEIGHT ";
- shaders_header += ftos(g_settings->getFloat("water_wave_height"));
- shaders_header += "\n";
- shaders_header += "#define WATER_WAVE_LENGTH ";
- shaders_header += ftos(g_settings->getFloat("water_wave_length"));
- shaders_header += "\n";
- shaders_header += "#define WATER_WAVE_SPEED ";
- shaders_header += ftos(g_settings->getFloat("water_wave_speed"));
- shaders_header += "\n";
- } else{
- shaders_header += "#define ENABLE_WAVING_WATER 0\n";
- }
-
- shaders_header += "#define ENABLE_WAVING_LEAVES ";
- if (g_settings->getBool("enable_waving_leaves"))
- shaders_header += "1\n";
- else
- shaders_header += "0\n";
-
- shaders_header += "#define ENABLE_WAVING_PLANTS ";
- if (g_settings->getBool("enable_waving_plants"))
- shaders_header += "1\n";
- else
- shaders_header += "0\n";
-
- if (g_settings->getBool("tone_mapping"))
- shaders_header += "#define ENABLE_TONE_MAPPING\n";
-
- shaders_header += "#define FOG_START ";
- shaders_header += ftos(rangelim(g_settings->getFloat("fog_start"), 0.0f, 0.99f));
- shaders_header += "\n";
-
- // Call addHighLevelShaderMaterial() or addShaderMaterial()
- const c8* vertex_program_ptr = 0;
- const c8* pixel_program_ptr = 0;
- const c8* geometry_program_ptr = 0;
- if (!vertex_program.empty()) {
- vertex_program = shaders_header + vertex_program;
- vertex_program_ptr = vertex_program.c_str();
- }
- if (!pixel_program.empty()) {
- pixel_program = shaders_header + pixel_program;
- pixel_program_ptr = pixel_program.c_str();
- }
- if (!geometry_program.empty()) {
- geometry_program = shaders_header + geometry_program;
- geometry_program_ptr = geometry_program.c_str();
- }
- ShaderCallback *cb = new ShaderCallback(setter_factories);
- s32 shadermat = -1;
- if(is_highlevel){
- infostream<<"Compiling high level shaders for "<<name<<std::endl;
- shadermat = gpu->addHighLevelShaderMaterial(
- vertex_program_ptr, // Vertex shader program
- "vertexMain", // Vertex shader entry point
- video::EVST_VS_1_1, // Vertex shader version
- pixel_program_ptr, // Pixel shader program
- "pixelMain", // Pixel shader entry point
- video::EPST_PS_1_2, // Pixel shader version
- geometry_program_ptr, // Geometry shader program
- "geometryMain", // Geometry shader entry point
- video::EGST_GS_4_0, // Geometry shader version
- scene::EPT_TRIANGLES, // Geometry shader input
- scene::EPT_TRIANGLE_STRIP, // Geometry shader output
- 0, // Support maximum number of vertices
- cb, // Set-constant callback
- shaderinfo.base_material, // Base material
- 1 // Userdata passed to callback
- );
- if(shadermat == -1){
- errorstream<<"generate_shader(): "
- "failed to generate \""<<name<<"\", "
- "addHighLevelShaderMaterial failed."
- <<std::endl;
- dumpShaderProgram(warningstream, "Vertex", vertex_program);
- dumpShaderProgram(warningstream, "Pixel", pixel_program);
- dumpShaderProgram(warningstream, "Geometry", geometry_program);
- delete cb;
- return shaderinfo;
- }
- }
- else{
- infostream<<"Compiling assembly shaders for "<<name<<std::endl;
- shadermat = gpu->addShaderMaterial(
- vertex_program_ptr, // Vertex shader program
- pixel_program_ptr, // Pixel shader program
- cb, // Set-constant callback
- shaderinfo.base_material, // Base material
- 0 // Userdata passed to callback
- );
-
- if(shadermat == -1){
- errorstream<<"generate_shader(): "
- "failed to generate \""<<name<<"\", "
- "addShaderMaterial failed."
- <<std::endl;
- dumpShaderProgram(warningstream, "Vertex", vertex_program);
- dumpShaderProgram(warningstream,"Pixel", pixel_program);
- delete cb;
- return shaderinfo;
- }
+ shaders_header << R"(
+ #version 120
+ #define lowp
+ #define mediump
+ #define highp
+ )";
+ vertex_header = R"(
+ #define mWorldView gl_ModelViewMatrix
+ #define mWorldViewProj gl_ModelViewProjectionMatrix
+ #define mTexture (gl_TextureMatrix[0])
+ #define mNormal gl_NormalMatrix
+
+ #define inVertexPosition gl_Vertex
+ #define inVertexColor gl_Color
+ #define inTexCoord0 gl_MultiTexCoord0
+ #define inVertexNormal gl_Normal
+ #define inVertexTangent gl_MultiTexCoord1
+ #define inVertexBinormal gl_MultiTexCoord2
+ )";
+ }
+
+ bool use_discard = use_gles;
+#ifdef __unix__
+ // For renderers that should use discard instead of GL_ALPHA_TEST
+ const char* gl_renderer = (const char*)glGetString(GL_RENDERER);
+ if (strstr(gl_renderer, "GC7000"))
+ use_discard = true;
+#endif
+ if (use_discard && shaderinfo.base_material != video::EMT_SOLID)
+ shaders_header << "#define USE_DISCARD 1\n";
+
+#define PROVIDE(constant) shaders_header << "#define " #constant " " << (int)constant << "\n"
+
+ PROVIDE(NDT_NORMAL);
+ PROVIDE(NDT_AIRLIKE);
+ PROVIDE(NDT_LIQUID);
+ PROVIDE(NDT_FLOWINGLIQUID);
+ PROVIDE(NDT_GLASSLIKE);
+ PROVIDE(NDT_ALLFACES);
+ PROVIDE(NDT_ALLFACES_OPTIONAL);
+ PROVIDE(NDT_TORCHLIKE);
+ PROVIDE(NDT_SIGNLIKE);
+ PROVIDE(NDT_PLANTLIKE);
+ PROVIDE(NDT_FENCELIKE);
+ PROVIDE(NDT_RAILLIKE);
+ PROVIDE(NDT_NODEBOX);
+ PROVIDE(NDT_GLASSLIKE_FRAMED);
+ PROVIDE(NDT_FIRELIKE);
+ PROVIDE(NDT_GLASSLIKE_FRAMED_OPTIONAL);
+ PROVIDE(NDT_PLANTLIKE_ROOTED);
+
+ PROVIDE(TILE_MATERIAL_BASIC);
+ PROVIDE(TILE_MATERIAL_ALPHA);
+ PROVIDE(TILE_MATERIAL_LIQUID_TRANSPARENT);
+ PROVIDE(TILE_MATERIAL_LIQUID_OPAQUE);
+ PROVIDE(TILE_MATERIAL_WAVING_LEAVES);
+ PROVIDE(TILE_MATERIAL_WAVING_PLANTS);
+ PROVIDE(TILE_MATERIAL_OPAQUE);
+ PROVIDE(TILE_MATERIAL_WAVING_LIQUID_BASIC);
+ PROVIDE(TILE_MATERIAL_WAVING_LIQUID_TRANSPARENT);
+ PROVIDE(TILE_MATERIAL_WAVING_LIQUID_OPAQUE);
+ PROVIDE(TILE_MATERIAL_PLAIN);
+ PROVIDE(TILE_MATERIAL_PLAIN_ALPHA);
+
+#undef PROVIDE
+
+ shaders_header << "#define MATERIAL_TYPE " << (int)material_type << "\n";
+ shaders_header << "#define DRAW_TYPE " << (int)drawtype << "\n";
+
+ bool enable_waving_water = g_settings->getBool("enable_waving_water");
+ shaders_header << "#define ENABLE_WAVING_WATER " << enable_waving_water << "\n";
+ if (enable_waving_water) {
+ shaders_header << "#define WATER_WAVE_HEIGHT " << g_settings->getFloat("water_wave_height") << "\n";
+ shaders_header << "#define WATER_WAVE_LENGTH " << g_settings->getFloat("water_wave_length") << "\n";
+ shaders_header << "#define WATER_WAVE_SPEED " << g_settings->getFloat("water_wave_speed") << "\n";
+ }
+
+ shaders_header << "#define ENABLE_WAVING_LEAVES " << g_settings->getBool("enable_waving_leaves") << "\n";
+ shaders_header << "#define ENABLE_WAVING_PLANTS " << g_settings->getBool("enable_waving_plants") << "\n";
+ shaders_header << "#define ENABLE_TONE_MAPPING " << g_settings->getBool("tone_mapping") << "\n";
+
+ shaders_header << "#define FOG_START " << core::clamp(g_settings->getFloat("fog_start"), 0.0f, 0.99f) << "\n";
+
+ std::string common_header = shaders_header.str();
+
+ std::string vertex_shader = m_sourcecache.getOrLoad(name, "opengl_vertex.glsl");
+ std::string fragment_shader = m_sourcecache.getOrLoad(name, "opengl_fragment.glsl");
+ std::string geometry_shader = m_sourcecache.getOrLoad(name, "opengl_geometry.glsl");
+
+ vertex_shader = common_header + vertex_header + vertex_shader;
+ fragment_shader = common_header + fragment_header + fragment_shader;
+ const char *geometry_shader_ptr = nullptr; // optional
+ if (!geometry_shader.empty()) {
+ geometry_shader = common_header + geometry_header + geometry_shader;
+ geometry_shader_ptr = geometry_shader.c_str();
+ }
+
+ irr_ptr<ShaderCallback> cb{new ShaderCallback(m_setter_factories)};
+ infostream<<"Compiling high level shaders for "<<name<<std::endl;
+ s32 shadermat = gpu->addHighLevelShaderMaterial(
+ vertex_shader.c_str(), nullptr, video::EVST_VS_1_1,
+ fragment_shader.c_str(), nullptr, video::EPST_PS_1_1,
+ geometry_shader_ptr, nullptr, video::EGST_GS_4_0, scene::EPT_TRIANGLES, scene::EPT_TRIANGLES, 0,
+ cb.get(), shaderinfo.base_material, 1);
+ if (shadermat == -1) {
+ errorstream<<"generate_shader(): "
+ "failed to generate \""<<name<<"\", "
+ "addHighLevelShaderMaterial failed."
+ <<std::endl;
+ dumpShaderProgram(warningstream, "Vertex", vertex_shader);
+ dumpShaderProgram(warningstream, "Fragment", fragment_shader);
+ dumpShaderProgram(warningstream, "Geometry", geometry_shader);
+ return shaderinfo;
}
- callbacks.push_back(cb);
-
- // HACK, TODO: investigate this better
- // Grab the material renderer once more so minetest doesn't crash on exit
- driver->getMaterialRenderer(shadermat)->grab();
// Apply the newly created material type
shaderinfo.material = (video::E_MATERIAL_TYPE) shadermat;
return shaderinfo;
}
-void load_shaders(const std::string &name, SourceShaderCache *sourcecache,
- video::E_DRIVER_TYPE drivertype, bool enable_shaders,
- std::string &vertex_program, std::string &pixel_program,
- std::string &geometry_program, bool &is_highlevel)
-{
- vertex_program = "";
- pixel_program = "";
- geometry_program = "";
- is_highlevel = false;
-
- if(enable_shaders){
- // Look for high level shaders
- if(drivertype == video::EDT_DIRECT3D9){
- // Direct3D 9: HLSL
- // (All shaders in one file)
- vertex_program = sourcecache->getOrLoad(name, "d3d9.hlsl");
- pixel_program = vertex_program;
- geometry_program = vertex_program;
- }
- else if(drivertype == video::EDT_OPENGL){
- // OpenGL: GLSL
- vertex_program = sourcecache->getOrLoad(name, "opengl_vertex.glsl");
- pixel_program = sourcecache->getOrLoad(name, "opengl_fragment.glsl");
- geometry_program = sourcecache->getOrLoad(name, "opengl_geometry.glsl");
- }
- if (!vertex_program.empty() || !pixel_program.empty() || !geometry_program.empty()){
- is_highlevel = true;
- return;
- }
- }
-
-}
-
void dumpShaderProgram(std::ostream &output_stream,
const std::string &program_type, const std::string &program)
{
diff --git a/src/client/shader.h b/src/client/shader.h
index 109d39336..38ab76704 100644
--- a/src/client/shader.h
+++ b/src/client/shader.h
@@ -20,9 +20,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#pragma once
-#include <IMaterialRendererServices.h>
#include "irrlichttypes_bloated.h"
+#include <IMaterialRendererServices.h>
#include <string>
+#include "tile.h"
+#include "nodedef.h"
class IGameDef;
@@ -46,8 +48,8 @@ struct ShaderInfo {
std::string name = "";
video::E_MATERIAL_TYPE base_material = video::EMT_SOLID;
video::E_MATERIAL_TYPE material = video::EMT_SOLID;
- u8 drawtype = 0;
- u8 material_type = 0;
+ NodeDrawType drawtype = NDT_NORMAL;
+ MaterialType material_type = TILE_MATERIAL_BASIC;
ShaderInfo() = default;
virtual ~ShaderInfo() = default;
@@ -65,8 +67,7 @@ namespace irr { namespace video {
class IShaderConstantSetter {
public:
virtual ~IShaderConstantSetter() = default;
- virtual void onSetConstants(video::IMaterialRendererServices *services,
- bool is_highlevel) = 0;
+ virtual void onSetConstants(video::IMaterialRendererServices *services) = 0;
virtual void onSetMaterial(const video::SMaterial& material)
{ }
};
@@ -128,10 +129,10 @@ public:
virtual ~IShaderSource() = default;
virtual u32 getShaderIdDirect(const std::string &name,
- const u8 material_type, const u8 drawtype){return 0;}
+ MaterialType material_type, NodeDrawType drawtype = NDT_NORMAL){return 0;}
virtual ShaderInfo getShaderInfo(u32 id){return ShaderInfo();}
virtual u32 getShader(const std::string &name,
- const u8 material_type, const u8 drawtype){return 0;}
+ MaterialType material_type, NodeDrawType drawtype = NDT_NORMAL){return 0;}
};
class IWritableShaderSource : public IShaderSource {
@@ -139,16 +140,12 @@ public:
IWritableShaderSource() = default;
virtual ~IWritableShaderSource() = default;
- virtual u32 getShaderIdDirect(const std::string &name,
- const u8 material_type, const u8 drawtype){return 0;}
- virtual ShaderInfo getShaderInfo(u32 id){return ShaderInfo();}
- virtual u32 getShader(const std::string &name,
- const u8 material_type, const u8 drawtype){return 0;}
-
virtual void processQueue()=0;
virtual void insertSourceShader(const std::string &name_of_shader,
const std::string &filename, const std::string &program)=0;
virtual void rebuildShaders()=0;
+
+ /// @note Takes ownership of @p setter.
virtual void addShaderConstantSetterFactory(IShaderConstantSetterFactory *setter) = 0;
};
diff --git a/src/client/sky.cpp b/src/client/sky.cpp
index 2e0cbca86..3a40321dd 100644
--- a/src/client/sky.cpp
+++ b/src/client/sky.cpp
@@ -1,6 +1,7 @@
/*
Minetest
Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2020 numzero, Lobachevskiy Vitaliy <numzer0@yandex.ru>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
@@ -34,16 +35,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "config.h"
using namespace irr::core;
-Sky::Sky(s32 id, ITextureSource *tsrc) :
- scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(),
- RenderingEngine::get_scene_manager(), id)
+static video::SMaterial baseMaterial()
{
- setAutomaticCulling(scene::EAC_OFF);
- m_box.MaxEdge.set(0, 0, 0);
- m_box.MinEdge.set(0, 0, 0);
-
- // Create material
-
video::SMaterial mat;
mat.Lighting = false;
#if ENABLE_GLES
@@ -56,14 +49,31 @@ Sky::Sky(s32 id, ITextureSource *tsrc) :
mat.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
mat.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
mat.BackfaceCulling = false;
+ return mat;
+};
+
+Sky::Sky(s32 id, ITextureSource *tsrc, IShaderSource *ssrc) :
+ scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(),
+ RenderingEngine::get_scene_manager(), id)
+{
+ setAutomaticCulling(scene::EAC_OFF);
+ m_box.MaxEdge.set(0, 0, 0);
+ m_box.MinEdge.set(0, 0, 0);
+
+ m_enable_shaders = g_settings->getBool("enable_shaders");
- m_materials[0] = mat;
+ // Create materials
- m_materials[1] = mat;
+ m_materials[0] = baseMaterial();
+ m_materials[0].MaterialType = ssrc->getShaderInfo(ssrc->getShader("stars_shader", TILE_MATERIAL_ALPHA)).material;
+ m_materials[0].Lighting = true;
+ m_materials[0].ColorMaterial = video::ECM_NONE;
+
+ m_materials[1] = baseMaterial();
//m_materials[1].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
m_materials[1].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
- m_materials[2] = mat;
+ m_materials[2] = baseMaterial();
m_materials[2].setTexture(0, tsrc->getTextureForMesh("sunrisebg.png"));
m_materials[2].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
//m_materials[2].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
@@ -80,7 +90,7 @@ Sky::Sky(s32 id, ITextureSource *tsrc) :
tsrc->getTexture(m_moon_params.tonemap) : NULL;
if (m_sun_texture) {
- m_materials[3] = mat;
+ m_materials[3] = baseMaterial();
m_materials[3].setTexture(0, m_sun_texture);
m_materials[3].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
// Disables texture filtering
@@ -92,7 +102,7 @@ Sky::Sky(s32 id, ITextureSource *tsrc) :
m_materials[3].Lighting = true;
}
if (m_moon_texture) {
- m_materials[4] = mat;
+ m_materials[4] = baseMaterial();
m_materials[4].setTexture(0, m_moon_texture);
m_materials[4].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
// Disables texture filtering
@@ -105,7 +115,7 @@ Sky::Sky(s32 id, ITextureSource *tsrc) :
}
for (int i = 5; i < 11; i++) {
- m_materials[i] = mat;
+ m_materials[i] = baseMaterial();
m_materials[i].Lighting = true;
m_materials[i].MaterialType = video::EMT_SOLID;
}
@@ -202,7 +212,7 @@ void Sky::render()
const f32 t = 1.0f;
const f32 o = 0.0f;
- static const u16 indices[4] = {0, 1, 2, 3};
+ static const u16 indices[6] = {0, 1, 2, 0, 2, 3};
video::S3DVertex vertices[4];
driver->setMaterial(m_materials[1]);
@@ -244,7 +254,7 @@ void Sky::render()
vertex.Pos.rotateXZBy(180);
}
}
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
+ driver->drawIndexedTriangleList(&vertices[0], 4, indices, 2);
}
}
@@ -270,7 +280,7 @@ void Sky::render()
// Switch from -Z (south) to +Z (north)
vertex.Pos.rotateXZBy(-180);
}
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
+ driver->drawIndexedTriangleList(&vertices[0], 4, indices, 2);
}
}
@@ -301,7 +311,7 @@ void Sky::render()
// Switch from -Z (south) to -X (west)
vertex.Pos.rotateXZBy(-90);
}
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
+ driver->drawIndexedTriangleList(&vertices[0], 4, indices, 2);
}
// Draw sun
@@ -337,7 +347,7 @@ void Sky::render()
// Switch from -Z (south) to +Z (north)
vertex.Pos.rotateXZBy(-180);
}
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
+ driver->drawIndexedTriangleList(&vertices[0], 4, indices, 2);
}
// Draw bottom far cloudy fog thing in front of sun, moon and stars
@@ -346,7 +356,7 @@ void Sky::render()
vertices[1] = video::S3DVertex( 1, -1.0, -1, 0, 1, 0, c, o, t);
vertices[2] = video::S3DVertex( 1, -1.0, 1, 0, 1, 0, c, o, o);
vertices[3] = video::S3DVertex(-1, -1.0, 1, 0, 1, 0, c, t, o);
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
+ driver->drawIndexedTriangleList(&vertices[0], 4, indices, 2);
}
}
}
@@ -590,7 +600,7 @@ void Sky::draw_sun(video::IVideoDriver *driver, float sunsize, const video::SCol
* wicked_time_of_day: current time of day, to know where should be the sun in the sky
*/
{
- static const u16 indices[4] = {0, 1, 2, 3};
+ static const u16 indices[] = {0, 1, 2, 0, 2, 3};
std::array<video::S3DVertex, 4> vertices;
if (!m_sun_texture) {
driver->setMaterial(m_materials[1]);
@@ -608,7 +618,7 @@ void Sky::draw_sun(video::IVideoDriver *driver, float sunsize, const video::SCol
for (int i = 0; i < 4; i++) {
draw_sky_body(vertices, -sunsizes[i], sunsizes[i], colors[i]);
place_sky_body(vertices, 90, wicked_time_of_day * 360 - 90);
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
+ driver->drawIndexedTriangleList(&vertices[0], 4, indices, 2);
}
} else {
driver->setMaterial(m_materials[3]);
@@ -620,7 +630,7 @@ void Sky::draw_sun(video::IVideoDriver *driver, float sunsize, const video::SCol
c = video::SColor(255, 255, 255, 255);
draw_sky_body(vertices, -d, d, c);
place_sky_body(vertices, 90, wicked_time_of_day * 360 - 90);
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
+ driver->drawIndexedTriangleList(&vertices[0], 4, indices, 2);
}
}
@@ -637,7 +647,7 @@ void Sky::draw_moon(video::IVideoDriver *driver, float moonsize, const video::SC
* the sky
*/
{
- static const u16 indices[4] = {0, 1, 2, 3};
+ static const u16 indices[] = {0, 1, 2, 0, 2, 3};
std::array<video::S3DVertex, 4> vertices;
if (!m_moon_texture) {
driver->setMaterial(m_materials[1]);
@@ -661,7 +671,7 @@ void Sky::draw_moon(video::IVideoDriver *driver, float moonsize, const video::SC
for (int i = 0; i < 4; i++) {
draw_sky_body(vertices, moonsizes_1[i], moonsizes_2[i], colors[i]);
place_sky_body(vertices, -90, wicked_time_of_day * 360 - 90);
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
+ driver->drawIndexedTriangleList(&vertices[0], 4, indices, 2);
}
} else {
driver->setMaterial(m_materials[4]);
@@ -673,13 +683,12 @@ void Sky::draw_moon(video::IVideoDriver *driver, float moonsize, const video::SC
c = video::SColor(255, 255, 255, 255);
draw_sky_body(vertices, -d, d, c);
place_sky_body(vertices, -90, wicked_time_of_day * 360 - 90);
- driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
+ driver->drawIndexedTriangleList(&vertices[0], 4, indices, 2);
}
}
void Sky::draw_stars(video::IVideoDriver * driver, float wicked_time_of_day)
{
- driver->setMaterial(m_materials[1]);
// Tune values so that stars first appear just after the sun
// disappears over the horizon, and disappear just before the sun
// appears over the horizon.
@@ -687,87 +696,18 @@ void Sky::draw_stars(video::IVideoDriver * driver, float wicked_time_of_day)
// to time 4000.
float tod = wicked_time_of_day < 0.5f ? wicked_time_of_day : (1.0f - wicked_time_of_day);
- float starbrightness = clamp((0.25f - fabsf(tod)) * 20.0f, 0.0f, 1.0f);
-
- float f = starbrightness;
- float d = (0.006 / 2) * m_star_params.scale;
-
- video::SColor starcolor = m_star_params.starcolor;
- starcolor.setAlpha(f * m_star_params.starcolor.getAlpha());
-
- // Stars are only drawn when not fully transparent
- if (m_star_params.starcolor.getAlpha() < 1)
+ float starbrightness = (0.25f - fabsf(tod)) * 20.0f;
+ m_star_color = m_star_params.starcolor;
+ m_star_color.a *= clamp(starbrightness, 0.0f, 1.0f);
+ if (m_star_color.a <= 0.0f) // Stars are only drawn when not fully transparent
return;
-#if ENABLE_GLES
- u16 *indices = new u16[m_star_params.count * 3];
- video::S3DVertex *vertices =
- new video::S3DVertex[m_star_params.count * 3];
- for (u32 i = 0; i < m_star_params.count; i++) {
- indices[i * 3 + 0] = i * 3 + 0;
- indices[i * 3 + 1] = i * 3 + 1;
- indices[i * 3 + 2] = i * 3 + 2;
- v3f r = m_stars[i];
- core::CMatrix4<f32> a;
- a.buildRotateFromTo(v3f(0, 1, 0), r);
- v3f p = v3f(-d, 1, -d);
- v3f p1 = v3f(d, 1, 0);
- v3f p2 = v3f(-d, 1, d);
- a.rotateVect(p);
- a.rotateVect(p1);
- a.rotateVect(p2);
- p.rotateXYBy(wicked_time_of_day * 360 - 90);
- p1.rotateXYBy(wicked_time_of_day * 360 - 90);
- p2.rotateXYBy(wicked_time_of_day * 360 - 90);
- vertices[i * 3 + 0].Pos = p;
- vertices[i * 3 + 0].Color = starcolor;
- vertices[i * 3 + 1].Pos = p1;
- vertices[i * 3 + 1].Color = starcolor;
- vertices[i * 3 + 2].Pos = p2;
- vertices[i * 3 + 2].Color = starcolor;
- }
- driver->drawIndexedTriangleList(vertices, m_star_params.count * 3,
- indices, m_star_params.count);
- delete[] indices;
- delete[] vertices;
-#else
- u16 *indices = new u16[m_star_params.count * 4];
- video::S3DVertex *vertices =
- new video::S3DVertex[m_star_params.count * 4];
- for (u32 i = 0; i < m_star_params.count; i++) {
- indices[i * 4 + 0] = i * 4 + 0;
- indices[i * 4 + 1] = i * 4 + 1;
- indices[i * 4 + 2] = i * 4 + 2;
- indices[i * 4 + 3] = i * 4 + 3;
- v3f r = m_stars[i];
- core::CMatrix4<f32> a;
- a.buildRotateFromTo(v3f(0, 1, 0), r);
- v3f p = v3f(-d, 1, -d);
- v3f p1 = v3f(d, 1, -d);
- v3f p2 = v3f(d, 1, d);
- v3f p3 = v3f(-d, 1, d);
- a.rotateVect(p);
- a.rotateVect(p1);
- a.rotateVect(p2);
- a.rotateVect(p3);
- p.rotateXYBy(wicked_time_of_day * 360 - 90);
- p1.rotateXYBy(wicked_time_of_day * 360 - 90);
- p2.rotateXYBy(wicked_time_of_day * 360 - 90);
- p3.rotateXYBy(wicked_time_of_day * 360 - 90);
- vertices[i * 4 + 0].Pos = p;
- vertices[i * 4 + 0].Color = starcolor;
- vertices[i * 4 + 1].Pos = p1;
- vertices[i * 4 + 1].Color = starcolor;
- vertices[i * 4 + 2].Pos = p2;
- vertices[i * 4 + 2].Color = starcolor;
- vertices[i * 4 + 3].Pos = p3;
- vertices[i * 4 + 3].Color = starcolor;
- }
- driver->drawVertexPrimitiveList(vertices, m_star_params.count * 4,
- indices, m_star_params.count, video::EVT_STANDARD,
- scene::EPT_QUADS, video::EIT_16BIT);
- delete[] indices;
- delete[] vertices;
-#endif
+ m_materials[0].DiffuseColor = m_materials[0].EmissiveColor = m_star_color.toSColor();
+ auto sky_rotation = core::matrix4().setRotationAxisRadians(2.0f * M_PI * (wicked_time_of_day - 0.25f), v3f(0.0f, 0.0f, 1.0f));
+ auto world_matrix = driver->getTransform(video::ETS_WORLD);
+ driver->setTransform(video::ETS_WORLD, world_matrix * sky_rotation);
+ driver->setMaterial(m_materials[0]);
+ driver->drawMeshBuffer(m_stars.get());
+ driver->setTransform(video::ETS_WORLD, world_matrix);
}
void Sky::draw_sky_body(std::array<video::S3DVertex, 4> &vertices, float pos_1, float pos_2, const video::SColor &c)
@@ -822,7 +762,7 @@ void Sky::setSunTexture(std::string sun_texture,
m_sun_texture = tsrc->getTextureForMesh(m_sun_params.texture);
if (m_sun_texture) {
- m_materials[3] = m_materials[0];
+ m_materials[3] = baseMaterial();
m_materials[3].setTexture(0, m_sun_texture);
m_materials[3].MaterialType = video::
EMT_TRANSPARENT_ALPHA_CHANNEL;
@@ -870,7 +810,7 @@ void Sky::setMoonTexture(std::string moon_texture,
m_moon_texture = tsrc->getTextureForMesh(m_moon_params.texture);
if (m_moon_texture) {
- m_materials[4] = m_materials[0];
+ m_materials[4] = baseMaterial();
m_materials[4].setTexture(0, m_moon_texture);
m_materials[4].MaterialType = video::
EMT_TRANSPARENT_ALPHA_CHANNEL;
@@ -892,19 +832,58 @@ 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_stars.clear();
- // Rebuild the stars surrounding the camera
- for (u16 i = 0; i < star_count; i++) {
- v3f star = v3f(
- myrand_range(-10000, 10000),
- myrand_range(-10000, 10000),
- myrand_range(-10000, 10000)
- );
-
- star.normalize();
- m_stars.emplace_back(star);
- }
+ m_seed = (u64)myrand() << 32 | myrand();
+ updateStars();
+ }
+}
+
+void Sky::updateStars()
+{
+ m_stars.reset(new scene::SMeshBuffer());
+ // Stupid IrrLicht doesn’t allow non-indexed rendering, and indexed quad
+ // rendering is slow due to lack of hardware support. So as indices are
+ // 16-bit and there are 4 vertices per star... the limit is 2^16/4 = 0x4000.
+ // That should be well enough actually.
+ if (m_star_params.count > 0x4000) {
+ warningstream << "Requested " << m_star_params.count << " stars but " << 0x4000 << " is the max\n";
+ m_star_params.count = 0x4000;
+ }
+ m_stars->Vertices.reallocate(4 * m_star_params.count);
+ m_stars->Indices.reallocate(6 * m_star_params.count);
+
+ video::SColor fallback_color = m_star_params.starcolor; // used on GLES 2 “without shaders”
+ PcgRandom rgen(m_seed);
+ float d = (0.006 / 2) * m_star_params.scale;
+ for (u16 i = 0; i < m_star_params.count; i++) {
+ v3f r = v3f(
+ rgen.range(-10000, 10000),
+ rgen.range(-10000, 10000),
+ rgen.range(-10000, 10000)
+ );
+ core::CMatrix4<f32> a;
+ a.buildRotateFromTo(v3f(0, 1, 0), r);
+ v3f p = v3f(-d, 1, -d);
+ v3f p1 = v3f(d, 1, -d);
+ v3f p2 = v3f(d, 1, d);
+ v3f p3 = v3f(-d, 1, d);
+ a.rotateVect(p);
+ a.rotateVect(p1);
+ a.rotateVect(p2);
+ a.rotateVect(p3);
+ m_stars->Vertices.push_back(video::S3DVertex(p, {}, fallback_color, {}));
+ m_stars->Vertices.push_back(video::S3DVertex(p1, {}, fallback_color, {}));
+ m_stars->Vertices.push_back(video::S3DVertex(p2, {}, fallback_color, {}));
+ m_stars->Vertices.push_back(video::S3DVertex(p3, {}, fallback_color, {}));
+ }
+ for (u16 i = 0; i < m_star_params.count; i++) {
+ m_stars->Indices.push_back(i * 4 + 0);
+ m_stars->Indices.push_back(i * 4 + 1);
+ m_stars->Indices.push_back(i * 4 + 2);
+ m_stars->Indices.push_back(i * 4 + 2);
+ m_stars->Indices.push_back(i * 4 + 3);
+ m_stars->Indices.push_back(i * 4 + 0);
}
+ m_stars->setHardwareMappingHint(scene::EHM_STATIC);
}
void Sky::setSkyColors(const SkyColor &sky_color)
@@ -936,7 +915,7 @@ void Sky::addTextureToSkybox(std::string texture, int material_id,
// Keep a list of texture names handy.
m_sky_params.textures.emplace_back(texture);
video::ITexture *result = tsrc->getTextureForMesh(texture);
- m_materials[material_id+5] = m_materials[0];
+ m_materials[material_id+5] = baseMaterial();
m_materials[material_id+5].setTexture(0, result);
m_materials[material_id+5].MaterialType = video::EMT_SOLID;
}
diff --git a/src/client/sky.h b/src/client/sky.h
index 3227e8f59..342a97596 100644
--- a/src/client/sky.h
+++ b/src/client/sky.h
@@ -17,10 +17,12 @@ 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 <ISceneNode.h>
#include <array>
#include "camera.h"
-#include "irrlichttypes_extrabloated.h"
+#include "irr_ptr.h"
+#include "shader.h"
#include "skyparams.h"
#pragma once
@@ -34,7 +36,7 @@ class Sky : public scene::ISceneNode
{
public:
//! constructor
- Sky(s32 id, ITextureSource *tsrc);
+ Sky(s32 id, ITextureSource *tsrc, IShaderSource *ssrc);
virtual void OnRegisterSceneNode();
@@ -77,7 +79,7 @@ public:
void setStarsVisible(bool stars_visible) { m_star_params.visible = stars_visible; }
void setStarCount(u16 star_count, bool force_update);
void setStarColor(video::SColor star_color) { m_star_params.starcolor = star_color; }
- void setStarScale(f32 star_scale) { m_star_params.scale = star_scale; }
+ void setStarScale(f32 star_scale) { m_star_params.scale = star_scale; updateStars(); }
bool getCloudsVisible() const { return m_clouds_visible && m_clouds_enabled; }
const video::SColorf &getCloudColor() const { return m_cloudcolor_f; }
@@ -101,6 +103,8 @@ public:
void clearSkyboxTextures() { m_sky_params.textures.clear(); }
void addTextureToSkybox(std::string texture, int material_id,
ITextureSource *tsrc);
+ const video::SColorf &getCurrentStarColor() const { return m_star_color; }
+
private:
aabb3f m_box;
video::SMaterial m_materials[SKY_MATERIAL_COUNT];
@@ -154,6 +158,7 @@ private:
bool m_clouds_enabled = true; // Initialised to true, reset only by set_sky API
bool m_directional_colored_fog;
bool m_in_clouds = true; // Prevent duplicating bools to remember old values
+ bool m_enable_shaders = false;
video::SColorf m_bgcolor_bright_f = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f);
video::SColorf m_skycolor_bright_f = video::SColorf(1.0f, 1.0f, 1.0f, 1.0f);
@@ -178,13 +183,17 @@ private:
bool m_default_tint = true;
- std::vector<v3f> m_stars;
+ u64 m_seed = 0;
+ irr_ptr<scene::SMeshBuffer> m_stars;
+ video::SColorf m_star_color;
video::ITexture *m_sun_texture;
video::ITexture *m_moon_texture;
video::ITexture *m_sun_tonemap;
video::ITexture *m_moon_tonemap;
+ void updateStars();
+
void draw_sun(video::IVideoDriver *driver, float sunsize, const video::SColor &suncolor,
const video::SColor &suncolor2, float wicked_time_of_day);
void draw_moon(video::IVideoDriver *driver, float moonsize, const video::SColor &mooncolor,
diff --git a/src/client/sound_openal.cpp b/src/client/sound_openal.cpp
index 20a651c1d..f4e61f93e 100644
--- a/src/client/sound_openal.cpp
+++ b/src/client/sound_openal.cpp
@@ -28,6 +28,7 @@ with this program; ifnot, write to the Free Software Foundation, Inc.,
#include <alc.h>
//#include <alext.h>
#elif defined(__APPLE__)
+ #define OPENAL_DEPRECATED
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
//#include <OpenAL/alext.h>
@@ -337,14 +338,12 @@ private:
};
std::unordered_map<int, FadeState> m_sounds_fading;
- float m_fade_delay;
public:
OpenALSoundManager(SoundManagerSingleton *smg, OnDemandSoundFetcher *fetcher):
m_fetcher(fetcher),
m_device(smg->m_device.get()),
m_context(smg->m_context.get()),
- m_next_id(1),
- m_fade_delay(0)
+ m_next_id(1)
{
infostream << "Audio: Initialized: OpenAL " << std::endl;
}
@@ -616,38 +615,45 @@ public:
void fadeSound(int soundid, float step, float gain)
{
- m_sounds_fading[soundid] = FadeState(step, getSoundGain(soundid), gain);
+ // Ignore the command if step isn't valid.
+ if (step == 0)
+ return;
+ float current_gain = getSoundGain(soundid);
+ step = gain - current_gain > 0 ? abs(step) : -abs(step);
+ if (m_sounds_fading.find(soundid) != m_sounds_fading.end()) {
+ auto current_fade = m_sounds_fading[soundid];
+ // Do not replace the fade if it's equivalent.
+ if (current_fade.target_gain == gain && current_fade.step == step)
+ return;
+ m_sounds_fading.erase(soundid);
+ }
+ gain = rangelim(gain, 0, 1);
+ m_sounds_fading[soundid] = FadeState(step, current_gain, gain);
}
void doFades(float dtime)
{
- m_fade_delay += dtime;
-
- if (m_fade_delay < 0.1f)
- return;
+ for (auto i = m_sounds_fading.begin(); i != m_sounds_fading.end();) {
+ FadeState& fade = i->second;
+ assert(fade.step != 0);
+ fade.current_gain += (fade.step * dtime);
- float chkGain = 0;
- for (auto i = m_sounds_fading.begin();
- i != m_sounds_fading.end();) {
- if (i->second.step < 0.f)
- chkGain = -(i->second.current_gain);
+ if (fade.step < 0.f)
+ fade.current_gain = std::max(fade.current_gain, fade.target_gain);
else
- chkGain = i->second.current_gain;
+ fade.current_gain = std::min(fade.current_gain, fade.target_gain);
- if (chkGain < i->second.target_gain) {
- i->second.current_gain += (i->second.step * m_fade_delay);
- i->second.current_gain = rangelim(i->second.current_gain, 0, 1);
-
- updateSoundGain(i->first, i->second.current_gain);
- ++i;
- } else {
- if (i->second.target_gain <= 0.f)
- stopSound(i->first);
+ if (fade.current_gain <= 0.f)
+ stopSound(i->first);
+ else
+ updateSoundGain(i->first, fade.current_gain);
+ // The increment must happen during the erase call, or else it'll segfault.
+ if (fade.current_gain == fade.target_gain)
m_sounds_fading.erase(i++);
- }
+ else
+ i++;
}
- m_fade_delay = 0;
}
bool soundExists(int sound)
diff --git a/src/client/tile.cpp b/src/client/tile.cpp
index d03588b2b..f2639757e 100644
--- a/src/client/tile.cpp
+++ b/src/client/tile.cpp
@@ -429,7 +429,6 @@ private:
// Cached settings needed for making textures from meshes
bool m_setting_trilinear_filter;
bool m_setting_bilinear_filter;
- bool m_setting_anisotropic_filter;
};
IWritableTextureSource *createTextureSource()
@@ -450,7 +449,6 @@ TextureSource::TextureSource()
// for these settings to take effect
m_setting_trilinear_filter = g_settings->getBool("trilinear_filter");
m_setting_bilinear_filter = g_settings->getBool("bilinear_filter");
- m_setting_anisotropic_filter = g_settings->getBool("anisotropic_filter");
}
TextureSource::~TextureSource()
@@ -1633,6 +1631,13 @@ bool TextureSource::generateImagePart(std::string part_of_name,
/* IMPORTANT: When changing this, getTextureForMesh() needs to be
* updated too. */
+ if (!baseimg) {
+ errorstream << "generateImagePart(): baseimg == NULL "
+ << "for part_of_name=\"" << part_of_name
+ << "\", cancelling." << std::endl;
+ return false;
+ }
+
// Apply the "clean transparent" filter, if configured.
if (g_settings->getBool("texture_clean_transparent"))
imageCleanTransparent(baseimg, 127);
@@ -2219,9 +2224,14 @@ video::SColor TextureSource::getTextureAverageColor(const std::string &name)
video::IVideoDriver *driver = RenderingEngine::get_video_driver();
video::SColor c(0, 0, 0, 0);
video::ITexture *texture = getTexture(name);
+ if (!texture)
+ return c;
video::IImage *image = driver->createImage(texture,
core::position2d<s32>(0, 0),
texture->getOriginalSize());
+ if (!image)
+ return c;
+
u32 total = 0;
u32 tR = 0;
u32 tG = 0;
diff --git a/src/client/tile.h b/src/client/tile.h
index 52e0a2b2b..49c46f749 100644
--- a/src/client/tile.h
+++ b/src/client/tile.h
@@ -25,7 +25,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <string>
#include <vector>
#include <SMaterial.h>
-#include <memory>
#include "util/numeric.h"
#include "config.h"
@@ -272,7 +271,7 @@ struct TileLayer
u32 texture_id = 0;
u16 animation_frame_length_ms = 0;
- u8 animation_frame_count = 1;
+ u16 animation_frame_count = 1;
u8 material_type = TILE_MATERIAL_BASIC;
u8 material_flags =
@@ -284,7 +283,7 @@ struct TileLayer
//! If true, the tile has its own color.
bool has_color = false;
- std::shared_ptr<std::vector<FrameSpec>> frames = nullptr;
+ std::vector<FrameSpec> *frames = nullptr;
/*!
* The color of the tile, or if the tile does not own
diff --git a/src/client/wieldmesh.cpp b/src/client/wieldmesh.cpp
index 8cd3e29a9..ad583210a 100644
--- a/src/client/wieldmesh.cpp
+++ b/src/client/wieldmesh.cpp
@@ -303,13 +303,24 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename,
}
}
-scene::SMesh *createSpecialNodeMesh(Client *client, content_t id, std::vector<ItemPartColor> *colors)
+scene::SMesh *createSpecialNodeMesh(Client *client, content_t id, std::vector<ItemPartColor> *colors, const ContentFeatures &f)
{
- MeshMakeData mesh_make_data(client, false, false);
+ MeshMakeData mesh_make_data(client, false);
MeshCollector collector;
mesh_make_data.setSmoothLighting(false);
MapblockMeshGenerator gen(&mesh_make_data, &collector);
- gen.renderSingle(id);
+ u8 param2 = 0;
+ if (f.param_type_2 == CPT2_WALLMOUNTED ||
+ f.param_type_2 == CPT2_COLORED_WALLMOUNTED) {
+ if (f.drawtype == NDT_TORCHLIKE)
+ param2 = 1;
+ else if (f.drawtype == NDT_SIGNLIKE ||
+ f.drawtype == NDT_NODEBOX ||
+ f.drawtype == NDT_MESH)
+ param2 = 4;
+ }
+ gen.renderSingle(id, param2);
+
colors->clear();
scene::SMesh *mesh = new scene::SMesh();
for (auto &prebuffers : collector.prebuffers)
@@ -319,8 +330,9 @@ scene::SMesh *createSpecialNodeMesh(Client *client, content_t id, std::vector<It
p.layer.texture = frame.texture;
p.layer.normal_texture = frame.normal_texture;
}
- for (video::S3DVertex &v : p.vertices)
+ for (video::S3DVertex &v : p.vertices) {
v.Color.setAlpha(255);
+ }
scene::SMeshBuffer *buf = new scene::SMeshBuffer();
buf->Material.setTexture(0, p.layer.texture);
p.layer.applyMaterialOptions(buf->Material);
@@ -368,73 +380,61 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che
// Handle nodes
// See also CItemDefManager::createClientCached()
if (def.type == ITEM_NODE) {
- if (f.mesh_ptr[0]) {
- // e.g. mesh nodes and nodeboxes
- mesh = cloneMesh(f.mesh_ptr[0]);
- postProcessNodeMesh(mesh, f, m_enable_shaders, true,
- &m_material_type, &m_colors);
+ bool cull_backface = f.needsBackfaceCulling();
+
+ // Select rendering method
+ switch (f.drawtype) {
+ case NDT_AIRLIKE:
+ setExtruded("no_texture_airlike.png", "",
+ v3f(1.0, 1.0, 1.0), tsrc, 1);
+ break;
+ case NDT_SIGNLIKE:
+ 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)
+ wscale.Z *= 0.1f;
+ setExtruded(tsrc->getTextureName(f.tiles[0].layers[0].texture_id),
+ tsrc->getTextureName(f.tiles[0].layers[1].texture_id),
+ wscale, tsrc,
+ f.tiles[0].layers[0].animation_frame_count);
+ // Add color
+ const TileLayer &l0 = f.tiles[0].layers[0];
+ m_colors.emplace_back(l0.has_color, l0.color);
+ const TileLayer &l1 = f.tiles[0].layers[1];
+ m_colors.emplace_back(l1.has_color, l1.color);
+ break;
+ }
+ case NDT_NORMAL:
+ case NDT_ALLFACES:
+ case NDT_LIQUID:
+ setCube(f, def.wield_scale);
+ break;
+ default:
+ // Render non-trivial drawtypes like the actual node
+ mesh = createSpecialNodeMesh(client, id, &m_colors, f);
changeToMesh(mesh);
mesh->drop();
- // mesh is pre-scaled by BS * f->visual_scale
m_meshnode->setScale(
- def.wield_scale * WIELD_SCALE_FACTOR
- / (BS * f.visual_scale));
- } else {
- switch (f.drawtype) {
- case NDT_AIRLIKE: {
- changeToMesh(nullptr);
- break;
- }
- case NDT_PLANTLIKE: {
- setExtruded(tsrc->getTextureName(f.tiles[0].layers[0].texture_id),
- tsrc->getTextureName(f.tiles[0].layers[1].texture_id),
- def.wield_scale, tsrc,
- f.tiles[0].layers[0].animation_frame_count);
- // Add color
- const TileLayer &l0 = f.tiles[0].layers[0];
- m_colors.emplace_back(l0.has_color, l0.color);
- const TileLayer &l1 = f.tiles[0].layers[1];
- 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:
- case NDT_FLOWINGLIQUID: {
- setCube(f, def.wield_scale);
- break;
- }
- default: {
- mesh = createSpecialNodeMesh(client, id, &m_colors);
- changeToMesh(mesh);
- mesh->drop();
- m_meshnode->setScale(
- def.wield_scale * WIELD_SCALE_FACTOR
- / (BS * f.visual_scale));
- }
- }
+ def.wield_scale * WIELD_SCALE_FACTOR
+ / (BS * f.visual_scale));
+ break;
}
+
u32 material_count = m_meshnode->getMaterialCount();
for (u32 i = 0; i < material_count; ++i) {
video::SMaterial &material = m_meshnode->getMaterial(i);
material.MaterialType = m_material_type;
material.MaterialTypeParam = 0.5f;
- material.setFlag(video::EMF_BACK_FACE_CULLING, true);
+ material.setFlag(video::EMF_BACK_FACE_CULLING, cull_backface);
material.setFlag(video::EMF_BILINEAR_FILTER, m_bilinear_filter);
material.setFlag(video::EMF_TRILINEAR_FILTER, m_trilinear_filter);
}
return;
- }
- else if (!def.inventory_image.empty()) {
+ } else if (!def.inventory_image.empty()) {
setExtruded(def.inventory_image, def.inventory_overlay, def.wield_scale,
tsrc, 1);
m_colors.emplace_back();
@@ -529,6 +529,8 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
// Shading is on by default
result->needs_shading = true;
+ bool cull_backface = f.needsBackfaceCulling();
+
// If inventory_image is defined, it overrides everything else
if (!def.inventory_image.empty()) {
mesh = getExtrudedMesh(tsrc, def.inventory_image,
@@ -538,51 +540,56 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
result->buffer_colors.emplace_back(true, video::SColor(0xFFFFFFFF));
// Items with inventory images do not need shading
result->needs_shading = false;
+ } else if (def.type == ITEM_NODE && f.drawtype == NDT_AIRLIKE) {
+ // Fallback image for airlike node
+ mesh = getExtrudedMesh(tsrc, "no_texture_airlike.png",
+ def.inventory_overlay);
+ result->needs_shading = false;
} else if (def.type == ITEM_NODE) {
- if (f.mesh_ptr[0]) {
- mesh = cloneMesh(f.mesh_ptr[0]);
- scaleMesh(mesh, v3f(0.12, 0.12, 0.12));
+ switch (f.drawtype) {
+ case NDT_NORMAL:
+ case NDT_ALLFACES:
+ case NDT_LIQUID:
+ case NDT_FLOWINGLIQUID: {
+ scene::IMesh *cube = g_extrusion_mesh_cache->createCube();
+ mesh = cloneMesh(cube);
+ cube->drop();
+ if (f.drawtype == NDT_FLOWINGLIQUID) {
+ scaleMesh(mesh, v3f(1.2, 0.03, 1.2));
+ translateMesh(mesh, v3f(0, -0.57, 0));
+ } else
+ scaleMesh(mesh, v3f(1.2, 1.2, 1.2));
+ // add overlays
postProcessNodeMesh(mesh, f, false, false, nullptr,
- &result->buffer_colors);
- } else {
- switch (f.drawtype) {
- case NDT_PLANTLIKE: {
- mesh = getExtrudedMesh(tsrc,
- tsrc->getTextureName(f.tiles[0].layers[0].texture_id),
- tsrc->getTextureName(f.tiles[0].layers[1].texture_id));
- // Add color
- const TileLayer &l0 = f.tiles[0].layers[0];
- result->buffer_colors.emplace_back(l0.has_color, l0.color);
- const TileLayer &l1 = f.tiles[0].layers[1];
- result->buffer_colors.emplace_back(l1.has_color, l1.color);
- break;
- }
- case NDT_PLANTLIKE_ROOTED: {
- mesh = getExtrudedMesh(tsrc,
- tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id), "");
- // Add color
- const TileLayer &l0 = f.special_tiles[0].layers[0];
- result->buffer_colors.emplace_back(l0.has_color, l0.color);
- break;
- }
- case NDT_NORMAL:
- case NDT_ALLFACES:
- case NDT_LIQUID:
- case NDT_FLOWINGLIQUID: {
- scene::IMesh *cube = g_extrusion_mesh_cache->createCube();
- mesh = cloneMesh(cube);
- cube->drop();
- scaleMesh(mesh, v3f(1.2, 1.2, 1.2));
- // add overlays
- postProcessNodeMesh(mesh, f, false, false, nullptr,
- &result->buffer_colors);
- break;
- }
- default: {
- mesh = createSpecialNodeMesh(client, id, &result->buffer_colors);
- scaleMesh(mesh, v3f(0.12, 0.12, 0.12));
- }
- }
+ &result->buffer_colors, true);
+ if (f.drawtype == NDT_ALLFACES)
+ scaleMesh(mesh, v3f(f.visual_scale));
+ break;
+ }
+ case NDT_PLANTLIKE: {
+ mesh = getExtrudedMesh(tsrc,
+ tsrc->getTextureName(f.tiles[0].layers[0].texture_id),
+ tsrc->getTextureName(f.tiles[0].layers[1].texture_id));
+ // Add color
+ const TileLayer &l0 = f.tiles[0].layers[0];
+ result->buffer_colors.emplace_back(l0.has_color, l0.color);
+ const TileLayer &l1 = f.tiles[0].layers[1];
+ result->buffer_colors.emplace_back(l1.has_color, l1.color);
+ break;
+ }
+ case NDT_PLANTLIKE_ROOTED: {
+ mesh = getExtrudedMesh(tsrc,
+ tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id), "");
+ // Add color
+ const TileLayer &l0 = f.special_tiles[0].layers[0];
+ result->buffer_colors.emplace_back(l0.has_color, l0.color);
+ break;
+ }
+ default:
+ // Render non-trivial drawtypes like the actual node
+ mesh = createSpecialNodeMesh(client, id, &result->buffer_colors, f);
+ scaleMesh(mesh, v3f(0.12, 0.12, 0.12));
+ break;
}
u32 mc = mesh->getMeshBufferCount();
@@ -593,7 +600,7 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result)
material.MaterialTypeParam = 0.5f;
material.setFlag(video::EMF_BILINEAR_FILTER, false);
material.setFlag(video::EMF_TRILINEAR_FILTER, false);
- material.setFlag(video::EMF_BACK_FACE_CULLING, true);
+ material.setFlag(video::EMF_BACK_FACE_CULLING, cull_backface);
material.setFlag(video::EMF_LIGHTING, false);
}