diff --git a/irr/include/EDebugSceneTypes.h b/irr/include/EDebugSceneTypes.h index 29ca8ad0e..2994eca6c 100644 --- a/irr/include/EDebugSceneTypes.h +++ b/irr/include/EDebugSceneTypes.h @@ -34,7 +34,7 @@ enum E_DEBUG_SCENE_TYPE EDS_BBOX_ALL = EDS_BBOX | EDS_BBOX_BUFFERS, //! Show all debug infos - EDS_FULL = 0xffffffff + EDS_FULL = 0xffff }; } // end namespace scene diff --git a/irr/include/ISceneManager.h b/irr/include/ISceneManager.h index 25e1e5fe4..31604214f 100644 --- a/irr/include/ISceneManager.h +++ b/irr/include/ISceneManager.h @@ -387,6 +387,14 @@ public: pass currently is active they can render the correct part of their geometry. */ virtual E_SCENE_NODE_RENDER_PASS getSceneNodeRenderPass() const = 0; + /** + * Sets debug data flags that will be set on every rendered scene node. + * Refer to `E_DEBUG_SCENE_TYPE`. + * @param setBits bit mask of types to enable + * @param unsetBits bit mask of types to disable + */ + virtual void setGlobalDebugData(u16 setBits, u16 unsetBits) = 0; + //! Creates a new scene manager. /** This can be used to easily draw and/or store two independent scenes at the same time. The mesh cache will be diff --git a/irr/include/ISceneNode.h b/irr/include/ISceneNode.h index 0438d855f..897cfb350 100644 --- a/irr/include/ISceneNode.h +++ b/irr/include/ISceneNode.h @@ -403,14 +403,14 @@ public: their geometry because it is their only reason for existence, for example the OctreeSceneNode. \param state The culling state to be used. Check E_CULLING_TYPE for possible values.*/ - void setAutomaticCulling(u32 state) + void setAutomaticCulling(u16 state) { AutomaticCullingState = state; } //! Gets the automatic culling state. /** \return The automatic culling state. */ - u32 getAutomaticCulling() const + u16 getAutomaticCulling() const { return AutomaticCullingState; } @@ -419,7 +419,7 @@ public: /** A bitwise OR of the types from @ref irr::scene::E_DEBUG_SCENE_TYPE. Please note that not all scene nodes support all debug data types. \param state The debug data visibility state to be used. */ - virtual void setDebugDataVisible(u32 state) + virtual void setDebugDataVisible(u16 state) { DebugDataVisible = state; } @@ -427,7 +427,7 @@ public: //! Returns if debug data like bounding boxes are drawn. /** \return A bitwise OR of the debug data values from @ref irr::scene::E_DEBUG_SCENE_TYPE that are currently visible. */ - u32 isDebugDataVisible() const + u16 isDebugDataVisible() const { return DebugDataVisible; } @@ -581,10 +581,10 @@ protected: s32 ID; //! Automatic culling state - u32 AutomaticCullingState; + u16 AutomaticCullingState; //! Flag if debug data should be drawn, such as Bounding Boxes. - u32 DebugDataVisible; + u16 DebugDataVisible; //! Is the node visible? bool IsVisible; diff --git a/irr/src/CAnimatedMeshSceneNode.cpp b/irr/src/CAnimatedMeshSceneNode.cpp index 3871d52a3..dffc867de 100644 --- a/irr/src/CAnimatedMeshSceneNode.cpp +++ b/irr/src/CAnimatedMeshSceneNode.cpp @@ -276,9 +276,6 @@ void CAnimatedMeshSceneNode::render() debug_mat.ZBuffer = video::ECFN_DISABLED; driver->setMaterial(debug_mat); - if (DebugDataVisible & scene::EDS_BBOX) - driver->draw3DBox(Box, video::SColor(255, 255, 255, 255)); - // show bounding box if (DebugDataVisible & scene::EDS_BBOX_BUFFERS) { for (u32 g = 0; g < m->getMeshBufferCount(); ++g) { @@ -290,6 +287,9 @@ void CAnimatedMeshSceneNode::render() } } + if (DebugDataVisible & scene::EDS_BBOX) + driver->draw3DBox(Box, video::SColor(255, 255, 255, 255)); + // show skeleton if (DebugDataVisible & scene::EDS_SKELETON) { if (Mesh->getMeshType() == EAMT_SKINNED) { diff --git a/irr/src/CMeshSceneNode.cpp b/irr/src/CMeshSceneNode.cpp index 2d9e400e9..cffdbf855 100644 --- a/irr/src/CMeshSceneNode.cpp +++ b/irr/src/CMeshSceneNode.cpp @@ -110,11 +110,9 @@ void CMeshSceneNode::render() if (DebugDataVisible && PassCount == 1) { video::SMaterial m; m.AntiAliasing = 0; + m.ZBuffer = video::ECFN_DISABLED; driver->setMaterial(m); - if (DebugDataVisible & scene::EDS_BBOX) { - driver->draw3DBox(Box, video::SColor(255, 255, 255, 255)); - } if (DebugDataVisible & scene::EDS_BBOX_BUFFERS) { for (u32 g = 0; g < Mesh->getMeshBufferCount(); ++g) { driver->draw3DBox( @@ -123,6 +121,10 @@ void CMeshSceneNode::render() } } + if (DebugDataVisible & scene::EDS_BBOX) { + driver->draw3DBox(Box, video::SColor(255, 255, 255, 255)); + } + if (DebugDataVisible & scene::EDS_NORMALS) { // draw normals const f32 debugNormalLength = 1.f; diff --git a/irr/src/CSceneManager.cpp b/irr/src/CSceneManager.cpp index d8a147b34..23e5335ce 100644 --- a/irr/src/CSceneManager.cpp +++ b/irr/src/CSceneManager.cpp @@ -490,13 +490,19 @@ void CSceneManager::drawAll() // let all nodes register themselves OnRegisterSceneNode(); + const auto &render_node = [this] (ISceneNode *node) { + u32 flags = node->isDebugDataVisible(); + node->setDebugDataVisible((flags & DebugDataMask) | DebugDataBits); + node->render(); + }; + // render camera scenes { CurrentRenderPass = ESNRP_CAMERA; Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); for (auto *node : CameraList) - node->render(); + render_node(node); CameraList.clear(); } @@ -507,7 +513,7 @@ void CSceneManager::drawAll() Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); for (auto *node : SkyBoxList) - node->render(); + render_node(node); SkyBoxList.clear(); } @@ -520,7 +526,7 @@ void CSceneManager::drawAll() std::sort(SolidNodeList.begin(), SolidNodeList.end()); for (auto &it : SolidNodeList) - it.Node->render(); + render_node(it.Node); SolidNodeList.clear(); } @@ -533,7 +539,7 @@ void CSceneManager::drawAll() std::sort(TransparentNodeList.begin(), TransparentNodeList.end()); for (auto &it : TransparentNodeList) - it.Node->render(); + render_node(it.Node); TransparentNodeList.clear(); } @@ -546,7 +552,7 @@ void CSceneManager::drawAll() std::sort(TransparentEffectNodeList.begin(), TransparentEffectNodeList.end()); for (auto &it : TransparentEffectNodeList) - it.Node->render(); + render_node(it.Node); TransparentEffectNodeList.clear(); } @@ -557,7 +563,7 @@ void CSceneManager::drawAll() Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); for (auto *node : GuiNodeList) - node->render(); + render_node(node); GuiNodeList.clear(); } diff --git a/irr/src/CSceneManager.h b/irr/src/CSceneManager.h index 2a4fb7f7b..8f03a1fec 100644 --- a/irr/src/CSceneManager.h +++ b/irr/src/CSceneManager.h @@ -179,6 +179,11 @@ public: //! Set current render time. void setCurrentRenderPass(E_SCENE_NODE_RENDER_PASS nextPass) override { CurrentRenderPass = nextPass; } + void setGlobalDebugData(u16 setBits, u16 unsetBits) override { + DebugDataMask = ~unsetBits; + DebugDataBits = setBits; + } + //! returns if node is culled bool isCulled(const ISceneNode *node) const override; @@ -268,6 +273,9 @@ private: //! Mesh cache IMeshCache *MeshCache; + //! Global debug render state + u16 DebugDataMask = 0, DebugDataBits = 0; + E_SCENE_NODE_RENDER_PASS CurrentRenderPass; }; diff --git a/src/client/game.cpp b/src/client/game.cpp index c5f67a745..f04e265e9 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -427,6 +427,8 @@ public: const static float object_hit_delay = 0.2; +const static u16 bbox_debug_flag = scene::EDS_BBOX_ALL; + /* The reason the following structs are not anonymous structs within the * class is that they are not used by the majority of member functions and * many functions that do require objects of thse types do not modify them @@ -635,6 +637,8 @@ protected: private: struct Flags { bool disable_camera_update = false; + /// 0 = no debug text active, see toggleDebug() for the rest + int debug_state = 0; }; void pauseAnimation(); @@ -1663,6 +1667,7 @@ void Game::updateDebugState() hud->disableBlockBounds(); if (!has_debug) { draw_control->show_wireframe = false; + smgr->setGlobalDebugData(0, bbox_debug_flag); m_flags.disable_camera_update = false; m_game_formspec.disableDebugView(); } @@ -2222,46 +2227,41 @@ void Game::toggleDebug() LocalPlayer *player = client->getEnv().getLocalPlayer(); bool has_debug = client->checkPrivilege("debug"); bool has_basic_debug = has_debug || (player->hud_flags & HUD_FLAG_BASIC_DEBUG); + // Initial: No debug info // 1x toggle: Debug text // 2x toggle: Debug text with profiler graph // 3x toggle: Debug text and wireframe (needs "debug" priv) - // Next toggle: Back to initial + // 4x toggle: Debug text and bbox (needs "debug" priv) // // The debug text can be in 2 modes: minimal and basic. // * Minimal: Only technical client info that not gameplay-relevant // * Basic: Info that might give gameplay advantage, e.g. pos, angle // Basic mode is used when player has the debug HUD flag set, // otherwise the Minimal mode is used. - if (!m_game_ui->m_flags.show_minimal_debug) { - m_game_ui->m_flags.show_minimal_debug = true; - if (has_basic_debug) - m_game_ui->m_flags.show_basic_debug = true; - m_game_ui->m_flags.show_profiler_graph = false; - draw_control->show_wireframe = false; + + auto &state = m_flags.debug_state; + state = (state + 1) % 5; + if (state >= 3 && !has_debug) + state = 0; + + m_game_ui->m_flags.show_minimal_debug = state > 0; + m_game_ui->m_flags.show_basic_debug = state > 0 && has_basic_debug; + m_game_ui->m_flags.show_profiler_graph = state == 2; + draw_control->show_wireframe = state == 3; + smgr->setGlobalDebugData(state == 4 ? bbox_debug_flag : 0, + state == 4 ? 0 : bbox_debug_flag); + + if (state == 1) m_game_ui->showTranslatedStatusText("Debug info shown"); - } else if (!m_game_ui->m_flags.show_profiler_graph && !draw_control->show_wireframe) { - if (has_basic_debug) - m_game_ui->m_flags.show_basic_debug = true; - m_game_ui->m_flags.show_profiler_graph = true; + else if (state == 2) m_game_ui->showTranslatedStatusText("Profiler graph shown"); - } else if (!draw_control->show_wireframe && client->checkPrivilege("debug")) { - if (has_basic_debug) - m_game_ui->m_flags.show_basic_debug = true; - m_game_ui->m_flags.show_profiler_graph = false; - draw_control->show_wireframe = true; + else if (state == 3) m_game_ui->showTranslatedStatusText("Wireframe shown"); - } else { - m_game_ui->m_flags.show_minimal_debug = false; - m_game_ui->m_flags.show_basic_debug = false; - m_game_ui->m_flags.show_profiler_graph = false; - draw_control->show_wireframe = false; - if (has_debug) { - m_game_ui->showTranslatedStatusText("Debug info, profiler graph, and wireframe hidden"); - } else { - m_game_ui->showTranslatedStatusText("Debug info and profiler graph hidden"); - } - } + else if (state == 4) + m_game_ui->showTranslatedStatusText("Bounding boxes shown"); + else + m_game_ui->showTranslatedStatusText("All debug info hidden"); }