/* -*-c++-*- */
/* osgEarth - Geospatial SDK for OpenSceneGraph
* Copyright 2018 Pelican Mapping
* http://osgearth.org
*
* osgEarth is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see
*/
#pragma once
#include
#include
#include
namespace osgEarth
{
using namespace osgEarth::Util;
/**
* GUI for the EarthManipulator settings
*/
struct CameraGUI : public ImGuiPanel
{
double _vfov, _ar, _zn, _zf;
EarthManipulator::Settings* _settings = nullptr;
Config _loadConf;
CameraGUI() :
ImGuiPanel("Camera"),
_vfov(30), _ar(1), _zn(1), _zf(100)
{
//nop
}
void load(const Config& conf) override
{
// remember, the settings come in one at a time so we have to use merge
_loadConf.merge(conf);
}
void save(Config& conf) override
{
if (_settings)
{
conf.set("SingleAxisRotation", _settings->singleAxisRotation());
conf.set("LockAzimuthWhilePanning", _settings->lockAzimuthWhilePanning());
conf.set("TerrainAvoidance", _settings->terrainAvoidanceEnabled());
conf.set("Throwing", _settings->throwingEnabled());
conf.set("ThrowingDecay", _settings->throwDecayRate());
conf.set("ZoomToMouse", _settings->zoomToMouse());
}
}
void draw(osg::RenderInfo& ri)
{
if (!isVisible())
return;
auto* man = dynamic_cast(view(ri)->getCameraManipulator());
if (man)
{
_settings = man->getSettings();
if (_settings && !_loadConf.empty())
{
_loadConf.get("SingleAxisRotation", _settings->singleAxisRotation());
_loadConf.get("LockAzimuthWhilePanning", _settings->lockAzimuthWhilePanning());
_loadConf.get("TerrainAvoidance", _settings->terrainAvoidanceEnabled());
_loadConf.get("Throwing", _settings->throwingEnabled());
_loadConf.get("ThrowingDecay", _settings->throwDecayRate());
_loadConf.get("ZoomToMouse", _settings->zoomToMouse());
_loadConf = {};
}
}
if (!_settings)
{
ImGui::TextColored(ImVec4(1, 0, 0, 1), "No earth manipulator");
ImGui::End();
return;
}
ImGui::Begin(name(), visible());
{
if (ImGuiLTable::Begin("CameraGUI"))
{
osg::Matrix pm = camera(ri)->getProjectionMatrix();
bool ortho = ProjectionMatrix::isOrtho(pm);
if (ImGuiLTable::Checkbox("Orthographic", &ortho))
{
if (ortho) {
ProjectionMatrix::getPerspective(pm, _vfov, _ar, _zn, _zf);
ProjectionMatrix::setOrtho(pm, -1, 1, -1, 1, _zn, _zf);
}
else {
ProjectionMatrix::setPerspective(pm, _vfov, _ar, _zn, _zf);
}
camera(ri)->setProjectionMatrix(pm);
}
if (_settings)
{
if (ImGuiLTable::Checkbox("Lock azimuth", &_settings->lockAzimuthWhilePanning()))
dirtySettings();
if (ImGuiLTable::Checkbox("Avoid terrain", &_settings->terrainAvoidanceEnabled()))
dirtySettings();
if (ImGuiLTable::Checkbox("Zoom to mouse", &_settings->zoomToMouse()))
dirtySettings();
if (ImGuiLTable::Checkbox("Throwing", &_settings->throwingEnabled()))
dirtySettings();
if (_settings->getThrowingEnabled())
{
if (ImGuiLTable::SliderDouble("Decay", &_settings->throwDecayRate(), 0.0f, 0.3f))
dirtySettings();
}
}
static float magnification_old = 1.0f, magnification_new = 1.0f;
static osg::Matrix ref_proj;
if (ImGuiLTable::SliderFloat("Magnification", &magnification_new, 1.0f, 25.0f))
{
auto proj = camera(ri)->getProjectionMatrix();
if (magnification_old == 1.0f ||
ref_proj.isIdentity() ||
ProjectionMatrix::isOrtho(proj) != ProjectionMatrix::isOrtho(ref_proj))
{
ref_proj = proj;
}
double rangeScale = 1.0 / magnification_new;
osg::Matrix new_proj;
if (ProjectionMatrix::isPerspective(ref_proj))
{
double vfov, ar, n, f;
ProjectionMatrix::getPerspective(ref_proj, vfov, ar, n, f);
ProjectionMatrix::setPerspective(new_proj, vfov * rangeScale, ar, n, f);
_settings->setOrthoTracksPerspective(true);
}
else
{
double L, R, B, T, N, F;
double M, H;
ProjectionMatrix::getOrtho(ref_proj, L, R, B, T, N, F);
M = B + (T - B) / 2;
H = (T - B) * rangeScale / 2;
B = M - H, T = M + H;
M = L + (R - L) / 2;
H = (R - L) * rangeScale / 2;
L = M - H, R = M + H;
ProjectionMatrix::setOrtho(new_proj, L, R, B, T, N, F);
_settings->setOrthoTracksPerspective(false);
}
camera(ri)->setProjectionMatrix(new_proj);
camera(ri)->setLODScale(rangeScale);
magnification_old = magnification_new;
}
if (!ortho)
{
static osg::CullSettings::ComputeNearFarMode old_near_far_mode = osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR;
static bool lock_far_clip = false;
static float locked_far_clip = 0.0f;
if (ImGuiLTable::Checkbox("Lock far clip", &lock_far_clip))
{
if (lock_far_clip)
{
old_near_far_mode = camera(ri)->getComputeNearFarMode();
double L, R, B, T, N, F;
camera(ri)->getProjectionMatrixAsFrustum(L, R, B, T, N, F);
locked_far_clip = F;
camera(ri)->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
camera(ri)->setProjectionMatrixAsFrustum(L, R, B, T, N, F);
}
else
{
camera(ri)->setComputeNearFarMode(old_near_far_mode);
}
}
}
auto& proj = camera(ri)->getProjectionMatrix();
if (ProjectionMatrix::isPerspective(proj))
{
ImGui::Separator();
double vfov, ar, n, f;
ProjectionMatrix::getPerspective(proj, vfov, ar, n, f);
ImGuiLTable::Text("VFOV", "%.2f", vfov);
ImGuiLTable::Text("Near", "%.2f", n);
ImGuiLTable::Text("Far", "%.1f", f);
}
ImGuiLTable::End();
}
}
ImGui::End();
}
};
}