From 28841961ba91b943b7478704181604fa3e24e81e Mon Sep 17 00:00:00 2001 From: Vitaliy Date: Tue, 31 Oct 2017 21:27:10 +0300 Subject: [PATCH] Rewrite rendering engine (#6253) * Clean draw_*() arguments * Split rendering core * Add anaglyph 3D * Interlaced 3D * Drop obsolete methods --- builtin/settingtypes.txt | 1 + .../3d_interlaced_merge/opengl_fragment.glsl | 21 + .../3d_interlaced_merge/opengl_vertex.glsl | 6 + minetest.conf.example | 1 + src/client/CMakeLists.txt | 9 +- src/client/render/anaglyph.cpp | 51 ++ src/client/render/anaglyph.h | 34 + src/client/render/core.cpp | 101 +++ src/client/render/core.h | 75 +++ src/client/render/factory.cpp | 45 ++ src/client/render/factory.h | 25 + src/client/render/interlaced.cpp | 116 ++++ src/client/render/interlaced.h | 43 ++ src/client/render/pageflip.cpp | 55 ++ src/client/render/pageflip.h | 37 ++ src/client/render/plain.cpp | 76 +++ src/client/render/plain.h | 38 ++ src/client/render/sidebyside.cpp | 74 +++ src/client/render/sidebyside.h | 42 ++ src/client/render/stereo.cpp | 60 ++ src/client/render/stereo.h | 38 ++ src/client/renderingengine.cpp | 579 +----------------- src/client/renderingengine.h | 75 +-- src/game.cpp | 22 +- src/settings_translation_file.cpp | 2 +- 25 files changed, 1008 insertions(+), 618 deletions(-) create mode 100644 client/shaders/3d_interlaced_merge/opengl_fragment.glsl create mode 100644 client/shaders/3d_interlaced_merge/opengl_vertex.glsl create mode 100644 src/client/render/anaglyph.cpp create mode 100644 src/client/render/anaglyph.h create mode 100644 src/client/render/core.cpp create mode 100644 src/client/render/core.h create mode 100644 src/client/render/factory.cpp create mode 100644 src/client/render/factory.h create mode 100644 src/client/render/interlaced.cpp create mode 100644 src/client/render/interlaced.h create mode 100644 src/client/render/pageflip.cpp create mode 100644 src/client/render/pageflip.h create mode 100644 src/client/render/plain.cpp create mode 100644 src/client/render/plain.h create mode 100644 src/client/render/sidebyside.cpp create mode 100644 src/client/render/sidebyside.h create mode 100644 src/client/render/stereo.cpp create mode 100644 src/client/render/stereo.h diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index ad88b97d0..dac135363 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -608,6 +608,7 @@ fall_bobbing_amount (Fall bobbing factor) float 0.0 # - topbottom: split screen top/bottom. # - sidebyside: split screen side by side. # - pageflip: quadbuffer based 3d. +# Note that the interlaced mode requires shaders to be enabled. 3d_mode (3D mode) enum none none,anaglyph,interlaced,topbottom,sidebyside,pageflip # In-game chat console height, between 0.1 (10%) and 1.0 (100%). diff --git a/client/shaders/3d_interlaced_merge/opengl_fragment.glsl b/client/shaders/3d_interlaced_merge/opengl_fragment.glsl new file mode 100644 index 000000000..25945ad7f --- /dev/null +++ b/client/shaders/3d_interlaced_merge/opengl_fragment.glsl @@ -0,0 +1,21 @@ +uniform sampler2D baseTexture; +uniform sampler2D normalTexture; +uniform sampler2D textureFlags; + +#define leftImage baseTexture +#define rightImage normalTexture +#define maskImage textureFlags + +void main(void) +{ + vec2 uv = gl_TexCoord[0].st; + vec4 left = texture2D(leftImage, uv).rgba; + vec4 right = texture2D(rightImage, uv).rgba; + vec4 mask = texture2D(maskImage, uv).rgba; + vec4 color; + if (mask.r > 0.5) + color = right; + else + color = left; + gl_FragColor = color; +} diff --git a/client/shaders/3d_interlaced_merge/opengl_vertex.glsl b/client/shaders/3d_interlaced_merge/opengl_vertex.glsl new file mode 100644 index 000000000..4e0b2b125 --- /dev/null +++ b/client/shaders/3d_interlaced_merge/opengl_vertex.glsl @@ -0,0 +1,6 @@ +void main(void) +{ + gl_TexCoord[0] = gl_MultiTexCoord0; + gl_Position = gl_Vertex; + gl_FrontColor = gl_BackColor = gl_Color; +} diff --git a/minetest.conf.example b/minetest.conf.example index 684904a22..40adcf503 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -700,6 +700,7 @@ # - topbottom: split screen top/bottom. # - sidebyside: split screen side by side. # - pageflip: quadbuffer based 3d. +# Note that the interlaced mode requires shaders to be enabled. # type: enum values: none, anaglyph, interlaced, topbottom, sidebyside, pageflip # 3d_mode = none diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index 4ba8fea5b..3cc6c0351 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -1,4 +1,12 @@ set(client_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/render/anaglyph.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/render/core.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/render/factory.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/render/interlaced.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/render/pageflip.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/render/plain.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/render/sidebyside.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/render/stereo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/renderingengine.cpp ${CMAKE_CURRENT_SOURCE_DIR}/clientlauncher.cpp ${CMAKE_CURRENT_SOURCE_DIR}/inputhandler.cpp @@ -6,4 +14,3 @@ set(client_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/joystick_controller.cpp PARENT_SCOPE ) - diff --git a/src/client/render/anaglyph.cpp b/src/client/render/anaglyph.cpp new file mode 100644 index 000000000..1fad9e8d3 --- /dev/null +++ b/src/client/render/anaglyph.cpp @@ -0,0 +1,51 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2017 numzero, Lobachesky Vitaly + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "anaglyph.h" + +void RenderingCoreAnaglyph::drawAll() +{ + renderBothImages(); + drawPostFx(); + drawHUD(); +} + +void RenderingCoreAnaglyph::setupMaterial(int color_mask) +{ + video::SOverrideMaterial &mat = driver->getOverrideMaterial(); + mat.Material.ColorMask = color_mask; + mat.EnableFlags = video::EMF_COLOR_MASK; + mat.EnablePasses = scene::ESNRP_SKY_BOX | scene::ESNRP_SOLID | + scene::ESNRP_TRANSPARENT | scene::ESNRP_TRANSPARENT_EFFECT | + scene::ESNRP_SHADOW; +} + +void RenderingCoreAnaglyph::useEye(bool right) +{ + RenderingCoreStereo::useEye(right); + driver->clearZBuffer(); + setupMaterial(right ? video::ECP_GREEN | video::ECP_BLUE : video::ECP_RED); +} + +void RenderingCoreAnaglyph::resetEye() +{ + setupMaterial(video::ECP_ALL); + RenderingCoreStereo::resetEye(); +} diff --git a/src/client/render/anaglyph.h b/src/client/render/anaglyph.h new file mode 100644 index 000000000..6305efb90 --- /dev/null +++ b/src/client/render/anaglyph.h @@ -0,0 +1,34 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2017 numzero, Lobachesky Vitaly + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#pragma once +#include "stereo.h" + +class RenderingCoreAnaglyph : public RenderingCoreStereo +{ +protected: + void setupMaterial(int color_mask); + void useEye(bool right) override; + void resetEye() override; + +public: + using RenderingCoreStereo::RenderingCoreStereo; + void drawAll() override; +}; diff --git a/src/client/render/core.cpp b/src/client/render/core.cpp new file mode 100644 index 000000000..7a4230c84 --- /dev/null +++ b/src/client/render/core.cpp @@ -0,0 +1,101 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2017 numzero, Lobachesky Vitaly + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "core.h" +#include "camera.h" +#include "client.h" +#include "clientmap.h" +#include "hud.h" +#include "minimap.h" + +RenderingCore::RenderingCore(IrrlichtDevice *_device, Client *_client, Hud *_hud) + : device(_device), driver(device->getVideoDriver()), smgr(device->getSceneManager()), + guienv(device->getGUIEnvironment()), client(_client), camera(client->getCamera()), + mapper(client->getMinimap()), hud(_hud) +{ + screensize = driver->getScreenSize(); + virtual_size = screensize; +} + +RenderingCore::~RenderingCore() +{ + clearTextures(); +} + +void RenderingCore::initialize() +{ + // have to be called late as the VMT is not ready in the constructor: + initTextures(); +} + +void RenderingCore::updateScreenSize() +{ + virtual_size = screensize; + clearTextures(); + initTextures(); +} + +void RenderingCore::draw(video::SColor _skycolor, bool _show_hud, bool _show_minimap, + bool _draw_wield_tool, bool _draw_crosshair) +{ + v2u32 ss = driver->getScreenSize(); + if (screensize != ss) { + screensize = ss; + updateScreenSize(); + } + skycolor = _skycolor; + show_hud = _show_hud; + show_minimap = _show_minimap; + draw_wield_tool = _draw_wield_tool; + draw_crosshair = _draw_crosshair; + + beforeDraw(); + drawAll(); +} + +void RenderingCore::draw3D() +{ + smgr->drawAll(); + driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); + if (!show_hud) + return; + hud->drawSelectionMesh(); + if (draw_wield_tool) + camera->drawWieldedTool(); +} + +void RenderingCore::drawHUD() +{ + if (show_hud) { + if (draw_crosshair) + hud->drawCrosshair(); + hud->drawHotbar(client->getPlayerItem()); + hud->drawLuaElements(camera->getOffset()); + camera->drawNametags(); + if (mapper && show_minimap) + mapper->drawMinimap(); + } + guienv->drawAll(); +} + +void RenderingCore::drawPostFx() +{ + client->getEnv().getClientMap().renderPostFx(camera->getCameraMode()); +} diff --git a/src/client/render/core.h b/src/client/render/core.h new file mode 100644 index 000000000..35def7f20 --- /dev/null +++ b/src/client/render/core.h @@ -0,0 +1,75 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2017 numzero, Lobachesky Vitaly + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#pragma once +#include "irrlichttypes_extrabloated.h" + +class Camera; +class Client; +class Hud; +class Minimap; + +class RenderingCore +{ +protected: + v2u32 screensize; + v2u32 virtual_size; + video::SColor skycolor; + bool show_hud; + bool show_minimap; + bool draw_wield_tool; + bool draw_crosshair; + + IrrlichtDevice *device; + video::IVideoDriver *driver; + scene::ISceneManager *smgr; + gui::IGUIEnvironment *guienv; + + Client *client; + Camera *camera; + Minimap *mapper; + Hud *hud; + + void updateScreenSize(); + virtual void initTextures() {} + virtual void clearTextures() {} + + virtual void beforeDraw() {} + virtual void drawAll() = 0; + + void draw3D(); + void drawHUD(); + void drawPostFx(); + +public: + RenderingCore(IrrlichtDevice *_device, Client *_client, Hud *_hud); + RenderingCore(const RenderingCore &) = delete; + RenderingCore(RenderingCore &&) = delete; + virtual ~RenderingCore(); + + RenderingCore &operator=(const RenderingCore &) = delete; + RenderingCore &operator=(RenderingCore &&) = delete; + + void initialize(); + void draw(video::SColor _skycolor, bool _show_hud, bool _show_minimap, + bool _draw_wield_tool, bool _draw_crosshair); + + inline v2u32 getVirtualSize() const { return virtual_size; } +}; diff --git a/src/client/render/factory.cpp b/src/client/render/factory.cpp new file mode 100644 index 000000000..c2c3f341e --- /dev/null +++ b/src/client/render/factory.cpp @@ -0,0 +1,45 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2017 numzero, Lobachesky Vitaly + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "factory.h" +#include +#include "plain.h" +#include "anaglyph.h" +#include "interlaced.h" +#include "pageflip.h" +#include "sidebyside.h" + +RenderingCore *createRenderingCore(const std::string &stereo_mode, IrrlichtDevice *device, + Client *client, Hud *hud) +{ + if (stereo_mode == "none") + return new RenderingCorePlain(device, client, hud); + if (stereo_mode == "anaglyph") + return new RenderingCoreAnaglyph(device, client, hud); + if (stereo_mode == "interlaced") + return new RenderingCoreInterlaced(device, client, hud); + if (stereo_mode == "pageflip") + return new RenderingCorePageflip(device, client, hud); + if (stereo_mode == "sidebyside") + return new RenderingCoreSideBySide(device, client, hud); + if (stereo_mode == "topbottom") + return new RenderingCoreSideBySide(device, client, hud, true); + throw std::invalid_argument("Invalid rendering mode: " + stereo_mode); +} diff --git a/src/client/render/factory.h b/src/client/render/factory.h new file mode 100644 index 000000000..c7c5cdc1e --- /dev/null +++ b/src/client/render/factory.h @@ -0,0 +1,25 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2017 numzero, Lobachesky Vitaly + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include +#include "core.h" + +RenderingCore *createRenderingCore(const std::string &stereo_mode, IrrlichtDevice *device, + Client *client, Hud *hud); diff --git a/src/client/render/interlaced.cpp b/src/client/render/interlaced.cpp new file mode 100644 index 000000000..ccd4e60cf --- /dev/null +++ b/src/client/render/interlaced.cpp @@ -0,0 +1,116 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2017 numzero, Lobachesky Vitaly + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "interlaced.h" +#include "client.h" +#include "shader.h" +#include "client/tile.h" + +RenderingCoreInterlaced::RenderingCoreInterlaced( + IrrlichtDevice *_device, Client *_client, Hud *_hud) + : RenderingCoreStereo(_device, _client, _hud) +{ + initMaterial(); +} + +void RenderingCoreInterlaced::initMaterial() +{ + IShaderSource *s = client->getShaderSource(); + mat.UseMipMaps = false; + mat.ZBuffer = false; + mat.ZWriteEnable = false; + u32 shader = s->getShader("3d_interlaced_merge", TILE_MATERIAL_BASIC, 0); + mat.MaterialType = s->getShaderInfo(shader).material; + for (int k = 0; k < 3; ++k) { + mat.TextureLayer[k].AnisotropicFilter = false; + mat.TextureLayer[k].BilinearFilter = false; + mat.TextureLayer[k].TrilinearFilter = false; + mat.TextureLayer[k].TextureWrapU = video::ETC_CLAMP_TO_EDGE; + mat.TextureLayer[k].TextureWrapV = video::ETC_CLAMP_TO_EDGE; + } +} + +void RenderingCoreInterlaced::initTextures() +{ + v2u32 image_size{screensize.X, screensize.Y / 2}; + left = driver->addRenderTargetTexture( + image_size, "3d_render_left", video::ECF_A8R8G8B8); + right = driver->addRenderTargetTexture( + image_size, "3d_render_right", video::ECF_A8R8G8B8); + mask = driver->addTexture(screensize, "3d_render_mask", video::ECF_A8R8G8B8); + initMask(); + mat.TextureLayer[0].Texture = left; + mat.TextureLayer[1].Texture = right; + mat.TextureLayer[2].Texture = mask; +} + +void RenderingCoreInterlaced::clearTextures() +{ + driver->removeTexture(left); + driver->removeTexture(right); + driver->removeTexture(mask); +} + +void RenderingCoreInterlaced::initMask() +{ + u8 *data = reinterpret_cast(mask->lock()); + for (u32 j = 0; j < screensize.Y; j++) { + u8 val = j % 2 ? 0xff : 0x00; + memset(data, val, 4 * screensize.X); + data += 4 * screensize.X; + } + mask->unlock(); +} + +void RenderingCoreInterlaced::drawAll() +{ + renderBothImages(); + merge(); + drawHUD(); +} + +void RenderingCoreInterlaced::merge() +{ + static const video::S3DVertex vertices[4] = { + video::S3DVertex(1.0, -1.0, 0.0, 0.0, 0.0, -1.0, + video::SColor(255, 0, 255, 255), 1.0, 0.0), + video::S3DVertex(-1.0, -1.0, 0.0, 0.0, 0.0, -1.0, + video::SColor(255, 255, 0, 255), 0.0, 0.0), + video::S3DVertex(-1.0, 1.0, 0.0, 0.0, 0.0, -1.0, + video::SColor(255, 255, 255, 0), 0.0, 1.0), + video::S3DVertex(1.0, 1.0, 0.0, 0.0, 0.0, -1.0, + video::SColor(255, 255, 255, 255), 1.0, 1.0), + }; + static const u16 indices[6] = {0, 1, 2, 2, 3, 0}; + driver->setMaterial(mat); + driver->drawVertexPrimitiveList(&vertices, 4, &indices, 2); +} + +void RenderingCoreInterlaced::useEye(bool _right) +{ + driver->setRenderTarget(_right ? right : left, true, true, skycolor); + RenderingCoreStereo::useEye(_right); +} + +void RenderingCoreInterlaced::resetEye() +{ + driver->setRenderTarget(nullptr, false, false, skycolor); + RenderingCoreStereo::resetEye(); +} diff --git a/src/client/render/interlaced.h b/src/client/render/interlaced.h new file mode 100644 index 000000000..d0c1d9e62 --- /dev/null +++ b/src/client/render/interlaced.h @@ -0,0 +1,43 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2017 numzero, Lobachesky Vitaly + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#pragma once +#include "stereo.h" + +class RenderingCoreInterlaced : public RenderingCoreStereo +{ +protected: + video::ITexture *left = nullptr; + video::ITexture *right = nullptr; + video::ITexture *mask = nullptr; + video::SMaterial mat; + + void initMaterial(); + void initTextures() override; + void clearTextures() override; + void initMask(); + void useEye(bool right) override; + void resetEye() override; + void merge(); + +public: + RenderingCoreInterlaced(IrrlichtDevice *_device, Client *_client, Hud *_hud); + void drawAll() override; +}; diff --git a/src/client/render/pageflip.cpp b/src/client/render/pageflip.cpp new file mode 100644 index 000000000..8d6fa7423 --- /dev/null +++ b/src/client/render/pageflip.cpp @@ -0,0 +1,55 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2017 numzero, Lobachesky Vitaly + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "pageflip.h" + +void RenderingCorePageflip::initTextures() +{ + hud = driver->addRenderTargetTexture( + screensize, "3d_render_hud", video::ECF_A8R8G8B8); +} + +void RenderingCorePageflip::clearTextures() +{ + driver->removeTexture(hud); +} + +void RenderingCorePageflip::drawAll() +{ + driver->setRenderTarget(hud, true, true, video::SColor(0, 0, 0, 0)); + drawHUD(); + driver->setRenderTarget(nullptr, false, false, skycolor); + renderBothImages(); +} + +void RenderingCorePageflip::useEye(bool _right) +{ + driver->setRenderTarget(_right ? video::ERT_STEREO_RIGHT_BUFFER + : video::ERT_STEREO_LEFT_BUFFER, + true, true, skycolor); + RenderingCoreStereo::useEye(_right); +} + +void RenderingCorePageflip::resetEye() +{ + driver->draw2DImage(hud, v2s32(0, 0)); + driver->setRenderTarget(video::ERT_FRAME_BUFFER, false, false, skycolor); + RenderingCoreStereo::resetEye(); +} diff --git a/src/client/render/pageflip.h b/src/client/render/pageflip.h new file mode 100644 index 000000000..ee4567ac4 --- /dev/null +++ b/src/client/render/pageflip.h @@ -0,0 +1,37 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2017 numzero, Lobachesky Vitaly + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#pragma once +#include "stereo.h" + +class RenderingCorePageflip : public RenderingCoreStereo +{ +protected: + video::ITexture *hud = nullptr; + + void initTextures() override; + void clearTextures() override; + void useEye(bool right) override; + void resetEye() override; + +public: + using RenderingCoreStereo::RenderingCoreStereo; + void drawAll() override; +}; diff --git a/src/client/render/plain.cpp b/src/client/render/plain.cpp new file mode 100644 index 000000000..94921245b --- /dev/null +++ b/src/client/render/plain.cpp @@ -0,0 +1,76 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2017 numzero, Lobachesky Vitaly + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "plain.h" +#include "settings.h" + +inline u32 scaledown(u32 coef, u32 size) +{ + return (size + coef - 1) / coef; +} + +RenderingCorePlain::RenderingCorePlain( + IrrlichtDevice *_device, Client *_client, Hud *_hud) + : RenderingCore(_device, _client, _hud) +{ + scale = g_settings->getU16("undersampling"); +} + +void RenderingCorePlain::initTextures() +{ + if (!scale) + return; + v2u32 size{scaledown(scale, screensize.X), scaledown(scale, screensize.Y)}; + lowres = driver->addRenderTargetTexture( + size, "render_lowres", video::ECF_A8R8G8B8); +} + +void RenderingCorePlain::clearTextures() +{ + if (!scale) + return; + driver->removeTexture(lowres); +} + +void RenderingCorePlain::beforeDraw() +{ + if (!scale) + return; + driver->setRenderTarget(lowres, true, true, skycolor); +} + +void RenderingCorePlain::upscale() +{ + if (!scale) + return; + driver->setRenderTarget(0, true, true); + v2u32 size{scaledown(scale, screensize.X), scaledown(scale, screensize.Y)}; + v2u32 dest_size{scale * size.X, scale * size.Y}; + driver->draw2DImage(lowres, core::rect(0, 0, dest_size.X, dest_size.Y), + core::rect(0, 0, size.X, size.Y)); +} + +void RenderingCorePlain::drawAll() +{ + draw3D(); + drawPostFx(); + upscale(); + drawHUD(); +} diff --git a/src/client/render/plain.h b/src/client/render/plain.h new file mode 100644 index 000000000..af9d7036b --- /dev/null +++ b/src/client/render/plain.h @@ -0,0 +1,38 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2017 numzero, Lobachesky Vitaly + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#pragma once +#include "core.h" + +class RenderingCorePlain : public RenderingCore +{ +protected: + int scale = 0; + video::ITexture *lowres = nullptr; + + void initTextures() override; + void clearTextures() override; + void beforeDraw() override; + void upscale(); + +public: + RenderingCorePlain(IrrlichtDevice *_device, Client *_client, Hud *_hud); + void drawAll() override; +}; diff --git a/src/client/render/sidebyside.cpp b/src/client/render/sidebyside.cpp new file mode 100644 index 000000000..2af09ee33 --- /dev/null +++ b/src/client/render/sidebyside.cpp @@ -0,0 +1,74 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2017 numzero, Lobachesky Vitaly + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "sidebyside.h" +#include +#include "hud.h" + +RenderingCoreSideBySide::RenderingCoreSideBySide( + IrrlichtDevice *_device, Client *_client, Hud *_hud, bool _horizontal) + : RenderingCoreStereo(_device, _client, _hud), horizontal(_horizontal) +{ +} + +void RenderingCoreSideBySide::initTextures() +{ + if (horizontal) { + image_size = {screensize.X, screensize.Y / 2}; + rpos = v2s32(0, screensize.Y / 2); + } else { + image_size = {screensize.X / 2, screensize.Y}; + rpos = v2s32(screensize.X / 2, 0); + } + virtual_size = image_size; + left = driver->addRenderTargetTexture( + image_size, "3d_render_left", video::ECF_A8R8G8B8); + right = driver->addRenderTargetTexture( + image_size, "3d_render_right", video::ECF_A8R8G8B8); +} + +void RenderingCoreSideBySide::clearTextures() +{ + driver->removeTexture(left); + driver->removeTexture(right); +} + +void RenderingCoreSideBySide::drawAll() +{ + driver->OnResize(image_size); // HACK to make GUI smaller + renderBothImages(); + driver->OnResize(screensize); + driver->draw2DImage(left, {}); + driver->draw2DImage(right, rpos); +} + +void RenderingCoreSideBySide::useEye(bool _right) +{ + driver->setRenderTarget(_right ? right : left, true, true, skycolor); + RenderingCoreStereo::useEye(_right); +} + +void RenderingCoreSideBySide::resetEye() +{ + hud->resizeHotbar(); + drawHUD(); + driver->setRenderTarget(nullptr, false, false, skycolor); + RenderingCoreStereo::resetEye(); +} diff --git a/src/client/render/sidebyside.h b/src/client/render/sidebyside.h new file mode 100644 index 000000000..70b2bdcf5 --- /dev/null +++ b/src/client/render/sidebyside.h @@ -0,0 +1,42 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2017 numzero, Lobachesky Vitaly + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#pragma once +#include "stereo.h" + +class RenderingCoreSideBySide : public RenderingCoreStereo +{ +protected: + video::ITexture *left = nullptr; + video::ITexture *right = nullptr; + bool horizontal = false; + core::dimension2du image_size; + v2s32 rpos; + + void initTextures() override; + void clearTextures() override; + void useEye(bool right) override; + void resetEye() override; + +public: + RenderingCoreSideBySide(IrrlichtDevice *_device, Client *_client, Hud *_hud, + bool _horizontal = false); + void drawAll() override; +}; diff --git a/src/client/render/stereo.cpp b/src/client/render/stereo.cpp new file mode 100644 index 000000000..eec9f8ced --- /dev/null +++ b/src/client/render/stereo.cpp @@ -0,0 +1,60 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2017 numzero, Lobachesky Vitaly + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "stereo.h" +#include "camera.h" +#include "constants.h" +#include "settings.h" + +RenderingCoreStereo::RenderingCoreStereo( + IrrlichtDevice *_device, Client *_client, Hud *_hud) + : RenderingCore(_device, _client, _hud) +{ + eye_offset = BS * g_settings->getFloat("3d_paralax_strength"); +} + +void RenderingCoreStereo::beforeDraw() +{ + cam = camera->getCameraNode(); + base_transform = cam->getRelativeTransformation(); +} + +void RenderingCoreStereo::useEye(bool right) +{ + core::matrix4 move; + move.setTranslation( + core::vector3df(right ? eye_offset : -eye_offset, 0.0f, 0.0f)); + cam->setPosition((base_transform * move).getTranslation()); +} + +void RenderingCoreStereo::resetEye() +{ + cam->setPosition(base_transform.getTranslation()); +} + +void RenderingCoreStereo::renderBothImages() +{ + useEye(false); + draw3D(); + resetEye(); + useEye(true); + draw3D(); + resetEye(); +} diff --git a/src/client/render/stereo.h b/src/client/render/stereo.h new file mode 100644 index 000000000..0b13de376 --- /dev/null +++ b/src/client/render/stereo.h @@ -0,0 +1,38 @@ +/* +Minetest +Copyright (C) 2010-2013 celeron55, Perttu Ahola +Copyright (C) 2017 numzero, Lobachesky Vitaly + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#pragma once +#include "core.h" + +class RenderingCoreStereo : public RenderingCore +{ +protected: + scene::ICameraSceneNode *cam; + core::matrix4 base_transform; + float eye_offset; + + void beforeDraw() override; + virtual void useEye(bool right); + virtual void resetEye(); + void renderBothImages(); + +public: + RenderingCoreStereo(IrrlichtDevice *_device, Client *_client, Hud *_hud); +}; diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp index a57388596..f9da178b9 100644 --- a/src/client/renderingengine.cpp +++ b/src/client/renderingengine.cpp @@ -31,6 +31,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "minimap.h" #include "clientmap.h" #include "renderingengine.h" +#include "render/core.h" +#include "render/factory.h" #include "inputhandler.h" #include "gettext.h" @@ -102,17 +104,22 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver) #endif m_device = createDeviceEx(params); + driver = m_device->getVideoDriver(); + s_singleton = this; } RenderingEngine::~RenderingEngine() { + core.reset(); m_device->drop(); s_singleton = nullptr; } v2u32 RenderingEngine::getWindowSize() const { + if (core) + return core->getVirtualSize(); return m_device->getVideoDriver()->getScreenSize(); } @@ -121,11 +128,6 @@ void RenderingEngine::setResizable(bool resize) m_device->setResizable(resize); } -video::IVideoDriver *RenderingEngine::getVideoDriver() -{ - return m_device->getVideoDriver(); -} - bool RenderingEngine::print_video_modes() { IrrlichtDevice *nulldevice; @@ -213,11 +215,10 @@ bool RenderingEngine::setWindowIcon() "-xorg-icon-128.png"); #endif #elif defined(_WIN32) - const video::SExposedVideoData exposedData = - m_device->getVideoDriver()->getExposedVideoData(); + const video::SExposedVideoData exposedData = driver->getExposedVideoData(); HWND hWnd; // Window handle - switch (m_device->getVideoDriver()->getDriverType()) { + switch (driver->getDriverType()) { case video::EDT_DIRECT3D8: hWnd = reinterpret_cast(exposedData.D3D8.HWnd); break; @@ -253,14 +254,12 @@ bool RenderingEngine::setXorgWindowIconFromPath(const std::string &icon_file) { #ifdef XORG_USED - video::IVideoDriver *v_driver = m_device->getVideoDriver(); - video::IImageLoader *image_loader = NULL; - u32 cnt = v_driver->getImageLoaderCount(); + u32 cnt = driver->getImageLoaderCount(); for (u32 i = 0; i < cnt; i++) { - if (v_driver->getImageLoader(i)->isALoadableFileExtension( + if (driver->getImageLoader(i)->isALoadableFileExtension( icon_file.c_str())) { - image_loader = v_driver->getImageLoader(i); + image_loader = driver->getImageLoader(i); break; } } @@ -313,7 +312,7 @@ bool RenderingEngine::setXorgWindowIconFromPath(const std::string &icon_file) img->drop(); icon_f->drop(); - const video::SExposedVideoData &video_data = v_driver->getExposedVideoData(); + const video::SExposedVideoData &video_data = driver->getExposedVideoData(); Display *x11_dpl = (Display *)video_data.OpenGLLinux.X11Display; @@ -442,558 +441,22 @@ std::vector RenderingEngine::getSupportedVideoDrivers return drivers; } -void RenderingEngine::_draw_scene(Camera *camera, Client *client, LocalPlayer *player, - Hud *hud, Minimap *mapper, gui::IGUIEnvironment *guienv, - const v2u32 &screensize, const video::SColor &skycolor, bool show_hud, - bool show_minimap) +void RenderingEngine::_initialize(Client *client, Hud *hud) { - bool draw_wield_tool = - (show_hud && (player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE) && - camera->getCameraMode() < CAMERA_MODE_THIRD); - - bool draw_crosshair = ((player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE) && - (camera->getCameraMode() != CAMERA_MODE_THIRD_FRONT)); - -#ifdef HAVE_TOUCHSCREENGUI - try { - draw_crosshair = !g_settings->getBool("touchtarget"); - } catch (SettingNotFoundException) { - } -#endif - const std::string &draw_mode = g_settings->get("3d_mode"); - - if (draw_mode == "anaglyph") { - draw_anaglyph_3d_mode( - camera, show_hud, hud, draw_wield_tool, client, guienv); - draw_crosshair = false; - } else if (draw_mode == "interlaced") { - draw_interlaced_3d_mode(camera, show_hud, hud, screensize, - draw_wield_tool, client, guienv, skycolor); - draw_crosshair = false; - } else if (draw_mode == "sidebyside") { - draw_sidebyside_3d_mode(camera, show_hud, hud, screensize, - draw_wield_tool, client, guienv, skycolor); - show_hud = false; - } else if (draw_mode == "topbottom") { - draw_top_bottom_3d_mode(camera, show_hud, hud, screensize, - draw_wield_tool, client, guienv, skycolor); - show_hud = false; - } else if (draw_mode == "pageflip") { - draw_pageflip_3d_mode(camera, show_hud, hud, screensize, draw_wield_tool, - client, guienv, skycolor); - draw_crosshair = false; - show_hud = false; - } else { - draw_plain(camera, show_hud, hud, screensize, draw_wield_tool, client, - guienv, skycolor); - } - - /* - Post effects - */ - client->getEnv().getClientMap().renderPostFx(camera->getCameraMode()); - - // TODO how to make those 3d too - if (show_hud) { - if (draw_crosshair) - hud->drawCrosshair(); - - hud->drawHotbar(client->getPlayerItem()); - hud->drawLuaElements(camera->getOffset()); - camera->drawNametags(); - - if (mapper && show_minimap) - mapper->drawMinimap(); - } - - guienv->drawAll(); + core.reset(createRenderingCore(draw_mode, m_device, client, hud)); + core->initialize(); } -void RenderingEngine::draw_anaglyph_3d_mode(Camera *camera, bool show_hud, Hud *hud, - bool draw_wield_tool, Client *client, gui::IGUIEnvironment *guienv) +void RenderingEngine::_finalize() { - - /* preserve old setup*/ - irr::core::vector3df oldPosition = camera->getCameraNode()->getPosition(); - irr::core::vector3df oldTarget = camera->getCameraNode()->getTarget(); - - irr::core::matrix4 startMatrix = - camera->getCameraNode()->getAbsoluteTransformation(); - irr::core::vector3df focusPoint = - (camera->getCameraNode()->getTarget() - - camera->getCameraNode()->getAbsolutePosition()) - .setLength(1) + - camera->getCameraNode()->getAbsolutePosition(); - - // Left eye... - irr::core::vector3df leftEye; - irr::core::matrix4 leftMove; - leftMove.setTranslation(irr::core::vector3df( - -g_settings->getFloat("3d_paralax_strength"), 0.0f, 0.0f)); - leftEye = (startMatrix * leftMove).getTranslation(); - - // clear the depth buffer, and color - getVideoDriver()->beginScene(true, true, irr::video::SColor(0, 200, 200, 255)); - getVideoDriver()->getOverrideMaterial().Material.ColorMask = irr::video::ECP_RED; - getVideoDriver()->getOverrideMaterial().EnableFlags = irr::video::EMF_COLOR_MASK; - getVideoDriver()->getOverrideMaterial().EnablePasses = - irr::scene::ESNRP_SKY_BOX + irr::scene::ESNRP_SOLID + - irr::scene::ESNRP_TRANSPARENT + - irr::scene::ESNRP_TRANSPARENT_EFFECT + irr::scene::ESNRP_SHADOW; - camera->getCameraNode()->setPosition(leftEye); - camera->getCameraNode()->setTarget(focusPoint); - get_scene_manager()->drawAll(); - getVideoDriver()->setTransform(video::ETS_WORLD, core::IdentityMatrix); - if (show_hud) { - hud->drawSelectionMesh(); - if (draw_wield_tool) - camera->drawWieldedTool(&leftMove); - } - - guienv->drawAll(); - - // Right eye... - irr::core::vector3df rightEye; - irr::core::matrix4 rightMove; - rightMove.setTranslation(irr::core::vector3df( - g_settings->getFloat("3d_paralax_strength"), 0.0f, 0.0f)); - rightEye = (startMatrix * rightMove).getTranslation(); - - // clear the depth buffer - getVideoDriver()->clearZBuffer(); - getVideoDriver()->getOverrideMaterial().Material.ColorMask = - irr::video::ECP_GREEN + irr::video::ECP_BLUE; - getVideoDriver()->getOverrideMaterial().EnableFlags = irr::video::EMF_COLOR_MASK; - getVideoDriver()->getOverrideMaterial().EnablePasses = - irr::scene::ESNRP_SKY_BOX + irr::scene::ESNRP_SOLID + - irr::scene::ESNRP_TRANSPARENT + - irr::scene::ESNRP_TRANSPARENT_EFFECT + irr::scene::ESNRP_SHADOW; - camera->getCameraNode()->setPosition(rightEye); - camera->getCameraNode()->setTarget(focusPoint); - get_scene_manager()->drawAll(); - getVideoDriver()->setTransform(video::ETS_WORLD, core::IdentityMatrix); - if (show_hud) { - hud->drawSelectionMesh(); - if (draw_wield_tool) - camera->drawWieldedTool(&rightMove); - } - - guienv->drawAll(); - - getVideoDriver()->getOverrideMaterial().Material.ColorMask = irr::video::ECP_ALL; - getVideoDriver()->getOverrideMaterial().EnableFlags = 0; - getVideoDriver()->getOverrideMaterial().EnablePasses = 0; - camera->getCameraNode()->setPosition(oldPosition); - camera->getCameraNode()->setTarget(oldTarget); + core.reset(); } -void RenderingEngine::init_texture( - const v2u32 &screensize, video::ITexture **texture, const char *name) +void RenderingEngine::_draw_scene(video::SColor skycolor, bool show_hud, + bool show_minimap, bool draw_wield_tool, bool draw_crosshair) { - if (*texture) { - getVideoDriver()->removeTexture(*texture); - } - *texture = getVideoDriver()->addRenderTargetTexture( - core::dimension2d(screensize.X, screensize.Y), name, - irr::video::ECF_A8R8G8B8); -} - -video::ITexture *RenderingEngine::draw_image(const v2u32 &screensize, parallax_sign psign, - const irr::core::matrix4 &startMatrix, - const irr::core::vector3df &focusPoint, bool show_hud, Camera *camera, - Hud *hud, bool draw_wield_tool, Client *client, - gui::IGUIEnvironment *guienv, const video::SColor &skycolor) -{ - static video::ITexture *images[2] = {NULL, NULL}; - static v2u32 last_screensize = v2u32(0, 0); - - video::ITexture *image = NULL; - - if (screensize != last_screensize) { - init_texture(screensize, &images[1], "mt_drawimage_img1"); - init_texture(screensize, &images[0], "mt_drawimage_img2"); - last_screensize = screensize; - } - - if (psign == RIGHT) - image = images[1]; - else - image = images[0]; - - getVideoDriver()->setRenderTarget(image, true, true, - irr::video::SColor(255, skycolor.getRed(), skycolor.getGreen(), - skycolor.getBlue())); - - irr::core::vector3df eye_pos; - irr::core::matrix4 movement; - movement.setTranslation(irr::core::vector3df( - (int)psign * g_settings->getFloat("3d_paralax_strength"), 0.0f, - 0.0f)); - eye_pos = (startMatrix * movement).getTranslation(); - - // clear the depth buffer - getVideoDriver()->clearZBuffer(); - camera->getCameraNode()->setPosition(eye_pos); - camera->getCameraNode()->setTarget(focusPoint); - get_scene_manager()->drawAll(); - - getVideoDriver()->setTransform(video::ETS_WORLD, core::IdentityMatrix); - - if (show_hud) { - hud->drawSelectionMesh(); - if (draw_wield_tool) - camera->drawWieldedTool(&movement); - } - - guienv->drawAll(); - - /* switch back to real renderer */ - getVideoDriver()->setRenderTarget(0, true, true, - irr::video::SColor(0, skycolor.getRed(), skycolor.getGreen(), - skycolor.getBlue())); - - return image; -} - -video::ITexture *RenderingEngine::draw_hud(const v2u32 &screensize, bool show_hud, - Hud *hud, Client *client, bool draw_crosshair, - const video::SColor &skycolor, gui::IGUIEnvironment *guienv, - Camera *camera) -{ - static video::ITexture *image = nullptr; - init_texture(screensize, &image, "mt_drawimage_hud"); - getVideoDriver()->setRenderTarget( - image, true, true, irr::video::SColor(255, 0, 0, 0)); - - if (show_hud) { - if (draw_crosshair) - hud->drawCrosshair(); - hud->drawHotbar(client->getPlayerItem()); - hud->drawLuaElements(camera->getOffset()); - camera->drawNametags(); - guienv->drawAll(); - } - - getVideoDriver()->setRenderTarget(0, true, true, - irr::video::SColor(0, skycolor.getRed(), skycolor.getGreen(), - skycolor.getBlue())); - - return image; -} - -void RenderingEngine::draw_interlaced_3d_mode(Camera *camera, bool show_hud, Hud *hud, - const v2u32 &screensize, bool draw_wield_tool, Client *client, - gui::IGUIEnvironment *guienv, const video::SColor &skycolor) -{ - /* save current info */ - irr::core::vector3df oldPosition = camera->getCameraNode()->getPosition(); - irr::core::vector3df oldTarget = camera->getCameraNode()->getTarget(); - irr::core::matrix4 startMatrix = - camera->getCameraNode()->getAbsoluteTransformation(); - irr::core::vector3df focusPoint = - (camera->getCameraNode()->getTarget() - - camera->getCameraNode()->getAbsolutePosition()) - .setLength(1) + - camera->getCameraNode()->getAbsolutePosition(); - - /* create left view */ - video::ITexture *left_image = draw_image(screensize, LEFT, startMatrix, - focusPoint, show_hud, camera, hud, draw_wield_tool, client, - guienv, skycolor); - - // Right eye... - irr::core::vector3df rightEye; - irr::core::matrix4 rightMove; - rightMove.setTranslation(irr::core::vector3df( - g_settings->getFloat("3d_paralax_strength"), 0.0f, 0.0f)); - rightEye = (startMatrix * rightMove).getTranslation(); - - // clear the depth buffer - getVideoDriver()->clearZBuffer(); - camera->getCameraNode()->setPosition(rightEye); - camera->getCameraNode()->setTarget(focusPoint); - get_scene_manager()->drawAll(); - - getVideoDriver()->setTransform(video::ETS_WORLD, core::IdentityMatrix); - - if (show_hud) { - hud->drawSelectionMesh(); - if (draw_wield_tool) - camera->drawWieldedTool(&rightMove); - } - guienv->drawAll(); - - for (unsigned int i = 0; i < screensize.Y; i += 2) { -#if (IRRLICHT_VERSION_MAJOR >= 1) && (IRRLICHT_VERSION_MINOR >= 8) - getVideoDriver()->draw2DImage(left_image, - irr::core::position2d(0, i), -#else - getVideoDriver()->draw2DImage(left_image, - irr::core::position2d(0, screensize.Y - i), -#endif - irr::core::rect(0, i, screensize.X, i + 1), 0, - irr::video::SColor(255, 255, 255, 255), false); - } - - /* cleanup */ - camera->getCameraNode()->setPosition(oldPosition); - camera->getCameraNode()->setTarget(oldTarget); -} - -void RenderingEngine::draw_sidebyside_3d_mode(Camera *camera, bool show_hud, Hud *hud, - const v2u32 &screensize, bool draw_wield_tool, Client *client, - gui::IGUIEnvironment *guienv, const video::SColor &skycolor) -{ - /* save current info */ - irr::core::vector3df oldPosition = camera->getCameraNode()->getPosition(); - irr::core::vector3df oldTarget = camera->getCameraNode()->getTarget(); - irr::core::matrix4 startMatrix = - camera->getCameraNode()->getAbsoluteTransformation(); - irr::core::vector3df focusPoint = - (camera->getCameraNode()->getTarget() - - camera->getCameraNode()->getAbsolutePosition()) - .setLength(1) + - camera->getCameraNode()->getAbsolutePosition(); - - /* create left view */ - video::ITexture *left_image = draw_image(screensize, LEFT, startMatrix, - focusPoint, show_hud, camera, hud, draw_wield_tool, client, - guienv, skycolor); - - /* create right view */ - video::ITexture *right_image = draw_image(screensize, RIGHT, startMatrix, - focusPoint, show_hud, camera, hud, draw_wield_tool, client, - guienv, skycolor); - - /* create hud overlay */ - video::ITexture *hudtexture = draw_hud(screensize, show_hud, hud, client, false, - skycolor, guienv, camera); - getVideoDriver()->makeColorKeyTexture( - hudtexture, irr::video::SColor(255, 0, 0, 0)); - // makeColorKeyTexture mirrors texture so we do it twice to get it right again - getVideoDriver()->makeColorKeyTexture( - hudtexture, irr::video::SColor(255, 0, 0, 0)); - - draw2DImageFilterScaled(getVideoDriver(), left_image, - irr::core::rect(0, 0, screensize.X / 2, screensize.Y), - irr::core::rect(0, 0, screensize.X, screensize.Y), 0, 0, - false); - - draw2DImageFilterScaled(getVideoDriver(), hudtexture, - irr::core::rect(0, 0, screensize.X / 2, screensize.Y), - irr::core::rect(0, 0, screensize.X, screensize.Y), 0, 0, - true); - - draw2DImageFilterScaled(getVideoDriver(), right_image, - irr::core::rect( - screensize.X / 2, 0, screensize.X, screensize.Y), - irr::core::rect(0, 0, screensize.X, screensize.Y), 0, 0, - false); - - draw2DImageFilterScaled(getVideoDriver(), hudtexture, - irr::core::rect( - screensize.X / 2, 0, screensize.X, screensize.Y), - irr::core::rect(0, 0, screensize.X, screensize.Y), 0, 0, - true); - - left_image = nullptr; - right_image = nullptr; - - /* cleanup */ - camera->getCameraNode()->setPosition(oldPosition); - camera->getCameraNode()->setTarget(oldTarget); -} - -void RenderingEngine::draw_top_bottom_3d_mode(Camera *camera, bool show_hud, Hud *hud, - const v2u32 &screensize, bool draw_wield_tool, Client *client, - gui::IGUIEnvironment *guienv, const video::SColor &skycolor) -{ - /* save current info */ - irr::core::vector3df oldPosition = camera->getCameraNode()->getPosition(); - irr::core::vector3df oldTarget = camera->getCameraNode()->getTarget(); - irr::core::matrix4 startMatrix = - camera->getCameraNode()->getAbsoluteTransformation(); - irr::core::vector3df focusPoint = - (camera->getCameraNode()->getTarget() - - camera->getCameraNode()->getAbsolutePosition()) - .setLength(1) + - camera->getCameraNode()->getAbsolutePosition(); - - /* create left view */ - video::ITexture *left_image = draw_image(screensize, LEFT, startMatrix, - focusPoint, show_hud, camera, hud, draw_wield_tool, client, - guienv, skycolor); - - /* create right view */ - video::ITexture *right_image = draw_image(screensize, RIGHT, startMatrix, - focusPoint, show_hud, camera, hud, draw_wield_tool, client, - guienv, skycolor); - - /* create hud overlay */ - video::ITexture *hudtexture = draw_hud(screensize, show_hud, hud, client, false, - skycolor, guienv, camera); - getVideoDriver()->makeColorKeyTexture( - hudtexture, irr::video::SColor(255, 0, 0, 0)); - // makeColorKeyTexture mirrors texture so we do it twice to get it right again - getVideoDriver()->makeColorKeyTexture( - hudtexture, irr::video::SColor(255, 0, 0, 0)); - - draw2DImageFilterScaled(getVideoDriver(), left_image, - irr::core::rect(0, 0, screensize.X, screensize.Y / 2), - irr::core::rect(0, 0, screensize.X, screensize.Y), 0, 0, - false); - - draw2DImageFilterScaled(getVideoDriver(), hudtexture, - irr::core::rect(0, 0, screensize.X, screensize.Y / 2), - irr::core::rect(0, 0, screensize.X, screensize.Y), 0, 0, - true); - - draw2DImageFilterScaled(getVideoDriver(), right_image, - irr::core::rect( - 0, screensize.Y / 2, screensize.X, screensize.Y), - irr::core::rect(0, 0, screensize.X, screensize.Y), 0, 0, - false); - - draw2DImageFilterScaled(getVideoDriver(), hudtexture, - irr::core::rect( - 0, screensize.Y / 2, screensize.X, screensize.Y), - irr::core::rect(0, 0, screensize.X, screensize.Y), 0, 0, - true); - - left_image = NULL; - right_image = NULL; - - /* cleanup */ - camera->getCameraNode()->setPosition(oldPosition); - camera->getCameraNode()->setTarget(oldTarget); -} - -void RenderingEngine::draw_pageflip_3d_mode(Camera *camera, bool show_hud, Hud *hud, - const v2u32 &screensize, bool draw_wield_tool, Client *client, - gui::IGUIEnvironment *guienv, const video::SColor &skycolor) -{ -#if IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR > 8 - errorstream << "Pageflip 3D mode is not supported" - << " with your Irrlicht version!" << std::endl; -#else - /* preserve old setup*/ - irr::core::vector3df oldPosition = camera->getCameraNode()->getPosition(); - irr::core::vector3df oldTarget = camera->getCameraNode()->getTarget(); - - irr::core::matrix4 startMatrix = - camera->getCameraNode()->getAbsoluteTransformation(); - irr::core::vector3df focusPoint = - (camera->getCameraNode()->getTarget() - - camera->getCameraNode()->getAbsolutePosition()) - .setLength(1) + - camera->getCameraNode()->getAbsolutePosition(); - - // Left eye... - getVideoDriver()->setRenderTarget(irr::video::ERT_STEREO_LEFT_BUFFER); - - irr::core::vector3df leftEye; - irr::core::matrix4 leftMove; - leftMove.setTranslation(irr::core::vector3df( - -g_settings->getFloat("3d_paralax_strength"), 0.0f, 0.0f)); - leftEye = (startMatrix * leftMove).getTranslation(); - - // clear the depth buffer, and color - getVideoDriver()->beginScene(true, true, irr::video::SColor(200, 200, 200, 255)); - camera->getCameraNode()->setPosition(leftEye); - camera->getCameraNode()->setTarget(focusPoint); - get_scene_manager()->drawAll(); - getVideoDriver()->setTransform(video::ETS_WORLD, core::IdentityMatrix); - - if (show_hud) { - hud->drawSelectionMesh(); - if (draw_wield_tool) - camera->drawWieldedTool(&leftMove); - hud->drawHotbar(client->getPlayerItem()); - hud->drawLuaElements(camera->getOffset()); - camera->drawNametags(); - } - - guienv->drawAll(); - - // Right eye... - getVideoDriver()->setRenderTarget(irr::video::ERT_STEREO_RIGHT_BUFFER); - - irr::core::vector3df rightEye; - irr::core::matrix4 rightMove; - rightMove.setTranslation(irr::core::vector3df( - g_settings->getFloat("3d_paralax_strength"), 0.0f, 0.0f)); - rightEye = (startMatrix * rightMove).getTranslation(); - - // clear the depth buffer, and color - getVideoDriver()->beginScene(true, true, irr::video::SColor(200, 200, 200, 255)); - camera->getCameraNode()->setPosition(rightEye); - camera->getCameraNode()->setTarget(focusPoint); - get_scene_manager()->drawAll(); - getVideoDriver()->setTransform(video::ETS_WORLD, core::IdentityMatrix); - - if (show_hud) { - hud->drawSelectionMesh(); - if (draw_wield_tool) - camera->drawWieldedTool(&rightMove); - hud->drawHotbar(client->getPlayerItem()); - hud->drawLuaElements(camera->getOffset()); - camera->drawNametags(); - } - - guienv->drawAll(); - - camera->getCameraNode()->setPosition(oldPosition); - camera->getCameraNode()->setTarget(oldTarget); -#endif -} - -// returns (size / coef), rounded upwards -inline int scaledown(int coef, int size) -{ - return (size + coef - 1) / coef; -} - -void RenderingEngine::draw_plain(Camera *camera, bool show_hud, Hud *hud, - const v2u32 &screensize, bool draw_wield_tool, Client *client, - gui::IGUIEnvironment *guienv, const video::SColor &skycolor) -{ - // Undersampling-specific stuff - static video::ITexture *image = NULL; - static v2u32 last_pixelated_size = v2u32(0, 0); - static thread_local int undersampling = g_settings->getU16("undersampling"); - v2u32 pixelated_size; - v2u32 dest_size; - if (undersampling > 0) { - pixelated_size = v2u32(scaledown(undersampling, screensize.X), - scaledown(undersampling, screensize.Y)); - dest_size = v2u32(undersampling * pixelated_size.X, - undersampling * pixelated_size.Y); - if (pixelated_size != last_pixelated_size) { - init_texture(pixelated_size, &image, "mt_drawimage_img1"); - last_pixelated_size = pixelated_size; - } - getVideoDriver()->setRenderTarget(image, true, true, skycolor); - } - - // Render - get_scene_manager()->drawAll(); - getVideoDriver()->setTransform(video::ETS_WORLD, core::IdentityMatrix); - if (show_hud) { - hud->drawSelectionMesh(); - if (draw_wield_tool) { - camera->drawWieldedTool(); - } - } - - // Upscale lowres render - if (undersampling > 0) { - getVideoDriver()->setRenderTarget(0, true, true); - getVideoDriver()->draw2DImage(image, - irr::core::rect(0, 0, dest_size.X, dest_size.Y), - irr::core::rect(0, 0, pixelated_size.X, - pixelated_size.Y)); - } + core->draw(skycolor, show_hud, show_minimap, draw_wield_tool, draw_crosshair); } const char *RenderingEngine::getVideoDriverName(irr::video::E_DRIVER_TYPE type) diff --git a/src/client/renderingengine.h b/src/client/renderingengine.h index 40fbaa87d..ac6b6926c 100644 --- a/src/client/renderingengine.h +++ b/src/client/renderingengine.h @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once #include +#include #include #include "irrlichttypes_extrabloated.h" #include "debug.h" @@ -32,6 +33,8 @@ class LocalPlayer; class Hud; class Minimap; +class RenderingCore; + class RenderingEngine { public: @@ -41,7 +44,7 @@ public: v2u32 getWindowSize() const; void setResizable(bool resize); - video::IVideoDriver *getVideoDriver(); + video::IVideoDriver *getVideoDriver() { return driver; } static const char *getVideoDriverName(irr::video::E_DRIVER_TYPE type); static const char *getVideoDriverFriendlyName(irr::video::E_DRIVER_TYPE type); @@ -107,15 +110,20 @@ public: text, guienv, tsrc, dtime, percent, clouds); } - inline static void draw_scene(Camera *camera, Client *client, LocalPlayer *player, - Hud *hud, Minimap *mapper, gui::IGUIEnvironment *guienv, - const v2u32 &screensize, const video::SColor &skycolor, - bool show_hud, bool show_minimap) + 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(camera, client, player, hud, mapper, guienv, - screensize, skycolor, show_hud, show_minimap); + s_singleton->_draw_scene(skycolor, show_hud, show_minimap, + draw_wield_tool, draw_crosshair); } + inline static void initialize(Client *client, Hud *hud) + { + s_singleton->_initialize(client, hud); + } + + inline static void finalize() { s_singleton->_finalize(); } + static bool run() { sanity_check(s_singleton && s_singleton->m_device); @@ -126,60 +134,19 @@ public: static std::vector getSupportedVideoDrivers(); private: - enum parallax_sign - { - LEFT = -1, - RIGHT = 1, - EYECOUNT = 2 - }; - void _draw_load_screen(const std::wstring &text, gui::IGUIEnvironment *guienv, ITextureSource *tsrc, float dtime = 0, int percent = 0, bool clouds = true); - void _draw_scene(Camera *camera, Client *client, LocalPlayer *player, Hud *hud, - Minimap *mapper, gui::IGUIEnvironment *guienv, - const v2u32 &screensize, const video::SColor &skycolor, - bool show_hud, bool show_minimap); + void _draw_scene(video::SColor skycolor, bool show_hud, bool show_minimap, + bool draw_wield_tool, bool draw_crosshair); - void draw_anaglyph_3d_mode(Camera *camera, bool show_hud, Hud *hud, - bool draw_wield_tool, Client *client, - gui::IGUIEnvironment *guienv); + void _initialize(Client *client, Hud *hud); - void draw_interlaced_3d_mode(Camera *camera, bool show_hud, Hud *hud, - const v2u32 &screensize, bool draw_wield_tool, Client *client, - gui::IGUIEnvironment *guienv, const video::SColor &skycolor); - - void draw_sidebyside_3d_mode(Camera *camera, bool show_hud, Hud *hud, - const v2u32 &screensize, bool draw_wield_tool, Client *client, - gui::IGUIEnvironment *guienv, const video::SColor &skycolor); - - void draw_top_bottom_3d_mode(Camera *camera, bool show_hud, Hud *hud, - const v2u32 &screensize, bool draw_wield_tool, Client *client, - gui::IGUIEnvironment *guienv, const video::SColor &skycolor); - - void draw_pageflip_3d_mode(Camera *camera, bool show_hud, Hud *hud, - const v2u32 &screensize, bool draw_wield_tool, Client *client, - gui::IGUIEnvironment *guienv, const video::SColor &skycolor); - - void draw_plain(Camera *camera, bool show_hud, Hud *hud, const v2u32 &screensize, - bool draw_wield_tool, Client *client, - gui::IGUIEnvironment *guienv, const video::SColor &skycolor); - - void init_texture(const v2u32 &screensize, video::ITexture **texture, - const char *name); - - video::ITexture *draw_image(const v2u32 &screensize, parallax_sign psign, - const irr::core::matrix4 &startMatrix, - const irr::core::vector3df &focusPoint, bool show_hud, - Camera *camera, Hud *hud, bool draw_wield_tool, Client *client, - gui::IGUIEnvironment *guienv, const video::SColor &skycolor); - - video::ITexture *draw_hud(const v2u32 &screensize, bool show_hud, Hud *hud, - Client *client, bool draw_crosshair, - const video::SColor &skycolor, gui::IGUIEnvironment *guienv, - Camera *camera); + void _finalize(); + std::unique_ptr core; irr::IrrlichtDevice *m_device = nullptr; + irr::video::IVideoDriver *driver; static RenderingEngine *s_singleton; }; diff --git a/src/game.cpp b/src/game.cpp index fd3914356..200de2c59 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1656,6 +1656,8 @@ bool Game::startup(bool *kill, if (!createClient(playername, password, address, port)) return false; + RenderingEngine::initialize(client, hud); + return true; } @@ -1745,6 +1747,7 @@ void Game::run() void Game::shutdown() { + RenderingEngine::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); @@ -4339,9 +4342,20 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, TimeTaker tt_draw("mainloop: draw"); driver->beginScene(true, true, skycolor); - RenderingEngine::draw_scene(camera, client, player, hud, mapper, - guienv, screensize, skycolor, flags.show_hud, - flags.show_minimap); + bool draw_wield_tool = (flags.show_hud && + (player->hud_flags & HUD_FLAG_WIELDITEM_VISIBLE) && + (camera->getCameraMode() == CAMERA_MODE_FIRST)); + bool draw_crosshair = ( + (player->hud_flags & HUD_FLAG_CROSSHAIR_VISIBLE) && + (camera->getCameraMode() != CAMERA_MODE_THIRD_FRONT)); +#ifdef HAVE_TOUCHSCREENGUI + try { + draw_crosshair = !g_settings->getBool("touchtarget"); + } catch (SettingNotFoundException) { + } +#endif + RenderingEngine::draw_scene(skycolor, flags.show_hud, flags.show_minimap, + draw_wield_tool, draw_crosshair); /* Profiler graph @@ -4402,7 +4416,7 @@ inline static const char *yawToDirectionString(int yaw) void Game::updateGui(const RunStats &stats, f32 dtime, const CameraOrientation &cam) { - v2u32 screensize = driver->getScreenSize(); + v2u32 screensize = RenderingEngine::get_instance()->getWindowSize(); LocalPlayer *player = client->getEnv().getLocalPlayer(); v3f player_position = player->getPosition(); diff --git a/src/settings_translation_file.cpp b/src/settings_translation_file.cpp index e72b0a9f0..ec0c0db6b 100644 --- a/src/settings_translation_file.cpp +++ b/src/settings_translation_file.cpp @@ -286,7 +286,7 @@ fake_function() { gettext("Fall bobbing factor"); gettext("Multiplier for fall bobbing.\nFor example: 0 for no view bobbing; 1.0 for normal; 2.0 for double."); gettext("3D mode"); - gettext("3D support.\nCurrently supported:\n- none: no 3d output.\n- anaglyph: cyan/magenta color 3d.\n- interlaced: odd/even line based polarisation screen support.\n- topbottom: split screen top/bottom.\n- sidebyside: split screen side by side.\n- pageflip: quadbuffer based 3d."); + gettext("3D support.\nCurrently supported:\n- none: no 3d output.\n- anaglyph: cyan/magenta color 3d.\n- interlaced: odd/even line based polarisation screen support.\n- topbottom: split screen top/bottom.\n- sidebyside: split screen side by side.\n- pageflip: quadbuffer based 3d.\nNote that the interlaced mode requires shaders to be enabled."); gettext("Console height"); gettext("In-game chat console height, between 0.1 (10%) and 1.0 (100%)."); gettext("Console color");