/* * Copyright (C) 2012 Open Source Robotics Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include #include "gazebo/rendering/ogre_gazebo.h" #include "gazebo/math/Pose.hh" #include "gazebo/common/Assert.hh" #include "gazebo/common/Console.hh" #include "gazebo/common/Events.hh" #include "gazebo/rendering/selection_buffer/SelectionBuffer.hh" #include "gazebo/rendering/RenderEngine.hh" #include "gazebo/rendering/WindowManager.hh" #include "gazebo/rendering/FPSViewController.hh" #include "gazebo/rendering/OrbitViewController.hh" #include "gazebo/rendering/OrthoViewController.hh" #include "gazebo/rendering/RenderTypes.hh" #include "gazebo/rendering/Scene.hh" #include "gazebo/rendering/UserCameraPrivate.hh" #include "gazebo/rendering/Conversions.hh" #include "gazebo/rendering/UserCamera.hh" using namespace gazebo; using namespace rendering; ////////////////////////////////////////////////// UserCamera::UserCamera(const std::string &_name, ScenePtr _scene, bool _stereoEnabled) : Camera(_name, _scene), dataPtr(new UserCameraPrivate) { this->dataPtr->orbitViewController = NULL; this->dataPtr->orthoViewController = NULL; this->dataPtr->fpsViewController = NULL; this->dataPtr->viewController = NULL; this->dataPtr->selectionBuffer = NULL; this->dataPtr->joyTwistControl = true; this->dataPtr->joystickButtonToggleLast = false; this->dataPtr->joyPoseControl = true; this->dataPtr->rightCamera = NULL; this->dataPtr->rightViewport = NULL; this->dataPtr->stereoEnabled = _stereoEnabled; // Set default UserCamera render rate to 120Hz when stereo rendering is // enabled. Otherwise use 60Hz. // Some padding is added for safety. this->SetRenderRate(_stereoEnabled ? 130.0 : 70.0); this->SetUseSDFPose(false); } ////////////////////////////////////////////////// UserCamera::~UserCamera() { delete this->dataPtr->orbitViewController; delete this->dataPtr->orthoViewController; delete this->dataPtr->fpsViewController; this->connections.clear(); delete this->dataPtr; this->dataPtr = NULL; } ////////////////////////////////////////////////// void UserCamera::Load(sdf::ElementPtr _sdf) { Camera::Load(_sdf); } ////////////////////////////////////////////////// void UserCamera::Load() { Camera::Load(); this->dataPtr->node = transport::NodePtr(new transport::Node()); this->dataPtr->node->Init(); this->dataPtr->joySubTwist = this->dataPtr->node->Subscribe("~/user_camera/joy_twist", &UserCamera::OnJoyTwist, this); this->dataPtr->joySubPose = this->dataPtr->node->Subscribe("~/user_camera/joy_pose", &UserCamera::OnJoyPose, this); this->dataPtr->posePub = this->dataPtr->node->Advertise("~/user_camera/pose", 1, 30.0); } ////////////////////////////////////////////////// void UserCamera::Init() { this->dataPtr->orbitViewController = new OrbitViewController( boost::dynamic_pointer_cast(shared_from_this())); this->dataPtr->orthoViewController = new OrthoViewController( boost::dynamic_pointer_cast(shared_from_this())); this->dataPtr->fpsViewController = new FPSViewController( boost::dynamic_pointer_cast(shared_from_this())); this->dataPtr->viewController = this->dataPtr->orbitViewController; Camera::Init(); // Don't yaw along variable axis, causes leaning this->camera->setFixedYawAxis(true, Ogre::Vector3::UNIT_Z); this->camera->setDirection(1, 0, 0); this->camera->setAutoAspectRatio(false); // Right camera if (this->dataPtr->stereoEnabled) { this->dataPtr->rightCamera = this->scene->OgreSceneManager()->createCamera( "StereoUserRight"); this->dataPtr->rightCamera->pitch(Ogre::Degree(90)); // Don't yaw along variable axis, causes leaning this->dataPtr->rightCamera->setFixedYawAxis(true, Ogre::Vector3::UNIT_Z); this->dataPtr->rightCamera->setDirection(1, 0, 0); this->dataPtr->rightCamera->setAutoAspectRatio(false); this->sceneNode->attachObject(this->dataPtr->rightCamera); } this->SetHFOV(static_cast(IGN_DTOR(60))); // Careful when setting this value. // A far clip that is too close will have bad side effects on the // lighting. When using deferred shading, the light's use geometry that // trigger shaders. If the far clip is too close, the light's geometry is // clipped and wholes appear in the lighting. switch (RenderEngine::Instance()->GetRenderPathType()) { case RenderEngine::VERTEX: this->SetClipDist(0.1, 100); break; case RenderEngine::DEFERRED: case RenderEngine::FORWARD: this->SetClipDist(.1, 5000); break; default: this->SetClipDist(.1, 5000); break; } // Removing for now because the axis doesn't not move properly when the // window is resized /* this->axisNode = this->sceneNode->createChildSceneNode(this->name + "AxisNode"); const Ogre::Vector3 *corners = this->camera->getWorldSpaceCorners(); double width = corners[1].y - corners[0].y; this->axisNode->setPosition(corners[0].x + 0.01, corners[0].y + 0.0005, corners[0].z + 0.0005); axisNode->setScale(width * 0.05, width * 0.05, width * 0.05); axisNode->setInheritOrientation(false); Ogre::ManualObject *x = this->scene->OgreSceneManager()->createManualObject("MyXAxis"); x->begin("Gazebo/Red", Ogre::RenderOperation::OT_LINE_LIST); x->position(0, 0, 0); x->position(1, 0, 0); x->end(); x->setVisibilityFlags(GZ_VISIBILITY_GUI); Ogre::ManualObject *y = this->scene->OgreSceneManager()->createManualObject("MyYAxis"); y->begin("Gazebo/Green", Ogre::RenderOperation::OT_LINE_LIST); y->position(0, 0, 0); y->position(0, 1, 0); y->end(); y->setVisibilityFlags(GZ_VISIBILITY_GUI); Ogre::ManualObject *z = this->scene->OgreSceneManager()->createManualObject("MyZAxis"); z->begin("Gazebo/Blue", Ogre::RenderOperation::OT_LINE_LIST); z->position(0, 0, 0); z->position(0, 0, 1); z->end(); z->setVisibilityFlags(GZ_VISIBILITY_GUI); this->axisNode->attachObject(x); this->axisNode->attachObject(y); this->axisNode->attachObject(z); */ } ////////////////////////////////////////////////// void UserCamera::SetDefaultPose(const math::Pose &_pose) { this->dataPtr->defaultPose = _pose; this->SetWorldPose(_pose); } ////////////////////////////////////////////////// math::Pose UserCamera::DefaultPose() const { return this->dataPtr->defaultPose; } ////////////////////////////////////////////////// void UserCamera::SetWorldPose(const math::Pose &_pose) { Camera::SetWorldPose(_pose.Ign()); this->dataPtr->viewController->Init(); } ////////////////////////////////////////////////// void UserCamera::Update() { Camera::Update(); if (this->dataPtr->viewController) this->dataPtr->viewController->Update(); // publish camera pose this->dataPtr->posePub->Publish(msgs::Convert(this->WorldPose())); } ////////////////////////////////////////////////// void UserCamera::AnimationComplete() { this->dataPtr->viewController->Init(); } ////////////////////////////////////////////////// void UserCamera::PostRender() { Camera::PostRender(); } ////////////////////////////////////////////////// void UserCamera::Fini() { Camera::Fini(); } ////////////////////////////////////////////////// void UserCamera::HandleMouseEvent(const common::MouseEvent &_evt) { // DEBUG: this->dataPtr->selectionBuffer->ShowOverlay(true); // Don't update the camera if it's being animated. if (!this->animState) this->dataPtr->viewController->HandleMouseEvent(_evt); } ///////////////////////////////////////////////// void UserCamera::HandleKeyPressEvent(const std::string &_key) { this->dataPtr->viewController->HandleKeyPressEvent(_key); } ///////////////////////////////////////////////// void UserCamera::HandleKeyReleaseEvent(const std::string &_key) { this->dataPtr->viewController->HandleKeyReleaseEvent(_key); } ///////////////////////////////////////////////// bool UserCamera::IsCameraSetInWorldFile() { // note: this function is used in rendering::Heightmap // to check if user specified custom pose for the camera. // Otherwise, camera is raised based on heightmap height // automatically. return this->dataPtr->isCameraSetInWorldFile; } ////////////////////////////////////////////////// void UserCamera::SetUseSDFPose(bool _value) { // true if user specified custom pose for the camera. this->dataPtr->isCameraSetInWorldFile = _value; } ////////////////////////////////////////////////// void UserCamera::SetJoyTwistControl(bool _value) { this->dataPtr->joyTwistControl = _value; } ////////////////////////////////////////////////// void UserCamera::SetJoyPoseControl(bool _value) { this->dataPtr->joyPoseControl = _value; } ///////////////////////////////////////////////// bool UserCamera::AttachToVisualImpl(VisualPtr _visual, bool _inheritOrientation, double /*_minDist*/, double /*_maxDist*/) { Camera::AttachToVisualImpl(_visual, _inheritOrientation); if (_visual) { ignition::math::Pose3d origPose = this->WorldPose(); ignition::math::Angle yaw = _visual->GetWorldPose().rot.GetAsEuler().z; double zDiff = origPose.Pos().Z() - _visual->GetWorldPose().pos.z; ignition::math::Angle pitch = 0; if (fabs(zDiff) > 1e-3) { double dist = _visual->GetWorldPose().pos.Ign().Distance( this->WorldPose().Pos()); pitch = acos(zDiff/dist); } this->Yaw(yaw); this->Pitch(pitch); math::Box bb = _visual->GetBoundingBox(); math::Vector3 pos = bb.GetCenter(); pos.z = bb.max.z; this->SetViewController(OrbitViewController::GetTypeString(), pos); } else this->SetViewController(FPSViewController::GetTypeString()); return true; } ////////////////////////////////////////////////// bool UserCamera::TrackVisualImpl(VisualPtr _visual) { Camera::TrackVisualImpl(_visual); /*if (_visual) this->SetViewController(OrbitViewController::GetTypeString()); else this->SetViewController(FPSViewController::GetTypeString()); */ return true; } ////////////////////////////////////////////////// void UserCamera::SetViewController(const std::string &_type) { if (_type.empty() || this->dataPtr->viewController->GetTypeString() == _type) { return; } std::string vc = this->dataPtr->viewController->GetTypeString(); if (_type == OrbitViewController::GetTypeString()) { this->dataPtr->viewController = this->dataPtr->orbitViewController; this->dataPtr->viewController->Init(); this->dataPtr->prevViewControllerName = vc; } else if (_type == OrthoViewController::GetTypeString()) { this->dataPtr->viewController = this->dataPtr->orthoViewController; if (vc == "orbit") { this->dataPtr->viewController->Init( this->dataPtr->orbitViewController->GetFocalPoint(), this->dataPtr->orbitViewController->Yaw(), this->dataPtr->orbitViewController->Pitch()); } else this->dataPtr->viewController->Init(); this->dataPtr->prevViewControllerName = vc; } else if (_type == FPSViewController::GetTypeString()) { this->dataPtr->viewController = this->dataPtr->fpsViewController; this->dataPtr->viewController->Init(); this->dataPtr->prevViewControllerName = vc; } else { gzerr << "Invalid view controller type[" << _type << "]. " << "The view controller is not changed.\n"; } } ////////////////////////////////////////////////// void UserCamera::SetViewController(const std::string &_type, const math::Vector3 &_pos) { if (_type.empty() || this->dataPtr->viewController->GetTypeString() == _type) { return; } std::string vc = this->dataPtr->viewController->GetTypeString(); if (_type == OrbitViewController::GetTypeString()) this->dataPtr->viewController = this->dataPtr->orbitViewController; else if (_type == OrthoViewController::GetTypeString()) this->dataPtr->viewController = this->dataPtr->orthoViewController; else if (_type == FPSViewController::GetTypeString()) this->dataPtr->viewController = this->dataPtr->fpsViewController; else gzthrow("Invalid view controller type: " + _type); this->dataPtr->prevViewControllerName = vc; this->dataPtr->viewController->Init(_pos); } ////////////////////////////////////////////////// unsigned int UserCamera::GetImageWidth() const { return this->viewport->getActualWidth(); } ////////////////////////////////////////////////// unsigned int UserCamera::GetImageHeight() const { return this->viewport->getActualHeight(); } ////////////////////////////////////////////////// void UserCamera::Resize(unsigned int _w, unsigned int _h) { this->UpdateFOV(); this->dataPtr->viewController->Resize(_w, _h); // reload ogre compositors on window resize // otherwise some compositors can cause the client to crash Ogre::CompositorManager *compMgr = Ogre::CompositorManager::getSingletonPtr(); if (compMgr->hasCompositorChain(this->viewport)) { Ogre::CompositorChain *chain = compMgr->getCompositorChain(this->viewport); std::vector> compositors; Ogre::CompositorChain::InstanceIterator it = chain->getCompositors(); while (it.hasMoreElements()) { Ogre::CompositorInstance* nextCompInst = it.getNext(); compositors.push_back( std::make_pair(nextCompInst->getCompositor()->getName(), nextCompInst->getEnabled())); } compMgr->removeCompositorChain(this->viewport); for (unsigned int i = 0; i < compositors.size(); ++i) { compMgr->addCompositor(this->viewport, compositors[i].first); compMgr->setCompositorEnabled(this->viewport, compositors[i].first, compositors[i].second); } } } ////////////////////////////////////////////////// void UserCamera::UpdateFOV() { Camera::UpdateFOV(); if (this->dataPtr->stereoEnabled && this->viewport) { double ratio = static_cast(this->viewport->getActualWidth()) / static_cast(this->viewport->getActualHeight()); double hfov = this->sdf->Get("horizontal_fov"); double vfov = 2.0 * atan(tan(hfov / 2.0) / ratio); this->dataPtr->rightCamera->setAspectRatio(ratio); this->dataPtr->rightCamera->setFOVy(Ogre::Radian(vfov)); } } ////////////////////////////////////////////////// void UserCamera::SetViewportDimensions(float /*x_*/, float /*y_*/, float /*w_*/, float /*h_*/) { // this->viewport->setDimensions(x, y, w, h); } ////////////////////////////////////////////////// void UserCamera::ToggleShowVisual() { // this->visual->ToggleVisible(); } ////////////////////////////////////////////////// void UserCamera::ShowVisual(bool /*_s*/) { // this->visual->SetVisible(_s); } ////////////////////////////////////////////////// bool UserCamera::MoveToPosition(const math::Pose &_pose, double _time) { return Camera::MoveToPosition(_pose.Ign(), _time); } ////////////////////////////////////////////////// void UserCamera::MoveToVisual(const std::string &_name) { VisualPtr visualPtr = this->scene->GetVisual(_name); if (visualPtr) this->MoveToVisual(visualPtr); else gzerr << "MoveTo Unknown visual[" << _name << "]\n"; } ////////////////////////////////////////////////// void UserCamera::MoveToVisual(VisualPtr _visual) { if (!_visual) return; if (this->scene->OgreSceneManager()->hasAnimation("cameratrack")) { this->scene->OgreSceneManager()->destroyAnimation("cameratrack"); } ignition::math::Box box = _visual->GetBoundingBox().Ign(); ignition::math::Vector3d size = box.Size(); double maxSize = size.Max(); ignition::math::Vector3d start = this->WorldPose().Pos(); start.Correct(); ignition::math::Vector3d end = box.Center() + _visual->GetWorldPose().pos.Ign(); end.Correct(); ignition::math::Vector3d dir = end - start; dir.Correct(); dir.Normalize(); double dist = start.Distance(end) - maxSize; ignition::math::Vector3d mid = start + dir*(dist*.5); mid.Z(box.Center().Z() + box.Size().Z() + 2.0); dir = end - mid; dir.Correct(); dist = mid.Distance(end) - maxSize; double yawAngle = atan2(dir.Y(), dir.X()); double pitchAngle = atan2(-dir.Z(), sqrt(dir.X()*dir.X() + dir.Y()*dir.Y())); ignition::math::Quaterniond pitchYawOnly(0, pitchAngle, yawAngle); Ogre::Quaternion pitchYawFinal = Conversions::Convert(pitchYawOnly); dir.Normalize(); double scale = maxSize / tan((this->HFOV()/2.0).Radian()); end = mid + dir*(dist - scale); // dist = start.Distance(end); // double vel = 5.0; double time = 0.5; // dist / vel; Ogre::Animation *anim = this->scene->OgreSceneManager()->createAnimation("cameratrack", time); anim->setInterpolationMode(Ogre::Animation::IM_SPLINE); Ogre::NodeAnimationTrack *strack = anim->createNodeTrack(0, this->sceneNode); Ogre::TransformKeyFrame *key; key = strack->createNodeKeyFrame(0); key->setTranslate(Conversions::Convert(start)); key->setRotation(this->sceneNode->getOrientation()); /*key = strack->createNodeKeyFrame(time * 0.5); key->setTranslate(Ogre::Vector3(mid.x, mid.y, mid.z)); key->setRotation(pitchYawFinal); */ key = strack->createNodeKeyFrame(time); key->setTranslate(Conversions::Convert(end)); key->setRotation(pitchYawFinal); this->animState = this->scene->OgreSceneManager()->createAnimationState("cameratrack"); this->animState->setTimePosition(0); this->animState->setEnabled(true); this->animState->setLoop(false); this->prevAnimTime = common::Time::GetWallTime(); // this->dataPtr->orbitViewController->SetFocalPoint( // _visual->GetWorldPose().pos); this->onAnimationComplete = boost::bind(&UserCamera::OnMoveToVisualComplete, this); } ///////////////////////////////////////////////// void UserCamera::OnMoveToVisualComplete() { this->dataPtr->orbitViewController->SetDistance( this->WorldPose().Pos().Distance( this->dataPtr->orbitViewController->GetFocalPoint().Ign())); } ////////////////////////////////////////////////// void UserCamera::SetRenderTarget(Ogre::RenderTarget *_target) { Camera::SetRenderTarget(_target); // Setup stereo rendering viewports if (this->dataPtr->stereoEnabled) { float focalLength = 1.0; // Defaulting to 0.03m stereo baseline. Ogre::Vector2 offset(0.03f, 0.0f); this->camera->setFocalLength(focalLength); this->camera->setFrustumOffset(offset); this->dataPtr->rightCamera->setFocalLength(focalLength); this->dataPtr->rightCamera->setFrustumOffset(-offset); this->dataPtr->rightViewport = this->renderTarget->addViewport(this->dataPtr->rightCamera, 1); this->dataPtr->rightViewport->setBackgroundColour( Conversions::Convert(this->scene->BackgroundColor())); #if OGRE_VERSION_MAJOR > 1 || OGRE_VERSION_MINOR > 9 this->viewport->setDrawBuffer(Ogre::CBT_BACK_LEFT); this->dataPtr->rightViewport->setDrawBuffer(Ogre::CBT_BACK_RIGHT); #endif this->dataPtr->rightViewport->setVisibilityMask( GZ_VISIBILITY_ALL & ~GZ_VISIBILITY_SELECTABLE); } this->viewport->setVisibilityMask( GZ_VISIBILITY_ALL & ~GZ_VISIBILITY_SELECTABLE); this->initialized = true; this->dataPtr->selectionBuffer = new SelectionBuffer(this->scopedUniqueName, this->scene->OgreSceneManager(), this->renderTarget); } ////////////////////////////////////////////////// void UserCamera::EnableViewController(bool _value) const { this->dataPtr->viewController->SetEnabled(_value); } ////////////////////////////////////////////////// VisualPtr UserCamera::GetVisual(const math::Vector2i &_mousePos, std::string &_mod) { VisualPtr result; if (!this->dataPtr->selectionBuffer) return result; Ogre::Entity *entity = this->dataPtr->selectionBuffer->OnSelectionClick(_mousePos.x, _mousePos.y); _mod = ""; if (entity) { // Make sure we set the _mod only if we have found a selection object if (entity->getName().substr(0, 15) == "__SELECTION_OBJ" && !entity->getUserObjectBindings().getUserAny().isEmpty() && entity->getUserObjectBindings().getUserAny().getType() == typeid(std::string)) { try { _mod = Ogre::any_cast( entity->getUserObjectBindings().getUserAny()); } catch(Ogre::Exception &e) { gzerr << "Ogre Error:" << e.getFullDescription() << "\n"; gzthrow("Unable to get visual " + _mod); } } if (!entity->getUserObjectBindings().getUserAny().isEmpty()) { try { result = this->scene->GetVisual( Ogre::any_cast( entity->getUserObjectBindings().getUserAny())); } catch(Ogre::Exception &e) { gzerr << "Ogre Error:" << e.getFullDescription() << "\n"; gzthrow("Unable to get visual " + _mod); } } } return result; } ////////////////////////////////////////////////// void UserCamera::SetFocalPoint(const math::Vector3 &_pt) { this->dataPtr->orbitViewController->SetFocalPoint(_pt); } ////////////////////////////////////////////////// VisualPtr UserCamera::GetVisual(const math::Vector2i &_mousePos) const { VisualPtr result; Ogre::Entity *entity = this->dataPtr->selectionBuffer->OnSelectionClick(_mousePos.x, _mousePos.y); if (entity && !entity->getUserObjectBindings().getUserAny().isEmpty()) { result = this->scene->GetVisual( Ogre::any_cast( entity->getUserObjectBindings().getUserAny())); } return result; } ////////////////////////////////////////////////// std::string UserCamera::GetViewControllerTypeString() { GZ_ASSERT(this->dataPtr->viewController, "ViewController != NULL"); return this->dataPtr->viewController->GetTypeString(); } ////////////////////////////////////////////////// void UserCamera::OnJoyTwist(ConstJoystickPtr &_msg) { // Scaling factor applied to rotations. static ignition::math::Vector3d rpyFactor(0, 0.01, 0.05); // toggle using joystick to move camera if (this->dataPtr->joystickButtonToggleLast == false && _msg->buttons().size() == 2 && _msg->buttons(0) == 1) { this->dataPtr->joyTwistControl = !this->dataPtr->joyTwistControl; this->dataPtr->joystickButtonToggleLast = true; if (this->dataPtr->joyTwistControl) gzmsg << "Joystick camera viewpoint control active.\n"; else gzmsg << "Joystick camera viewpoint control deactivated.\n"; } else if (_msg->buttons().size() == 2 && _msg->buttons(0) == 0) { // detect button release this->dataPtr->joystickButtonToggleLast = false; } // This function was establish when integrating the space navigator // joystick. if (this->dataPtr->joyTwistControl && (_msg->has_translation() || _msg->has_rotation())) { ignition::math::Pose3d pose = this->WorldPose(); // Get the joystick XYZ if (_msg->has_translation()) { const double transRotRatio = 0.05; ignition::math::Vector3d trans = msgs::ConvertIgn(_msg->translation()) * transRotRatio; pose.Pos() = pose.Rot().RotateVector(trans) + pose.Pos(); } // Get the jostick RPY. We are disabling rotation around x. if (_msg->has_rotation()) { ignition::math::Vector3d rot = msgs::ConvertIgn(_msg->rotation()) * rpyFactor; pose.Rot().Euler(pose.Rot().Euler() + rot); } this->SetWorldPose(pose); } } ////////////////////////////////////////////////// void UserCamera::OnJoyPose(ConstPosePtr &_msg) { if (!this->dataPtr->joyPoseControl) return; if (_msg->has_position() && _msg->has_orientation()) { // Get the XYZ ignition::math::Pose3d pose(msgs::ConvertIgn(_msg->position()), msgs::ConvertIgn(_msg->orientation())); this->SetWorldPose(pose); } } ////////////////////////////////////////////////// void UserCamera::SetClipDist(float _near, float _far) { Camera::SetClipDist(_near, _far); // Update right camera, if it exists. if (this->dataPtr->stereoEnabled) { this->dataPtr->rightCamera->setNearClipDistance( this->camera->getNearClipDistance()); this->dataPtr->rightCamera->setFarClipDistance( this->camera->getFarClipDistance()); this->dataPtr->rightCamera->setRenderingDistance( this->camera->getRenderingDistance()); } } ////////////////////////////////////////////////// bool UserCamera::StereoEnabled() const { return this->dataPtr->stereoEnabled; } ////////////////////////////////////////////////// void UserCamera::EnableStereo(bool _enable) { #if OGRE_VERSION_MAJOR > 1 || OGRE_VERSION_MINOR > 9 if (this->dataPtr->rightViewport) { if (_enable) { this->dataPtr->rightViewport->setDrawBuffer(Ogre::CBT_BACK_RIGHT); this->dataPtr->rightViewport->setAutoUpdated(true); this->viewport->setDrawBuffer(Ogre::CBT_BACK_LEFT); } else { this->dataPtr->rightViewport->setAutoUpdated(false); this->dataPtr->rightViewport->setDrawBuffer(Ogre::CBT_BACK); this->viewport->setDrawBuffer(Ogre::CBT_BACK); } } else { gzwarn << "Tried to enable/disable stereo. " << "However, stereo is turned off via the gui.ini file.\n"; } #else gzwarn << "Tried to EnableStereo(" << _enable << "). However, Ogre version >= 1.10.0 is required.\n"; #endif } ///////////////////////////////////////////////// bool UserCamera::SetProjectionType(const std::string &_type) { if (_type == "orthographic") this->SetViewController("ortho"); else if (!this->dataPtr->prevViewControllerName.empty()) this->SetViewController(this->dataPtr->prevViewControllerName); return Camera::SetProjectionType(_type); }