X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fclient%2Frenderingengine.cpp;h=6ebcc784d151abd0ccb7fecc6ec38fbf07dc096c;hb=21df26984da91143c15587f5a03c98d68c3adc4e;hp=f9da178b9ad90f2eca68824baebadb800646f894;hpb=28841961ba91b943b7478704181604fa3e24e81e;p=dragonfireclient.git diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp index f9da178b9..6ebcc784d 100644 --- a/src/client/renderingengine.cpp +++ b/src/client/renderingengine.cpp @@ -19,14 +19,13 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include -#include #include "fontengine.h" #include "client.h" #include "clouds.h" #include "util/numeric.h" #include "guiscalingfilter.h" -#include "hud.h" #include "localplayer.h" +#include "client/hud.h" #include "camera.h" #include "minimap.h" #include "clientmap.h" @@ -35,6 +34,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "render/factory.h" #include "inputhandler.h" #include "gettext.h" +#include "../gui/guiSkin.h" #if !defined(_WIN32) && !defined(__APPLE__) && !defined(__ANDROID__) && \ !defined(SERVER) && !defined(__HAIKU__) @@ -43,10 +43,43 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifdef XORG_USED #include #include +#include +#endif + +#ifdef _WIN32 +#include +#include +#endif + +#if ENABLE_GLES +#include "filesys.h" #endif RenderingEngine *RenderingEngine::s_singleton = nullptr; + +static gui::GUISkin *createSkin(gui::IGUIEnvironment *environment, + gui::EGUI_SKIN_TYPE type, video::IVideoDriver *driver) +{ + gui::GUISkin *skin = new gui::GUISkin(type, driver); + + gui::IGUIFont *builtinfont = environment->getBuiltInFont(); + gui::IGUIFontBitmap *bitfont = nullptr; + if (builtinfont && builtinfont->getType() == gui::EGFT_BITMAP) + bitfont = (gui::IGUIFontBitmap*)builtinfont; + + gui::IGUISpriteBank *bank = 0; + skin->setFont(builtinfont); + + if (bitfont) + bank = bitfont->getSpriteBank(); + + skin->setSpriteBank(bank); + + return skin; +} + + RenderingEngine::RenderingEngine(IEventReceiver *receiver) { sanity_check(!s_singleton); @@ -58,7 +91,6 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver) // bpp, fsaa, vsync bool vsync = g_settings->getBool("vsync"); - u16 bits = g_settings->getU16("fullscreen_bpp"); u16 fsaa = g_settings->getU16("fsaa"); // stereo buffer required for pageflip stereo @@ -72,7 +104,7 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver) u32 i; for (i = 0; i != drivers.size(); i++) { if (!strcasecmp(driverstring.c_str(), - RenderingEngine::getVideoDriverName(drivers[i]))) { + RenderingEngine::getVideoDriverInfo(drivers[i]).name.c_str())) { driverType = drivers[i]; break; } @@ -84,39 +116,46 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver) } SIrrlichtCreationParameters params = SIrrlichtCreationParameters(); + if (tracestream) + params.LoggingLevel = irr::ELL_DEBUG; params.DriverType = driverType; params.WindowSize = core::dimension2d(screen_w, screen_h); - params.Bits = bits; params.AntiAlias = fsaa; params.Fullscreen = fullscreen; params.Stencilbuffer = false; params.Stereobuffer = stereo_buffer; params.Vsync = vsync; params.EventReceiver = receiver; - params.HighPrecisionFPU = g_settings->getBool("high_precision_fpu"); - params.ZBufferBits = 24; + params.HighPrecisionFPU = true; #ifdef __ANDROID__ - // clang-format off params.PrivateData = porting::app_global; - params.OGLES2ShaderPath = std::string(porting::path_user + DIR_DELIM + "media" + - DIR_DELIM + "Shaders" + DIR_DELIM).c_str(); - // clang-format on +#endif +#if ENABLE_GLES + // there is no standardized path for these on desktop + std::string rel_path = std::string("client") + DIR_DELIM + + "shaders" + DIR_DELIM + "Irrlicht"; + params.OGLES2ShaderPath = (porting::path_share + DIR_DELIM + rel_path + DIR_DELIM).c_str(); #endif m_device = createDeviceEx(params); driver = m_device->getVideoDriver(); s_singleton = this; + + auto skin = createSkin(m_device->getGUIEnvironment(), + gui::EGST_WINDOWS_METALLIC, driver); + m_device->getGUIEnvironment()->setSkin(skin); + skin->drop(); } RenderingEngine::~RenderingEngine() { core.reset(); - m_device->drop(); + m_device->closeDevice(); s_singleton = nullptr; } -v2u32 RenderingEngine::getWindowSize() const +v2u32 RenderingEngine::_getWindowSize() const { if (core) return core->getVirtualSize(); @@ -128,109 +167,155 @@ void RenderingEngine::setResizable(bool resize) m_device->setResizable(resize); } -bool RenderingEngine::print_video_modes() +void RenderingEngine::removeMesh(const scene::IMesh* mesh) { - IrrlichtDevice *nulldevice; - - bool vsync = g_settings->getBool("vsync"); - u16 fsaa = g_settings->getU16("fsaa"); - MyEventReceiver *receiver = new MyEventReceiver(); - - SIrrlichtCreationParameters params = SIrrlichtCreationParameters(); - params.DriverType = video::EDT_NULL; - params.WindowSize = core::dimension2d(640, 480); - params.Bits = 24; - params.AntiAlias = fsaa; - params.Fullscreen = false; - params.Stencilbuffer = false; - params.Vsync = vsync; - params.EventReceiver = receiver; - params.HighPrecisionFPU = g_settings->getBool("high_precision_fpu"); - - nulldevice = createDeviceEx(params); + m_device->getSceneManager()->getMeshCache()->removeMesh(mesh); +} - if (!nulldevice) { - delete receiver; - return false; +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); } +} - std::cout << _("Available video modes (WxHxD):") << std::endl; - - video::IVideoModeList *videomode_list = nulldevice->getVideoModeList(); +bool RenderingEngine::setupTopLevelWindow(const std::string &name) +{ + // FIXME: It would make more sense for there to be a switch of some + // sort here that would call the correct toplevel setup methods for + // the environment Minetest is running in. - if (videomode_list != NULL) { - s32 videomode_count = videomode_list->getVideoModeCount(); - core::dimension2d videomode_res; - s32 videomode_depth; - for (s32 i = 0; i < videomode_count; ++i) { - videomode_res = videomode_list->getVideoModeResolution(i); - videomode_depth = videomode_list->getVideoModeDepth(i); - std::cout << videomode_res.Width << "x" << videomode_res.Height - << "x" << videomode_depth << std::endl; - } + /* Setting Xorg properties for the top level window */ + setupTopLevelXorgWindow(name); - std::cout << _("Active video mode (WxHxD):") << std::endl; - videomode_res = videomode_list->getDesktopResolution(); - videomode_depth = videomode_list->getDesktopDepth(); - std::cout << videomode_res.Width << "x" << videomode_res.Height << "x" - << videomode_depth << std::endl; - } + /* Setting general properties for the top level window */ + verbosestream << "Client: Configuring general top level" + << " window properties" + << std::endl; + bool result = setWindowIcon(); - nulldevice->drop(); - delete receiver; - - return videomode_list != NULL; + return result; } -void RenderingEngine::setXorgClassHint( - const video::SExposedVideoData &video_data, const std::string &name) +void RenderingEngine::setupTopLevelXorgWindow(const std::string &name) { #ifdef XORG_USED - if (video_data.OpenGLLinux.X11Display == NULL) + const video::SExposedVideoData exposedData = driver->getExposedVideoData(); + + Display *x11_dpl = reinterpret_cast(exposedData.OpenGLLinux.X11Display); + if (x11_dpl == NULL) { + warningstream << "Client: Could not find X11 Display in ExposedVideoData" + << std::endl; return; + } + verbosestream << "Client: Configuring X11-specific top level" + << " window properties" + << std::endl; + + + Window x11_win = reinterpret_cast(exposedData.OpenGLLinux.X11Window); + + // Set application name and class hints. For now name and class are the same. XClassHint *classhint = XAllocClassHint(); - classhint->res_name = (char *)name.c_str(); - classhint->res_class = (char *)name.c_str(); + classhint->res_name = const_cast(name.c_str()); + classhint->res_class = const_cast(name.c_str()); - XSetClassHint((Display *)video_data.OpenGLLinux.X11Display, - video_data.OpenGLLinux.X11Window, classhint); + XSetClassHint(x11_dpl, x11_win, classhint); XFree(classhint); + + // FIXME: In the future WMNormalHints should be set ... e.g see the + // gtk/gdk code (gdk/x11/gdksurface-x11.c) for the setup_top_level + // method. But for now (as it would require some significant changes) + // leave the code as is. + + // The following is borrowed from the above gdk source for setting top + // level windows. The source indicates and the Xlib docs suggest that + // this will set the WM_CLIENT_MACHINE and WM_LOCAL_NAME. This will not + // set the WM_CLIENT_MACHINE to a Fully Qualified Domain Name (FQDN) which is + // required by the Extended Window Manager Hints (EWMH) spec when setting + // the _NET_WM_PID (see further down) but running Minetest in an env + // where the window manager is on another machine from Minetest (therefore + // making the PID useless) is not expected to be a problem. Further + // more, using gtk/gdk as the model it would seem that not using a FQDN is + // not an issue for modern Xorg window managers. + + verbosestream << "Client: Setting Xorg window manager Properties" + << std::endl; + + XSetWMProperties (x11_dpl, x11_win, NULL, NULL, NULL, 0, NULL, NULL, NULL); + + // Set the _NET_WM_PID window property according to the EWMH spec. _NET_WM_PID + // (in conjunction with WM_CLIENT_MACHINE) can be used by window managers to + // force a shutdown of an application if it doesn't respond to the destroy + // window message. + + verbosestream << "Client: Setting Xorg _NET_WM_PID extended window manager property" + << std::endl; + + Atom NET_WM_PID = XInternAtom(x11_dpl, "_NET_WM_PID", false); + + pid_t pid = getpid(); + + XChangeProperty(x11_dpl, x11_win, NET_WM_PID, + XA_CARDINAL, 32, PropModeReplace, + reinterpret_cast(&pid),1); + + // Set the WM_CLIENT_LEADER window property here. Minetest has only one + // window and that window will always be the leader. + + verbosestream << "Client: Setting Xorg WM_CLIENT_LEADER property" + << std::endl; + + Atom WM_CLIENT_LEADER = XInternAtom(x11_dpl, "WM_CLIENT_LEADER", false); + + XChangeProperty (x11_dpl, x11_win, WM_CLIENT_LEADER, + XA_WINDOW, 32, PropModeReplace, + reinterpret_cast(&x11_win), 1); #endif } +#ifdef _WIN32 +static bool getWindowHandle(irr::video::IVideoDriver *driver, HWND &hWnd) +{ + const video::SExposedVideoData exposedData = driver->getExposedVideoData(); + + switch (driver->getDriverType()) { +#if ENABLE_GLES + case video::EDT_OGLES1: + case video::EDT_OGLES2: +#endif + case video::EDT_OPENGL: + hWnd = reinterpret_cast(exposedData.OpenGLWin32.HWnd); + break; + default: + return false; + } + + return true; +} +#endif + bool RenderingEngine::setWindowIcon() { #if defined(XORG_USED) #if RUN_IN_PLACE return setXorgWindowIconFromPath( - porting::path_share + "/misc/" PROJECT_NAME "-xorg-icon-128.png"); + porting::path_share + "/misc/dragonfire-xorg-icon-128.png"); #else // We have semi-support for reading in-place data if we are // compiled with RUN_IN_PLACE. Don't break with this and // also try the path_share location. return setXorgWindowIconFromPath( - ICON_DIR "/hicolor/128x128/apps/" PROJECT_NAME ".png") || - setXorgWindowIconFromPath(porting::path_share + "/misc/" PROJECT_NAME - "-xorg-icon-128.png"); + ICON_DIR "/hicolor/128x128/apps/dragonfire.png") || + setXorgWindowIconFromPath(porting::path_share + "/misc/dragonfire-xorg-icon-128.png"); #endif #elif defined(_WIN32) - const video::SExposedVideoData exposedData = driver->getExposedVideoData(); HWND hWnd; // Window handle - - switch (driver->getDriverType()) { - case video::EDT_DIRECT3D8: - hWnd = reinterpret_cast(exposedData.D3D8.HWnd); - break; - case video::EDT_DIRECT3D9: - hWnd = reinterpret_cast(exposedData.D3D9.HWnd); - break; - case video::EDT_OPENGL: - hWnd = reinterpret_cast(exposedData.OpenGLWin32.HWnd); - break; - default: + if (!getWindowHandle(driver, hWnd)) return false; - } // Load the ICON from resource file const HICON hicon = LoadIcon(GetModuleHandle(NULL), @@ -341,11 +426,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); @@ -410,89 +495,77 @@ void RenderingEngine::_draw_load_screen(const std::wstring &text, guitext->remove(); } -std::vector> RenderingEngine::getSupportedVideoModes() +/* + Draws the menu scene including (optional) cloud background. +*/ +void RenderingEngine::draw_menu_scene(gui::IGUIEnvironment *guienv, + float dtime, bool clouds) { - IrrlichtDevice *nulldevice = createDevice(video::EDT_NULL); - sanity_check(nulldevice); - - std::vector> mlist; - video::IVideoModeList *modelist = nulldevice->getVideoModeList(); - - s32 num_modes = modelist->getVideoModeCount(); - for (s32 i = 0; i != num_modes; i++) { - core::dimension2d mode_res = modelist->getVideoModeResolution(i); - u32 mode_depth = (u32)modelist->getVideoModeDepth(i); - mlist.emplace_back(mode_res.Width, mode_res.Height, mode_depth); - } + bool cloud_menu_background = clouds && g_settings->getBool("menu_clouds"); + if (cloud_menu_background) { + g_menuclouds->step(dtime * 3); + g_menuclouds->render(); + get_video_driver()->beginScene( + true, true, video::SColor(255, 140, 186, 250)); + g_menucloudsmgr->drawAll(); + } else + get_video_driver()->beginScene(true, true, video::SColor(255, 0, 0, 0)); - nulldevice->drop(); - return mlist; + guienv->drawAll(); + get_video_driver()->endScene(); } std::vector RenderingEngine::getSupportedVideoDrivers() { + // Only check these drivers. + // We do not support software and D3D in any capacity. + static const irr::video::E_DRIVER_TYPE glDrivers[4] = { + irr::video::EDT_NULL, + irr::video::EDT_OPENGL, + irr::video::EDT_OGLES1, + irr::video::EDT_OGLES2, + }; std::vector drivers; - for (int i = 0; i != irr::video::EDT_COUNT; i++) { - if (irr::IrrlichtDevice::isDriverSupported((irr::video::E_DRIVER_TYPE)i)) - drivers.push_back((irr::video::E_DRIVER_TYPE)i); + for (int i = 0; i < 4; i++) { + if (irr::IrrlichtDevice::isDriverSupported(glDrivers[i])) + drivers.push_back(glDrivers[i]); } 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); } -const char *RenderingEngine::getVideoDriverName(irr::video::E_DRIVER_TYPE type) -{ - static const char *driver_ids[] = { - "null", - "software", - "burningsvideo", - "direct3d8", - "direct3d9", - "opengl", - "ogles1", - "ogles2", - }; - - return driver_ids[type]; -} - -const char *RenderingEngine::getVideoDriverFriendlyName(irr::video::E_DRIVER_TYPE type) +const VideoDriverInfo &RenderingEngine::getVideoDriverInfo(irr::video::E_DRIVER_TYPE type) { - static const char *driver_names[] = { - "NULL Driver", - "Software Renderer", - "Burning's Video", - "Direct3D 8", - "Direct3D 9", - "OpenGL", - "OpenGL ES1", - "OpenGL ES2", + static const std::unordered_map driver_info_map = { + {(int)video::EDT_NULL, {"null", "NULL Driver"}}, + {(int)video::EDT_OPENGL, {"opengl", "OpenGL"}}, + {(int)video::EDT_OGLES1, {"ogles1", "OpenGL ES1"}}, + {(int)video::EDT_OGLES2, {"ogles2", "OpenGL ES2"}}, }; - - return driver_names[type]; + return driver_info_map.at((int)type); } #ifndef __ANDROID__ -#ifdef XORG_USED +#if defined(XORG_USED) static float calcDisplayDensity() { @@ -503,20 +576,17 @@ static float calcDisplayDensity() if (x11display != NULL) { /* try x direct */ - float dpi_height = floor( - DisplayHeight(x11display, 0) / - (DisplayHeightMM(x11display, 0) * - 0.039370) + - 0.5); - float dpi_width = floor( - DisplayWidth(x11display, 0) / - (DisplayWidthMM(x11display, 0) * - 0.039370) + - 0.5); - + int dh = DisplayHeight(x11display, 0); + int dw = DisplayWidth(x11display, 0); + int dh_mm = DisplayHeightMM(x11display, 0); + int dw_mm = DisplayWidthMM(x11display, 0); XCloseDisplay(x11display); - return std::max(dpi_height, dpi_width) / 96.0; + if (dh_mm != 0 && dw_mm != 0) { + float dpi_height = floor(dh / (dh_mm * 0.039370) + 0.5); + float dpi_width = floor(dw / (dw_mm * 0.039370) + 0.5); + return std::max(dpi_height, dpi_width) / 96.0; + } } } @@ -527,15 +597,45 @@ static float calcDisplayDensity() float RenderingEngine::getDisplayDensity() { static float cached_display_density = calcDisplayDensity(); - return cached_display_density; + return cached_display_density * g_settings->getFloat("display_density_factor"); +} + +#elif defined(_WIN32) + + +static float calcDisplayDensity(irr::video::IVideoDriver *driver) +{ + HWND hWnd; + if (getWindowHandle(driver, hWnd)) { + HDC hdc = GetDC(hWnd); + float dpi = GetDeviceCaps(hdc, LOGPIXELSX); + ReleaseDC(hWnd, hdc); + return dpi / 96.0f; + } + + /* return manually specified dpi */ + return g_settings->getFloat("screen_dpi") / 96.0f; } -#else // XORG_USED float RenderingEngine::getDisplayDensity() { - return g_settings->getFloat("screen_dpi") / 96.0; + static bool cached = false; + static float display_density; + if (!cached) { + display_density = calcDisplayDensity(get_video_driver()); + cached = true; + } + return display_density * g_settings->getFloat("display_density_factor"); } -#endif // XORG_USED + +#else + +float RenderingEngine::getDisplayDensity() +{ + return (g_settings->getFloat("screen_dpi") / 96.0) * g_settings->getFloat("display_density_factor"); +} + +#endif v2u32 RenderingEngine::getDisplaySize() { @@ -547,4 +647,15 @@ v2u32 RenderingEngine::getDisplaySize() return deskres; } + +#else // __ANDROID__ +float RenderingEngine::getDisplayDensity() +{ + return porting::getDisplayDensity(); +} + +v2u32 RenderingEngine::getDisplaySize() +{ + return porting::getDisplaySize(); +} #endif // __ANDROID__