Improved zooming movement in views (See details).
- Added smooth zoom animation upon mouse wheel movement for System and Galactic views, as for SectorView. - Made zooming commands be affected by shift keys, for faster movement, as for paning in SectorView. - Moved the "shift key factors" into "Pi::GetMoveSpeedShiftModifier()" for maintenability. - Coded value animation in a separate header (still for maintenability).master
parent
136fe236dd
commit
0507de86d0
|
@ -0,0 +1,40 @@
|
|||
#ifndef ANIMATION_H
|
||||
#define ANIMATION_H
|
||||
|
||||
/// Namespace contains simple functions for value animation.
|
||||
/// This is very simple implementation, which could be improved in the future.
|
||||
///\todo Many interesting things could be added, such as play/pause/reset animations, loop/mirror animation, interpolations, etc. But implementations exist, and if we need something tougher, we should have a look at them instead of reinventing the wheel.
|
||||
namespace Animation {
|
||||
|
||||
/// Animates linearily a value over time, given a speed.
|
||||
/// The speed must be "towards" the target value. Function will not go further than target.
|
||||
template<class T>
|
||||
inline void Linear(T & cur, const T target, const T speed, const float frameTime) {
|
||||
//static_assert(static_cast<T>(-1) <0); // Assert type is signed
|
||||
const T delta(target - cur);
|
||||
assert(delta * speed >=0);
|
||||
cur += pow(speed, frameTime);
|
||||
// Check for arrival
|
||||
const T newDelta(target - cur);
|
||||
if (newDelta*delta <0) cur = target;
|
||||
}
|
||||
|
||||
/// Animates a value with "approach style" over time (zooming).
|
||||
/// The speeds must be positive. Function will not go further than target.
|
||||
template<class T>
|
||||
inline void Approach(T & cur, const T target, float frameTime, const T deltaFactor=10, T targetFactor=1) {
|
||||
//static_assert(static_cast<T>(-1) <0); // Assert type is signed
|
||||
if (frameTime>1) frameTime = 1; // Clamp in case game hangs for a second
|
||||
assert(deltaFactor>0 && targetFactor >=0);
|
||||
const T delta(target - cur);
|
||||
if (delta == 0) return;
|
||||
if (delta<0) targetFactor=-targetFactor;
|
||||
cur += (delta*deltaFactor + target*targetFactor)*frameTime;
|
||||
// Check for arrival
|
||||
const T newDelta(target - cur);
|
||||
if (newDelta*delta <0) cur = target;
|
||||
}
|
||||
|
||||
} // namespace Animation
|
||||
|
||||
#endif // ANIMATION_H
|
|
@ -10,11 +10,15 @@
|
|||
#include "Galaxy.h"
|
||||
#include "Lang.h"
|
||||
#include "StringF.h"
|
||||
#include "Animation.h"
|
||||
#include "graphics/Material.h"
|
||||
#include "graphics/Renderer.h"
|
||||
#include "graphics/TextureBuilder.h"
|
||||
|
||||
using namespace Graphics;
|
||||
static const float ZOOM_IN_SPEED = 2;
|
||||
static const float ZOOM_OUT_SPEED = 1.f/ZOOM_IN_SPEED;
|
||||
static const float WHEEL_SENSITIVITY = .2f; // Should be a variable in user settings.
|
||||
|
||||
GalacticView::GalacticView() :
|
||||
m_quad(Graphics::TextureBuilder::UI("galaxy.bmp").CreateTexture(Gui::Screen::GetRenderer()))
|
||||
|
@ -22,6 +26,7 @@ GalacticView::GalacticView() :
|
|||
|
||||
SetTransparency(true);
|
||||
m_zoom = 1.0f;
|
||||
m_zoomTo = m_zoom;
|
||||
|
||||
m_zoomInButton = new Gui::ImageButton("icons/zoom_in.png");
|
||||
m_zoomInButton->SetToolTip(Lang::ZOOM_IN);
|
||||
|
@ -132,16 +137,18 @@ void GalacticView::Draw3D()
|
|||
|
||||
void GalacticView::Update()
|
||||
{
|
||||
const float frameTime = Pi::GetFrameTime();
|
||||
|
||||
if (m_zoomInButton->IsPressed()) m_zoom *= pow(4.0f, frameTime);
|
||||
if (m_zoomOutButton->IsPressed()) m_zoom *= pow(0.25f, frameTime);
|
||||
const float ft = Pi::GetFrameTime();
|
||||
|
||||
if (m_zoomInButton->IsPressed()) m_zoomTo *= pow(ZOOM_IN_SPEED * Pi::GetMoveSpeedShiftModifier(), ft);
|
||||
if (m_zoomOutButton->IsPressed()) m_zoomTo *= pow(ZOOM_OUT_SPEED / Pi::GetMoveSpeedShiftModifier(), ft);
|
||||
// XXX ugly hack checking for console here
|
||||
if (!Pi::IsConsoleActive()) {
|
||||
if (Pi::KeyState(SDLK_EQUALS)) m_zoom *= pow(4.0f, frameTime);
|
||||
if (Pi::KeyState(SDLK_MINUS)) m_zoom *= pow(0.25f, frameTime);
|
||||
if (Pi::KeyState(SDLK_EQUALS)) m_zoomTo *= pow(ZOOM_IN_SPEED * Pi::GetMoveSpeedShiftModifier(), ft);
|
||||
if (Pi::KeyState(SDLK_MINUS)) m_zoomTo *= pow(ZOOM_OUT_SPEED / Pi::GetMoveSpeedShiftModifier(), ft);
|
||||
}
|
||||
m_zoomTo = Clamp(m_zoomTo, 0.5f, 100.0f);
|
||||
m_zoom = Clamp(m_zoom, 0.5f, 100.0f);
|
||||
Animation::Approach(m_zoom, m_zoomTo, ft);
|
||||
|
||||
m_scaleReadout->SetText(stringf(Lang::INT_LY, formatarg("scale", int(0.5*Galaxy::GALAXY_RADIUS/m_zoom))));
|
||||
}
|
||||
|
@ -149,11 +156,10 @@ void GalacticView::Update()
|
|||
void GalacticView::MouseButtonDown(int button, int x, int y)
|
||||
{
|
||||
if (this == Pi::GetView()) {
|
||||
const float ft = Pi::GetFrameTime();
|
||||
if (Pi::MouseButtonState(SDL_BUTTON_WHEELDOWN))
|
||||
m_zoom *= pow(0.25f, ft);
|
||||
if (Pi::MouseButtonState(SDL_BUTTON_WHEELUP))
|
||||
m_zoom *= pow(4.0f, ft);
|
||||
if (Pi::MouseButtonState(SDL_BUTTON_WHEELDOWN))
|
||||
m_zoomTo *= ((ZOOM_OUT_SPEED-1) * WHEEL_SENSITIVITY+1) / Pi::GetMoveSpeedShiftModifier();
|
||||
else if (Pi::MouseButtonState(SDL_BUTTON_WHEELUP))
|
||||
m_zoomTo *= ((ZOOM_IN_SPEED-1) * WHEEL_SENSITIVITY+1) * Pi::GetMoveSpeedShiftModifier();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ private:
|
|||
Gui::ImageButton *m_zoomOutButton;
|
||||
Gui::Label *m_scaleReadout;
|
||||
Gui::LabelSet *m_labels;
|
||||
float m_zoom;
|
||||
float m_zoom, m_zoomTo;
|
||||
Gui::TexturedQuad m_quad;
|
||||
sigc::connection m_onMouseButtonDown;
|
||||
};
|
||||
|
|
|
@ -11,6 +11,7 @@ bin_PROGRAMS = pioneer modelviewer
|
|||
noinst_HEADERS = \
|
||||
Aabb.h \
|
||||
AmbientSounds.h \
|
||||
Animation.h \
|
||||
Background.h \
|
||||
BezierCurve.h \
|
||||
Body.h \
|
||||
|
|
|
@ -1488,3 +1488,10 @@ void Pi::SetMouseGrab(bool on)
|
|||
doingMouseGrab = false;
|
||||
}
|
||||
}
|
||||
|
||||
float Pi::GetMoveSpeedShiftModifier() {
|
||||
// Suggestion: make x1000 speed on pressing both keys?
|
||||
if (Pi::KeyState(SDLK_LSHIFT)) return 100.f;
|
||||
if (Pi::KeyState(SDLK_RSHIFT)) return 10.f;
|
||||
return 1;
|
||||
}
|
||||
|
|
3
src/Pi.h
3
src/Pi.h
|
@ -85,6 +85,9 @@ public:
|
|||
static void SetMouseYInvert(bool state) { mouseYInvert = state; }
|
||||
static bool IsMouseYInvert() { return mouseYInvert; }
|
||||
static int MouseButtonState(int button) { return mouseButton[button]; }
|
||||
/// Get the default speed modifier to apply to movement (scrolling, zooming...), depending on the "shift" keys.
|
||||
/// This is a default value only, centralized here to promote uniform user expericience.
|
||||
static float GetMoveSpeedShiftModifier();
|
||||
static void GetMouseMotion(int motion[2]) {
|
||||
memcpy(motion, mouseMotion, sizeof(int)*2);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,8 @@ using namespace Graphics;
|
|||
|
||||
#define INNER_RADIUS (Sector::SIZE*1.5f)
|
||||
#define OUTER_RADIUS (Sector::SIZE*3.0f)
|
||||
static const float ZOOM_SPEED = 10;
|
||||
static const float WHEEL_SENSITIVITY = .2f; // Should be a variable in user settings.
|
||||
|
||||
SectorView::SectorView()
|
||||
{
|
||||
|
@ -756,9 +758,7 @@ void SectorView::Update()
|
|||
// don't check raw keypresses if the search box is active
|
||||
// XXX ugly hack checking for Lua console here
|
||||
if (!m_searchBox->IsFocused() && !Pi::IsConsoleActive()) {
|
||||
float moveSpeed = 1.0;
|
||||
if (Pi::KeyState(SDLK_LSHIFT)) moveSpeed = 100.0;
|
||||
if (Pi::KeyState(SDLK_RSHIFT)) moveSpeed = 10.0;
|
||||
const float moveSpeed = Pi::GetMoveSpeedShiftModifier();
|
||||
|
||||
float move = moveSpeed*frameTime;
|
||||
if (Pi::KeyState(SDLK_LEFT) || Pi::KeyState(SDLK_RIGHT))
|
||||
|
@ -807,7 +807,7 @@ void SectorView::Update()
|
|||
else m_rotZ = m_rotZ + travelZ;
|
||||
|
||||
float diffZoom = m_zoomMovingTo - m_zoom;
|
||||
float travelZoom = diffZoom * 10.0f*frameTime;
|
||||
float travelZoom = diffZoom * ZOOM_SPEED*frameTime;
|
||||
if (fabs(travelZoom) > fabs(diffZoom)) m_zoom = m_zoomMovingTo;
|
||||
else m_zoom = m_zoom + travelZoom;
|
||||
}
|
||||
|
@ -854,11 +854,15 @@ void SectorView::ShowAll()
|
|||
void SectorView::MouseButtonDown(int button, int x, int y)
|
||||
{
|
||||
if (this == Pi::GetView()) {
|
||||
const float ft = Pi::GetFrameTime();
|
||||
if (Pi::MouseButtonState(SDL_BUTTON_WHEELDOWN))
|
||||
m_zoomMovingTo += 10.0*ft;
|
||||
if (Pi::MouseButtonState(SDL_BUTTON_WHEELUP))
|
||||
m_zoomMovingTo -= 10.0*ft;
|
||||
if (Pi::MouseButtonState(SDL_BUTTON_WHEELDOWN))
|
||||
m_zoomMovingTo += ZOOM_SPEED * WHEEL_SENSITIVITY * Pi::GetMoveSpeedShiftModifier();
|
||||
else if (Pi::MouseButtonState(SDL_BUTTON_WHEELUP))
|
||||
m_zoomMovingTo -= ZOOM_SPEED * WHEEL_SENSITIVITY * Pi::GetMoveSpeedShiftModifier();
|
||||
//const float ft = Pi::GetFrameTime() * Pi::GetMoveSpeedShiftModifier();
|
||||
//if (Pi::MouseButtonState(SDL_BUTTON_WHEELDOWN))
|
||||
// m_zoomMovingTo += 10.0*ft;
|
||||
//if (Pi::MouseButtonState(SDL_BUTTON_WHEELUP))
|
||||
// m_zoomMovingTo -= 10.0*ft;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,12 +8,18 @@
|
|||
#include "Player.h"
|
||||
#include "FloatComparison.h"
|
||||
#include "Game.h"
|
||||
#include "Animation.h"
|
||||
#include "graphics/Material.h"
|
||||
#include "graphics/Renderer.h"
|
||||
|
||||
using namespace Graphics;
|
||||
|
||||
const double SystemView::PICK_OBJECT_RECT_SIZE = 12.0;
|
||||
static const float MIN_ZOOM = 1e-30f; // Just to avoid having 0
|
||||
static const float MAX_ZOOM = 1e30f;
|
||||
static const float ZOOM_IN_SPEED = 2;
|
||||
static const float ZOOM_OUT_SPEED = 1.f/ZOOM_IN_SPEED;
|
||||
static const float WHEEL_SENSITIVITY = .2f; // Should be a variable in user settings.
|
||||
|
||||
SystemView::SystemView()
|
||||
{
|
||||
|
@ -93,6 +99,7 @@ void SystemView::ResetViewpoint()
|
|||
m_rot_z = 0;
|
||||
m_rot_x = 50;
|
||||
m_zoom = 1.0f/float(AU);
|
||||
m_zoomTo = m_zoom;
|
||||
m_timeStep = 1.0f;
|
||||
m_time = Pi::game->GetTime();
|
||||
}
|
||||
|
@ -327,11 +334,16 @@ void SystemView::Update()
|
|||
if (!Pi::IsConsoleActive()) {
|
||||
if (Pi::KeyState(SDLK_EQUALS) ||
|
||||
m_zoomInButton->IsPressed())
|
||||
m_zoom *= pow(4.0f, ft);
|
||||
m_zoomTo *= pow(ZOOM_IN_SPEED * Pi::GetMoveSpeedShiftModifier(), ft);
|
||||
if (Pi::KeyState(SDLK_MINUS) ||
|
||||
m_zoomOutButton->IsPressed())
|
||||
m_zoom *= pow(0.25f, ft);
|
||||
m_zoomTo *= pow(ZOOM_OUT_SPEED / Pi::GetMoveSpeedShiftModifier(), ft);
|
||||
}
|
||||
// TODO: add "true" lower/upper bounds to m_zoomTo / m_zoom
|
||||
m_zoomTo = Clamp(m_zoomTo, MIN_ZOOM, MAX_ZOOM);
|
||||
m_zoom = Clamp(m_zoom, MIN_ZOOM, MAX_ZOOM);
|
||||
Animation::Approach(m_zoom, m_zoomTo, ft);
|
||||
|
||||
if (Pi::MouseButtonState(SDL_BUTTON_RIGHT)) {
|
||||
int motion[2];
|
||||
Pi::GetMouseMotion(motion);
|
||||
|
@ -343,10 +355,9 @@ void SystemView::Update()
|
|||
void SystemView::MouseButtonDown(int button, int x, int y)
|
||||
{
|
||||
if (this == Pi::GetView()) {
|
||||
const float ft = Pi::GetFrameTime();
|
||||
if (Pi::MouseButtonState(SDL_BUTTON_WHEELDOWN))
|
||||
m_zoom *= pow(0.25f, ft);
|
||||
if (Pi::MouseButtonState(SDL_BUTTON_WHEELUP))
|
||||
m_zoom *= pow(4.0f, ft);
|
||||
if (Pi::MouseButtonState(SDL_BUTTON_WHEELDOWN))
|
||||
m_zoomTo *= ((ZOOM_OUT_SPEED-1) * WHEEL_SENSITIVITY+1) / Pi::GetMoveSpeedShiftModifier();
|
||||
else if (Pi::MouseButtonState(SDL_BUTTON_WHEELUP))
|
||||
m_zoomTo *= ((ZOOM_IN_SPEED-1) * WHEEL_SENSITIVITY+1) * Pi::GetMoveSpeedShiftModifier();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ private:
|
|||
RefCountedPtr<StarSystem> m_system;
|
||||
SBody *m_selectedObject;
|
||||
float m_rot_x, m_rot_z;
|
||||
float m_zoom;
|
||||
float m_zoom, m_zoomTo;
|
||||
double m_time;
|
||||
double m_timeStep;
|
||||
Gui::ImageButton *m_zoomInButton;
|
||||
|
|
Loading…
Reference in New Issue