Improve camera restraints at edge of map to be independent of zoom, and to work on circular maps.
Fixes #573. This was SVN commit r9011.
This commit is contained in:
parent
bec4c6437b
commit
3a5ca7fdbc
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -55,6 +55,7 @@
|
||||
#include "simulation/LOSManager.h"
|
||||
#include "simulation2/Simulation2.h"
|
||||
#include "simulation2/components/ICmpPosition.h"
|
||||
#include "simulation2/components/ICmpRangeManager.h"
|
||||
|
||||
extern int g_xres, g_yres;
|
||||
|
||||
@ -62,7 +63,10 @@ const float CGameView::defaultFOV = DEGTORAD(20.f);
|
||||
const float CGameView::defaultNear = 16.f;
|
||||
const float CGameView::defaultFar = 4096.f;
|
||||
const float CGameView::defaultCullFOV = CGameView::defaultFOV + DEGTORAD(6.0f); //add 6 degrees to the default FOV for use with the culling frustum
|
||||
const float CGameView::cameraPivotMargin = -20.0f;
|
||||
|
||||
// Maximum distance outside the edge of the map that the camera's
|
||||
// focus point can be moved
|
||||
static const float CAMERA_EDGE_MARGIN = 2.0f*CELL_SIZE;
|
||||
|
||||
/**
|
||||
* A value with exponential decay towards the target value.
|
||||
@ -292,7 +296,7 @@ public:
|
||||
static void ScriptingInit();
|
||||
};
|
||||
|
||||
static void SetupCameraMatrix(CGameViewImpl* m, CMatrix3D* orientation)
|
||||
static void SetupCameraMatrixSmooth(CGameViewImpl* m, CMatrix3D* orientation)
|
||||
{
|
||||
orientation->SetIdentity();
|
||||
orientation->RotateX(m->RotateX.GetSmoothedValue());
|
||||
@ -300,6 +304,22 @@ static void SetupCameraMatrix(CGameViewImpl* m, CMatrix3D* orientation)
|
||||
orientation->Translate(m->PosX.GetSmoothedValue(), m->PosY.GetSmoothedValue(), m->PosZ.GetSmoothedValue());
|
||||
}
|
||||
|
||||
static void SetupCameraMatrixSmoothRot(CGameViewImpl* m, CMatrix3D* orientation)
|
||||
{
|
||||
orientation->SetIdentity();
|
||||
orientation->RotateX(m->RotateX.GetSmoothedValue());
|
||||
orientation->RotateY(m->RotateY.GetSmoothedValue());
|
||||
orientation->Translate(m->PosX.GetValue(), m->PosY.GetValue(), m->PosZ.GetValue());
|
||||
}
|
||||
|
||||
static void SetupCameraMatrixNonSmooth(CGameViewImpl* m, CMatrix3D* orientation)
|
||||
{
|
||||
orientation->SetIdentity();
|
||||
orientation->RotateX(m->RotateX.GetValue());
|
||||
orientation->RotateY(m->RotateY.GetValue());
|
||||
orientation->Translate(m->PosX.GetValue(), m->PosY.GetValue(), m->PosZ.GetValue());
|
||||
}
|
||||
|
||||
CGameView::CGameView(CGame *pGame):
|
||||
m(new CGameViewImpl(pGame))
|
||||
{
|
||||
@ -311,7 +331,7 @@ CGameView::CGameView(CGame *pGame):
|
||||
m->ViewCamera.SetViewPort(vp);
|
||||
|
||||
m->ViewCamera.SetProjection(defaultNear, defaultFar, defaultFOV);
|
||||
SetupCameraMatrix(m, &m->ViewCamera.m_Orientation);
|
||||
SetupCameraMatrixSmooth(m, &m->ViewCamera.m_Orientation);
|
||||
m->ViewCamera.UpdateFrustum();
|
||||
|
||||
m->CullCamera = m->ViewCamera;
|
||||
@ -569,11 +589,7 @@ static void ClampDistance(CGameViewImpl* m, bool smooth)
|
||||
return;
|
||||
|
||||
CCamera targetCam = m->ViewCamera;
|
||||
targetCam.m_Orientation.SetIdentity();
|
||||
targetCam.m_Orientation.RotateX(m->RotateX.GetSmoothedValue());
|
||||
targetCam.m_Orientation.RotateY(m->RotateY.GetSmoothedValue());
|
||||
// Use non-smoothed position:
|
||||
targetCam.m_Orientation.Translate(m->PosX.GetValue(), m->PosY.GetValue(), m->PosZ.GetValue());
|
||||
SetupCameraMatrixSmoothRot(m, &targetCam.m_Orientation);
|
||||
|
||||
CVector3D forwards = targetCam.m_Orientation.GetIn();
|
||||
|
||||
@ -721,14 +737,9 @@ void CGameView::Update(float DeltaTime)
|
||||
}
|
||||
else
|
||||
{
|
||||
// move the camera after unit
|
||||
// use smoothed values of rotation around X and Y, since we need to hold user's rotation done
|
||||
// in this function above
|
||||
// Move the camera to match the unit
|
||||
CCamera targetCam = m->ViewCamera;
|
||||
targetCam.m_Orientation.SetIdentity();
|
||||
targetCam.m_Orientation.RotateX(m->RotateX.GetSmoothedValue());
|
||||
targetCam.m_Orientation.RotateY(m->RotateY.GetSmoothedValue());
|
||||
targetCam.m_Orientation.Translate(m->PosX.GetValue(), m->PosY.GetValue(), m->PosZ.GetValue());
|
||||
SetupCameraMatrixSmoothRot(m, &targetCam.m_Orientation);
|
||||
|
||||
CVector3D pivot = targetCam.GetFocus();
|
||||
CVector3D delta = pos - pivot;
|
||||
@ -768,18 +779,35 @@ void CGameView::Update(float DeltaTime)
|
||||
if (m->ConstrainCamera)
|
||||
{
|
||||
CCamera targetCam = m->ViewCamera;
|
||||
SetupCameraMatrix(m, &targetCam.m_Orientation);
|
||||
SetupCameraMatrixSmoothRot(m, &targetCam.m_Orientation);
|
||||
|
||||
CTerrain* pTerrain = m->Game->GetWorld()->GetTerrain();
|
||||
float min_x = pTerrain->GetMinX() + cameraPivotMargin;
|
||||
float max_x = pTerrain->GetMaxX() - cameraPivotMargin;
|
||||
float min_z = pTerrain->GetMinZ() + cameraPivotMargin;
|
||||
float max_z = pTerrain->GetMaxZ() - cameraPivotMargin;
|
||||
|
||||
// Clamp so that pos+in is within the margin
|
||||
CVector3D in = targetCam.m_Orientation.GetIn() * m->ViewZoomDefault;
|
||||
m->PosX.ClampSmoothly(min_x - in.X, max_x - in.X);
|
||||
m->PosZ.ClampSmoothly(min_z - in.Z, max_z - in.Z);
|
||||
CVector3D pivot = targetCam.GetFocus();
|
||||
CVector3D delta = targetCam.m_Orientation.GetTranslation() - pivot;
|
||||
|
||||
CVector3D desiredPivot = pivot;
|
||||
|
||||
CmpPtr<ICmpRangeManager> cmpRangeManager(*m->Game->GetSimulation2(), SYSTEM_ENTITY);
|
||||
if (!cmpRangeManager.null() && 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(DeltaTime);
|
||||
@ -789,7 +817,7 @@ void CGameView::Update(float DeltaTime)
|
||||
// Handle rotation around the Y (vertical) axis
|
||||
{
|
||||
CCamera targetCam = m->ViewCamera;
|
||||
SetupCameraMatrix(m, &targetCam.m_Orientation);
|
||||
SetupCameraMatrixSmooth(m, &targetCam.m_Orientation);
|
||||
|
||||
float rotateYDelta = m->RotateY.Update(DeltaTime);
|
||||
if (rotateYDelta)
|
||||
@ -816,7 +844,7 @@ void CGameView::Update(float DeltaTime)
|
||||
// Handle rotation around the X (sideways, relative to camera) axis
|
||||
{
|
||||
CCamera targetCam = m->ViewCamera;
|
||||
SetupCameraMatrix(m, &targetCam.m_Orientation);
|
||||
SetupCameraMatrixSmooth(m, &targetCam.m_Orientation);
|
||||
|
||||
float rotateXDelta = m->RotateX.Update(DeltaTime);
|
||||
if (rotateXDelta)
|
||||
@ -858,7 +886,7 @@ void CGameView::Update(float DeltaTime)
|
||||
m->RotateY.Wrap(-(float)M_PI, (float)M_PI);
|
||||
|
||||
// Update the camera matrix
|
||||
SetupCameraMatrix(m, &m->ViewCamera.m_Orientation);
|
||||
SetupCameraMatrixSmooth(m, &m->ViewCamera.m_Orientation);
|
||||
m->ViewCamera.UpdateFrustum();
|
||||
}
|
||||
|
||||
@ -870,10 +898,7 @@ void CGameView::MoveCameraTarget(const CVector3D& target, bool minimap)
|
||||
// that difference to our new target)
|
||||
|
||||
CCamera targetCam = m->ViewCamera;
|
||||
targetCam.m_Orientation.SetIdentity();
|
||||
targetCam.m_Orientation.RotateX(m->RotateX.GetValue());
|
||||
targetCam.m_Orientation.RotateY(m->RotateY.GetValue());
|
||||
targetCam.m_Orientation.Translate(m->PosX.GetValue(), m->PosY.GetValue(), m->PosZ.GetValue());
|
||||
SetupCameraMatrixNonSmooth(m, &targetCam.m_Orientation);
|
||||
|
||||
CVector3D pivot = targetCam.GetFocus();
|
||||
CVector3D delta = target - pivot;
|
||||
@ -906,7 +931,7 @@ void CGameView::ResetCameraTarget(const CVector3D& target)
|
||||
|
||||
ClampDistance(m, false);
|
||||
|
||||
SetupCameraMatrix(m, &m->ViewCamera.m_Orientation);
|
||||
SetupCameraMatrixSmooth(m, &m->ViewCamera.m_Orientation);
|
||||
m->ViewCamera.UpdateFrustum();
|
||||
|
||||
// Break out of following mode so the camera really moves to the target
|
||||
@ -916,10 +941,7 @@ void CGameView::ResetCameraTarget(const CVector3D& target)
|
||||
void CGameView::ResetCameraAngleZoom()
|
||||
{
|
||||
CCamera targetCam = m->ViewCamera;
|
||||
targetCam.m_Orientation.SetIdentity();
|
||||
targetCam.m_Orientation.RotateX(m->RotateX.GetValue());
|
||||
targetCam.m_Orientation.RotateY(m->RotateY.GetValue());
|
||||
targetCam.m_Orientation.Translate(m->PosX.GetValue(), m->PosY.GetValue(), m->PosZ.GetValue());
|
||||
SetupCameraMatrixNonSmooth(m, &targetCam.m_Orientation);
|
||||
|
||||
// Compute the zoom adjustment to get us back to the default
|
||||
CVector3D forwards = targetCam.m_Orientation.GetIn();
|
||||
|
@ -46,7 +46,6 @@ public:
|
||||
static const float defaultFOV, defaultCullFOV, defaultNear, defaultFar;
|
||||
|
||||
private:
|
||||
static const float cameraPivotMargin;
|
||||
CGameViewImpl* m;
|
||||
|
||||
// Check whether lighting environment has changed and update vertex data if necessary
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2009 Wildfire Games.
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -26,6 +26,14 @@
|
||||
#include "maths/Bound.h"
|
||||
#include "maths/Vector3D.h"
|
||||
|
||||
// To cope well with points that are slightly off the edge of the map,
|
||||
// we act as if there's an N-tile margin around the edges of the heightfield.
|
||||
// (N shouldn't be too huge else it'll hurt performance a little when
|
||||
// RayIntersect loops through it all.)
|
||||
// CTerrain::CalcPosition implements clamp-to-edge behaviour so the tracer
|
||||
// will have that behaviour.
|
||||
static const int MARGIN_SIZE = 64;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CHFTracer constructor
|
||||
CHFTracer::CHFTracer(CTerrain *pTerrain):
|
||||
@ -121,8 +129,8 @@ bool CHFTracer::RayIntersect(const CVector3D& origin, const CVector3D& dir, int&
|
||||
{
|
||||
// intersect first against bounding box
|
||||
CBound bound;
|
||||
bound[0]=CVector3D(0,0,0);
|
||||
bound[1]=CVector3D(m_MapSize*m_CellSize,65535*m_HeightScale,m_MapSize*m_CellSize);
|
||||
bound[0] = CVector3D(-MARGIN_SIZE * m_CellSize, 0, -MARGIN_SIZE * m_CellSize);
|
||||
bound[1] = CVector3D((m_MapSize + MARGIN_SIZE) * m_CellSize, 65535 * m_HeightScale, (m_MapSize + MARGIN_SIZE) * m_CellSize);
|
||||
|
||||
float tmin,tmax;
|
||||
if (!bound.RayIntersect(origin,dir,tmin,tmax)) {
|
||||
@ -145,10 +153,10 @@ bool CHFTracer::RayIntersect(const CVector3D& origin, const CVector3D& dir, int&
|
||||
float invCellSize=1.0f/float(m_CellSize);
|
||||
|
||||
float fcx=traversalPt.X*invCellSize;
|
||||
int cx=int(fcx);
|
||||
int cx=(int)floor(fcx);
|
||||
|
||||
float fcz=traversalPt.Z*invCellSize;
|
||||
int cz=int(fcz);
|
||||
int cz=(int)floor(fcz);
|
||||
|
||||
float invdx = 1.0e20f;
|
||||
float invdz = 1.0e20f;
|
||||
@ -160,7 +168,8 @@ bool CHFTracer::RayIntersect(const CVector3D& origin, const CVector3D& dir, int&
|
||||
|
||||
do {
|
||||
// test current cell
|
||||
if (cx>=0 && cx<int(m_MapSize-1) && cz>=0 && cz<int(m_MapSize-1)) {
|
||||
if (cx >= -MARGIN_SIZE && cx < int(m_MapSize + MARGIN_SIZE - 1) && cz >= -MARGIN_SIZE && cz < int(m_MapSize + MARGIN_SIZE - 1))
|
||||
{
|
||||
float dist;
|
||||
|
||||
if (CellIntersect(cx,cz,origin,dir,dist)) {
|
||||
@ -174,14 +183,14 @@ bool CHFTracer::RayIntersect(const CVector3D& origin, const CVector3D& dir, int&
|
||||
{
|
||||
// Degenerate case: y close to zero
|
||||
// catch travelling off the map
|
||||
if( ( cx < 0 ) && ( sx < 0 ) )
|
||||
return( false );
|
||||
if( ( cx >= (int)m_MapSize ) && ( sx > 0 ) )
|
||||
return( false );
|
||||
if( ( cz < 0 ) && ( sz < 0 ) )
|
||||
return( false );
|
||||
if( ( cz >= (int)m_MapSize ) && ( sz > 0 ) )
|
||||
return( false );
|
||||
if ((cx < -MARGIN_SIZE) && (sx < 0))
|
||||
return false;
|
||||
if ((cx >= (int)(m_MapSize + MARGIN_SIZE - 1)) && (sx > 0))
|
||||
return false;
|
||||
if ((cz < -MARGIN_SIZE) && (sz < 0))
|
||||
return false;
|
||||
if ((cz >= (int)(m_MapSize + MARGIN_SIZE - 1)) && (sz > 0))
|
||||
return false;
|
||||
}
|
||||
|
||||
// get coords of current cell
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2010 Wildfire Games.
|
||||
/* Copyright (C) 2011 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -105,13 +105,13 @@ CStr8 CTerrain::GetMovementClass(ssize_t i, ssize_t j) const
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CalcPosition: calculate the world space position of the vertex at (i,j)
|
||||
// If i,j is off the map, it acts as if the edges of the terrain are extended
|
||||
// outwards to infinity
|
||||
void CTerrain::CalcPosition(ssize_t i, ssize_t j, CVector3D& pos) const
|
||||
{
|
||||
u16 height;
|
||||
if ((size_t)i < (size_t)m_MapSize && (size_t)j < (size_t)m_MapSize) // will reject negative coordinates
|
||||
height = m_Heightmap[j*m_MapSize + i];
|
||||
else
|
||||
height = 0;
|
||||
ssize_t hi = clamp(i, (ssize_t)0, m_MapSize-1);
|
||||
ssize_t hj = clamp(j, (ssize_t)0, m_MapSize-1);
|
||||
u16 height = m_Heightmap[hj*m_MapSize + hi];
|
||||
pos.X = float(i*CELL_SIZE);
|
||||
pos.Y = float(height*HEIGHT_SCALE);
|
||||
pos.Z = float(j*CELL_SIZE);
|
||||
@ -121,11 +121,9 @@ void CTerrain::CalcPosition(ssize_t i, ssize_t j, CVector3D& pos) const
|
||||
// CalcPositionFixed: calculate the world space position of the vertex at (i,j)
|
||||
void CTerrain::CalcPositionFixed(ssize_t i, ssize_t j, CFixedVector3D& pos) const
|
||||
{
|
||||
u16 height;
|
||||
if ((size_t)i < (size_t)m_MapSize && (size_t)j < (size_t)m_MapSize) // will reject negative coordinates
|
||||
height = m_Heightmap[j*m_MapSize + i];
|
||||
else
|
||||
height = 0;
|
||||
ssize_t hi = clamp(i, (ssize_t)0, m_MapSize-1);
|
||||
ssize_t hj = clamp(j, (ssize_t)0, m_MapSize-1);
|
||||
u16 height = m_Heightmap[hj*m_MapSize + hi];
|
||||
pos.X = fixed::FromInt(i) * (int)CELL_SIZE;
|
||||
pos.Y = fixed::FromInt(height) / (int)HEIGHT_UNITS_PER_METRE;
|
||||
pos.Z = fixed::FromInt(j) * (int)CELL_SIZE;
|
||||
|
@ -83,6 +83,13 @@ void CVector3D::Normalize ()
|
||||
Z *= scale;
|
||||
}
|
||||
|
||||
CVector3D CVector3D::Normalized () const
|
||||
{
|
||||
float scale = 1.0f/Length ();
|
||||
|
||||
return CVector3D(X * scale, Y * scale, Z * scale);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
@ -102,6 +102,7 @@ class CVector3D
|
||||
float Length () const;
|
||||
float LengthSquared () const;
|
||||
void Normalize ();
|
||||
CVector3D Normalized () const;
|
||||
|
||||
// Returns 3 element array of floats, e.g. for glVertex3fv
|
||||
const float* GetFloatArray() const { return &X; }
|
||||
|
Loading…
Reference in New Issue
Block a user