#include "stdafx.h" #include "cameracontroller.h" #include "ObjectManager.h" #include "GameInterface.h" #include "DrawInfo.h" #include "Refresher.h" #include #include #include 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()) { } } */