From 63266928a5e2b6f4b712695eb56cb1de3899ba21 Mon Sep 17 00:00:00 2001
From: Kahrl <kahrl@gmx.net>
Date: Thu, 15 Sep 2011 00:32:11 +0200
Subject: [PATCH] Made wielded tool move slightly (and smoothly) during view
 bobbing. Making the tool be a child node of an empty scene node instead of
 the camera scene node seemingly fixed the uncontrollable tool jitter, too.

---
 src/camera.cpp | 33 ++++++++++++++++++++++++++++-----
 src/camera.h   | 15 +++++++++++++--
 src/game.cpp   | 12 ++----------
 3 files changed, 43 insertions(+), 17 deletions(-)

diff --git a/src/camera.cpp b/src/camera.cpp
index a84ee953c..2cc27fd6e 100644
--- a/src/camera.cpp
+++ b/src/camera.cpp
@@ -30,6 +30,7 @@ const s32 BOBFRAMES = 0x1000000; // must be a power of two
 Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control):
 	m_smgr(smgr),
 	m_playernode(NULL),
+	m_headnode(NULL),
 	m_cameranode(NULL),
 	m_draw_control(draw_control),
 	m_viewing_range_min(5.0),
@@ -59,6 +60,7 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control):
 	// note: making the camera node a child of the player node
 	// would lead to unexpected behaviour, so we don't do that.
 	m_playernode = smgr->addEmptySceneNode(smgr->getRootSceneNode());
+	m_headnode = smgr->addEmptySceneNode(m_playernode);
 	m_cameranode = smgr->addCameraSceneNode(smgr->getRootSceneNode());
 	m_cameranode->bindTargetAndRotation(true);
 
@@ -69,6 +71,26 @@ Camera::~Camera()
 {
 }
 
+bool Camera::successfullyCreated(std::wstring& error_message)
+{
+	if (m_playernode == NULL)
+	{
+		error_message = L"Failed to create the player scene node";
+		return false;
+	}
+	if (m_headnode == NULL)
+	{
+		error_message = L"Failed to create the head scene node";
+		return false;
+	}
+	if (m_cameranode == NULL)
+	{
+		error_message = L"Failed to create the camera scene node";
+		return false;
+	}
+	return true;
+}
+
 void Camera::step(f32 dtime)
 {
 	if (m_view_bobbing_state != 0)
@@ -90,16 +112,18 @@ void Camera::step(f32 dtime)
 
 void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize)
 {
-	if (m_playernode == NULL || m_cameranode == NULL)
-		return;
-
 	// Set player node transformation
 	m_playernode->setPosition(player->getPosition());
 	m_playernode->setRotation(v3f(0, -1 * player->getYaw(), 0));
 	m_playernode->updateAbsolutePosition();
 
+	// Set head node transformation
+	v3f eye_offset = player->getEyePosition() - player->getPosition();
+	m_headnode->setPosition(eye_offset);
+	m_headnode->setRotation(v3f(player->getPitch(), 0, 0));
+
 	// Compute relative camera position and target
-	v3f relative_cam_pos = player->getEyePosition() - player->getPosition();
+	v3f relative_cam_pos = eye_offset;
 	v3f relative_cam_target = v3f(0,0,1);
 	relative_cam_target.rotateYZBy(player->getPitch());
 	relative_cam_target += relative_cam_pos;
@@ -128,7 +152,6 @@ void Camera::update(LocalPlayer* player, f32 frametime, v2u32 screensize)
 	m_cameranode->setPosition(m_camera_position);
 	// *100.0 helps in large map coordinates
 	m_cameranode->setTarget(m_camera_position + 100.0 * m_camera_direction);
-
 	// FOV and and aspect ratio
 	m_aspect = (f32)screensize.X / (f32) screensize.Y;
 	m_fov_x = 2 * atan(0.5 * m_aspect * tan(m_fov_y));
diff --git a/src/camera.h b/src/camera.h
index ba5d72bf4..a6dd7476f 100644
--- a/src/camera.h
+++ b/src/camera.h
@@ -39,14 +39,21 @@ class Camera
 	// Get player scene node.
 	// This node is positioned at the player's torso (without any view bobbing),
 	// as given by Player::m_position. Yaw is applied but not pitch.
-	// Things like wielded tools should be positioned relative to this node.
 	inline scene::ISceneNode* getPlayerNode() const
 	{
 		return m_playernode;
 	}
 
+	// Get head scene node.
+	// It has the eye transformation and pitch applied,
+	// but no view bobbing.
+	inline scene::ISceneNode* getHeadNode() const
+	{
+		return m_headnode;
+	}
+
 	// Get camera scene node.
-	// It has the eye transformation and view bobbing applied.
+	// It has the eye transformation, pitch and view bobbing applied.
 	inline scene::ICameraSceneNode* getCameraNode() const
 	{
 		return m_cameranode;
@@ -84,6 +91,9 @@ class Camera
 		return MYMAX(m_fov_x, m_fov_y);
 	}
 
+	// Checks if the constructor was able to create the scene nodes
+	bool successfullyCreated(std::wstring& error_message);
+
 	// Step the camera: updates the viewing range and view bobbing.
 	void step(f32 dtime);
 
@@ -101,6 +111,7 @@ class Camera
 	// Scene manager and nodes
 	scene::ISceneManager* m_smgr;
 	scene::ISceneNode* m_playernode;
+	scene::ISceneNode* m_headnode;
 	scene::ICameraSceneNode* m_cameranode;
 
 	// draw control
diff --git a/src/game.cpp b/src/game.cpp
index cb7594c30..a712323b5 100644
--- a/src/game.cpp
+++ b/src/game.cpp
@@ -813,16 +813,8 @@ void the_game(
 		Create the camera node
 	*/
 	Camera camera(smgr, draw_control);
-	if (camera.getPlayerNode() == NULL)
-	{
-		error_message = L"Failed to create the player node";
+	if (!camera.successfullyCreated(error_message))
 		return;
-	}
-	if (camera.getCameraNode() == NULL)
-	{
-		error_message = L"Failed to create the camera node";
-		return;
-	}
 
 	f32 camera_yaw = 0; // "right/left"
 	f32 camera_pitch = 0; // "up/down"
@@ -856,7 +848,7 @@ void the_game(
 		mesh->addMeshBuffer(buf);
 		buf->drop();
 	
-		tool_wield = smgr->addMeshSceneNode(mesh, camera.getCameraNode());
+		tool_wield = smgr->addMeshSceneNode(mesh, camera.getHeadNode());
 		mesh->drop();
 	}
 	tool_wield->setVisible(false);
-- 
GitLab