mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 01:05:48 +01:00 
			
		
		
		
	Add debug mode that shows mesh buffer bounding boxes
This commit is contained in:
		@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user