From: <de...@us...> - 2004-04-03 22:28:55
|
Update of /cvsroot/csp/APPLICATIONS/CSPSim/Source/Views In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23816 Added Files: View.cpp CameraKinematics.cpp CameraAgent.cpp Log Message: see CHANGES.current --- NEW FILE: View.cpp --- // Combat Simulator Project - FlightSim Demo // Copyright (C) 2004 The Combat Simulator Project // http://csp.sourceforge.net // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** * @file View.cpp * **/ #include "Views/View.h" #include "Views/CameraAgent.h" #include "VirtualBattlefield.h" #include "CSPSim.h" #include "DynamicObject.h" void View::updateBody(simdata::Vector3& ep,simdata::Vector3& lp,simdata::Vector3& up) { simdata::Vector3 object_up = m_ActiveObject->getUpDirection(); simdata::Vector3 object_dir = m_ActiveObject->getDirection(); simdata::Quat q = simdata::Quat(-m_CameraKinematics->getAngleZ(),object_up,-m_CameraKinematics->getAngleX(), object_dir^object_up,0.0,object_dir); simdata::Vector3 object_pos = m_ActiveObject->getGlobalPosition(); ep = object_pos + m_CameraKinematics->getDistance() * q.rotate(-object_dir); lp = object_pos; up = q.rotate(object_up); } void View::updateWorld(simdata::Vector3& ep,simdata::Vector3& lp,simdata::Vector3& up) { simdata::Quat q = simdata::Quat(-m_CameraKinematics->getAngleZ(),simdata::Vector3::ZAXIS,-m_CameraKinematics->getAngleX(), simdata::Vector3::XAXIS,0.0,simdata::Vector3::YAXIS); simdata::Vector3 object_pos = m_ActiveObject->getGlobalPosition(); ep = object_pos + m_CameraKinematics->getDistance() * q.rotate(-simdata::Vector3::YAXIS); lp = object_pos; up = q.rotate(simdata::Vector3::ZAXIS); } View::View(size_t vm): m_ViewMode(vm), m_InternalView(false), m_ActiveObject(CSPSim::theSim->getActiveObject()){ } void View::cull() { VirtualScene* scene = CSPSim::theSim->getScene(); if (scene && m_ActiveObject.valid()) { bool isNear = m_ActiveObject->getNearFlag(); if (isNear && !m_InternalView) { scene->setNearObject(m_ActiveObject, false); } else if (!isNear && m_InternalView) { scene->setNearObject(m_ActiveObject, true); } } } void InternalView::constrain() { float limit = simdata::PI_2; m_CameraKinematics->clampX(m_CameraKinematics->getAngleX(),-limit,limit); m_CameraKinematics->clampZ(m_CameraKinematics->getAngleZ(),-limit,limit); } void InternalView::update(simdata::Vector3& ep,simdata::Vector3& lp,simdata::Vector3& up,double dt) { constrain(); simdata::Vector3 object_up = m_ActiveObject->getUpDirection(); simdata::Vector3 object_dir = m_ActiveObject->getDirection(); simdata::Quat q = simdata::Quat(m_CameraKinematics->getAngleZ(),object_up,m_CameraKinematics->getAngleX(), object_dir^object_up,0.0,object_dir); simdata::Vector3 object_pos = m_ActiveObject->getGlobalPosition(); ep = object_pos + m_ActiveObject->getViewPoint(); lp = ep + m_CameraKinematics->getDistance() * q.rotate(object_dir); up = q.rotate(object_up); } void InternalView::activate() { m_CameraKinematics->reset(); } void InternalViewHist::update(simdata::Vector3& ep,simdata::Vector3& lp,simdata::Vector3& up,double dt) { const float c = 0.001; simdata::Vector3 displ = c*dt*m_ActiveObject->getVelocity(); static simdata::Vector3 prev_displ = displ; InternalView::update(ep,lp,up,dt); ep += 0.5*(prev_displ + displ); prev_displ = displ; } void ExternalViewBody::activate() { m_CameraKinematics->resetDistance(); } void ExternalViewBody::update(simdata::Vector3& ep,simdata::Vector3& lp,simdata::Vector3& up,double dt) { updateBody(ep,lp,up); } void ExternalViewWorld::activate() { m_CameraKinematics->resetDistance(); } void ExternalViewWorld::update(simdata::Vector3& ep,simdata::Vector3& lp,simdata::Vector3& up,double dt) { updateWorld(ep,lp,up); } void FlybyView::newFixedCamPos(SimObject* target) { simdata::Vector3 object_pos = target->getGlobalPosition(); DynamicObject* dynamic = dynamic_cast<DynamicObject*>(target); if (dynamic) { simdata::Vector3 up = dynamic->getUpDirection(); simdata::Vector3 object_dir = dynamic->getDirection(); //double speed_level = dynamic->getSpeed()/50.0; m_FixedCameraPosition = object_pos + 900.0* object_dir + ( 12.0 - (rand() % 5) ) * (object_dir^up) + ( 6.0 + (rand () % 3) ) * up; } else { m_FixedCameraPosition = object_pos + 100.0 * simdata::Vector3::ZAXIS + 100.0 * simdata::Vector3::XAXIS; } } void FlybyView::activate() { newFixedCamPos(m_ActiveObject.get()); } void FlybyView::update(simdata::Vector3& ep,simdata::Vector3& lp,simdata::Vector3& up,double dt) { lp = m_ActiveObject->getGlobalPosition(); ep = m_FixedCameraPosition; if ((lp - ep).length() > 900.0) newFixedCamPos(m_ActiveObject.get()); up = simdata::Vector3::ZAXIS; } void FlybyView::recalculate(simdata::Vector3& ep,simdata::Vector3& lp,simdata::Vector3& up,double dt) { VirtualScene* scene = CSPSim::theSim->getScene(); const simdata::Ref<TerrainObject> terrain = scene->getTerrain(); const float SAFETY = 2.0; TerrainObject::IntersectionHint camera_hint = 0; float h = SAFETY + terrain->getGroundElevation(ep.x(),ep.y(),camera_hint); float d = ep.z() - h; if (d<0) ep.z() -= d; } void SatelliteView::activate() { m_CameraKinematics->setAngleZ(0.0); m_CameraKinematics->setAngleX(0.5*simdata::PI); m_CameraKinematics->setDistance(500.0); } void SatelliteView::update(simdata::Vector3& ep,simdata::Vector3& lp,simdata::Vector3& up,double dt) { updateWorld(ep,lp,up); } PadlockView::PadlockView(size_t vm): View(vm), m_Padlock(m_ActiveObject) { m_InternalView = true; } void PadlockView::activate() { m_CameraKinematics->reset(); VirtualBattlefield* battlefield = CSPSim::theSim->getBattlefield(); m_Padlock = battlefield->getNextUnit(m_ActiveObject, -1, -1, -1); if (m_Padlock == m_ActiveObject) { m_Padlock = battlefield->getNextUnit(m_Padlock, -1, -1, -1); } if (m_Padlock != m_ActiveObject) { m_NeckTheta = m_CameraKinematics->getAngleX() - 0.5*simdata::PI; m_NeckPhi = m_CameraKinematics->getAngleZ(); } } void PadlockView::constrain(simdata::Vector3& ep,simdata::Vector3& lp,simdata::Vector3& up,double dt) { if (m_Padlock.valid()) { ep = m_ActiveObject->getGlobalPosition(); m_Attitude = m_ActiveObject->getAttitude(); ep += m_ActiveObject->getViewPoint(); simdata::Vector3 dir = (m_Padlock->getGlobalPosition() - ep).normalized(); dir = m_Attitude.invrotate(dir); float phi = atan2(-dir.x(), dir.y()); float theta = acos(dir.z()); float phi_max = 2.6 - std::max(0.0, 1.57 - 2.0*theta); if (phi > phi_max) { phi = phi_max; m_NeckLimit = true; } else if (phi < -phi_max) { phi = -phi_max; m_NeckLimit = true; } else { m_NeckLimit = false; } float motion = std::min(3.0*dt, 0.3); phi = m_NeckPhi * (1.0-motion) + phi * motion; m_psi = phi * std::max(0.0, std::min(1.0, 2.0*theta)); m_NeckTheta = theta; m_NeckPhi = phi; } } void PadlockView::update(simdata::Vector3& ep,simdata::Vector3& lp,simdata::Vector3& up,double dt) { if (m_Padlock.valid()) { constrain(ep,lp,up,dt); simdata::Vector3 dir(-sin(m_NeckTheta)*sin(m_NeckPhi), sin(m_NeckTheta)*cos(m_NeckPhi), cos(m_NeckTheta)); simdata::Vector3 d(sin(m_psi), -cos(m_psi), 0.0); up.set(d.x()*cos(m_NeckTheta), d.y()*cos(m_NeckTheta), sin(m_NeckTheta)); up = m_Attitude.rotate(up); float offset = std::max(0.0, std::min(0.4, 0.3*(abs(m_psi) - 1.57))); if (m_psi > 0.0) offset = -offset; ep += m_Attitude.rotate(offset * simdata::Vector3::XAXIS); dir = m_Attitude.rotate(dir); lp = ep + 100.0 * dir; } } View* ViewFactory::createView_1() const { return new InternalView(1); } View* ViewFactory::createView_2() const { return new ExternalViewBody(2); } View* ViewFactory::createView_3() const { return new ExternalViewWorld(3); } View* ViewFactory::createView_4() const { return new InternalViewHist(4); } View* ViewFactory::createView_7() const { return new SatelliteView(7); } View* ViewFactory::createView_8() const { return new FlybyView(8); } View* ViewFactory::createView_9() const { return new PadlockView(9); } void ViewFactory::attachAllView(CameraAgent* ca) const { ca->attach(1,createView_1()); ca->attach(2,createView_2()); ca->attach(3,createView_3()); ca->attach(4,createView_4()); ca->attach(7,createView_7()); ca->attach(8,createView_8()); ca->attach(9,createView_9()); } --- NEW FILE: CameraKinematics.cpp --- // Combat Simulator Project - FlightSim Demo // Copyright (C) 2004 The Combat Simulator Project // http://csp.sourceforge.net // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** * @file CameraKinematics.cpp * **/ #include <SimData/Math.h> #include "Views/CameraKinematics.h" #include "CSPSim.h" #include "DynamicObject.h" #include "VirtualScene.h" #include "Views/CameraCommand.h" void CameraKinematics::scale(double dt) { float scale_factor = 1.0 + m_ZoomRate * dt; if ((m_DistanceToObject > m_MinimumDistance && scale_factor < 1.0) || (m_DistanceToObject < m_AbsoluteMaximumDistance && scale_factor > 1.0) ) { m_DistanceToObject *= scale_factor; } m_DistanceToObject = simdata::clampTo<double>(m_DistanceToObject,m_MinimumDistance,m_AbsoluteMaximumDistance); } void CameraKinematics::update(double dt) { rotateAboutZ(dt); rotateAboutX(dt); scale(dt); } float CameraKinematics::smooth(double value, float min_value,float max_value) const { float epsilon = 0.1 * abs(max_value - min_value); float damping = std::min(value - min_value, max_value - value)/epsilon; if (damping > 0.0 && damping < 1.0) return damping; else return 1.0; } CameraKinematics::CameraKinematics(): // XXX: serialize those parameters m_BaseRate(simdata::toRadians(30.0)), m_DisplacementCoefficient(0.001), m_MinimumDistanceOffset(10.0), m_AbsoluteMaximumDistance(2000.0) { reset(); } void CameraKinematics::clampX(double& value,float min_value,float max_value, bool smooth_on) { if (smooth_on && m_PanRateX != 0.0) { m_PanRateX = simdata::sign(m_PanRateX)*smooth(value,min_value,max_value)*m_BaseRate; } value = simdata::clampTo<double>(value,min_value,max_value); } void CameraKinematics::clampZ(double& value,float min_value,float max_value, bool smooth_on) { if (smooth_on && m_PanRateZ != 0.0) { m_PanRateZ = simdata::sign(m_PanRateZ)*smooth(value,min_value,max_value)*m_BaseRate; } value = simdata::clampTo<double>(value,min_value,max_value); } void CameraKinematics::reset() { m_AngleRotX = 0.0; m_AngleRotZ = 0.0; m_PanRateX = 0.0; m_PanRateZ = 0.0; m_ZoomRate = 0.0; resetDistance(); } void CameraKinematics::resetDistance() { const simdata::Ref<DynamicObject> active_object = CSPSim::theSim->getActiveObject(); if (active_object.valid()) m_MinimumDistance = active_object->getModel()->getBoundingSphereRadius()+CSPSim::theSim->getScene()->getNearPlane(); else m_MinimumDistance = m_MinimumDistanceOffset; m_DistanceToObject = m_MinimumDistance + m_MinimumDistanceOffset; } void CameraKinematics::panLeft() { m_PanRateZ = m_BaseRate; } void CameraKinematics::panRight() { m_PanRateZ = -m_BaseRate; } void CameraKinematics::panLeftRightStop() { m_PanRateZ = 0.0; } void CameraKinematics::panUp() { m_PanRateX = m_BaseRate; } void CameraKinematics::panDown() { m_PanRateX = -m_BaseRate; } void CameraKinematics::panUpDownStop() { m_PanRateX = 0.0; } void CameraKinematics::zoomIn() { m_ZoomRate = -m_BaseRate; } void CameraKinematics::zoomOut() { m_ZoomRate = m_BaseRate; } void CameraKinematics::zoomStop() { m_ZoomRate = 0.0; } void CameraKinematics::displacement(int x, int y, int dx, int dy) { m_PanRateX = 0.0; m_PanRateZ = 0.0; m_AngleRotZ += dx * m_DisplacementCoefficient; m_AngleRotX += dy * m_DisplacementCoefficient; } void CameraKinematics::accept(CameraCommand* cm) { if (cm) { if (std::find(m_CameraCommandList.begin(),m_CameraCommandList.end(),cm) == m_CameraCommandList.end()) { m_CameraCommandList.push_back(cm); cm->setCameraKinematics(this); } cm->execute(); } } --- NEW FILE: CameraAgent.cpp --- // Combat Simulator Project - FlightSim Demo // Copyright (C) 2004 The Combat Simulator Project // http://csp.sourceforge.net // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. /** * @file CameraAgent.cpp * **/ #include <SimData/Math.h> #include "Views/CameraAgent.h" #include "CSPSim.h" #include "DynamicObject.h" #include "VirtualScene.h" #include "Views/CameraCommand.h" CameraAgent::CameraAgent(const ViewFactory& vf): m_ViewMode(0) { vf.attachAllView(this); notifyCameraKinematicsToViews(); } void CameraAgent::attach(size_t mode,View* vm){ m_ViewList[mode] = vm; } CameraAgent::~CameraAgent() { deleteViews(); } void CameraAgent::validate(double dt) { VirtualScene* scene = CSPSim::theSim->getScene(); const simdata::Ref<TerrainObject> terrain = scene->getTerrain(); simdata::Vector3 normal; double const SAFETY = 2.0; TerrainObject::IntersectionHint camera_hint = 0; float h = SAFETY + terrain->getGroundElevation(m_EyePoint.x(),m_EyePoint.y(),normal,camera_hint); if (m_EyePoint.z() <= h) { double alpha_2 = simdata::toRadians(scene->getViewAngle()/2.0); double near_dist = scene->getNearPlane(); double aspect = scene->getAspect(); simdata::Vector3 eye_look = m_LookPoint - m_EyePoint; simdata::Vector3 eye_look_unit = eye_look.normalized(); simdata::Vector3 up_vec_unit = m_UpVector.normalized(); double tan_alpha_2 = tan(alpha_2); simdata::Vector3 right_unit = eye_look_unit^up_vec_unit; double min_elev = 0.0; // iterate on the pyramide edges for (double i = -1.0; i <= 1.0; i += 2.0) for (double j = -1.0;j <= 1.0; j += 2.0) { simdata::Vector3 edge_vector = near_dist * (eye_look_unit + tan_alpha_2 * ( i * up_vec_unit + j * aspect * right_unit)); simdata::Vector3 edge = m_EyePoint + edge_vector; double edge_elev = edge.z()-(SAFETY+terrain->getGroundElevation(edge.x(),edge.y(),camera_hint)); if (min_elev > edge_elev) min_elev = edge_elev; } double dh = abs(h - m_LookPoint.z() - min_elev); double angle_x = asin(dh/m_CameraKinematics.getDistance()); if (abs(m_CameraKinematics.getAngleX()) < 0.5*simdata::PI) m_CameraKinematics.setAngleX(angle_x); else m_CameraKinematics.setAngleX(simdata::PI-angle_x); m_CameraKinematics.panUpDownStop(); m_ViewList[m_ViewMode]->recalculate(m_EyePoint,m_LookPoint,m_UpVector,dt); } } void CameraAgent::set(size_t vm,CameraCommand* ck) { if (m_ViewMode != vm) { ViewList::iterator view_it = m_ViewList.find(vm); if (view_it != m_ViewList.end()) { view_it->second->activate(); m_ViewMode = vm; } } m_CameraKinematics.accept(ck); } void CameraAgent::updateCamera(double dt) { ViewList::iterator view = m_ViewList.find(m_ViewMode); if (view != m_ViewList.end()) { m_CameraKinematics.update(dt); view->second->update(m_EyePoint,m_LookPoint,m_UpVector,dt); validate(dt); view->second->cull(); } } struct DestroyView { void operator()(std::pair<const size_t,View*>& vm) { delete vm.second; } }; void CameraAgent::deleteViews() { std::for_each(m_ViewList.begin(),m_ViewList.end(),DestroyView()); } class AcceptObject { simdata::Ref<DynamicObject> m_ActiveObject; public: AcceptObject(const simdata::Ref<DynamicObject> object):m_ActiveObject(object){} void operator()(std::pair<const size_t,View*>& vm) { vm.second->accept(m_ActiveObject); } }; void CameraAgent::notifyObjectToViews(simdata::Ref<DynamicObject> object) { std::for_each(m_ViewList.begin(),m_ViewList.end(),AcceptObject(object)); m_CameraKinematics.reset(); } class AcceptCameraKinematics { CameraKinematics* m_CameraKinematics; public: AcceptCameraKinematics(CameraKinematics* ck):m_CameraKinematics(ck) {} void operator()(std::pair<const size_t,View*>& vm) { vm.second->accept(m_CameraKinematics); } }; void CameraAgent::notifyCameraKinematicsToViews() { std::for_each(m_ViewList.begin(),m_ViewList.end(),AcceptCameraKinematics(&m_CameraKinematics)); } |