Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
693 lines
14 KiB
C++
693 lines
14 KiB
C++
|
|
#include "stdafx.h"
|
|
|
|
#include "cameracontroller.h"
|
|
|
|
#include "ObjectManager.h"
|
|
#include "GameInterface.h"
|
|
#include "DrawInfo.h"
|
|
#include "Refresher.h"
|
|
#include <MW4\MW4.hpp>
|
|
#include <MW4\MW4Headers.hpp>
|
|
#include <MW4\VehicleInterface.hpp>
|
|
|
|
const float rotate_size = -Stuff::Pi * 0.2f;
|
|
const float pitch_size = 0.4f;
|
|
const float zoom_size = 44.0f;
|
|
const float speed_size = 40.0f;
|
|
const float height_size = 20.0f;
|
|
const float default_speed = 80.0f;
|
|
const float default_height = 5;
|
|
|
|
|
|
|
|
CameraController* CameraController::m_Instance = 0;
|
|
|
|
#define REALSMALLRANGE 0.0000001f
|
|
|
|
CameraController::CameraController(ObjectManager& object_manager)
|
|
: m_ObjectManager(object_manager)
|
|
, m_LastCameraAnimateTime(0)
|
|
{
|
|
m_Speed=default_speed;
|
|
Verify(m_Instance == 0);
|
|
m_Instance = this;
|
|
LastTime=0.0f;
|
|
LookAtMode=false;
|
|
m_YawPitchRange.range=REALSMALLRANGE;
|
|
OldDistance=100.0f;
|
|
RBMode=false;
|
|
RevMouse=false;
|
|
TerrainFollow=true;
|
|
Reset();
|
|
}
|
|
|
|
CameraController::~CameraController()
|
|
{
|
|
Verify(m_Instance == this);
|
|
m_Instance = 0;
|
|
}
|
|
|
|
CameraController* CameraController::GetInstance()
|
|
{
|
|
return (m_Instance);
|
|
}
|
|
|
|
inline bool PointIsInsideBounds(const Stuff::Point3D& point, const Stuff::Point3D& map_size)
|
|
{
|
|
if((point.x >= map_size.x * 0.5f) ||
|
|
(point.z >= map_size.z * 0.5f) ||
|
|
(point.x < -map_size.x * 0.5f) ||
|
|
(point.z < -map_size.z * 0.5f))
|
|
{
|
|
return (false);
|
|
}
|
|
|
|
return (true);
|
|
}
|
|
|
|
bool CameraController::StaysInsideBounds(const Stuff::Point3D& new_point, const Stuff::YawPitchRange& new_ypr) const
|
|
{
|
|
if (PointIsInsideBounds(new_point,m_ObjectManager.GetMapSize()) == false)
|
|
{
|
|
return (false);
|
|
}
|
|
|
|
Stuff::LinearMatrix4D matrix(new_point);
|
|
matrix.BuildLookAt(new_ypr);
|
|
|
|
return (PointIsInsideBounds((Stuff::Point3D)matrix,m_ObjectManager.GetMapSize()));
|
|
}
|
|
|
|
void CameraController::PutPointInsideBounds(Stuff::Point3D& point)
|
|
{
|
|
Stuff::Point3D map_size(m_ObjectManager.GetMapSize());
|
|
|
|
Clamp(point.x,-map_size.x * 0.5f,map_size.x * 0.5f);
|
|
Clamp(point.z,-map_size.z * 0.5f,map_size.z * 0.5f);
|
|
}
|
|
|
|
void CameraController::PutYPRInsideBounds(Stuff::YawPitchRange& ypr)
|
|
{
|
|
if (StaysInsideBounds(m_LookAtPoint,ypr) == true)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Stuff::YawPitchRange ypr2(ypr);
|
|
|
|
{for (Stuff::Scalar yaw_add = 0.1f;
|
|
yaw_add < (GetMaxYaw() * 0.5f) + 0.1f;
|
|
yaw_add += 0.1f)
|
|
{
|
|
{
|
|
ypr2.yaw = ypr.yaw + yaw_add;
|
|
if (StaysInsideBounds(m_LookAtPoint,ypr2) == true)
|
|
{
|
|
ypr = ypr2;
|
|
return;
|
|
}
|
|
}
|
|
|
|
{
|
|
ypr2.yaw = ypr.yaw - yaw_add;
|
|
if (StaysInsideBounds(m_LookAtPoint,ypr2) == true)
|
|
{
|
|
ypr = ypr2;
|
|
return;
|
|
}
|
|
}
|
|
}}
|
|
}
|
|
|
|
void CameraController::Update()
|
|
{
|
|
if (!GameInitilized)
|
|
return;
|
|
|
|
if ((Adept::Player::GetInstance() == 0) ||
|
|
(Adept::Player::GetInstance()->playerInterface == 0))
|
|
{
|
|
return;
|
|
}
|
|
|
|
PutPointInsideBounds(m_LookAtPoint);
|
|
PutYPRInsideBounds(m_YawPitchRange);
|
|
|
|
if (StaysInsideBounds(m_LookAtPoint,m_YawPitchRange) == false)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Stuff::LinearMatrix4D matrix(m_LookAtPoint);
|
|
matrix.BuildLookAt(m_YawPitchRange);
|
|
|
|
Stuff::Point3D camera_pos(matrix);
|
|
|
|
if(TerrainFollow)
|
|
{
|
|
Stuff::Scalar terrain_height(ComputeTerrainElevation(camera_pos.x,camera_pos.z,0));
|
|
|
|
|
|
if (camera_pos.y < terrain_height + GetMinHeight())
|
|
{
|
|
camera_pos.y = terrain_height + GetMinHeight();
|
|
matrix.BuildTranslation(camera_pos);
|
|
}
|
|
}
|
|
|
|
Adept::Player::GetInstance()->SetNewLocalToParent(matrix);
|
|
Adept::Player::GetInstance()->SyncMatrices(true);
|
|
}
|
|
|
|
Stuff::YawPitchRange CameraController::GetYawPitchRange() const
|
|
{
|
|
return (m_YawPitchRange);
|
|
}
|
|
|
|
void CameraController::SetYawPitchRange(Stuff::YawPitchRange ypr)
|
|
{
|
|
Clamp(ypr.pitch,GetMinPitch(),GetMaxPitch());
|
|
m_YawPitchRange = ypr;
|
|
}
|
|
|
|
void CameraController::Reset()
|
|
{
|
|
m_YawPitchRange = Stuff::YawPitchRange(GetDefaultYaw(),GetDefaultPitch(),REALSMALLRANGE);
|
|
LookAtMode=false;
|
|
OldDistance=100.0f;
|
|
m_LookAtPoint = Stuff::Point3D(0,0,0);
|
|
m_Speed = default_speed;
|
|
m_Height = default_height;
|
|
|
|
// put camera in "editor view" mode
|
|
if (GameInitilized && (Adept::Player::GetInstance() != 0))
|
|
{
|
|
Adept::Interface* iface = Adept::Player::GetInstance()->playerInterface;
|
|
|
|
if ((iface != 0) &&
|
|
(iface->IsDerivedFrom(MechWarrior4::VehicleInterface::DefaultData) == true))
|
|
{
|
|
MechWarrior4::VehicleInterface* vehicle_interface = Cast_Object(VehicleInterface*,iface);
|
|
vehicle_interface->SetCameraMode(MechWarrior4::VehicleInterface::EditorCameraView);
|
|
}
|
|
}
|
|
|
|
m_LookAtPoint.y = ComputeTerrainElevation(m_LookAtPoint.x,m_LookAtPoint.z,0) + m_Height;
|
|
|
|
Update();
|
|
}
|
|
|
|
void CameraController::SetHeight(Stuff::Scalar height)
|
|
{
|
|
m_Height = height;
|
|
|
|
if(TerrainFollow)
|
|
m_LookAtPoint.y = ComputeTerrainElevation(m_LookAtPoint.x,m_LookAtPoint.z,0) + m_Height;
|
|
Update();
|
|
}
|
|
|
|
void CameraController::SetSpeed(Stuff::Scalar speed)
|
|
{
|
|
m_Speed = speed;
|
|
}
|
|
|
|
Stuff::Scalar CameraController::GetHeight() const
|
|
{
|
|
return (m_Height);
|
|
}
|
|
|
|
Stuff::Scalar CameraController::GetSpeed() const
|
|
{
|
|
return (m_Speed);
|
|
}
|
|
|
|
void CameraController::SetLookAt(const Stuff::Point3D& look_at, bool adjust_to_terrain)
|
|
{
|
|
m_LookAtPoint = look_at;
|
|
|
|
const Stuff::Scalar terrain_elevation(ComputeTerrainElevation(m_LookAtPoint.x,m_LookAtPoint.z,0));
|
|
|
|
if (adjust_to_terrain )
|
|
{
|
|
m_LookAtPoint.y = terrain_elevation + m_Height;
|
|
}
|
|
else
|
|
{
|
|
m_Height = m_LookAtPoint.y-terrain_elevation;
|
|
}
|
|
}
|
|
|
|
Stuff::Point3D CameraController::GetLookAt() const
|
|
{
|
|
return (m_LookAtPoint);
|
|
}
|
|
|
|
void CameraController::Draw(DrawInfo& dinf)
|
|
{
|
|
dinf.SetPen(DrawInfo::HelperPen);
|
|
|
|
CPoint start(dinf.vinf.DataToScreen(m_LookAtPoint));
|
|
Stuff::LinearMatrix4D matrix(m_LookAtPoint);
|
|
|
|
matrix.BuildLookAt(Stuff::YawPitchRange(m_YawPitchRange.yaw,m_YawPitchRange.pitch,GetLookAtMode()?m_YawPitchRange.range:-100.0f));
|
|
CPoint end(dinf.vinf.DataToScreen((Stuff::Point3D)matrix));
|
|
|
|
/*
|
|
RECT r;
|
|
dinf.GetDC()->GetClipBox(&r);
|
|
|
|
if ((start.x > r.right)||
|
|
(end.x > r.right) ||
|
|
(start.y > r.bottom) ||
|
|
(end.y > r.bottom))
|
|
{
|
|
return;
|
|
}
|
|
*/
|
|
/*
|
|
if(!GetLookAtMode())
|
|
{
|
|
int ydist,xdist;
|
|
ydist=end.y-start.y;
|
|
xdist=end.x-start.x;
|
|
end.y=(ydist*10)/xdist;
|
|
end.x=(xdist*10)/ydist;
|
|
|
|
|
|
}
|
|
*/
|
|
|
|
dinf.GetDC()->MoveTo(start);
|
|
dinf.GetDC()->LineTo(end);
|
|
|
|
{
|
|
const int circle_size(4);
|
|
CRect rect(start.x - circle_size,
|
|
start.y - circle_size,
|
|
start.x + circle_size,
|
|
start.y + circle_size);
|
|
dinf.GetDC()->Ellipse(&rect);
|
|
}
|
|
|
|
if(GetLookAtMode())
|
|
{
|
|
const int circle_size(6);
|
|
CRect rect(end.x - circle_size,
|
|
end.y - circle_size,
|
|
end.x + circle_size,
|
|
end.y + circle_size);
|
|
dinf.GetDC()->Ellipse(&rect);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
float GetCurTime()
|
|
{
|
|
return GetTickCount()/1000.0f;
|
|
}
|
|
|
|
bool CameraController::ProcessIO()
|
|
{
|
|
Scalar new_time= GetCurTime();
|
|
Scalar frame_time=new_time-LastTime;
|
|
LastTime=new_time;
|
|
|
|
if(frame_time<(1/1000.0f)) frame_time=(1/1000.0f);
|
|
|
|
|
|
YawPitchRange ypr_offset(0,0,0);
|
|
Point3D offset(0,0,0);
|
|
bool yaw_changed = false;
|
|
bool poschanged=false;
|
|
|
|
if(GetLookAtMode())
|
|
{
|
|
|
|
|
|
if(GetAsyncKeyState('C') || GetAsyncKeyState('A'))
|
|
{
|
|
ypr_offset.yaw = rotate_size*frame_time;
|
|
poschanged=true;
|
|
}
|
|
|
|
if(GetAsyncKeyState('Z') || GetAsyncKeyState('D'))
|
|
{
|
|
ypr_offset.yaw = -rotate_size*frame_time;
|
|
poschanged=true;
|
|
}
|
|
|
|
if(GetAsyncKeyState(VK_SHIFT))
|
|
{
|
|
if(GetAsyncKeyState('S'))
|
|
{
|
|
ypr_offset.pitch = rotate_size*frame_time * pitch_size;
|
|
poschanged=true;
|
|
}
|
|
|
|
if(GetAsyncKeyState('W'))
|
|
{
|
|
ypr_offset.pitch = -rotate_size*frame_time * pitch_size;
|
|
poschanged=true;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if(GetAsyncKeyState('W'))
|
|
{
|
|
ypr_offset.range = -m_Speed * frame_time;
|
|
poschanged=true;
|
|
}
|
|
|
|
if(GetAsyncKeyState('S'))
|
|
{
|
|
ypr_offset.range = m_Speed * frame_time;
|
|
poschanged=true;
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
if(RBMode)
|
|
{
|
|
if(GetAsyncKeyState('W'))
|
|
{
|
|
TranslateForward(m_Speed*frame_time);
|
|
}
|
|
|
|
if(GetAsyncKeyState('S'))
|
|
{
|
|
TranslateForward(-m_Speed*frame_time);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if(GetAsyncKeyState(VK_SHIFT))
|
|
{
|
|
if(GetAsyncKeyState('W'))
|
|
{
|
|
m_Height += m_Speed * frame_time;
|
|
poschanged=true;
|
|
}
|
|
|
|
if(GetAsyncKeyState('S'))
|
|
{
|
|
m_Height -= m_Speed * frame_time;
|
|
poschanged=true;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
if(GetAsyncKeyState('W'))
|
|
{
|
|
offset.z = m_Speed*frame_time;
|
|
poschanged=true;
|
|
}
|
|
|
|
if(GetAsyncKeyState('S'))
|
|
{
|
|
offset.z = -m_Speed*frame_time;
|
|
poschanged=true;
|
|
}
|
|
}
|
|
}
|
|
if(GetAsyncKeyState('A'))
|
|
{
|
|
offset.x = m_Speed*frame_time;
|
|
poschanged=true;
|
|
}
|
|
|
|
if(GetAsyncKeyState('D'))
|
|
{
|
|
offset.x = -m_Speed*frame_time;
|
|
poschanged=true;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(GetAsyncKeyState('X'))
|
|
{
|
|
m_Height = default_height;
|
|
poschanged=true;
|
|
}
|
|
|
|
|
|
if(GetAsyncKeyState('E'))
|
|
{
|
|
ypr_offset.yaw = rotate_size*frame_time;
|
|
poschanged=true;
|
|
if(GetLookAtMode())
|
|
{
|
|
SetLookAtMode(false);
|
|
|
|
}
|
|
m_YawPitchRange.range=REALSMALLRANGE;
|
|
}
|
|
|
|
if(GetAsyncKeyState('Q'))
|
|
{
|
|
ypr_offset.yaw = -rotate_size*frame_time;
|
|
poschanged=true;
|
|
if(GetLookAtMode())
|
|
{
|
|
SetLookAtMode(false);
|
|
}
|
|
m_YawPitchRange.range=REALSMALLRANGE;
|
|
}
|
|
|
|
if(GetAsyncKeyState('R'))
|
|
{
|
|
ypr_offset.pitch = rotate_size*frame_time * pitch_size;
|
|
poschanged=true;
|
|
}
|
|
|
|
if(GetAsyncKeyState('F'))
|
|
{
|
|
ypr_offset.pitch = -rotate_size*frame_time * pitch_size;
|
|
poschanged=true;
|
|
}
|
|
|
|
|
|
|
|
Point3D new_point(m_LookAtPoint);
|
|
YawPitchRange new_ypr(m_YawPitchRange);
|
|
|
|
new_ypr.yaw+=ypr_offset.yaw;
|
|
new_ypr.pitch+=ypr_offset.pitch;
|
|
new_ypr.range+=ypr_offset.range;
|
|
|
|
|
|
while (new_ypr.yaw < 0)
|
|
{
|
|
new_ypr.yaw += Stuff::Two_Pi;
|
|
poschanged=true;
|
|
}
|
|
|
|
while (new_ypr.yaw > Stuff::Two_Pi)
|
|
{
|
|
new_ypr.yaw -= Stuff::Two_Pi;
|
|
poschanged=true;
|
|
}
|
|
|
|
|
|
|
|
if(poschanged)
|
|
{
|
|
Clamp(new_ypr.pitch,GetMinPitch(),GetMaxPitch());
|
|
Clamp(new_ypr.range,GetMinDistance(),GetMaxDistance());
|
|
|
|
Clamp(m_Height,GetMinHeight(),GetMaxHeight());
|
|
|
|
|
|
m_YawPitchRange = new_ypr;
|
|
|
|
LinearMatrix4D rotation(YawPitchRoll(m_YawPitchRange.yaw,0,0));
|
|
offset *= rotation;
|
|
new_point += offset;
|
|
|
|
if(!GetLookAtMode())
|
|
{
|
|
|
|
if(TerrainFollow && !RBMode)
|
|
new_point.y = ComputeTerrainElevation(new_point.x,new_point.z,0) + m_Height;
|
|
else
|
|
new_point.y = m_Height;
|
|
}
|
|
|
|
m_LookAtPoint=new_point;
|
|
|
|
}
|
|
|
|
Update();
|
|
|
|
return true;
|
|
}
|
|
|
|
void CameraController::SetLookAtMode(bool lmode)
|
|
{
|
|
if(LookAtMode && !lmode)
|
|
{
|
|
OldDistance=m_YawPitchRange.range;
|
|
m_YawPitchRange.range=REALSMALLRANGE;
|
|
TranslateForward(-OldDistance);
|
|
// LinearMatrix4D pos(),rot,trans;
|
|
|
|
|
|
LookAtMode=false;
|
|
}
|
|
else if(!LookAtMode && lmode)
|
|
{
|
|
LookAtMode=true;
|
|
m_YawPitchRange.range=OldDistance;
|
|
Point3D top_left,bottom_right;
|
|
|
|
if (m_ObjectManager.GetSelectionExtents(&top_left,&bottom_right))
|
|
{
|
|
Point3D center(top_left);
|
|
SetLookAt(center,false);
|
|
center += bottom_right;
|
|
center *= 0.5f;
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Stuff::Scalar CameraController::GetCameraYaw() const
|
|
{
|
|
Stuff::Scalar rv(m_YawPitchRange.yaw + Stuff::Pi);
|
|
|
|
while (rv > Stuff::Two_Pi)
|
|
{
|
|
rv -= Stuff::Two_Pi;
|
|
}
|
|
|
|
return (rv);
|
|
}
|
|
|
|
void CameraController::SetCameraYaw(Stuff::Scalar yaw)
|
|
{
|
|
Stuff::LinearMatrix4D old_matrix(m_LookAtPoint);
|
|
old_matrix.BuildLookAt(m_YawPitchRange);
|
|
|
|
m_YawPitchRange.yaw = yaw - Stuff::Pi;
|
|
while (m_YawPitchRange.yaw < 0)
|
|
{
|
|
m_YawPitchRange.yaw += Stuff::Two_Pi;
|
|
}
|
|
|
|
Stuff::LinearMatrix4D new_matrix(m_LookAtPoint);
|
|
new_matrix.BuildLookAt(m_YawPitchRange);
|
|
|
|
Stuff::Point3D old_pos(old_matrix);
|
|
Stuff::Point3D new_pos(new_matrix);
|
|
Stuff::Point3D delta;
|
|
delta.Subtract(old_pos,new_pos);
|
|
|
|
Stuff::Point3D pos(m_LookAtPoint);
|
|
pos += delta;
|
|
|
|
SetLookAt(pos,TerrainFollow);
|
|
}
|
|
|
|
void CameraController::TranslateForward(float dist)
|
|
{
|
|
Stuff::LinearMatrix4D mat(m_LookAtPoint),tmat(Point3D(0,0,dist));
|
|
mat.BuildLookAt(m_YawPitchRange);
|
|
|
|
tmat*=mat;
|
|
Stuff::Point3D new_pos(tmat);
|
|
SetLookAt(new_pos,false);
|
|
// if(!TerrainFollow)
|
|
{
|
|
m_Height=new_pos.y;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void CameraController::UpdateCamera()
|
|
{
|
|
|
|
Point3D top_left,bottom_right;
|
|
|
|
if(GetLookAtMode())
|
|
{
|
|
if (m_ObjectManager.GetSelectionExtents(&top_left,&bottom_right))
|
|
{
|
|
Point3D center(top_left);
|
|
center += bottom_right;
|
|
center *= 0.5f;
|
|
SetLookAt(center,false);
|
|
}
|
|
else
|
|
{
|
|
SetLookAtMode(false);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void CameraController::SaveToReg()
|
|
{
|
|
CString wintitle="Camera";
|
|
gos_SaveDataToRegistry((char *)(LPCSTR)(wintitle+"TerrainFollow"),&TerrainFollow,sizeof(TerrainFollow));
|
|
gos_SaveDataToRegistry((char *)(LPCSTR)(wintitle+"RevMouse"),&RevMouse,sizeof(RevMouse));
|
|
gos_SaveDataToRegistry((char *)(LPCSTR)(wintitle+"Speed"),&m_Speed,sizeof(m_Speed));
|
|
}
|
|
|
|
void CameraController::LoadFromReg()
|
|
{
|
|
CString wintitle="Camera";
|
|
unsigned long size;
|
|
CRect rct;
|
|
|
|
size=sizeof(TerrainFollow);
|
|
gos_LoadDataFromRegistry((char *)(LPCSTR)(wintitle+"TerrainFollow"),&TerrainFollow,&size);
|
|
size=sizeof(RevMouse);
|
|
gos_LoadDataFromRegistry((char *)(LPCSTR)(wintitle+"RevMouse"),&RevMouse,&size);
|
|
size=sizeof(m_Speed);
|
|
gos_LoadDataFromRegistry((char *)(LPCSTR)(wintitle+"Speed"),&m_Speed,&size);
|
|
|
|
}
|
|
|
|
/*
|
|
LinearMatrix4D &CameraController::GetCameraMat()
|
|
{
|
|
Stuff::LinearMatrix4D matrix(m_LookAtPoint);
|
|
matrix.BuildLookAt(m_YawPitchRange);
|
|
|
|
return matrix;
|
|
}
|
|
|
|
void CameraController::SetCameraMat(LinearMatrix4D &mat)
|
|
{
|
|
|
|
m_LookAtPoint=mat;
|
|
m_Height=m_LookAtPoint.y-ComputeTerrainElevation(m_LookAtPoint.x,m_LookAtPoint.z,0);
|
|
if(GetLookAtMode())
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
*/ |