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
Sukender 2012-04-10 18:06:48 +02:00
parent 136fe236dd
commit 0507de86d0
9 changed files with 101 additions and 29 deletions

40
src/Animation.h Normal file
View File

@ -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

View File

@ -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();
}
}

View File

@ -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;
};

View File

@ -11,6 +11,7 @@ bin_PROGRAMS = pioneer modelviewer
noinst_HEADERS = \
Aabb.h \
AmbientSounds.h \
Animation.h \
Background.h \
BezierCurve.h \
Body.h \

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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;