Beispiel #1
0
void CModelDecal::SetTransform(const CMatrix3D& transform)
{
	// Since decals are assumed to be horizontal and projected downwards
	// onto the terrain, use just the Y-axis rotation and the translation
	CMatrix3D newTransform;
	newTransform.SetYRotation(transform.GetYRotation() + m_Decal.m_Angle);
	newTransform.Translate(transform.GetTranslation());

	CRenderableObject::SetTransform(newTransform);
	InvalidatePosition();
}
Beispiel #2
0
void CModelParticleEmitter::SetTransform(const CMatrix3D& transform)
{
	if (m_Transform == transform)
		return;

	m_Emitter->SetPosition(transform.GetTranslation());
	m_Emitter->SetRotation(transform.GetRotation());

	// call base class to set transform on this object
	CRenderableObject::SetTransform(transform);
}
Beispiel #3
0
void SimRender::ConstructAxesMarker(const CMatrix3D& coordSystem, SOverlayLine& outX, SOverlayLine& outY, SOverlayLine& outZ)
{
	outX.m_Coords.clear();
	outY.m_Coords.clear();
	outZ.m_Coords.clear();

	outX.m_Color = CColor(1, 0, 0, .5f); // X axis; red
	outY.m_Color = CColor(0, 1, 0, .5f); // Y axis; green
	outZ.m_Color = CColor(0, 0, 1, .5f); // Z axis; blue

	outX.m_Thickness = 2;
	outY.m_Thickness = 2;
	outZ.m_Thickness = 2;

	CVector3D origin = coordSystem.GetTranslation();
	outX.PushCoords(origin);
	outY.PushCoords(origin);
	outZ.PushCoords(origin);

	outX.PushCoords(origin + CVector3D(coordSystem(0,0), coordSystem(1,0), coordSystem(2,0)));
	outY.PushCoords(origin + CVector3D(coordSystem(0,1), coordSystem(1,1), coordSystem(2,1)));
	outZ.PushCoords(origin + CVector3D(coordSystem(0,2), coordSystem(1,2), coordSystem(2,2)));
}
Beispiel #4
0
void CModelParticleEmitter::SetTransform(const CMatrix3D& transform)
{
	m_Emitter->SetPosition(transform.GetTranslation());
}
Beispiel #5
0
void CGameView::Update(const float deltaRealTime)
{
	// If camera movement is being handled by the touch-input system,
	// then we should stop to avoid conflicting with it
	if (g_TouchInput.IsEnabled())
		return;

	if (!g_app_has_focus)
		return;

	// TODO: this is probably not an ideal place for this, it should probably go
	// in a CCmpWaterManager or some such thing (once such a thing exists)
	if (!m->Game->m_Paused)
		g_Renderer.GetWaterManager()->m_WaterTexTimer += deltaRealTime;

	if (m->TrackManager.IsActive() && m->TrackManager.IsPlaying())
	{
		if (! m->TrackManager.Update(deltaRealTime))
		{
//			ResetCamera();
		}
		return;
	}

	// Calculate mouse movement
	static int mouse_last_x = 0;
	static int mouse_last_y = 0;
	int mouse_dx = g_mouse_x - mouse_last_x;
	int mouse_dy = g_mouse_y - mouse_last_y;
	mouse_last_x = g_mouse_x;
	mouse_last_y = g_mouse_y;

	if (HotkeyIsPressed("camera.rotate.cw"))
		m->RotateY.AddSmoothly(m->ViewRotateYSpeed * deltaRealTime);
	if (HotkeyIsPressed("camera.rotate.ccw"))
		m->RotateY.AddSmoothly(-m->ViewRotateYSpeed * deltaRealTime);
	if (HotkeyIsPressed("camera.rotate.up"))
		m->RotateX.AddSmoothly(-m->ViewRotateXSpeed * deltaRealTime);
	if (HotkeyIsPressed("camera.rotate.down"))
		m->RotateX.AddSmoothly(m->ViewRotateXSpeed * deltaRealTime);

	float moveRightward = 0.f;
	float moveForward = 0.f;

	if (HotkeyIsPressed("camera.pan"))
	{
		moveRightward += m->ViewDragSpeed * mouse_dx;
		moveForward += m->ViewDragSpeed * -mouse_dy;
	}

	if (g_mouse_active)
	{
		if (g_mouse_x >= g_xres - 2 && g_mouse_x < g_xres)
			moveRightward += m->ViewScrollSpeed * deltaRealTime;
		else if (g_mouse_x <= 3 && g_mouse_x >= 0)
			moveRightward -= m->ViewScrollSpeed * deltaRealTime;

		if (g_mouse_y >= g_yres - 2 && g_mouse_y < g_yres)
			moveForward -= m->ViewScrollSpeed * deltaRealTime;
		else if (g_mouse_y <= 3 && g_mouse_y >= 0)
			moveForward += m->ViewScrollSpeed * deltaRealTime;
	}

	if (HotkeyIsPressed("camera.right"))
		moveRightward += m->ViewScrollSpeed * deltaRealTime;
	if (HotkeyIsPressed("camera.left"))
		moveRightward -= m->ViewScrollSpeed * deltaRealTime;
	if (HotkeyIsPressed("camera.up"))
		moveForward += m->ViewScrollSpeed * deltaRealTime;
	if (HotkeyIsPressed("camera.down"))
		moveForward -= m->ViewScrollSpeed * deltaRealTime;

	if (g_Joystick.IsEnabled())
	{
		// This could all be improved with extra speed and sensitivity settings
		// (maybe use pow to allow finer control?), and inversion settings

		moveRightward += g_Joystick.GetAxisValue(m->JoystickPanX) * m->ViewScrollSpeed * deltaRealTime;
		moveForward -= g_Joystick.GetAxisValue(m->JoystickPanY) * m->ViewScrollSpeed * deltaRealTime;

		m->RotateX.AddSmoothly(g_Joystick.GetAxisValue(m->JoystickRotateX) * m->ViewRotateXSpeed * deltaRealTime);
		m->RotateY.AddSmoothly(-g_Joystick.GetAxisValue(m->JoystickRotateY) * m->ViewRotateYSpeed * deltaRealTime);

		// Use a +1 bias for zoom because I want this to work with trigger buttons that default to -1
		m->Zoom.AddSmoothly((g_Joystick.GetAxisValue(m->JoystickZoomIn) + 1.0f) / 2.0f * m->ViewZoomSpeed * deltaRealTime);
		m->Zoom.AddSmoothly(-(g_Joystick.GetAxisValue(m->JoystickZoomOut) + 1.0f) / 2.0f * m->ViewZoomSpeed * deltaRealTime);
	}

	if (moveRightward || moveForward)
	{
		// Break out of following mode when the user starts scrolling
		m->FollowEntity = INVALID_ENTITY;

		float s = sin(m->RotateY.GetSmoothedValue());
		float c = cos(m->RotateY.GetSmoothedValue());
		m->PosX.AddSmoothly(c * moveRightward);
		m->PosZ.AddSmoothly(-s * moveRightward);
		m->PosX.AddSmoothly(s * moveForward);
		m->PosZ.AddSmoothly(c * moveForward);
	}

	if (m->FollowEntity)
	{
		CmpPtr<ICmpPosition> cmpPosition(*(m->Game->GetSimulation2()), m->FollowEntity);
		if (cmpPosition && cmpPosition->IsInWorld())
		{
			// Get the most recent interpolated position
			float frameOffset = m->Game->GetSimulation2()->GetLastFrameOffset();
			CMatrix3D transform = cmpPosition->GetInterpolatedTransform(frameOffset, false);
			CVector3D pos = transform.GetTranslation();

			if (m->FollowFirstPerson)
			{
				float x, z, angle;
				cmpPosition->GetInterpolatedPosition2D(frameOffset, x, z, angle);
				float height = 4.f;
				m->ViewCamera.m_Orientation.SetIdentity();
				m->ViewCamera.m_Orientation.RotateX((float)M_PI/24.f);
				m->ViewCamera.m_Orientation.RotateY(angle);
				m->ViewCamera.m_Orientation.Translate(pos.X, pos.Y + height, pos.Z);

				m->ViewCamera.UpdateFrustum();
				return;
			}
			else
			{
				// Move the camera to match the unit
				CCamera targetCam = m->ViewCamera;
				SetupCameraMatrixSmoothRot(m, &targetCam.m_Orientation);

				CVector3D pivot = GetSmoothPivot(targetCam);
				CVector3D delta = pos - pivot;
				m->PosX.AddSmoothly(delta.X);
				m->PosY.AddSmoothly(delta.Y);
				m->PosZ.AddSmoothly(delta.Z);
			}
		}
		else
		{
			// The unit disappeared (died or garrisoned etc), so stop following it
			m->FollowEntity = INVALID_ENTITY;
		}
	}

	if (HotkeyIsPressed("camera.zoom.in"))
		m->Zoom.AddSmoothly(-m->ViewZoomSpeed * deltaRealTime);
	if (HotkeyIsPressed("camera.zoom.out"))
		m->Zoom.AddSmoothly(m->ViewZoomSpeed * deltaRealTime);

	if (m->ConstrainCamera)
		m->Zoom.ClampSmoothly(m->ViewZoomMin, m->ViewZoomMax);

	float zoomDelta = -m->Zoom.Update(deltaRealTime);
	if (zoomDelta)
	{
		CVector3D forwards = m->ViewCamera.m_Orientation.GetIn();
		m->PosX.AddSmoothly(forwards.X * zoomDelta);
		m->PosY.AddSmoothly(forwards.Y * zoomDelta);
		m->PosZ.AddSmoothly(forwards.Z * zoomDelta);
	}

	if (m->ConstrainCamera)
		m->RotateX.ClampSmoothly(DEGTORAD(m->ViewRotateXMin), DEGTORAD(m->ViewRotateXMax));

	FocusHeight(m, true);

	// Ensure the ViewCamera focus is inside the map with the chosen margins
	// if not so - apply margins to the camera
	if (m->ConstrainCamera)
	{
		CCamera targetCam = m->ViewCamera;
		SetupCameraMatrixSmoothRot(m, &targetCam.m_Orientation);

		CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain();

		CVector3D pivot = GetSmoothPivot(targetCam);
		CVector3D delta = targetCam.m_Orientation.GetTranslation() - pivot;

		CVector3D desiredPivot = pivot;

		CmpPtr<ICmpRangeManager> cmpRangeManager(*m->Game->GetSimulation2(), SYSTEM_ENTITY);
		if (cmpRangeManager && cmpRangeManager->GetLosCircular())
		{
			// Clamp to a circular region around the center of the map
			float r = pTerrain->GetMaxX() / 2;
			CVector3D center(r, desiredPivot.Y, r);
			float dist = (desiredPivot - center).Length();
			if (dist > r - CAMERA_EDGE_MARGIN)
				desiredPivot = center + (desiredPivot - center).Normalized() * (r - CAMERA_EDGE_MARGIN);
		}
		else
		{
			// Clamp to the square edges of the map
			desiredPivot.X = Clamp(desiredPivot.X, pTerrain->GetMinX() + CAMERA_EDGE_MARGIN, pTerrain->GetMaxX() - CAMERA_EDGE_MARGIN);
			desiredPivot.Z = Clamp(desiredPivot.Z, pTerrain->GetMinZ() + CAMERA_EDGE_MARGIN, pTerrain->GetMaxZ() - CAMERA_EDGE_MARGIN);
		}

		// Update the position so that pivot is within the margin
		m->PosX.SetValueSmoothly(desiredPivot.X + delta.X);
		m->PosZ.SetValueSmoothly(desiredPivot.Z + delta.Z);
	}

	m->PosX.Update(deltaRealTime);
	m->PosY.Update(deltaRealTime);
	m->PosZ.Update(deltaRealTime);

	// Handle rotation around the Y (vertical) axis
	{
		CCamera targetCam = m->ViewCamera;
		SetupCameraMatrixSmooth(m, &targetCam.m_Orientation);

		float rotateYDelta = m->RotateY.Update(deltaRealTime);
		if (rotateYDelta)
		{
			// We've updated RotateY, and need to adjust Pos so that it's still
			// facing towards the original focus point (the terrain in the center
			// of the screen).

			CVector3D upwards(0.0f, 1.0f, 0.0f);

			CVector3D pivot = GetSmoothPivot(targetCam);
			CVector3D delta = targetCam.m_Orientation.GetTranslation() - pivot;

			CQuaternion q;
			q.FromAxisAngle(upwards, rotateYDelta);
			CVector3D d = q.Rotate(delta) - delta;

			m->PosX.Add(d.X);
			m->PosY.Add(d.Y);
			m->PosZ.Add(d.Z);
		}
	}

	// Handle rotation around the X (sideways, relative to camera) axis
	{
		CCamera targetCam = m->ViewCamera;
		SetupCameraMatrixSmooth(m, &targetCam.m_Orientation);

		float rotateXDelta = m->RotateX.Update(deltaRealTime);
		if (rotateXDelta)
		{
			CVector3D rightwards = targetCam.m_Orientation.GetLeft() * -1.0f;

			CVector3D pivot = GetSmoothPivot(targetCam);
			CVector3D delta = targetCam.m_Orientation.GetTranslation() - pivot;

			CQuaternion q;
			q.FromAxisAngle(rightwards, rotateXDelta);
			CVector3D d = q.Rotate(delta) - delta;

			m->PosX.Add(d.X);
			m->PosY.Add(d.Y);
			m->PosZ.Add(d.Z);
		}
	}

	/* This is disabled since it doesn't seem necessary:

	// Ensure the camera's near point is never inside the terrain
	if (m->ConstrainCamera)
	{
		CMatrix3D target;
		target.SetIdentity();
		target.RotateX(m->RotateX.GetValue());
		target.RotateY(m->RotateY.GetValue());
		target.Translate(m->PosX.GetValue(), m->PosY.GetValue(), m->PosZ.GetValue());

		CVector3D nearPoint = target.GetTranslation() + target.GetIn() * defaultNear;
		float ground = m->Game->GetWorld()->GetTerrain()->GetExactGroundLevel(nearPoint.X, nearPoint.Z);
		float limit = ground + 16.f;
		if (nearPoint.Y < limit)
			m->PosY.AddSmoothly(limit - nearPoint.Y);
	}
	*/

	m->RotateY.Wrap(-(float)M_PI, (float)M_PI);

	// Update the camera matrix
	m->ViewCamera.SetProjection(m->ViewNear, m->ViewFar, m->ViewFOV);
	SetupCameraMatrixSmooth(m, &m->ViewCamera.m_Orientation);
	m->ViewCamera.UpdateFrustum();
}
Beispiel #6
0
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// ValidatePosition: ensure that current transform and bone matrices are both uptodate
void CModel::ValidatePosition()
{
	if (m_PositionValid)
	{
		ENSURE(!m_Parent || m_Parent->m_PositionValid);
		return;
	}

	if (m_Parent && !m_Parent->m_PositionValid)
	{
		// Make sure we don't base our calculations on
		// a parent animation state that is out of date.
		m_Parent->ValidatePosition();

		// Parent will recursively call our validation.
		ENSURE(m_PositionValid);
		return;
	}

	if (m_Anim && m_BoneMatrices)
	{
//		PROFILE( "generating bone matrices" );

		ENSURE(m_pModelDef->GetNumBones() == m_Anim->m_AnimDef->GetNumKeys());

		m_Anim->m_AnimDef->BuildBoneMatrices(m_AnimTime, m_BoneMatrices, !(m_Flags & MODELFLAG_NOLOOPANIMATION));
	}
	else if (m_BoneMatrices)
	{
		// Bones but no animation - probably a buggy actor forgot to set up the animation,
		// so just render it in its bind pose

		for (size_t i = 0; i < m_pModelDef->GetNumBones(); i++)
		{
			m_BoneMatrices[i].SetIdentity();
			m_BoneMatrices[i].Rotate(m_pModelDef->GetBones()[i].m_Rotation);
			m_BoneMatrices[i].Translate(m_pModelDef->GetBones()[i].m_Translation);
		}
	}

	// For CPU skinning, we precompute as much as possible so that the only
	// per-vertex work is a single matrix*vec multiplication.
	// For GPU skinning, we try to minimise CPU work by doing most computation
	// in the vertex shader instead.
	// Using g_Renderer.m_Options to detect CPU vs GPU is a bit hacky,
	// and this doesn't allow the setting to change at runtime, but there isn't
	// an obvious cleaner way to determine what data needs to be computed,
	// and GPU skinning is a rarely-used experimental feature anyway.
	bool worldSpaceBoneMatrices = !g_Renderer.m_Options.m_GPUSkinning;
	bool computeBlendMatrices = !g_Renderer.m_Options.m_GPUSkinning;

	if (m_BoneMatrices && worldSpaceBoneMatrices)
	{
		// add world-space transformation to m_BoneMatrices
		const CMatrix3D transform = GetTransform();
		for (size_t i = 0; i < m_pModelDef->GetNumBones(); i++)
			m_BoneMatrices[i].Concatenate(transform);
	}

	// our own position is now valid; now we can safely update our props' positions without fearing
	// that doing so will cause a revalidation of this model (see recursion above).
	m_PositionValid = true;

	// re-position and validate all props
	for (size_t j = 0; j < m_Props.size(); ++j)
	{
		const Prop& prop=m_Props[j];

		CMatrix3D proptransform = prop.m_Point->m_Transform;

		if (prop.m_Point->m_BoneIndex != 0xff)
		{
			CMatrix3D boneMatrix = m_BoneMatrices[prop.m_Point->m_BoneIndex];
			if (!worldSpaceBoneMatrices)
				boneMatrix.Concatenate(GetTransform());
			proptransform.Concatenate(boneMatrix);
		}
		else
		{
			// not relative to any bone; just apply world-space transformation (i.e. relative to object-space origin)
			proptransform.Concatenate(m_Transform);
		}

		// Adjust prop height to terrain level when needed
		if (prop.m_MaxHeight != 0.f || prop.m_MinHeight != 0.f)
		{
			CVector3D propTranslation = proptransform.GetTranslation();
			CVector3D objTranslation = m_Transform.GetTranslation();

			CmpPtr<ICmpTerrain> cmpTerrain(m_Simulation, SYSTEM_ENTITY);
			if (cmpTerrain)
			{
				float objTerrain = cmpTerrain->GetExactGroundLevel(objTranslation.X, objTranslation.Z);
				float propTerrain = cmpTerrain->GetExactGroundLevel(propTranslation.X, propTranslation.Z);
				float translateHeight = std::min(prop.m_MaxHeight,
				                                 std::max(prop.m_MinHeight, propTerrain - objTerrain));
				CMatrix3D translate = CMatrix3D();
				translate.SetTranslation(0.f, translateHeight, 0.f);
				proptransform.Concatenate(translate);
			}
		}

		prop.m_Model->SetTransform(proptransform);
		prop.m_Model->ValidatePosition();
	}

	if (m_BoneMatrices)
	{
		for (size_t i = 0; i < m_pModelDef->GetNumBones(); i++)
		{
			m_BoneMatrices[i] = m_BoneMatrices[i] * m_pModelDef->GetInverseBindBoneMatrices()[i];
		}

		// Note: there is a special case of joint influence, in which the vertex
		//	is influenced by the bind-shape transform instead of a particular bone,
		//	which we indicate with the blending bone ID set to the total number
		//	of bones. But since we're skinning in world space, we use the model's
		//	world space transform and store that matrix in this special index.
		//	(see http://trac.wildfiregames.com/ticket/1012)
		m_BoneMatrices[m_pModelDef->GetNumBones()] = m_Transform;

		if (computeBlendMatrices)
			m_pModelDef->BlendBoneMatrices(m_BoneMatrices);
	}
}