diff options
Diffstat (limited to 'src/client')
44 files changed, 599 insertions, 516 deletions
diff --git a/src/client/camera.cpp b/src/client/camera.cpp index 854d9eae8..52bedcba9 100644 --- a/src/client/camera.cpp +++ b/src/client/camera.cpp @@ -44,11 +44,11 @@ with this program; if not, write to the Free Software Foundation, Inc., #define WIELDMESH_AMPLITUDE_X 7.0f #define WIELDMESH_AMPLITUDE_Y 10.0f -Camera::Camera(MapDrawControl &draw_control, Client *client): +Camera::Camera(MapDrawControl &draw_control, Client *client, RenderingEngine *rendering_engine): m_draw_control(draw_control), m_client(client) { - scene::ISceneManager *smgr = RenderingEngine::get_scene_manager(); + auto smgr = rendering_engine->get_scene_manager(); // note: making the camera node a child of the player node // would lead to unexpected behaviour, so we don't do that. m_playernode = smgr->addEmptySceneNode(smgr->getRootSceneNode()); @@ -542,7 +542,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, f32 tool_r m_curr_fov_degrees = rangelim(m_curr_fov_degrees, 1.0f, 160.0f); // FOV and aspect ratio - const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize(); + const v2u32 &window_size = RenderingEngine::getWindowSize(); m_aspect = (f32) window_size.X / (f32) window_size.Y; m_fov_y = m_curr_fov_degrees * M_PI / 180.0; // Increase vertical FOV on lower aspect ratios (<16:10) diff --git a/src/client/camera.h b/src/client/camera.h index c162df515..30fac5289 100644 --- a/src/client/camera.h +++ b/src/client/camera.h @@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc., class LocalPlayer; struct MapDrawControl; class Client; +class RenderingEngine; class WieldMeshSceneNode; struct Nametag @@ -104,7 +105,7 @@ enum CameraMode {CAMERA_MODE_FIRST, CAMERA_MODE_THIRD, CAMERA_MODE_THIRD_FRONT}; class Camera { public: - Camera(MapDrawControl &draw_control, Client *client); + Camera(MapDrawControl &draw_control, Client *client, RenderingEngine *rendering_engine); ~Camera(); // Get camera scene node. diff --git a/src/client/client.cpp b/src/client/client.cpp index e6025ed7b..57f8e6593 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -98,6 +98,7 @@ Client::Client( NodeDefManager *nodedef, ISoundManager *sound, MtEventManager *event, + RenderingEngine *rendering_engine, bool ipv6, GameUI *game_ui ): @@ -108,8 +109,9 @@ Client::Client( m_nodedef(nodedef), m_sound(sound), m_event(event), + m_rendering_engine(rendering_engine), m_env( - new ClientMap(this, control, 666), + new ClientMap(this, rendering_engine, control, 666), tsrc, this ), m_particle_manager(&m_env), @@ -301,12 +303,7 @@ Client::~Client() } // cleanup 3d model meshes on client shutdown - while (RenderingEngine::get_mesh_cache()->getMeshCount() != 0) { - scene::IAnimatedMesh *mesh = RenderingEngine::get_mesh_cache()->getMeshByIndex(0); - - if (mesh) - RenderingEngine::get_mesh_cache()->removeMesh(mesh); - } + m_rendering_engine->cleanupMeshCache(); delete m_minimap; m_minimap = nullptr; @@ -663,18 +660,11 @@ bool Client::loadMedia(const std::string &data, const std::string &filename, TRACESTREAM(<< "Client: Attempting to load image " << "file \"" << filename << "\"" << std::endl); - io::IFileSystem *irrfs = RenderingEngine::get_filesystem(); - video::IVideoDriver *vdrv = RenderingEngine::get_video_driver(); + io::IFileSystem *irrfs = m_rendering_engine->get_filesystem(); + video::IVideoDriver *vdrv = m_rendering_engine->get_video_driver(); -#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8 io::IReadFile *rfile = irrfs->createMemoryReadFile( data.c_str(), data.size(), "_tempreadfile"); -#else - // Silly irrlicht's const-incorrectness - Buffer<char> data_rw(data.c_str(), data.size()); - io::IReadFile *rfile = irrfs->createMemoryReadFile( - *data_rw, data_rw.getSize(), "_tempreadfile"); -#endif FATAL_ERROR_IF(!rfile, "Could not create irrlicht memory file."); @@ -1430,6 +1420,11 @@ bool Client::updateWieldedItem() return true; } +scene::ISceneManager* Client::getSceneManager() +{ + return m_rendering_engine->get_scene_manager(); +} + Inventory* Client::getInventory(const InventoryLocation &loc) { switch(loc.type){ @@ -1692,7 +1687,7 @@ typedef struct TextureUpdateArgs { ITextureSource *tsrc; } TextureUpdateArgs; -void texture_update_progress(void *args, u32 progress, u32 max_progress) +void Client::showUpdateProgressTexture(void *args, u32 progress, u32 max_progress) { TextureUpdateArgs* targs = (TextureUpdateArgs*) args; u16 cur_percent = ceil(progress / (double) max_progress * 100.); @@ -1711,7 +1706,7 @@ void texture_update_progress(void *args, u32 progress, u32 max_progress) targs->last_time_ms = time_ms; std::basic_stringstream<wchar_t> strm; strm << targs->text_base << " " << targs->last_percent << "%..."; - RenderingEngine::draw_load_screen(strm.str(), targs->guienv, targs->tsrc, 0, + m_rendering_engine->draw_load_screen(strm.str(), targs->guienv, targs->tsrc, 0, 72 + (u16) ((18. / 100.) * (double) targs->last_percent), true); } } @@ -1732,21 +1727,21 @@ void Client::afterContentReceived() // Rebuild inherited images and recreate textures infostream<<"- Rebuilding images and textures"<<std::endl; - RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 70); + m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 70); m_tsrc->rebuildImagesAndTextures(); delete[] text; // Rebuild shaders infostream<<"- Rebuilding shaders"<<std::endl; text = wgettext("Rebuilding shaders..."); - RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 71); + m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 71); m_shsrc->rebuildShaders(); delete[] text; // Update node aliases infostream<<"- Updating node aliases"<<std::endl; text = wgettext("Initializing nodes..."); - RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 72); + m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 72); m_nodedef->updateAliases(m_itemdef); for (const auto &path : getTextureDirs()) { TextureOverrideSource override_source(path + DIR_DELIM + "override.txt"); @@ -1765,7 +1760,7 @@ void Client::afterContentReceived() tu_args.last_percent = 0; tu_args.text_base = wgettext("Initializing nodes"); tu_args.tsrc = m_tsrc; - m_nodedef->updateTextures(this, texture_update_progress, &tu_args); + m_nodedef->updateTextures(this, &tu_args); delete[] tu_args.text_base; // Start mesh update thread after setting up content definitions @@ -1779,7 +1774,7 @@ void Client::afterContentReceived() m_script->on_client_ready(m_env.getLocalPlayer()); text = wgettext("Done!"); - RenderingEngine::draw_load_screen(text, guienv, m_tsrc, 0, 100); + m_rendering_engine->draw_load_screen(text, guienv, m_tsrc, 0, 100); infostream<<"Client::afterContentReceived() done"<<std::endl; delete[] text; } @@ -1797,7 +1792,7 @@ float Client::getCurRate() void Client::makeScreenshot() { - irr::video::IVideoDriver *driver = RenderingEngine::get_video_driver(); + irr::video::IVideoDriver *driver = m_rendering_engine->get_video_driver(); irr::video::IImage* const raw_image = driver->createScreenShot(); if (!raw_image) @@ -1947,23 +1942,17 @@ scene::IAnimatedMesh* Client::getMesh(const std::string &filename, bool cache) // Create the mesh, remove it from cache and return it // This allows unique vertex colors and other properties for each instance -#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8 - io::IReadFile *rfile = RenderingEngine::get_filesystem()->createMemoryReadFile( + io::IReadFile *rfile = m_rendering_engine->get_filesystem()->createMemoryReadFile( data.c_str(), data.size(), filename.c_str()); -#else - Buffer<char> data_rw(data.c_str(), data.size()); // Const-incorrect Irrlicht - io::IReadFile *rfile = RenderingEngine::get_filesystem()->createMemoryReadFile( - *data_rw, data_rw.getSize(), filename.c_str()); -#endif FATAL_ERROR_IF(!rfile, "Could not create/open RAM file"); - scene::IAnimatedMesh *mesh = RenderingEngine::get_scene_manager()->getMesh(rfile); + scene::IAnimatedMesh *mesh = m_rendering_engine->get_scene_manager()->getMesh(rfile); rfile->drop(); if (!mesh) return nullptr; mesh->grab(); if (!cache) - RenderingEngine::get_mesh_cache()->removeMesh(mesh); + m_rendering_engine->removeMesh(mesh); return mesh; } diff --git a/src/client/client.h b/src/client/client.h index 3e346369b..8d7f63c0c 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -45,6 +45,7 @@ struct ClientEvent; struct MeshMakeData; struct ChatMessage; class MapBlockMesh; +class RenderingEngine; class IWritableTextureSource; class IWritableShaderSource; class ISoundManager; @@ -122,6 +123,7 @@ public: NodeDefManager *nodedef, ISoundManager *sound, MtEventManager *event, + RenderingEngine *rendering_engine, bool ipv6, GameUI *game_ui ); @@ -346,6 +348,7 @@ public: float mediaReceiveProgress(); void afterContentReceived(); + void showUpdateProgressTexture(void *args, u32 progress, u32 max_progress); float getRTT(); float getCurRate(); @@ -354,6 +357,7 @@ public: void setCamera(Camera* camera) { m_camera = camera; } Camera* getCamera () { return m_camera; } + scene::ISceneManager *getSceneManager(); bool shouldShowMinimap() const; @@ -381,6 +385,7 @@ public: // Insert a media file appropriately into the appropriate manager bool loadMedia(const std::string &data, const std::string &filename, bool from_media_push = false); + // Send a request for conventional media transfer void request_media(const std::vector<std::string> &file_requests); @@ -476,6 +481,7 @@ private: NodeDefManager *m_nodedef; ISoundManager *m_sound; MtEventManager *m_event; + RenderingEngine *m_rendering_engine; ClientEnvironment m_env; diff --git a/src/client/clientenvironment.cpp b/src/client/clientenvironment.cpp index 8e0d00bc9..f9c20b2df 100644 --- a/src/client/clientenvironment.cpp +++ b/src/client/clientenvironment.cpp @@ -235,7 +235,16 @@ void ClientEnvironment::step(float dtime) &player_collisions); } - bool player_immortal = lplayer->getCAO() && lplayer->getCAO()->isImmortal(); + bool player_immortal = false; + f32 player_fall_factor = 1.0f; + GenericCAO *playercao = lplayer->getCAO(); + if (playercao) { + player_immortal = playercao->isImmortal(); + int addp_p = itemgroup_get(playercao->getGroups(), + "fall_damage_add_percent"); + // convert armor group into an usable fall damage factor + player_fall_factor = 1.0f + (float)addp_p / 100.0f; + } for (const CollisionInfo &info : player_collisions) { v3f speed_diff = info.new_speed - info.old_speed;; @@ -248,17 +257,20 @@ void ClientEnvironment::step(float dtime) speed_diff.Z = 0; f32 pre_factor = 1; // 1 hp per node/s f32 tolerance = BS*14; // 5 without damage - f32 post_factor = 1; // 1 hp per node/s if (info.type == COLLISION_NODE) { const ContentFeatures &f = m_client->ndef()-> get(m_map->getNode(info.node_p)); - // Determine fall damage multiplier - int addp = itemgroup_get(f.groups, "fall_damage_add_percent"); - pre_factor = 1.0f + (float)addp / 100.0f; + // Determine fall damage modifier + int addp_n = itemgroup_get(f.groups, "fall_damage_add_percent"); + // convert node group to an usable fall damage factor + f32 node_fall_factor = 1.0f + (float)addp_n / 100.0f; + // combine both player fall damage modifiers + pre_factor = node_fall_factor * player_fall_factor; } float speed = pre_factor * speed_diff.getLength(); - if (speed > tolerance && !player_immortal) { - f32 damage_f = (speed - tolerance) / BS * post_factor; + + if (speed > tolerance && !player_immortal && pre_factor > 0.0f) { + f32 damage_f = (speed - tolerance) / BS; u16 damage = (u16)MYMIN(damage_f + 0.5, U16_MAX); if (damage != 0) { damageLocalPlayer(damage, true); @@ -340,7 +352,7 @@ u16 ClientEnvironment::addActiveObject(ClientActiveObject *object) if (!m_ao_manager.registerObject(object)) return 0; - object->addToScene(m_texturesource); + object->addToScene(m_texturesource, m_client->getSceneManager()); // Update lighting immediately object->updateLight(getDayNightRatio()); diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index 2bb0bc385..6db5f2e70 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -80,7 +80,7 @@ ClientLauncher::~ClientLauncher() delete g_fontengine; delete g_gamecallback; - delete RenderingEngine::get_instance(); + delete m_rendering_engine; #if USE_SOUND g_sound_manager_singleton.reset(); @@ -101,7 +101,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args) // List video modes if requested if (list_video_modes) - return RenderingEngine::print_video_modes(); + return m_rendering_engine->print_video_modes(); #if USE_SOUND if (g_settings->getBool("enable_sound")) @@ -120,12 +120,12 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args) return true; } - if (RenderingEngine::get_video_driver() == NULL) { + if (m_rendering_engine->get_video_driver() == NULL) { errorstream << "Could not initialize video driver." << std::endl; return false; } - RenderingEngine::get_instance()->setupTopLevelWindow(PROJECT_NAME_C); + m_rendering_engine->setupTopLevelWindow(PROJECT_NAME_C); /* This changes the minimum allowed number of vertices in a VBO. @@ -136,15 +136,15 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args) // Create game callback for menus g_gamecallback = new MainGameCallback(); - RenderingEngine::get_instance()->setResizable(true); + m_rendering_engine->setResizable(true); init_input(); - RenderingEngine::get_scene_manager()->getParameters()-> + m_rendering_engine->get_scene_manager()->getParameters()-> setAttribute(scene::ALLOW_ZWRITE_ON_TRANSPARENT, true); - guienv = RenderingEngine::get_gui_env(); - skin = RenderingEngine::get_gui_env()->getSkin(); + guienv = m_rendering_engine->get_gui_env(); + skin = guienv->getSkin(); skin->setColor(gui::EGDC_BUTTON_TEXT, video::SColor(255, 255, 255, 255)); skin->setColor(gui::EGDC_3D_LIGHT, video::SColor(0, 0, 0, 0)); skin->setColor(gui::EGDC_3D_HIGH_LIGHT, video::SColor(255, 30, 30, 30)); @@ -166,7 +166,7 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args) sprite_path.append("checkbox_16.png"); // Texture dimensions should be a power of 2 gui::IGUISpriteBank *sprites = skin->getSpriteBank(); - video::IVideoDriver *driver = RenderingEngine::get_video_driver(); + video::IVideoDriver *driver = m_rendering_engine->get_video_driver(); video::ITexture *sprite_texture = driver->getTexture(sprite_path.c_str()); if (sprite_texture) { s32 sprite_id = sprites->addTextureAsSprite(sprite_texture); @@ -178,15 +178,13 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args) g_fontengine = new FontEngine(guienv); FATAL_ERROR_IF(g_fontengine == NULL, "Font engine creation failed."); -#if (IRRLICHT_VERSION_MAJOR >= 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2 // Irrlicht 1.8 input colours skin->setColor(gui::EGDC_EDITABLE, video::SColor(255, 128, 128, 128)); skin->setColor(gui::EGDC_FOCUSED_EDITABLE, video::SColor(255, 96, 134, 49)); -#endif // Create the menu clouds if (!g_menucloudsmgr) - g_menucloudsmgr = RenderingEngine::get_scene_manager()->createNewSceneManager(); + g_menucloudsmgr = m_rendering_engine->get_scene_manager()->createNewSceneManager(); if (!g_menuclouds) g_menuclouds = new Clouds(g_menucloudsmgr, -1, rand()); g_menuclouds->setHeight(100.0f); @@ -214,11 +212,11 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args) bool retval = true; bool *kill = porting::signal_handler_killstatus(); - while (RenderingEngine::run() && !*kill && + while (m_rendering_engine->run() && !*kill && !g_gamecallback->shutdown_requested) { // Set the window caption const wchar_t *text = wgettext("Main Menu"); - RenderingEngine::get_raw_device()-> + m_rendering_engine->get_raw_device()-> setWindowCaption((utf8_to_wide(PROJECT_NAME_C) + L" " + utf8_to_wide(g_version_hash) + L" [" + text + L"]").c_str()); @@ -226,14 +224,14 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args) try { // This is used for catching disconnects - RenderingEngine::get_gui_env()->clear(); + m_rendering_engine->get_gui_env()->clear(); /* We need some kind of a root node to be able to add custom gui elements directly on the screen. Otherwise they won't be automatically drawn. */ - guiroot = RenderingEngine::get_gui_env()->addStaticText(L"", + guiroot = m_rendering_engine->get_gui_env()->addStaticText(L"", core::rect<s32>(0, 0, 10000, 10000)); bool game_has_run = launch_game(error_message, reconnect_requested, @@ -256,29 +254,30 @@ bool ClientLauncher::run(GameStartData &start_data, const Settings &cmd_args) } // Break out of menu-game loop to shut down cleanly - if (!RenderingEngine::get_raw_device()->run() || *kill) { + if (!m_rendering_engine->run() || *kill) { if (!g_settings_path.empty()) g_settings->updateConfigFile(g_settings_path.c_str()); break; } - RenderingEngine::get_video_driver()->setTextureCreationFlag( + m_rendering_engine->get_video_driver()->setTextureCreationFlag( video::ETCF_CREATE_MIP_MAPS, g_settings->getBool("mip_map")); #ifdef HAVE_TOUCHSCREENGUI - receiver->m_touchscreengui = new TouchScreenGUI(RenderingEngine::get_raw_device(), receiver); + receiver->m_touchscreengui = new TouchScreenGUI(m_rendering_engine->get_raw_device(), receiver); g_touchscreengui = receiver->m_touchscreengui; #endif the_game( kill, input, + m_rendering_engine, start_data, error_message, chat_backend, &reconnect_requested ); - RenderingEngine::get_scene_manager()->clear(); + m_rendering_engine->get_scene_manager()->clear(); #ifdef HAVE_TOUCHSCREENGUI delete g_touchscreengui; @@ -346,8 +345,8 @@ void ClientLauncher::init_args(GameStartData &start_data, const Settings &cmd_ar bool ClientLauncher::init_engine() { receiver = new MyEventReceiver(); - new RenderingEngine(receiver); - return RenderingEngine::get_raw_device() != nullptr; + m_rendering_engine = new RenderingEngine(receiver); + return m_rendering_engine->get_raw_device() != nullptr; } void ClientLauncher::init_input() @@ -364,7 +363,7 @@ void ClientLauncher::init_input() // Make sure this is called maximum once per // irrlicht device, otherwise it will give you // multiple events for the same joystick. - if (RenderingEngine::get_raw_device()->activateJoysticks(infos)) { + if (m_rendering_engine->get_raw_device()->activateJoysticks(infos)) { infostream << "Joystick support enabled" << std::endl; joystick_infos.reserve(infos.size()); for (u32 i = 0; i < infos.size(); i++) { @@ -471,7 +470,7 @@ bool ClientLauncher::launch_game(std::string &error_message, start_data.address.empty() && !start_data.name.empty(); } - if (!RenderingEngine::run()) + if (!m_rendering_engine->run()) return false; if (!start_data.isSinglePlayer() && start_data.name.empty()) { @@ -543,14 +542,14 @@ bool ClientLauncher::launch_game(std::string &error_message, void ClientLauncher::main_menu(MainMenuData *menudata) { bool *kill = porting::signal_handler_killstatus(); - video::IVideoDriver *driver = RenderingEngine::get_video_driver(); + video::IVideoDriver *driver = m_rendering_engine->get_video_driver(); infostream << "Waiting for other menus" << std::endl; - while (RenderingEngine::get_raw_device()->run() && !*kill) { + while (m_rendering_engine->run() && !*kill) { if (!isMenuActive()) break; driver->beginScene(true, true, video::SColor(255, 128, 128, 128)); - RenderingEngine::get_gui_env()->drawAll(); + m_rendering_engine->get_gui_env()->drawAll(); driver->endScene(); // On some computers framerate doesn't seem to be automatically limited sleep_ms(25); @@ -559,14 +558,14 @@ void ClientLauncher::main_menu(MainMenuData *menudata) // Cursor can be non-visible when coming from the game #ifndef ANDROID - RenderingEngine::get_raw_device()->getCursorControl()->setVisible(true); + m_rendering_engine->get_raw_device()->getCursorControl()->setVisible(true); #endif /* show main menu */ - GUIEngine mymenu(&input->joystick, guiroot, &g_menumgr, menudata, *kill); + GUIEngine mymenu(&input->joystick, guiroot, m_rendering_engine, &g_menumgr, menudata, *kill); /* leave scene manager in a clean state */ - RenderingEngine::get_scene_manager()->clear(); + m_rendering_engine->get_scene_manager()->clear(); } void ClientLauncher::speed_tests() diff --git a/src/client/clientlauncher.h b/src/client/clientlauncher.h index b280d8e6b..79727e1fe 100644 --- a/src/client/clientlauncher.h +++ b/src/client/clientlauncher.h @@ -49,6 +49,7 @@ private: bool list_video_modes = false; bool skip_main_menu = false; bool random_input = false; + RenderingEngine *m_rendering_engine = nullptr; InputHandler *input = nullptr; MyEventReceiver *receiver = nullptr; gui::IGUISkin *skin = nullptr; diff --git a/src/client/clientmap.cpp b/src/client/clientmap.cpp index 6110c90e3..29a7fd3ba 100644 --- a/src/client/clientmap.cpp +++ b/src/client/clientmap.cpp @@ -64,12 +64,13 @@ void MeshBufListList::add(scene::IMeshBuffer *buf, v3s16 position, u8 layer) ClientMap::ClientMap( Client *client, + RenderingEngine *rendering_engine, MapDrawControl &control, s32 id ): Map(client), - scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(), - RenderingEngine::get_scene_manager(), id), + scene::ISceneNode(rendering_engine->get_scene_manager()->getRootSceneNode(), + rendering_engine->get_scene_manager(), id), m_client(client), m_control(control) { @@ -317,7 +318,7 @@ void ClientMap::renderMap(video::IVideoDriver* driver, s32 pass) v3f block_pos_r = intToFloat(block->getPosRelative() + MAP_BLOCKSIZE / 2, BS); float d = camera_position.getDistanceFrom(block_pos_r); d = MYMAX(0,d - BLOCK_MAX_RADIUS); - + // Mesh animation if (pass == scene::ESNRP_SOLID) { //MutexAutoLock lock(block->mesh_mutex); @@ -499,12 +500,12 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor, static v3f z_directions[50] = { v3f(-100, 0, 0) }; - static f32 z_offsets[sizeof(z_directions)/sizeof(*z_directions)] = { + static f32 z_offsets[50] = { -1000, }; - if(z_directions[0].X < -99){ - for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++){ + if (z_directions[0].X < -99) { + for (u32 i = 0; i < ARRLEN(z_directions); i++) { // Assumes FOV of 72 and 16/9 aspect ratio z_directions[i] = v3f( 0.02 * myrand_range(-100, 100), @@ -520,7 +521,8 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor, if(sunlight_min_d > 35*BS) sunlight_min_d = 35*BS; std::vector<int> values; - for(u32 i=0; i<sizeof(z_directions)/sizeof(*z_directions); i++){ + values.reserve(ARRLEN(z_directions)); + for (u32 i = 0; i < ARRLEN(z_directions); i++) { v3f z_dir = z_directions[i]; core::CMatrix4<f32> a; a.buildRotateFromTo(v3f(0,1,0), z_dir); diff --git a/src/client/clientmap.h b/src/client/clientmap.h index 57cc4427e..80add4a44 100644 --- a/src/client/clientmap.h +++ b/src/client/clientmap.h @@ -68,6 +68,7 @@ class ClientMap : public Map, public scene::ISceneNode public: ClientMap( Client *client, + RenderingEngine *rendering_engine, MapDrawControl &control, s32 id ); diff --git a/src/client/clientmedia.cpp b/src/client/clientmedia.cpp index c4c08c05d..0f9ba5356 100644 --- a/src/client/clientmedia.cpp +++ b/src/client/clientmedia.cpp @@ -216,7 +216,6 @@ void ClientMediaDownloader::initialStep(Client *client) // This is the first time we use httpfetch, so alloc a caller ID m_httpfetch_caller = httpfetch_caller_alloc(); - m_httpfetch_timeout = g_settings->getS32("curl_timeout"); // Set the active fetch limit to curl_parallel_limit or 84, // whichever is greater. This gives us some leeway so that @@ -258,8 +257,6 @@ void ClientMediaDownloader::initialStep(Client *client) remote->baseurl + MTHASHSET_FILE_NAME; fetch_request.caller = m_httpfetch_caller; fetch_request.request_id = m_httpfetch_next_id; // == i - fetch_request.timeout = m_httpfetch_timeout; - fetch_request.connect_timeout = m_httpfetch_timeout; fetch_request.method = HTTP_POST; fetch_request.raw_data = required_hash_set; fetch_request.extra_headers.emplace_back( @@ -432,9 +429,8 @@ void ClientMediaDownloader::startRemoteMediaTransfers() fetch_request.url = url; fetch_request.caller = m_httpfetch_caller; fetch_request.request_id = m_httpfetch_next_id; - fetch_request.timeout = 0; // no data timeout! - fetch_request.connect_timeout = - m_httpfetch_timeout; + fetch_request.timeout = + g_settings->getS32("curl_file_download_timeout"); httpfetch_async(fetch_request); m_remote_file_transfers.insert(std::make_pair( diff --git a/src/client/clientmedia.h b/src/client/clientmedia.h index 5a918535b..e97a0f24b 100644 --- a/src/client/clientmedia.h +++ b/src/client/clientmedia.h @@ -137,7 +137,6 @@ private: // Status of remote transfers unsigned long m_httpfetch_caller; unsigned long m_httpfetch_next_id = 0; - long m_httpfetch_timeout = 0; s32 m_httpfetch_active = 0; s32 m_httpfetch_active_limit = 0; s32 m_outstanding_hash_sets = 0; diff --git a/src/client/clientobject.h b/src/client/clientobject.h index 4a1743d72..c0b14497c 100644 --- a/src/client/clientobject.h +++ b/src/client/clientobject.h @@ -44,7 +44,7 @@ public: ClientActiveObject(u16 id, Client *client, ClientEnvironment *env); virtual ~ClientActiveObject(); - virtual void addToScene(ITextureSource *tsrc) {} + virtual void addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) = 0; virtual void removeFromScene(bool permanent) {} virtual void updateLight(u32 day_night_ratio) {} diff --git a/src/client/clouds.cpp b/src/client/clouds.cpp index 253dee8b9..5008047af 100644 --- a/src/client/clouds.cpp +++ b/src/client/clouds.cpp @@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc., // Menu clouds are created later class Clouds; Clouds *g_menuclouds = NULL; -irr::scene::ISceneManager *g_menucloudsmgr = NULL; +scene::ISceneManager *g_menucloudsmgr = NULL; // Constant for now static constexpr const float cloud_size = BS * 64.0f; @@ -170,7 +170,7 @@ void Clouds::render() // Read noise - std::vector<char> grid(m_cloud_radius_i * 2 * m_cloud_radius_i * 2); // vector<bool> is broken + std::vector<bool> grid(m_cloud_radius_i * 2 * m_cloud_radius_i * 2); std::vector<video::S3DVertex> vertices; vertices.reserve(16 * m_cloud_radius_i * m_cloud_radius_i); diff --git a/src/client/clouds.h b/src/client/clouds.h index a4d810faa..c009a05b7 100644 --- a/src/client/clouds.h +++ b/src/client/clouds.h @@ -29,8 +29,7 @@ class Clouds; extern Clouds *g_menuclouds; // Scene manager used for menu clouds -namespace irr{namespace scene{class ISceneManager;}} -extern irr::scene::ISceneManager *g_menucloudsmgr; +extern scene::ISceneManager *g_menucloudsmgr; class Clouds : public scene::ISceneNode { diff --git a/src/client/content_cao.cpp b/src/client/content_cao.cpp index 5e9060fc8..1259fcbd3 100644 --- a/src/client/content_cao.cpp +++ b/src/client/content_cao.cpp @@ -24,7 +24,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include <IMeshManipulator.h> #include <IAnimatedMeshSceneNode.h> #include "client/client.h" -#include "client/renderingengine.h" #include "client/sound.h" #include "client/tile.h" #include "util/basic_macros.h" @@ -190,7 +189,7 @@ public: static ClientActiveObject* create(Client *client, ClientEnvironment *env); - void addToScene(ITextureSource *tsrc); + void addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr); void removeFromScene(bool permanent); void updateLight(u32 day_night_ratio); void updateNodePos(); @@ -221,7 +220,7 @@ ClientActiveObject* TestCAO::create(Client *client, ClientEnvironment *env) return new TestCAO(client, env); } -void TestCAO::addToScene(ITextureSource *tsrc) +void TestCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) { if(m_node != NULL) return; @@ -250,7 +249,7 @@ void TestCAO::addToScene(ITextureSource *tsrc) // Add to mesh mesh->addMeshBuffer(buf); buf->drop(); - m_node = RenderingEngine::get_scene_manager()->addMeshSceneNode(mesh, NULL); + m_node = smgr->addMeshSceneNode(mesh, NULL); mesh->drop(); updateNodePos(); } @@ -595,9 +594,9 @@ void GenericCAO::removeFromScene(bool permanent) m_client->getMinimap()->removeMarker(&m_marker); } -void GenericCAO::addToScene(ITextureSource *tsrc) +void GenericCAO::addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr) { - m_smgr = RenderingEngine::get_scene_manager(); + m_smgr = smgr; if (getSceneNode() != NULL) { return; @@ -629,8 +628,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc) } auto grabMatrixNode = [this] { - m_matrixnode = RenderingEngine::get_scene_manager()-> - addDummyTransformationSceneNode(); + m_matrixnode = m_smgr->addDummyTransformationSceneNode(); m_matrixnode->grab(); }; @@ -648,7 +646,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc) if (m_prop.visual == "sprite") { grabMatrixNode(); - m_spritenode = RenderingEngine::get_scene_manager()->addBillboardSceneNode( + m_spritenode = m_smgr->addBillboardSceneNode( m_matrixnode, v2f(1, 1), v3f(0,0,0), -1); m_spritenode->grab(); m_spritenode->setMaterialTexture(0, @@ -733,8 +731,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc) mesh->addMeshBuffer(buf); buf->drop(); } - m_meshnode = RenderingEngine::get_scene_manager()-> - addMeshSceneNode(mesh, m_matrixnode); + m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode); m_meshnode->grab(); mesh->drop(); // Set it to use the materials of the meshbuffers directly. @@ -743,8 +740,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc) } else if (m_prop.visual == "cube") { grabMatrixNode(); scene::IMesh *mesh = createCubeMesh(v3f(BS,BS,BS)); - m_meshnode = RenderingEngine::get_scene_manager()-> - addMeshSceneNode(mesh, m_matrixnode); + m_meshnode = m_smgr->addMeshSceneNode(mesh, m_matrixnode); m_meshnode->grab(); mesh->drop(); @@ -757,8 +753,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc) grabMatrixNode(); scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true); if (mesh) { - m_animated_meshnode = RenderingEngine::get_scene_manager()-> - addAnimatedMeshSceneNode(mesh, m_matrixnode); + m_animated_meshnode = m_smgr->addAnimatedMeshSceneNode(mesh, m_matrixnode); m_animated_meshnode->grab(); mesh->drop(); // The scene node took hold of it @@ -799,8 +794,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc) infostream << "serialized form: " << m_prop.wield_item << std::endl; item.deSerialize(m_prop.wield_item, m_client->idef()); } - m_wield_meshnode = new WieldMeshSceneNode( - RenderingEngine::get_scene_manager(), -1); + m_wield_meshnode = new WieldMeshSceneNode(m_smgr, -1); m_wield_meshnode->setItem(item, m_client, (m_prop.visual == "wielditem")); @@ -1089,7 +1083,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env) } removeFromScene(false); - addToScene(m_client->tsrc()); + addToScene(m_client->tsrc(), m_smgr); // Attachments, part 2: Now that the parent has been refreshed, put its attachments back for (u16 cao_id : m_attachment_child_ids) { @@ -1488,11 +1482,8 @@ void GenericCAO::updateAnimation() if (m_animated_meshnode->getAnimationSpeed() != m_animation_speed) m_animated_meshnode->setAnimationSpeed(m_animation_speed); m_animated_meshnode->setTransitionTime(m_animation_blend); -// Requires Irrlicht 1.8 or greater -#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR > 1 if (m_animated_meshnode->getLoopMode() != m_animation_loop) m_animated_meshnode->setLoopMode(m_animation_loop); -#endif } void GenericCAO::updateAnimationSpeed() @@ -1508,10 +1499,10 @@ void GenericCAO::updateBonePosition() if (m_bone_position.empty() || !m_animated_meshnode) return; - m_animated_meshnode->setJointMode(irr::scene::EJUOR_CONTROL); // To write positions to the mesh on render + m_animated_meshnode->setJointMode(scene::EJUOR_CONTROL); // To write positions to the mesh on render for (auto &it : m_bone_position) { std::string bone_name = it.first; - irr::scene::IBoneSceneNode* bone = m_animated_meshnode->getJointNode(bone_name.c_str()); + scene::IBoneSceneNode* bone = m_animated_meshnode->getJointNode(bone_name.c_str()); if (bone) { bone->setPosition(it.second.X); bone->setRotation(it.second.Y); @@ -1520,7 +1511,7 @@ void GenericCAO::updateBonePosition() // search through bones to find mistakenly rotated bones due to bug in Irrlicht for (u32 i = 0; i < m_animated_meshnode->getJointCount(); ++i) { - irr::scene::IBoneSceneNode *bone = m_animated_meshnode->getJointNode(i); + scene::IBoneSceneNode *bone = m_animated_meshnode->getJointNode(i); if (!bone) continue; @@ -1965,7 +1956,7 @@ void GenericCAO::updateMeshCulling() return; } - irr::scene::ISceneNode *node = getSceneNode(); + scene::ISceneNode *node = getSceneNode(); if (!node) return; diff --git a/src/client/content_cao.h b/src/client/content_cao.h index 450023d19..7e9bb6671 100644 --- a/src/client/content_cao.h +++ b/src/client/content_cao.h @@ -189,6 +189,8 @@ public: const bool isImmortal(); + inline const ObjectProperties &getProperties() const { return m_prop; } + scene::ISceneNode *getSceneNode() const; scene::IAnimatedMeshSceneNode *getAnimatedMeshSceneNode() const; @@ -260,7 +262,7 @@ public: void removeFromScene(bool permanent); - void addToScene(ITextureSource *tsrc); + void addToScene(ITextureSource *tsrc, scene::ISceneManager *smgr); inline void expireVisuals() { diff --git a/src/client/content_mapblock.cpp b/src/client/content_mapblock.cpp index 90284ecce..810c57138 100644 --- a/src/client/content_mapblock.cpp +++ b/src/client/content_mapblock.cpp @@ -60,18 +60,16 @@ static constexpr u16 quad_indices[] = {0, 1, 2, 2, 3, 0}; const std::string MapblockMeshGenerator::raillike_groupname = "connect_to_raillike"; -MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output) +MapblockMeshGenerator::MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output, + scene::IMeshManipulator *mm): + data(input), + collector(output), + nodedef(data->m_client->ndef()), + meshmanip(mm), + blockpos_nodes(data->m_blockpos * MAP_BLOCKSIZE) { - data = input; - collector = output; - - nodedef = data->m_client->ndef(); - meshmanip = RenderingEngine::get_scene_manager()->getMeshManipulator(); - enable_mesh_cache = g_settings->getBool("enable_mesh_cache") && !data->m_smooth_lighting; // Mesh cache is not supported with smooth lighting - - blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE; } void MapblockMeshGenerator::useTile(int index, u8 set_flags, u8 reset_flags, bool special) @@ -968,7 +966,7 @@ void MapblockMeshGenerator::drawPlantlike() draw_style = PLANT_STYLE_CROSS; scale = BS / 2 * f->visual_scale; offset = v3f(0, 0, 0); - rotate_degree = 0; + rotate_degree = 0.0f; random_offset_Y = false; face_num = 0; plant_height = 1.0; @@ -988,7 +986,8 @@ void MapblockMeshGenerator::drawPlantlike() break; case CPT2_DEGROTATE: - rotate_degree = n.param2 * 2; + case CPT2_COLORED_DEGROTATE: + rotate_degree = 1.5f * n.getDegRotate(nodedef); break; case CPT2_LEVELED: @@ -1343,6 +1342,7 @@ void MapblockMeshGenerator::drawMeshNode() u8 facedir = 0; scene::IMesh* mesh; bool private_mesh; // as a grab/drop pair is not thread-safe + int degrotate = 0; if (f->param_type_2 == CPT2_FACEDIR || f->param_type_2 == CPT2_COLORED_FACEDIR) { @@ -1354,9 +1354,12 @@ void MapblockMeshGenerator::drawMeshNode() facedir = n.getWallMounted(nodedef); if (!enable_mesh_cache) facedir = wallmounted_to_facedir[facedir]; + } else if (f->param_type_2 == CPT2_DEGROTATE || + f->param_type_2 == CPT2_COLORED_DEGROTATE) { + degrotate = n.getDegRotate(nodedef); } - if (!data->m_smooth_lighting && f->mesh_ptr[facedir]) { + if (!data->m_smooth_lighting && f->mesh_ptr[facedir] && !degrotate) { // use cached meshes private_mesh = false; mesh = f->mesh_ptr[facedir]; @@ -1364,7 +1367,10 @@ void MapblockMeshGenerator::drawMeshNode() // no cache, clone and rotate mesh private_mesh = true; mesh = cloneMesh(f->mesh_ptr[0]); - rotateMeshBy6dFacedir(mesh, facedir); + if (facedir) + rotateMeshBy6dFacedir(mesh, facedir); + else if (degrotate) + rotateMeshXZby(mesh, 1.5f * degrotate); recalculateBoundingBox(mesh); meshmanip->recalculateNormals(mesh, true, false); } else diff --git a/src/client/content_mapblock.h b/src/client/content_mapblock.h index 487d84a07..237cc7847 100644 --- a/src/client/content_mapblock.h +++ b/src/client/content_mapblock.h @@ -139,7 +139,7 @@ public: // plantlike-specific PlantlikeStyle draw_style; v3f offset; - int rotate_degree; + float rotate_degree; bool random_offset_Y; int face_num; float plant_height; @@ -172,7 +172,8 @@ public: void drawNode(); public: - MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output); + MapblockMeshGenerator(MeshMakeData *input, MeshCollector *output, + scene::IMeshManipulator *mm); void generate(); void renderSingle(content_t node, u8 param2 = 0x00); }; diff --git a/src/client/fontengine.cpp b/src/client/fontengine.cpp index 47218c0d9..0382c2f18 100644 --- a/src/client/fontengine.cpp +++ b/src/client/fontengine.cpp @@ -56,7 +56,7 @@ FontEngine::FontEngine(gui::IGUIEnvironment* env) : readSettings(); - if (m_currentMode == FM_Standard) { + if (m_currentMode != FM_Simple) { g_settings->registerChangedCallback("font_size", font_setting_changed, NULL); g_settings->registerChangedCallback("font_bold", font_setting_changed, NULL); g_settings->registerChangedCallback("font_italic", font_setting_changed, NULL); @@ -66,12 +66,7 @@ FontEngine::FontEngine(gui::IGUIEnvironment* env) : g_settings->registerChangedCallback("font_path_bolditalic", font_setting_changed, NULL); g_settings->registerChangedCallback("font_shadow", font_setting_changed, NULL); g_settings->registerChangedCallback("font_shadow_alpha", font_setting_changed, NULL); - } - else if (m_currentMode == FM_Fallback) { - g_settings->registerChangedCallback("fallback_font_size", font_setting_changed, NULL); g_settings->registerChangedCallback("fallback_font_path", font_setting_changed, NULL); - g_settings->registerChangedCallback("fallback_font_shadow", font_setting_changed, NULL); - g_settings->registerChangedCallback("fallback_font_shadow_alpha", font_setting_changed, NULL); } g_settings->registerChangedCallback("mono_font_path", font_setting_changed, NULL); @@ -102,6 +97,11 @@ void FontEngine::cleanCache() /******************************************************************************/ irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec) { + return getFont(spec, false); +} + +irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec, bool may_fail) +{ if (spec.mode == FM_Unspecified) { spec.mode = m_currentMode; } else if (m_currentMode == FM_Simple) { @@ -112,6 +112,10 @@ irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec) // Support for those could be added, but who cares? spec.bold = false; spec.italic = false; + } else if (spec.mode == _FM_Fallback) { + // Fallback font doesn't support these either + spec.bold = false; + spec.italic = false; } // Fallback to default size @@ -130,6 +134,13 @@ irr::gui::IGUIFont *FontEngine::getFont(FontSpec spec) else font = initFont(spec); + if (!font && !may_fail) { + errorstream << "Minetest cannot continue without a valid font. " + "Please correct the 'font_path' setting or install the font " + "file in the proper location." << std::endl; + abort(); + } + m_font_cache[spec.getHash()][spec.size] = font; return font; @@ -204,20 +215,9 @@ unsigned int FontEngine::getFontSize(FontMode mode) void FontEngine::readSettings() { if (USE_FREETYPE && g_settings->getBool("freetype")) { - m_default_size[FM_Standard] = g_settings->getU16("font_size"); - m_default_size[FM_Fallback] = g_settings->getU16("fallback_font_size"); - m_default_size[FM_Mono] = g_settings->getU16("mono_font_size"); - - /*~ DO NOT TRANSLATE THIS LITERALLY! - This is a special string. Put either "no" or "yes" - into the translation field (literally). - Choose "yes" if the language requires use of the fallback - font, "no" otherwise. - The fallback font is (normally) required for languages with - non-Latin script, like Chinese. - When in doubt, test your translation. */ - m_currentMode = is_yes(gettext("needs_fallback_font")) ? - FM_Fallback : FM_Standard; + m_default_size[FM_Standard] = g_settings->getU16("font_size"); + m_default_size[_FM_Fallback] = g_settings->getU16("font_size"); + m_default_size[FM_Mono] = g_settings->getU16("mono_font_size"); m_default_bold = g_settings->getBool("font_bold"); m_default_italic = g_settings->getBool("font_italic"); @@ -271,18 +271,8 @@ gui::IGUIFont *FontEngine::initFont(const FontSpec &spec) assert(spec.size != FONT_SIZE_UNSPECIFIED); std::string setting_prefix = ""; - - switch (spec.mode) { - case FM_Fallback: - setting_prefix = "fallback_"; - break; - case FM_Mono: - case FM_SimpleMono: - setting_prefix = "mono_"; - break; - default: - break; - } + if (spec.mode == FM_Mono) + setting_prefix = "mono_"; std::string setting_suffix = ""; if (spec.bold) @@ -305,38 +295,41 @@ gui::IGUIFont *FontEngine::initFont(const FontSpec &spec) g_settings->getU16NoEx(setting_prefix + "font_shadow_alpha", font_shadow_alpha); - std::string wanted_font_path; - wanted_font_path = g_settings->get(setting_prefix + "font_path" + setting_suffix); + std::string path_setting; + if (spec.mode == _FM_Fallback) + path_setting = "fallback_font_path"; + else + path_setting = setting_prefix + "font_path" + setting_suffix; std::string fallback_settings[] = { - wanted_font_path, - g_settings->get("fallback_font_path"), - Settings::getLayer(SL_DEFAULTS)->get(setting_prefix + "font_path") + g_settings->get(path_setting), + Settings::getLayer(SL_DEFAULTS)->get(path_setting) }; #if USE_FREETYPE for (const std::string &font_path : fallback_settings) { - irr::gui::IGUIFont *font = gui::CGUITTFont::createTTFont(m_env, + gui::CGUITTFont *font = gui::CGUITTFont::createTTFont(m_env, font_path.c_str(), size, true, true, font_shadow, font_shadow_alpha); - if (font) - return font; - - errorstream << "FontEngine: Cannot load '" << font_path << + if (!font) { + errorstream << "FontEngine: Cannot load '" << font_path << "'. Trying to fall back to another path." << std::endl; - } - + continue; + } - // give up - errorstream << "minetest can not continue without a valid font. " - "Please correct the 'font_path' setting or install the font " - "file in the proper location" << std::endl; + if (spec.mode != _FM_Fallback) { + FontSpec spec2(spec); + spec2.mode = _FM_Fallback; + font->setFallback(getFont(spec2, true)); + } + return font; + } #else - errorstream << "FontEngine: Tried to load freetype fonts but Minetest was" - " not compiled with that library." << std::endl; + errorstream << "FontEngine: Tried to load TTF font but Minetest was" + " compiled without Freetype." << std::endl; #endif - abort(); + return nullptr; } /** initialize a font without freetype */ diff --git a/src/client/fontengine.h b/src/client/fontengine.h index e27ef60e9..3d389ea48 100644 --- a/src/client/fontengine.h +++ b/src/client/fontengine.h @@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc., enum FontMode : u8 { FM_Standard = 0, FM_Mono, - FM_Fallback, + _FM_Fallback, // do not use directly FM_Simple, FM_SimpleMono, FM_MaxMode, @@ -47,7 +47,7 @@ struct FontSpec { bold(bold), italic(italic) {} - u16 getHash() + u16 getHash() const { return (mode << 2) | (static_cast<u8>(bold) << 1) | static_cast<u8>(italic); } @@ -132,10 +132,12 @@ public: void readSettings(); private: + irr::gui::IGUIFont *getFont(FontSpec spec, bool may_fail); + /** update content of font cache in case of a setting change made it invalid */ void updateFontCache(); - /** initialize a new font */ + /** initialize a new TTF font */ gui::IGUIFont *initFont(const FontSpec &spec); /** initialize a font without freetype */ diff --git a/src/client/game.cpp b/src/client/game.cpp index e1f2fbe75..5bfe55e66 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -153,7 +153,7 @@ Game::~Game() delete itemdef_manager; delete draw_control; - extendedResourceCleanup(); + clearTextureNameCache(); g_settings->deregisterChangedCallback("doubletap_jump", &settingChangedCallback, this); @@ -191,6 +191,7 @@ Game::~Game() bool Game::startup(bool *kill, InputHandler *input, + RenderingEngine *rendering_engine, const GameStartData &start_data, std::string &error_message, bool *reconnect, @@ -198,21 +199,21 @@ bool Game::startup(bool *kill, { // "cache" - this->device = RenderingEngine::get_raw_device(); + m_rendering_engine = rendering_engine; + device = m_rendering_engine->get_raw_device(); this->kill = kill; this->error_message = &error_message; - this->reconnect_requested = reconnect; + reconnect_requested = reconnect; this->input = input; this->chat_backend = chat_backend; - this->simple_singleplayer_mode = start_data.isSinglePlayer(); + simple_singleplayer_mode = start_data.isSinglePlayer(); input->keycache.populate(); driver = device->getVideoDriver(); - smgr = RenderingEngine::get_scene_manager(); + smgr = m_rendering_engine->get_scene_manager(); - RenderingEngine::get_scene_manager()->getParameters()-> - setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true); + smgr->getParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_MATERIAL_FILES, true); // Reinit runData runData = GameRunData(); @@ -233,7 +234,7 @@ bool Game::startup(bool *kill, if (!createClient(start_data)) return false; - RenderingEngine::initialize(client, hud); + m_rendering_engine->initialize(client, hud); return true; } @@ -250,7 +251,7 @@ void Game::run() Profiler::GraphValues dummyvalues; g_profiler->graphGet(dummyvalues); - draw_times.last_time = RenderingEngine::get_timer_time(); + draw_times.last_time = m_rendering_engine->get_timer_time(); set_light_table(g_settings->getFloat("display_gamma")); @@ -262,12 +263,12 @@ void Game::run() irr::core::dimension2d<u32> previous_screen_size(g_settings->getU16("screen_w"), g_settings->getU16("screen_h")); - while (RenderingEngine::run() + while (m_rendering_engine->run() && !(*kill || g_gamecallback->shutdown_requested || (server && server->isShutdownRequested()))) { const irr::core::dimension2d<u32> ¤t_screen_size = - RenderingEngine::get_video_driver()->getScreenSize(); + m_rendering_engine->get_video_driver()->getScreenSize(); // Verify if window size has changed and save it if it's the case // Ensure evaluating settings->getBool after verifying screensize // First condition is cheaper @@ -280,7 +281,7 @@ void Game::run() } // Calculate dtime = - // RenderingEngine::run() from this iteration + // m_rendering_engine->run() from this iteration // + Sleep time until the wanted FPS are reached limitFps(&draw_times, &dtime); @@ -329,7 +330,7 @@ void Game::run() void Game::shutdown() { - RenderingEngine::finalize(); + m_rendering_engine->finalize(); #if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 8 if (g_settings->get("3d_mode") == "pageflip") { driver->setRenderTarget(irr::video::ERT_STEREO_BOTH_BUFFERS); @@ -488,7 +489,7 @@ bool Game::createClient(const GameStartData &start_data) { showOverlayMessage(N_("Creating client..."), 0, 10); - draw_control = new MapDrawControl; + draw_control = new MapDrawControl(); if (!draw_control) return false; @@ -529,7 +530,7 @@ bool Game::createClient(const GameStartData &start_data) /* Camera */ - camera = new Camera(*draw_control, client); + camera = new Camera(*draw_control, client, m_rendering_engine); if (!camera->successfullyCreated(*error_message)) return false; client->setCamera(camera); @@ -541,7 +542,7 @@ bool Game::createClient(const GameStartData &start_data) /* Skybox */ - sky = new Sky(-1, texture_src, shader_src); + sky = new Sky(-1, m_rendering_engine, texture_src, shader_src); scsf->setSky(sky); skybox = NULL; // This is used/set later on in the main run loop @@ -563,16 +564,28 @@ bool Game::createClient(const GameStartData &start_data) std::wstring str = utf8_to_wide(PROJECT_NAME_C); str += L" "; str += utf8_to_wide(g_version_hash); + { + const wchar_t *text = nullptr; + if (simple_singleplayer_mode) + text = wgettext("Singleplayer"); + else + text = wgettext("Multiplayer"); + str += L" ["; + str += text; + str += L"]"; + delete text; + } str += L" ["; str += L"Minetest Hackclient"; str += L"]"; + device->setWindowCaption(str.c_str()); LocalPlayer *player = client->getEnv().getLocalPlayer(); player->hurt_tilt_timer = 0; player->hurt_tilt_strength = 0; - hud = new Hud(guienv, client, player, &player->inventory); + hud = new Hud(client, player, &player->inventory); mapper = client->getMinimap(); @@ -663,7 +676,7 @@ bool Game::connectToServer(const GameStartData &start_data, start_data.password, start_data.address, *draw_control, texture_src, shader_src, itemdef_manager, nodedef_manager, sound, eventmgr, - connect_address.isIPv6(), m_game_ui.get()); + m_rendering_engine, connect_address.isIPv6(), m_game_ui.get()); client->m_simple_singleplayer_mode = simple_singleplayer_mode; @@ -685,9 +698,9 @@ bool Game::connectToServer(const GameStartData &start_data, f32 dtime; f32 wait_time = 0; // in seconds - fps_control.last_time = RenderingEngine::get_timer_time(); + fps_control.last_time = m_rendering_engine->get_timer_time(); - while (RenderingEngine::run()) { + while (m_rendering_engine->run()) { limitFps(&fps_control, &dtime); @@ -724,7 +737,7 @@ bool Game::connectToServer(const GameStartData &start_data, if (client->m_is_registration_confirmation_state) { if (registration_confirmation_shown) { // Keep drawing the GUI - RenderingEngine::draw_menu_scene(guienv, dtime, true); + m_rendering_engine->draw_menu_scene(guienv, dtime, true); } else { registration_confirmation_shown = true; (new GUIConfirmRegistration(guienv, guienv->getRootGUIElement(), -1, @@ -734,7 +747,7 @@ bool Game::connectToServer(const GameStartData &start_data, } else { wait_time += dtime; // Only time out if we aren't waiting for the server we started - if (!start_data.local_server && !start_data.isSinglePlayer() && wait_time > 10) { + if (!start_data.address.empty() && wait_time > 10) { *error_message = "Connection timed out."; errorstream << *error_message << std::endl; break; @@ -760,9 +773,9 @@ bool Game::getServerContent(bool *aborted) FpsControl fps_control = { 0 }; f32 dtime; // in seconds - fps_control.last_time = RenderingEngine::get_timer_time(); + fps_control.last_time = m_rendering_engine->get_timer_time(); - while (RenderingEngine::run()) { + while (m_rendering_engine->run()) { limitFps(&fps_control, &dtime); @@ -800,13 +813,13 @@ bool Game::getServerContent(bool *aborted) if (!client->itemdefReceived()) { const wchar_t *text = wgettext("Item definitions..."); progress = 25; - RenderingEngine::draw_load_screen(text, guienv, texture_src, + m_rendering_engine->draw_load_screen(text, guienv, texture_src, dtime, progress); delete[] text; } else if (!client->nodedefReceived()) { const wchar_t *text = wgettext("Node definitions..."); progress = 30; - RenderingEngine::draw_load_screen(text, guienv, texture_src, + m_rendering_engine->draw_load_screen(text, guienv, texture_src, dtime, progress); delete[] text; } else { @@ -833,7 +846,7 @@ bool Game::getServerContent(bool *aborted) } progress = 30 + client->mediaReceiveProgress() * 35 + 0.5; - RenderingEngine::draw_load_screen(utf8_to_wide(message.str()), guienv, + m_rendering_engine->draw_load_screen(utf8_to_wide(message.str()), guienv, texture_src, dtime, progress); } } @@ -1150,6 +1163,8 @@ void Game::processKeyInput() toggleCinematic(); } else if (wasKeyDown(KeyType::SCREENSHOT)) { client->makeScreenshot(); + } else if (wasKeyDown(KeyType::TOGGLE_BLOCK_BOUNDS)) { + hud->toggleBlockBounds(); } else if (wasKeyDown(KeyType::TOGGLE_HUD)) { m_game_ui->toggleHud(); } else if (wasKeyDown(KeyType::MINIMAP)) { @@ -1264,8 +1279,8 @@ void Game::openInventory() || !client->getScript()->on_inventory_open(fs_src->m_client->getInventory(inventoryloc))) { TextDest *txt_dst = new TextDestPlayerInventory(client); auto *&formspec = m_game_ui->updateFormspec(""); - GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src, - txt_dst, client->getFormspecPrepend(), sound); + GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(), + &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound); formspec->setFormSpec(fs_src->getForm(), inventoryloc); } @@ -1838,14 +1853,18 @@ void Game::handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation // Damage flash and hurt tilt are not used at death if (client->getHP() > 0) { - runData.damage_flash += 95.0f + 3.2f * event->player_damage.amount; - runData.damage_flash = MYMIN(runData.damage_flash, 127.0f); - LocalPlayer *player = client->getEnv().getLocalPlayer(); + f32 hp_max = player->getCAO() ? + player->getCAO()->getProperties()->hp_max : PLAYER_MAX_HP_DEFAULT; + f32 damage_ratio = event->player_damage.amount / hp_max; + + runData.damage_flash += 95.0f + 64.f * damage_ratio; + runData.damage_flash = MYMIN(runData.damage_flash, 127.0f); + player->hurt_tilt_timer = 1.5f; player->hurt_tilt_strength = - rangelim(event->player_damage.amount / 4.0f, 1.0f, 4.0f); + rangelim(damage_ratio * 5.0f, 1.0f, 4.0f); } // Play damage sound @@ -1889,8 +1908,8 @@ void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation new TextDestPlayerInventory(client, *(event->show_formspec.formname)); auto *&formspec = m_game_ui->updateFormspec(*(event->show_formspec.formname)); - GUIFormSpecMenu::create(formspec, client, &input->joystick, - fs_src, txt_dst, client->getFormspecPrepend(), sound); + GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(), + &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound); } delete event->show_formspec.formspec; @@ -1909,7 +1928,7 @@ void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrienta FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec); LocalFormspecHandler *txt_dst = new LocalFormspecHandler(*event->show_formspec.formname, client); - GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, &input->joystick, + GUIFormSpecMenu::create(m_game_ui->getFormspecGUI(), client, m_rendering_engine->get_gui_env(), &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound); } @@ -2075,6 +2094,7 @@ void Game::handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam) "custom" ); } + delete event->set_sky; } @@ -2607,8 +2627,8 @@ bool Game::nodePlacement(const ItemDefinition &selected_def, TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client); auto *&formspec = m_game_ui->updateFormspec(""); - GUIFormSpecMenu::create(formspec, client, &input->joystick, fs_src, - txt_dst, client->getFormspecPrepend(), sound); + GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(), + &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound); formspec->setFormSpec(meta->getString("formspec"), inventoryloc); return false; @@ -3170,7 +3190,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, } catch (SettingNotFoundException) { } #endif - RenderingEngine::draw_scene(skycolor, m_game_ui->m_flags.show_hud, + m_rendering_engine->draw_scene(skycolor, m_game_ui->m_flags.show_hud, m_game_ui->m_flags.show_minimap, draw_wield_tool, draw_crosshair); /* @@ -3309,7 +3329,7 @@ inline void Game::limitFps(FpsControl *fps_timings, f32 *dtime) void Game::showOverlayMessage(const char *msg, float dtime, int percent, bool draw_clouds) { const wchar_t *wmsg = wgettext(msg); - RenderingEngine::draw_load_screen(wmsg, guienv, texture_src, dtime, percent, + m_rendering_engine->draw_load_screen(wmsg, guienv, texture_src, dtime, percent, draw_clouds); delete[] wmsg; } @@ -3392,27 +3412,6 @@ bool Game::wasKeyReleased(GameKeyType k) ****************************************************************************/ /****************************************************************************/ -void Game::extendedResourceCleanup() -{ - // Extended resource accounting - infostream << "Irrlicht resources after cleanup:" << std::endl; - infostream << "\tRemaining meshes : " - << RenderingEngine::get_mesh_cache()->getMeshCount() << std::endl; - infostream << "\tRemaining textures : " - << driver->getTextureCount() << std::endl; - - for (unsigned int i = 0; i < driver->getTextureCount(); i++) { - irr::video::ITexture *texture = driver->getTextureByIndex(i); - infostream << "\t\t" << i << ":" << texture->getName().getPath().c_str() - << std::endl; - } - - clearTextureNameCache(); - infostream << "\tRemaining materials: " - << driver-> getMaterialRendererCount() - << " (note: irrlicht doesn't support removing renderers)" << std::endl; -} - void Game::showDeathFormspec() { static std::string formspec_str = @@ -3430,8 +3429,8 @@ void Game::showDeathFormspec() LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", client); auto *&formspec = m_game_ui->getFormspecGUI(); - GUIFormSpecMenu::create(formspec, client, &input->joystick, - fs_src, txt_dst, client->getFormspecPrepend(), sound); + GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(), + &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound); formspec->setFocus("btn_respawn"); } @@ -3572,8 +3571,8 @@ void Game::showPauseMenu() LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU"); auto *&formspec = m_game_ui->getFormspecGUI(); - GUIFormSpecMenu::create(formspec, client, &input->joystick, - fs_src, txt_dst, client->getFormspecPrepend(), sound); + GUIFormSpecMenu::create(formspec, client, m_rendering_engine->get_gui_env(), + &input->joystick, fs_src, txt_dst, client->getFormspecPrepend(), sound); formspec->setFocus("btn_continue"); formspec->doPause = true; @@ -3591,6 +3590,7 @@ Game *g_game; void the_game(bool *kill, InputHandler *input, + RenderingEngine *rendering_engine, const GameStartData &start_data, std::string &error_message, ChatBackend &chat_backend, @@ -3607,8 +3607,8 @@ void the_game(bool *kill, try { - if (game.startup(kill, input, start_data, error_message, - reconnect_requested, &chat_backend)) { + if (game.startup(kill, input, rendering_engine, start_data, + error_message, reconnect_requested, &chat_backend)) { game.run(); } diff --git a/src/client/game.h b/src/client/game.h index 4a5b829d5..8197b9a9b 100644 --- a/src/client/game.h +++ b/src/client/game.h @@ -76,7 +76,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include <string> class InputHandler; -class ChatBackend; /* to avoid having to include chat.h */ +class ChatBackend; +class RenderingEngine; struct SubgameSpec; struct GameStartData; @@ -417,12 +418,7 @@ public: }; -// before 1.8 there isn't a "integer interface", only float -#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) -typedef f32 SamplerLayer_t; -#else typedef s32 SamplerLayer_t; -#endif class GameGlobalShaderConstantSetter : public IShaderConstantSetter @@ -530,38 +526,20 @@ public: float eye_position_array[3]; v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition(); -#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) - eye_position_array[0] = epos.X; - eye_position_array[1] = epos.Y; - eye_position_array[2] = epos.Z; -#else epos.getAs3Values(eye_position_array); -#endif m_eye_position_pixel.set(eye_position_array, services); m_eye_position_vertex.set(eye_position_array, services); if (m_client->getMinimap()) { float minimap_yaw_array[3]; v3f minimap_yaw = m_client->getMinimap()->getYawVec(); -#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) - minimap_yaw_array[0] = minimap_yaw.X; - minimap_yaw_array[1] = minimap_yaw.Y; - minimap_yaw_array[2] = minimap_yaw.Z; -#else minimap_yaw.getAs3Values(minimap_yaw_array); -#endif m_minimap_yaw.set(minimap_yaw_array, services); } float camera_offset_array[3]; v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS); -#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) - camera_offset_array[0] = offset.X; - camera_offset_array[1] = offset.Y; - camera_offset_array[2] = offset.Z; -#else offset.getAs3Values(camera_offset_array); -#endif m_camera_offset_pixel.set(camera_offset_array, services); m_camera_offset_vertex.set(camera_offset_array, services); @@ -673,6 +651,7 @@ public: bool startup(bool *kill, InputHandler *input, + RenderingEngine *rendering_engine, const GameStartData &game_params, std::string &error_message, bool *reconnect, @@ -682,8 +661,6 @@ public: void run(); void shutdown(); - void extendedResourceCleanup(); - // Basic initialisation bool init(const std::string &map_dir, const std::string &address, u16 port, const SubgameSpec &gamespec); @@ -881,6 +858,7 @@ public: these items (e.g. device) */ IrrlichtDevice *device; + RenderingEngine *m_rendering_engine; video::IVideoDriver *driver; scene::ISceneManager *smgr; bool *kill; @@ -936,6 +914,7 @@ extern Game *g_game; void the_game(bool *kill, InputHandler *input, + RenderingEngine *rendering_engine, const GameStartData &start_data, std::string &error_message, ChatBackend &chat_backend, diff --git a/src/client/gameui.cpp b/src/client/gameui.cpp index 0c1da3915..c97ae93b8 100644 --- a/src/client/gameui.cpp +++ b/src/client/gameui.cpp @@ -55,7 +55,7 @@ void GameUI::init() { m_guitext_coords = gui::StaticText::add(guienv, L"", core::rect<s32>(0, 0, 0, 0), false, false, guiroot); - + // First line of debug text m_guitext = gui::StaticText::add(guienv, utf8_to_wide(PROJECT_NAME_C).c_str(), core::rect<s32>(0, 0, 0, 0), false, false, guiroot); @@ -102,7 +102,8 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_ { LocalPlayer *player = client->getEnv().getLocalPlayer(); v3f player_position = player->getPosition(); - v2u32 screensize = RenderingEngine::get_instance()->getWindowSize(); + + v2u32 screensize = RenderingEngine::getWindowSize(); bool show_coords = g_settings->getBool("coords"); @@ -115,7 +116,7 @@ void GameUI::update(const RunStats &stats, Client *client, MapDrawControl *draw_ setStaticText(m_guitext_coords, utf8_to_wide(os.str()).c_str()); m_guitext_coords->setRelativePosition(core::rect<s32>(5, screensize.Y - 5 - g_fontengine->getTextHeight(), screensize.X, screensize.Y)); } - + m_guitext_coords->setVisible(show_coords); if (m_flags.show_debug) { @@ -238,9 +239,9 @@ void GameUI::setChatText(const EnrichedString &chat_text, u32 recent_chat_count) { // Update gui element size and position - - const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize(); - + + const v2u32 &window_size = RenderingEngine::getWindowSize(); + s32 chat_y = window_size.Y - 150 - m_guitext_chat->getTextHeight(); if (m_flags.show_debug) @@ -276,7 +277,7 @@ void GameUI::updateProfiler() core::position2di upper_left(6, 50); core::position2di lower_right = upper_left; lower_right.X += size.Width + 10; - lower_right.Y += size.Height; + lower_right.Y += size.Height; m_guitext_profiler->setRelativePosition(core::rect<s32>(upper_left, lower_right)); } diff --git a/src/client/guiscalingfilter.cpp b/src/client/guiscalingfilter.cpp index 8c565a52f..232219237 100644 --- a/src/client/guiscalingfilter.cpp +++ b/src/client/guiscalingfilter.cpp @@ -23,7 +23,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/numeric.h" #include <cstdio> #include "client/renderingengine.h" -#include "client/tile.h" // hasNPotSupport() /* Maintain a static cache to store the images that correspond to textures * in a format that's manipulable by code. Some platforms exhibit issues @@ -102,7 +101,7 @@ video::ITexture *guiScalingResizeCached(video::IVideoDriver *driver, if (!g_settings->getBool("gui_scaling_filter_txr2img")) return src; srcimg = driver->createImageFromData(src->getColorFormat(), - src->getSize(), src->lock(), false); + src->getSize(), src->lock(video::ETLM_READ_ONLY), false); src->unlock(); g_imgCache[origname] = srcimg; } @@ -117,7 +116,7 @@ video::ITexture *guiScalingResizeCached(video::IVideoDriver *driver, #if ENABLE_GLES // Some platforms are picky about textures being powers of 2, so expand // the image dimensions to the next power of 2, if necessary. - if (!hasNPotSupport()) { + if (!driver->queryFeature(video::EVDF_TEXTURE_NPOT)) { video::IImage *po2img = driver->createImage(src->getColorFormat(), core::dimension2d<u32>(npot2((u32)destrect.getWidth()), npot2((u32)destrect.getHeight()))); diff --git a/src/client/hud.cpp b/src/client/hud.cpp index 5971948fd..391af0995 100644 --- a/src/client/hud.cpp +++ b/src/client/hud.cpp @@ -45,11 +45,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #define OBJECT_CROSSHAIR_LINE_SIZE 8 #define CROSSHAIR_LINE_SIZE 10 -Hud::Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player, +Hud::Hud(Client *client, LocalPlayer *player, Inventory *inventory) { driver = RenderingEngine::get_video_driver(); - this->guienv = guienv; this->client = client; this->player = player; this->inventory = inventory; @@ -315,7 +314,7 @@ bool Hud::calculateScreenPos(const v3s16 &camera_offset, HudElement *e, v2s32 *p { v3f w_pos = e->world_pos * BS; scene::ICameraSceneNode* camera = - RenderingEngine::get_scene_manager()->getActiveCamera(); + client->getSceneManager()->getActiveCamera(); w_pos -= intToFloat(camera_offset, BS); core::matrix4 trans = camera->getProjectionMatrix(); trans *= camera->getViewMatrix(); @@ -336,22 +335,22 @@ void Hud::drawLuaElements(const v3s16 &camera_offset) irr::gui::IGUIFont* font = g_fontengine->getFont(); // Reorder elements by z_index - std::vector<size_t> ids; + std::vector<HudElement*> elems; + elems.reserve(player->maxHudId()); for (size_t i = 0; i != player->maxHudId(); i++) { HudElement *e = player->getHud(i); if (!e) continue; - auto it = ids.begin(); - while (it != ids.end() && player->getHud(*it)->z_index <= e->z_index) + auto it = elems.begin(); + while (it != elems.end() && (*it)->z_index <= e->z_index) ++it; - ids.insert(it, i); + elems.insert(it, e); } - for (size_t i : ids) { - HudElement *e = player->getHud(i); + for (HudElement *e : elems) { v2s32 pos(floor(e->pos.X * (float) m_screensize.X + 0.5), floor(e->pos.Y * (float) m_screensize.Y + 0.5)); @@ -475,7 +474,7 @@ void Hud::drawLuaElements(const v3s16 &camera_offset) // Angle according to camera view v3f fore(0.f, 0.f, 1.f); - scene::ICameraSceneNode *cam = RenderingEngine::get_scene_manager()->getActiveCamera(); + scene::ICameraSceneNode *cam = client->getSceneManager()->getActiveCamera(); cam->getAbsoluteTransformation().rotateVect(fore); int angle = - fore.getHorizontalAngle().Y; @@ -522,8 +521,8 @@ void Hud::drawLuaElements(const v3s16 &camera_offset) client->getMinimap()->drawMinimap(rect); break; } default: - infostream << "Hud::drawLuaElements: ignoring drawform " << e->type << - " of hud element ID " << i << " due to unrecognized type" << std::endl; + infostream << "Hud::drawLuaElements: ignoring drawform " << e->type + << " due to unrecognized type" << std::endl; } } } @@ -747,7 +746,7 @@ void Hud::drawHotbar(u16 playeritem) { s32 width = hotbar_itemcount * (m_hotbar_imagesize + m_padding * 2); v2s32 pos = centerlowerpos - v2s32(width / 2, m_hotbar_imagesize + m_padding * 3); - const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize(); + const v2u32 &window_size = RenderingEngine::getWindowSize(); if ((float) width / (float) window_size.X <= g_settings->getFloat("hud_hotbar_max_width")) { if (player->hud_flags & HUD_FLAG_HOTBAR_VISIBLE) { @@ -862,6 +861,54 @@ void Hud::drawSelectionMesh() } } +void Hud::toggleBlockBounds() +{ + m_block_bounds_mode = static_cast<BlockBoundsMode>(m_block_bounds_mode + 1); + + if (m_block_bounds_mode >= BLOCK_BOUNDS_MAX) { + m_block_bounds_mode = BLOCK_BOUNDS_OFF; + } +} + +void Hud::drawBlockBounds() +{ + if (m_block_bounds_mode == BLOCK_BOUNDS_OFF) { + return; + } + + video::SMaterial old_material = driver->getMaterial2D(); + driver->setMaterial(m_selection_material); + + v3s16 pos = player->getStandingNodePos(); + + v3s16 blockPos( + floorf((float) pos.X / MAP_BLOCKSIZE), + floorf((float) pos.Y / MAP_BLOCKSIZE), + floorf((float) pos.Z / MAP_BLOCKSIZE) + ); + + v3f offset = intToFloat(client->getCamera()->getOffset(), BS); + + s8 radius = m_block_bounds_mode == BLOCK_BOUNDS_ALL ? 2 : 0; + + v3f halfNode = v3f(BS, BS, BS) / 2.0f; + + for (s8 x = -radius; x <= radius; x++) + for (s8 y = -radius; y <= radius; y++) + for (s8 z = -radius; z <= radius; z++) { + v3s16 blockOffset(x, y, z); + + aabb3f box( + intToFloat((blockPos + blockOffset) * MAP_BLOCKSIZE, BS) - offset - halfNode, + intToFloat(((blockPos + blockOffset) * MAP_BLOCKSIZE) + (MAP_BLOCKSIZE - 1), BS) - offset + halfNode + ); + + driver->draw3DBox(box, video::SColor(255, 255, 0, 0)); + } + + driver->setMaterial(old_material); +} + void Hud::updateSelectionMesh(const v3s16 &camera_offset) { m_camera_offset = camera_offset; @@ -908,7 +955,7 @@ void Hud::updateSelectionMesh(const v3s16 &camera_offset) } void Hud::resizeHotbar() { - const v2u32 &window_size = RenderingEngine::get_instance()->getWindowSize(); + const v2u32 &window_size = RenderingEngine::getWindowSize(); if (m_screensize != window_size) { m_hotbar_imagesize = floor(HOTBAR_IMAGE_SIZE * @@ -945,10 +992,18 @@ void drawItemStack( return; } + const static thread_local bool enable_animations = + g_settings->getBool("inventory_items_animations"); + const ItemDefinition &def = item.getDefinition(client->idef()); - ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client); - if (imesh && imesh->mesh) { + bool draw_overlay = false; + + // Render as mesh if animated or no inventory image + if ((enable_animations && rotation_kind < IT_ROT_NONE) || def.inventory_image.empty()) { + ItemMesh *imesh = client->idef()->getWieldMesh(def.name, client); + if (!imesh || !imesh->mesh) + return; scene::IMesh *mesh = imesh->mesh; driver->clearBuffers(video::ECBF_DEPTH); s32 delta = 0; @@ -992,9 +1047,6 @@ void drawItemStack( core::matrix4 matrix; matrix.makeIdentity(); - static thread_local bool enable_animations = - g_settings->getBool("inventory_items_animations"); - if (enable_animations) { float timer_f = (float) delta / 5000.f; matrix.setRotationDegrees(v3f( @@ -1040,15 +1092,29 @@ void drawItemStack( driver->setTransform(video::ETS_PROJECTION, oldProjMat); driver->setViewPort(oldViewPort); - // draw the inventory_overlay - if (def.type == ITEM_NODE && def.inventory_image.empty() && - !def.inventory_overlay.empty()) { - ITextureSource *tsrc = client->getTextureSource(); - video::ITexture *overlay_texture = tsrc->getTexture(def.inventory_overlay); - core::dimension2d<u32> dimens = overlay_texture->getOriginalSize(); - core::rect<s32> srcrect(0, 0, dimens.Width, dimens.Height); - draw2DImageFilterScaled(driver, overlay_texture, rect, srcrect, clip, 0, true); - } + draw_overlay = def.type == ITEM_NODE && def.inventory_image.empty(); + } else { // Otherwise just draw as 2D + video::ITexture *texture = client->idef()->getInventoryTexture(def.name, client); + if (!texture) + return; + video::SColor color = + client->idef()->getItemstackColor(item, client); + const video::SColor colors[] = { color, color, color, color }; + + draw2DImageFilterScaled(driver, texture, rect, + core::rect<s32>({0, 0}, core::dimension2di(texture->getOriginalSize())), + clip, colors, true); + + draw_overlay = true; + } + + // draw the inventory_overlay + if (!def.inventory_overlay.empty() && draw_overlay) { + ITextureSource *tsrc = client->getTextureSource(); + video::ITexture *overlay_texture = tsrc->getTexture(def.inventory_overlay); + core::dimension2d<u32> dimens = overlay_texture->getOriginalSize(); + core::rect<s32> srcrect(0, 0, dimens.Width, dimens.Height); + draw2DImageFilterScaled(driver, overlay_texture, rect, srcrect, clip, 0, true); } if (def.type == ITEM_TOOL && item.wear != 0) { diff --git a/src/client/hud.h b/src/client/hud.h index d46545d71..d341105d2 100644 --- a/src/client/hud.h +++ b/src/client/hud.h @@ -35,14 +35,6 @@ struct ItemStack; class Hud { public: - video::IVideoDriver *driver; - scene::ISceneManager *smgr; - gui::IGUIEnvironment *guienv; - Client *client; - LocalPlayer *player; - Inventory *inventory; - ITextureSource *tsrc; - video::SColor crosshair_argb; video::SColor selectionbox_argb; @@ -55,10 +47,13 @@ public: bool pointing_at_object = false; - Hud(gui::IGUIEnvironment *guienv, Client *client, LocalPlayer *player, + Hud(Client *client, LocalPlayer *player, Inventory *inventory); ~Hud(); + void toggleBlockBounds(); + void drawBlockBounds(); + void drawHotbar(u16 playeritem); void resizeHotbar(); void drawCrosshair(); @@ -103,6 +98,12 @@ private: void drawCompassRotate(HudElement *e, video::ITexture *texture, const core::rect<s32> &rect, int way); + Client *client = nullptr; + video::IVideoDriver *driver = nullptr; + LocalPlayer *player = nullptr; + Inventory *inventory = nullptr; + ITextureSource *tsrc = nullptr; + float m_hud_scaling; // cached minetest setting float m_scale_factor; v3s16 m_camera_offset; @@ -125,6 +126,14 @@ private: scene::SMeshBuffer m_rotation_mesh_buffer; + enum BlockBoundsMode + { + BLOCK_BOUNDS_OFF, + BLOCK_BOUNDS_CURRENT, + BLOCK_BOUNDS_ALL, + BLOCK_BOUNDS_MAX + } m_block_bounds_mode = BLOCK_BOUNDS_OFF; + enum { HIGHLIGHT_BOX, diff --git a/src/client/imagefilters.cpp b/src/client/imagefilters.cpp index 0fa501410..7b2ef9822 100644 --- a/src/client/imagefilters.cpp +++ b/src/client/imagefilters.cpp @@ -19,63 +19,134 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "imagefilters.h" #include "util/numeric.h" #include <cmath> +#include <cassert> +#include <vector> + +// Simple 2D bitmap class with just the functionality needed here +class Bitmap { + u32 linesize, lines; + std::vector<u8> data; + + static inline u32 bytepos(u32 index) { return index >> 3; } + static inline u8 bitpos(u32 index) { return index & 7; } + +public: + Bitmap(u32 width, u32 height) : linesize(width), lines(height), + data(bytepos(width * height) + 1) {} + + inline bool get(u32 x, u32 y) const { + u32 index = y * linesize + x; + return data[bytepos(index)] & (1 << bitpos(index)); + } + + inline void set(u32 x, u32 y) { + u32 index = y * linesize + x; + data[bytepos(index)] |= 1 << bitpos(index); + } + + inline bool all() const { + for (u32 i = 0; i < data.size() - 1; i++) { + if (data[i] != 0xff) + return false; + } + // last byte not entirely filled + for (u8 i = 0; i < bitpos(linesize * lines); i++) { + bool value_of_bit = data.back() & (1 << i); + if (!value_of_bit) + return false; + } + return true; + } + + inline void copy(Bitmap &to) const { + assert(to.linesize == linesize && to.lines == lines); + to.data = data; + } +}; /* Fill in RGB values for transparent pixels, to correct for odd colors * appearing at borders when blending. This is because many PNG optimizers * like to discard RGB values of transparent pixels, but when blending then - * with non-transparent neighbors, their RGB values will shpw up nonetheless. + * with non-transparent neighbors, their RGB values will show up nonetheless. * * This function modifies the original image in-place. * * Parameter "threshold" is the alpha level below which pixels are considered - * transparent. Should be 127 for 3d where alpha is threshold, but 0 for - * 2d where alpha is blended. + * transparent. Should be 127 when the texture is used with ALPHA_CHANNEL_REF, + * 0 when alpha blending is used. */ void imageCleanTransparent(video::IImage *src, u32 threshold) { core::dimension2d<u32> dim = src->getDimension(); - // Walk each pixel looking for fully transparent ones. + Bitmap bitmap(dim.Width, dim.Height); + + // First pass: Mark all opaque pixels // Note: loop y around x for better cache locality. for (u32 ctry = 0; ctry < dim.Height; ctry++) for (u32 ctrx = 0; ctrx < dim.Width; ctrx++) { + if (src->getPixel(ctrx, ctry).getAlpha() > threshold) + bitmap.set(ctrx, ctry); + } + + // Exit early if all pixels opaque + if (bitmap.all()) + return; + + Bitmap newmap = bitmap; + + // Then repeatedly look for transparent pixels, filling them in until + // we're finished (capped at 50 iterations). + for (u32 iter = 0; iter < 50; iter++) { - // Ignore opaque pixels. - irr::video::SColor c = src->getPixel(ctrx, ctry); - if (c.getAlpha() > threshold) + for (u32 ctry = 0; ctry < dim.Height; ctry++) + for (u32 ctrx = 0; ctrx < dim.Width; ctrx++) { + // Skip pixels we have already processed + if (bitmap.get(ctrx, ctry)) continue; - // Sample size and total weighted r, g, b values. + video::SColor c = src->getPixel(ctrx, ctry); + + // Sample size and total weighted r, g, b values u32 ss = 0, sr = 0, sg = 0, sb = 0; - // Walk each neighbor pixel (clipped to image bounds). + // Walk each neighbor pixel (clipped to image bounds) for (u32 sy = (ctry < 1) ? 0 : (ctry - 1); sy <= (ctry + 1) && sy < dim.Height; sy++) for (u32 sx = (ctrx < 1) ? 0 : (ctrx - 1); sx <= (ctrx + 1) && sx < dim.Width; sx++) { - - // Ignore transparent pixels. - irr::video::SColor d = src->getPixel(sx, sy); - if (d.getAlpha() <= threshold) + // Ignore pixels we haven't processed + if (!bitmap.get(sx, sy)) continue; - - // Add RGB values weighted by alpha. - u32 a = d.getAlpha(); + + // Add RGB values weighted by alpha IF the pixel is opaque, otherwise + // use full weight since we want to propagate colors. + video::SColor d = src->getPixel(sx, sy); + u32 a = d.getAlpha() <= threshold ? 255 : d.getAlpha(); ss += a; sr += a * d.getRed(); sg += a * d.getGreen(); sb += a * d.getBlue(); } - // If we found any neighbor RGB data, set pixel to average - // weighted by alpha. + // Set pixel to average weighted by alpha if (ss > 0) { c.setRed(sr / ss); c.setGreen(sg / ss); c.setBlue(sb / ss); src->setPixel(ctrx, ctry, c); + newmap.set(ctrx, ctry); } } + + if (newmap.all()) + return; + + // Apply changes to bitmap for next run. This is done so we don't introduce + // a bias in color propagation in the direction pixels are processed. + newmap.copy(bitmap); + + } } /* Scale a region of an image into another image, using nearest-neighbor with diff --git a/src/client/imagefilters.h b/src/client/imagefilters.h index 5676faf85..c9bdefbb6 100644 --- a/src/client/imagefilters.h +++ b/src/client/imagefilters.h @@ -23,13 +23,13 @@ with this program; if not, write to the Free Software Foundation, Inc., /* Fill in RGB values for transparent pixels, to correct for odd colors * appearing at borders when blending. This is because many PNG optimizers * like to discard RGB values of transparent pixels, but when blending then - * with non-transparent neighbors, their RGB values will shpw up nonetheless. + * with non-transparent neighbors, their RGB values will show up nonetheless. * * This function modifies the original image in-place. * * Parameter "threshold" is the alpha level below which pixels are considered - * transparent. Should be 127 for 3d where alpha is threshold, but 0 for - * 2d where alpha is blended. + * transparent. Should be 127 when the texture is used with ALPHA_CHANNEL_REF, + * 0 when alpha blending is used. */ void imageCleanTransparent(video::IImage *src, u32 threshold); diff --git a/src/client/inputhandler.cpp b/src/client/inputhandler.cpp index 8b9cb64f5..d833db2f1 100644 --- a/src/client/inputhandler.cpp +++ b/src/client/inputhandler.cpp @@ -61,6 +61,7 @@ void KeyCache::populate() key[KeyType::DEC_VOLUME] = getKeySetting("keymap_decrease_volume"); key[KeyType::CINEMATIC] = getKeySetting("keymap_cinematic"); key[KeyType::SCREENSHOT] = getKeySetting("keymap_screenshot"); + key[KeyType::TOGGLE_BLOCK_BOUNDS] = getKeySetting("keymap_toggle_block_bounds"); key[KeyType::TOGGLE_HUD] = getKeySetting("keymap_toggle_hud"); key[KeyType::TOGGLE_CHAT] = getKeySetting("keymap_toggle_chat"); key[KeyType::TOGGLE_FOG] = getKeySetting("keymap_toggle_fog"); diff --git a/src/client/keycode.cpp b/src/client/keycode.cpp index ce5214f54..fac077f0f 100644 --- a/src/client/keycode.cpp +++ b/src/client/keycode.cpp @@ -197,7 +197,6 @@ static const struct table_key table[] = { DEFINEKEY1(KEY_MODECHANGE, N_("IME Mode Change")) DEFINEKEY1(KEY_APPS, N_("Apps")) DEFINEKEY1(KEY_SLEEP, N_("Sleep")) -#if !(IRRLICHT_VERSION_MAJOR <= 1 && IRRLICHT_VERSION_MINOR <= 7 && IRRLICHT_VERSION_REVISION < 3) DEFINEKEY1(KEY_OEM_1, "OEM 1") // KEY_OEM_[0-9] and KEY_OEM_102 are assigned to multiple DEFINEKEY1(KEY_OEM_2, "OEM 2") // different chars (on different platforms too) and thus w/o char DEFINEKEY1(KEY_OEM_3, "OEM 3") @@ -208,7 +207,6 @@ static const struct table_key table[] = { DEFINEKEY1(KEY_OEM_8, "OEM 8") DEFINEKEY1(KEY_OEM_AX, "OEM AX") DEFINEKEY1(KEY_OEM_102, "OEM 102") -#endif DEFINEKEY1(KEY_ATTN, "Attn") DEFINEKEY1(KEY_CRSEL, "CrSel") DEFINEKEY1(KEY_EXSEL, "ExSel") diff --git a/src/client/keys.h b/src/client/keys.h index 1be398ff3..b81b571b2 100644 --- a/src/client/keys.h +++ b/src/client/keys.h @@ -60,6 +60,7 @@ public: DEC_VOLUME, CINEMATIC, SCREENSHOT, + TOGGLE_BLOCK_BOUNDS, TOGGLE_HUD, TOGGLE_CHAT, TOGGLE_FOG, diff --git a/src/client/mapblock_mesh.cpp b/src/client/mapblock_mesh.cpp index 25f734f0e..8877e0549 100644 --- a/src/client/mapblock_mesh.cpp +++ b/src/client/mapblock_mesh.cpp @@ -1140,8 +1140,8 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset): */ { - MapblockMeshGenerator generator(data, &collector); - generator.generate(); + MapblockMeshGenerator(data, &collector, + data->m_client->getSceneManager()->getMeshManipulator()).generate(); } /* diff --git a/src/client/mesh.cpp b/src/client/mesh.cpp index 2400a374c..e43139218 100644 --- a/src/client/mesh.cpp +++ b/src/client/mesh.cpp @@ -27,14 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include <SAnimatedMesh.h> #include <IAnimatedMeshSceneNode.h> -// In Irrlicht 1.8 the signature of ITexture::lock was changed from -// (bool, u32) to (E_TEXTURE_LOCK_MODE, u32). -#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR <= 7 -#define MY_ETLM_READ_ONLY true -#else -#define MY_ETLM_READ_ONLY video::ETLM_READ_ONLY -#endif - inline static void applyShadeFactor(video::SColor& color, float factor) { color.setRed(core::clamp(core::round32(color.getRed()*factor), 0, 255)); diff --git a/src/client/minimap.cpp b/src/client/minimap.cpp index 165fa80bd..3013e1406 100644 --- a/src/client/minimap.cpp +++ b/src/client/minimap.cpp @@ -491,7 +491,8 @@ video::ITexture *Minimap::getMinimapTexture() // Want to use texture source, to : 1 find texture, 2 cache it video::ITexture* texture = m_tsrc->getTexture(data->mode.texture); video::IImage* image = driver->createImageFromData( - texture->getColorFormat(), texture->getSize(), texture->lock(), true, false); + texture->getColorFormat(), texture->getSize(), + texture->lock(video::ETLM_READ_ONLY), true, false); texture->unlock(); auto dim = image->getDimension(); @@ -576,7 +577,7 @@ scene::SMeshBuffer *Minimap::getMinimapMeshBuffer() void Minimap::drawMinimap() { // Non hud managed minimap drawing (legacy minimap) - v2u32 screensize = RenderingEngine::get_instance()->getWindowSize(); + v2u32 screensize = RenderingEngine::getWindowSize(); const u32 size = 0.25 * screensize.Y; drawMinimap(core::rect<s32>( diff --git a/src/client/particles.cpp b/src/client/particles.cpp index 7acd996dc..288826a5f 100644 --- a/src/client/particles.cpp +++ b/src/client/particles.cpp @@ -64,8 +64,8 @@ Particle::Particle( v2f texsize, video::SColor color ): - scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(), - RenderingEngine::get_scene_manager()) + scene::ISceneNode(((Client *)gamedef)->getSceneManager()->getRootSceneNode(), + ((Client *)gamedef)->getSceneManager()) { // Misc m_gamedef = gamedef; diff --git a/src/client/render/core.cpp b/src/client/render/core.cpp index 794ec0186..99af085f9 100644 --- a/src/client/render/core.cpp +++ b/src/client/render/core.cpp @@ -163,6 +163,7 @@ void RenderingCore::draw3D() driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); if (!show_hud) return; + hud->drawBlockBounds(); hud->drawSelectionMesh(); if (draw_entity_esp || draw_entity_tracers || draw_player_esp || draw_player_tracers || draw_node_esp || draw_node_tracers) drawTracersAndESP(); diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp index 703a988b5..138012414 100644 --- a/src/client/renderingengine.cpp +++ b/src/client/renderingengine.cpp @@ -159,7 +159,7 @@ RenderingEngine::~RenderingEngine() s_singleton = nullptr; } -v2u32 RenderingEngine::getWindowSize() const +v2u32 RenderingEngine::_getWindowSize() const { if (core) return core->getVirtualSize(); @@ -225,6 +225,20 @@ bool RenderingEngine::print_video_modes() return videomode_list != NULL; } +void RenderingEngine::removeMesh(const scene::IMesh* mesh) +{ + m_device->getSceneManager()->getMeshCache()->removeMesh(mesh); +} + +void RenderingEngine::cleanupMeshCache() +{ + auto mesh_cache = m_device->getSceneManager()->getMeshCache(); + while (mesh_cache->getMeshCount() != 0) { + if (scene::IAnimatedMesh *mesh = mesh_cache->getMeshByIndex(0)) + mesh_cache->removeMesh(mesh); + } +} + bool RenderingEngine::setupTopLevelWindow(const std::string &name) { // FIXME: It would make more sense for there to be a switch of some @@ -335,6 +349,10 @@ static bool getWindowHandle(irr::video::IVideoDriver *driver, HWND &hWnd) case video::EDT_DIRECT3D9: hWnd = reinterpret_cast<HWND>(exposedData.D3D9.HWnd); break; +#if ENABLE_GLES + case video::EDT_OGLES1: + case video::EDT_OGLES2: +#endif case video::EDT_OPENGL: hWnd = reinterpret_cast<HWND>(exposedData.OpenGLWin32.HWnd); break; @@ -474,11 +492,11 @@ bool RenderingEngine::setXorgWindowIconFromPath(const std::string &icon_file) Text will be removed when the screen is drawn the next time. Additionally, a progressbar can be drawn when percent is set between 0 and 100. */ -void RenderingEngine::_draw_load_screen(const std::wstring &text, +void RenderingEngine::draw_load_screen(const std::wstring &text, gui::IGUIEnvironment *guienv, ITextureSource *tsrc, float dtime, int percent, bool clouds) { - v2u32 screensize = RenderingEngine::get_instance()->getWindowSize(); + v2u32 screensize = getWindowSize(); v2s32 textsize(g_fontengine->getTextWidth(text), g_fontengine->getLineHeight()); v2s32 center(screensize.X / 2, screensize.Y / 2); @@ -546,7 +564,7 @@ void RenderingEngine::_draw_load_screen(const std::wstring &text, /* Draws the menu scene including (optional) cloud background. */ -void RenderingEngine::_draw_menu_scene(gui::IGUIEnvironment *guienv, +void RenderingEngine::draw_menu_scene(gui::IGUIEnvironment *guienv, float dtime, bool clouds) { bool cloud_menu_background = clouds && g_settings->getBool("menu_clouds"); @@ -594,19 +612,19 @@ std::vector<irr::video::E_DRIVER_TYPE> RenderingEngine::getSupportedVideoDrivers return drivers; } -void RenderingEngine::_initialize(Client *client, Hud *hud) +void RenderingEngine::initialize(Client *client, Hud *hud) { const std::string &draw_mode = g_settings->get("3d_mode"); core.reset(createRenderingCore(draw_mode, m_device, client, hud)); core->initialize(); } -void RenderingEngine::_finalize() +void RenderingEngine::finalize() { core.reset(); } -void RenderingEngine::_draw_scene(video::SColor skycolor, bool show_hud, +void RenderingEngine::draw_scene(video::SColor skycolor, bool show_hud, bool show_minimap, bool draw_wield_tool, bool draw_crosshair) { core->draw(skycolor, show_hud, show_minimap, draw_wield_tool, draw_crosshair); diff --git a/src/client/renderingengine.h b/src/client/renderingengine.h index 34cc60630..28ddc8652 100644 --- a/src/client/renderingengine.h +++ b/src/client/renderingengine.h @@ -41,7 +41,6 @@ public: RenderingEngine(IEventReceiver *eventReceiver); ~RenderingEngine(); - v2u32 getWindowSize() const; void setResizable(bool resize); video::IVideoDriver *getVideoDriver() { return driver; } @@ -56,31 +55,30 @@ public: bool setWindowIcon(); bool setXorgWindowIconFromPath(const std::string &icon_file); static bool print_video_modes(); + void cleanupMeshCache(); - static RenderingEngine *get_instance() { return s_singleton; } + void removeMesh(const scene::IMesh* mesh); - static io::IFileSystem *get_filesystem() + static v2u32 getWindowSize() { - sanity_check(s_singleton && s_singleton->m_device); - return s_singleton->m_device->getFileSystem(); + sanity_check(s_singleton); + return s_singleton->_getWindowSize(); } - static video::IVideoDriver *get_video_driver() + io::IFileSystem *get_filesystem() { - sanity_check(s_singleton && s_singleton->m_device); - return s_singleton->m_device->getVideoDriver(); + return m_device->getFileSystem(); } - static scene::IMeshCache *get_mesh_cache() + static video::IVideoDriver *get_video_driver() { sanity_check(s_singleton && s_singleton->m_device); - return s_singleton->m_device->getSceneManager()->getMeshCache(); + return s_singleton->m_device->getVideoDriver(); } - static scene::ISceneManager *get_scene_manager() + scene::ISceneManager *get_scene_manager() { - sanity_check(s_singleton && s_singleton->m_device); - return s_singleton->m_device->getSceneManager(); + return m_device->getSceneManager(); } static irr::IrrlichtDevice *get_raw_device() @@ -89,70 +87,37 @@ public: return s_singleton->m_device; } - static u32 get_timer_time() + u32 get_timer_time() { - sanity_check(s_singleton && s_singleton->m_device && - s_singleton->m_device->getTimer()); - return s_singleton->m_device->getTimer()->getTime(); + return m_device->getTimer()->getTime(); } - static gui::IGUIEnvironment *get_gui_env() + gui::IGUIEnvironment *get_gui_env() { - sanity_check(s_singleton && s_singleton->m_device); - return s_singleton->m_device->getGUIEnvironment(); + return m_device->getGUIEnvironment(); } - inline static void draw_load_screen(const std::wstring &text, + void draw_load_screen(const std::wstring &text, gui::IGUIEnvironment *guienv, ITextureSource *tsrc, - float dtime = 0, int percent = 0, bool clouds = true) - { - s_singleton->_draw_load_screen( - text, guienv, tsrc, dtime, percent, clouds); - } + float dtime = 0, int percent = 0, bool clouds = true); - inline static void draw_menu_scene( - gui::IGUIEnvironment *guienv, float dtime, bool clouds) - { - s_singleton->_draw_menu_scene(guienv, dtime, clouds); - } + void draw_menu_scene(gui::IGUIEnvironment *guienv, float dtime, bool clouds); + void draw_scene(video::SColor skycolor, bool show_hud, + bool show_minimap, bool draw_wield_tool, bool draw_crosshair); - inline static void draw_scene(video::SColor skycolor, bool show_hud, - bool show_minimap, bool draw_wield_tool, bool draw_crosshair) - { - s_singleton->_draw_scene(skycolor, show_hud, show_minimap, - draw_wield_tool, draw_crosshair); - } + void initialize(Client *client, Hud *hud); + void finalize(); - inline static void initialize(Client *client, Hud *hud) + bool run() { - s_singleton->_initialize(client, hud); - } - - inline static void finalize() { s_singleton->_finalize(); } - - static bool run() - { - sanity_check(s_singleton && s_singleton->m_device); - return s_singleton->m_device->run(); + return m_device->run(); } static std::vector<core::vector3d<u32>> getSupportedVideoModes(); static std::vector<irr::video::E_DRIVER_TYPE> getSupportedVideoDrivers(); private: - void _draw_load_screen(const std::wstring &text, gui::IGUIEnvironment *guienv, - ITextureSource *tsrc, float dtime = 0, int percent = 0, - bool clouds = true); - - void _draw_menu_scene(gui::IGUIEnvironment *guienv, float dtime = 0, - bool clouds = true); - - void _draw_scene(video::SColor skycolor, bool show_hud, bool show_minimap, - bool draw_wield_tool, bool draw_crosshair); - - void _initialize(Client *client, Hud *hud); - - void _finalize(); + v2u32 _getWindowSize() const; std::unique_ptr<RenderingCore> core; irr::IrrlichtDevice *m_device = nullptr; diff --git a/src/client/shader.cpp b/src/client/shader.cpp index b3e4911f4..58946b90f 100644 --- a/src/client/shader.cpp +++ b/src/client/shader.cpp @@ -579,8 +579,10 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, if (use_gles) { shaders_header << R"( #version 100 - )"; + )"; vertex_header = R"( + precision mediump float; + uniform highp mat4 mWorldView; uniform highp mat4 mWorldViewProj; uniform mediump mat4 mTexture; @@ -592,17 +594,17 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, attribute mediump vec3 inVertexNormal; attribute mediump vec4 inVertexTangent; attribute mediump vec4 inVertexBinormal; - )"; + )"; fragment_header = R"( precision mediump float; - )"; + )"; } else { shaders_header << R"( #version 120 #define lowp #define mediump #define highp - )"; + )"; vertex_header = R"( #define mWorldView gl_ModelViewMatrix #define mWorldViewProj gl_ModelViewProjectionMatrix @@ -615,7 +617,7 @@ ShaderInfo ShaderSource::generateShader(const std::string &name, #define inVertexNormal gl_Normal #define inVertexTangent gl_MultiTexCoord1 #define inVertexBinormal gl_MultiTexCoord2 - )"; + )"; } bool use_discard = use_gles; diff --git a/src/client/sky.cpp b/src/client/sky.cpp index caf695e7a..47296a7a5 100644 --- a/src/client/sky.cpp +++ b/src/client/sky.cpp @@ -53,10 +53,12 @@ static video::SMaterial baseMaterial() return mat; }; -Sky::Sky(s32 id, ITextureSource *tsrc, IShaderSource *ssrc) : - scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(), - RenderingEngine::get_scene_manager(), id) +Sky::Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShaderSource *ssrc) : + scene::ISceneNode(rendering_engine->get_scene_manager()->getRootSceneNode(), + rendering_engine->get_scene_manager(), id) { + m_seed = (u64)myrand() << 32 | myrand(); + setAutomaticCulling(scene::EAC_OFF); m_box.MaxEdge.set(0, 0, 0); m_box.MinEdge.set(0, 0, 0); @@ -82,13 +84,13 @@ Sky::Sky(s32 id, ITextureSource *tsrc, IShaderSource *ssrc) : // Ensures that sun and moon textures and tonemaps are correct. setSkyDefaults(); m_sun_texture = tsrc->isKnownSourceImage(m_sun_params.texture) ? - tsrc->getTextureForMesh(m_sun_params.texture) : NULL; + tsrc->getTextureForMesh(m_sun_params.texture) : nullptr; m_moon_texture = tsrc->isKnownSourceImage(m_moon_params.texture) ? - tsrc->getTextureForMesh(m_moon_params.texture) : NULL; + tsrc->getTextureForMesh(m_moon_params.texture) : nullptr; m_sun_tonemap = tsrc->isKnownSourceImage(m_sun_params.tonemap) ? - tsrc->getTexture(m_sun_params.tonemap) : NULL; + tsrc->getTexture(m_sun_params.tonemap) : nullptr; m_moon_tonemap = tsrc->isKnownSourceImage(m_moon_params.tonemap) ? - tsrc->getTexture(m_moon_params.tonemap) : NULL; + tsrc->getTexture(m_moon_params.tonemap) : nullptr; if (m_sun_texture) { m_materials[3] = baseMaterial(); @@ -744,14 +746,14 @@ void Sky::place_sky_body( } } -void Sky::setSunTexture(std::string sun_texture, - std::string sun_tonemap, ITextureSource *tsrc) +void Sky::setSunTexture(const std::string &sun_texture, + const std::string &sun_tonemap, ITextureSource *tsrc) { // Ignore matching textures (with modifiers) entirely, // but lets at least update the tonemap before hand. m_sun_params.tonemap = sun_tonemap; m_sun_tonemap = tsrc->isKnownSourceImage(m_sun_params.tonemap) ? - tsrc->getTexture(m_sun_params.tonemap) : NULL; + tsrc->getTexture(m_sun_params.tonemap) : nullptr; m_materials[3].Lighting = !!m_sun_tonemap; if (m_sun_params.texture == sun_texture) @@ -780,7 +782,7 @@ void Sky::setSunTexture(std::string sun_texture, } } -void Sky::setSunriseTexture(std::string sunglow_texture, +void Sky::setSunriseTexture(const std::string &sunglow_texture, ITextureSource* tsrc) { // Ignore matching textures (with modifiers) entirely. @@ -792,14 +794,14 @@ void Sky::setSunriseTexture(std::string sunglow_texture, ); } -void Sky::setMoonTexture(std::string moon_texture, - std::string moon_tonemap, ITextureSource *tsrc) +void Sky::setMoonTexture(const std::string &moon_texture, + const std::string &moon_tonemap, ITextureSource *tsrc) { // Ignore matching textures (with modifiers) entirely, // but lets at least update the tonemap before hand. m_moon_params.tonemap = moon_tonemap; m_moon_tonemap = tsrc->isKnownSourceImage(m_moon_params.tonemap) ? - tsrc->getTexture(m_moon_params.tonemap) : NULL; + tsrc->getTexture(m_moon_params.tonemap) : nullptr; m_materials[4].Lighting = !!m_moon_tonemap; if (m_moon_params.texture == moon_texture) @@ -833,7 +835,6 @@ void Sky::setStarCount(u16 star_count, bool force_update) // Allow force updating star count at game init. if (m_star_params.count != star_count || force_update) { m_star_params.count = star_count; - m_seed = (u64)myrand() << 32 | myrand(); updateStars(); } } @@ -893,7 +894,7 @@ void Sky::setSkyColors(const SkyColor &sky_color) } void Sky::setHorizonTint(video::SColor sun_tint, video::SColor moon_tint, - std::string use_sun_tint) + const std::string &use_sun_tint) { // Change sun and moon tinting: m_sky_params.fog_sun_tint = sun_tint; @@ -907,7 +908,7 @@ void Sky::setHorizonTint(video::SColor sun_tint, video::SColor moon_tint, m_default_tint = true; } -void Sky::addTextureToSkybox(std::string texture, int material_id, +void Sky::addTextureToSkybox(const std::string &texture, int material_id, ITextureSource *tsrc) { // Sanity check for more than six textures. diff --git a/src/client/sky.h b/src/client/sky.h index 342a97596..121a16bb7 100644 --- a/src/client/sky.h +++ b/src/client/sky.h @@ -36,7 +36,7 @@ class Sky : public scene::ISceneNode { public: //! constructor - Sky(s32 id, ITextureSource *tsrc, IShaderSource *ssrc); + Sky(s32 id, RenderingEngine *rendering_engine, ITextureSource *tsrc, IShaderSource *ssrc); virtual void OnRegisterSceneNode(); @@ -65,15 +65,15 @@ public: } void setSunVisible(bool sun_visible) { m_sun_params.visible = sun_visible; } - void setSunTexture(std::string sun_texture, - std::string sun_tonemap, ITextureSource *tsrc); + void setSunTexture(const std::string &sun_texture, + const std::string &sun_tonemap, ITextureSource *tsrc); void setSunScale(f32 sun_scale) { m_sun_params.scale = sun_scale; } void setSunriseVisible(bool glow_visible) { m_sun_params.sunrise_visible = glow_visible; } - void setSunriseTexture(std::string sunglow_texture, ITextureSource* tsrc); + void setSunriseTexture(const std::string &sunglow_texture, ITextureSource* tsrc); void setMoonVisible(bool moon_visible) { m_moon_params.visible = moon_visible; } - void setMoonTexture(std::string moon_texture, - std::string moon_tonemap, ITextureSource *tsrc); + void setMoonTexture(const std::string &moon_texture, + const std::string &moon_tonemap, ITextureSource *tsrc); void setMoonScale(f32 moon_scale) { m_moon_params.scale = moon_scale; } void setStarsVisible(bool stars_visible) { m_star_params.visible = stars_visible; } @@ -87,21 +87,21 @@ public: void setVisible(bool visible) { m_visible = visible; } // Set only from set_sky API void setCloudsEnabled(bool clouds_enabled) { m_clouds_enabled = clouds_enabled; } - void setFallbackBgColor(const video::SColor &fallback_bg_color) + void setFallbackBgColor(video::SColor fallback_bg_color) { m_fallback_bg_color = fallback_bg_color; } - void overrideColors(const video::SColor &bgcolor, const video::SColor &skycolor) + void overrideColors(video::SColor bgcolor, video::SColor skycolor) { m_bgcolor = bgcolor; m_skycolor = skycolor; } void setSkyColors(const SkyColor &sky_color); void setHorizonTint(video::SColor sun_tint, video::SColor moon_tint, - std::string use_sun_tint); + const std::string &use_sun_tint); void setInClouds(bool clouds) { m_in_clouds = clouds; } void clearSkyboxTextures() { m_sky_params.textures.clear(); } - void addTextureToSkybox(std::string texture, int material_id, + void addTextureToSkybox(const std::string &texture, int material_id, ITextureSource *tsrc); const video::SColorf &getCurrentStarColor() const { return m_star_color; } @@ -126,7 +126,7 @@ private: } // Mix two colors by a given amount - video::SColor m_mix_scolor(video::SColor col1, video::SColor col2, f32 factor) + static video::SColor m_mix_scolor(video::SColor col1, video::SColor col2, f32 factor) { video::SColor result = video::SColor( col1.getAlpha() * (1 - factor) + col2.getAlpha() * factor, @@ -135,7 +135,7 @@ private: col1.getBlue() * (1 - factor) + col2.getBlue() * factor); return result; } - video::SColorf m_mix_scolorf(video::SColorf col1, video::SColorf col2, f32 factor) + static video::SColorf m_mix_scolorf(video::SColorf col1, video::SColorf col2, f32 factor) { video::SColorf result = video::SColorf(col1.r * (1 - factor) + col2.r * factor, diff --git a/src/client/tile.cpp b/src/client/tile.cpp index 7e3901247..96312ea27 100644 --- a/src/client/tile.cpp +++ b/src/client/tile.cpp @@ -34,15 +34,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "guiscalingfilter.h" #include "renderingengine.h" - -#if ENABLE_GLES -#ifdef _IRR_COMPILE_WITH_OGLES1_ -#include <GLES/gl.h> -#else -#include <GLES2/gl2.h> -#endif -#endif - /* A cache from texture name to texture path */ @@ -427,6 +418,7 @@ private: std::unordered_map<std::string, Palette> m_palettes; // Cached settings needed for making textures from meshes + bool m_setting_mipmap; bool m_setting_trilinear_filter; bool m_setting_bilinear_filter; }; @@ -447,6 +439,7 @@ TextureSource::TextureSource() // Cache some settings // Note: Since this is only done once, the game must be restarted // for these settings to take effect + m_setting_mipmap = g_settings->getBool("mip_map"); m_setting_trilinear_filter = g_settings->getBool("trilinear_filter"); m_setting_bilinear_filter = g_settings->getBool("bilinear_filter"); } @@ -667,7 +660,7 @@ video::ITexture* TextureSource::getTexture(const std::string &name, u32 *id) video::ITexture* TextureSource::getTextureForMesh(const std::string &name, u32 *id) { static thread_local bool filter_needed = - g_settings->getBool("texture_clean_transparent") || + g_settings->getBool("texture_clean_transparent") || m_setting_mipmap || ((m_setting_trilinear_filter || m_setting_bilinear_filter) && g_settings->getS32("texture_min_size") > 1); // Avoid duplicating texture if it won't actually change @@ -1011,42 +1004,19 @@ video::IImage* TextureSource::generateImage(const std::string &name) #if ENABLE_GLES - -static inline u16 get_GL_major_version() -{ - const GLubyte *gl_version = glGetString(GL_VERSION); - return (u16) (gl_version[0] - '0'); -} - -/** - * Check if hardware requires npot2 aligned textures - * @return true if alignment NOT(!) requires, false otherwise - */ - -bool hasNPotSupport() -{ - // Only GLES2 is trusted to correctly report npot support - // Note: we cache the boolean result, the GL context will never change. - static const bool supported = get_GL_major_version() > 1 && - glGetString(GL_EXTENSIONS) && - strstr((char *)glGetString(GL_EXTENSIONS), "GL_OES_texture_npot"); - return supported; -} - /** * Check and align image to npot2 if required by hardware * @param image image to check for npot2 alignment * @param driver driver to use for image operations * @return image or copy of image aligned to npot2 */ - -video::IImage * Align2Npot2(video::IImage * image, - video::IVideoDriver* driver) +video::IImage *Align2Npot2(video::IImage *image, + video::IVideoDriver *driver) { if (image == NULL) return image; - if (hasNPotSupport()) + if (driver->queryFeature(video::EVDF_TEXTURE_NPOT)) return image; core::dimension2d<u32> dim = image->getDimension(); @@ -1636,8 +1606,8 @@ bool TextureSource::generateImagePart(std::string part_of_name, return false; } - // Apply the "clean transparent" filter, if configured. - if (g_settings->getBool("texture_clean_transparent")) + // Apply the "clean transparent" filter, if needed + if (m_setting_mipmap || g_settings->getBool("texture_clean_transparent")) imageCleanTransparent(baseimg, 127); /* Upscale textures to user's requested minimum size. This is a trick to make diff --git a/src/client/tile.h b/src/client/tile.h index 49c46f749..fcdc46460 100644 --- a/src/client/tile.h +++ b/src/client/tile.h @@ -134,8 +134,7 @@ public: IWritableTextureSource *createTextureSource(); #if ENABLE_GLES -bool hasNPotSupport(); -video::IImage * Align2Npot2(video::IImage * image, irr::video::IVideoDriver* driver); +video::IImage *Align2Npot2(video::IImage *image, video::IVideoDriver *driver); #endif enum MaterialType{ diff --git a/src/client/wieldmesh.cpp b/src/client/wieldmesh.cpp index 387eb17c3..08fd49fc0 100644 --- a/src/client/wieldmesh.cpp +++ b/src/client/wieldmesh.cpp @@ -294,9 +294,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename, } material.setFlag(video::EMF_ANISOTROPIC_FILTER, m_anisotropic_filter); // mipmaps cause "thin black line" artifacts -#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR >= 8) || IRRLICHT_VERSION_MAJOR >= 2 material.setFlag(video::EMF_USE_MIP_MAPS, false); -#endif if (m_enable_shaders) { material.setTexture(2, tsrc->getShaderFlagsTexture(false)); } @@ -309,18 +307,21 @@ static scene::SMesh *createSpecialNodeMesh(Client *client, MapNode n, MeshMakeData mesh_make_data(client, false); MeshCollector collector; mesh_make_data.setSmoothLighting(false); - MapblockMeshGenerator gen(&mesh_make_data, &collector); + MapblockMeshGenerator gen(&mesh_make_data, &collector, + client->getSceneManager()->getMeshManipulator()); if (n.getParam2()) { // keep it } else if (f.param_type_2 == CPT2_WALLMOUNTED || f.param_type_2 == CPT2_COLORED_WALLMOUNTED) { - if (f.drawtype == NDT_TORCHLIKE) - n.setParam2(1); - else if (f.drawtype == NDT_SIGNLIKE || + if (f.drawtype == NDT_TORCHLIKE || + f.drawtype == NDT_SIGNLIKE || f.drawtype == NDT_NODEBOX || - f.drawtype == NDT_MESH) + f.drawtype == NDT_MESH) { n.setParam2(4); + } + } else if (f.drawtype == NDT_SIGNLIKE || f.drawtype == NDT_TORCHLIKE) { + n.setParam2(1); } gen.renderSingle(n.getContent(), n.getParam2()); @@ -395,7 +396,6 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che case NDT_TORCHLIKE: case NDT_RAILLIKE: case NDT_PLANTLIKE: - case NDT_PLANTLIKE_ROOTED: case NDT_FLOWINGLIQUID: { v3f wscale = def.wield_scale; if (f.drawtype == NDT_FLOWINGLIQUID) @@ -411,6 +411,15 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client, bool che m_colors.emplace_back(l1.has_color, l1.color); break; } + case NDT_PLANTLIKE_ROOTED: { + setExtruded(tsrc->getTextureName(f.special_tiles[0].layers[0].texture_id), + "", def.wield_scale, tsrc, + f.special_tiles[0].layers[0].animation_frame_count); + // Add color + const TileLayer &l0 = f.special_tiles[0].layers[0]; + m_colors.emplace_back(l0.has_color, l0.color); + break; + } case NDT_NORMAL: case NDT_ALLFACES: case NDT_LIQUID: @@ -530,7 +539,7 @@ void getItemMesh(Client *client, const ItemStack &item, ItemMesh *result) content_t id = ndef->getId(def.name); FATAL_ERROR_IF(!g_extrusion_mesh_cache, "Extrusion mesh cache is not yet initialized"); - + scene::SMesh *mesh = nullptr; // Shading is on by default |