Added smooth zooming and translation, and zoom in/out based on mouse position.
This commit is contained in:
@@ -69,7 +69,9 @@ protected:
|
||||
JGL::RenderTarget *canvas;
|
||||
float u_time;
|
||||
float u_scale = 2.f;
|
||||
float u_scale_goal = 2.f;
|
||||
Vector2 u_translation {0.4f, 0.f};
|
||||
Vector2 u_translation_goal {0.4f, 0.f};
|
||||
Color4 u_rgb_1 = Colors::Greens::Chartreuse;
|
||||
Color4 u_rgb_2 = Colors::Reds::LightCoral;
|
||||
Color4 u_rgb_3 = Colors::Yellow;
|
||||
@@ -97,6 +99,8 @@ public:
|
||||
using CmdArgs = std::vector<std::string>;
|
||||
void PositionCmd(const CmdArgs& args);
|
||||
|
||||
void ZoomCmd(const CmdArgs &args);
|
||||
|
||||
void ParseCmdLineMessage(const std::string& message);
|
||||
|
||||
/// Loads the Julia set program -- consists of a shader program and special widget for parameters.
|
||||
@@ -122,6 +126,8 @@ public:
|
||||
|
||||
void ZoomInTowards(const Vector2 &dir, float rate);
|
||||
|
||||
void ZoomOutTowards(const Vector2 &dir, float rate);
|
||||
|
||||
void ZoomOut(float rate);
|
||||
|
||||
/// Performs a logic update.
|
||||
@@ -151,11 +157,24 @@ public:
|
||||
void OnKeyUp(const ReWindow::KeyUpEvent &e) override;
|
||||
|
||||
void OnMouseWheel(const ReWindow::MouseWheelEvent &e) override {
|
||||
|
||||
// Test of zooming in toward the mouse.
|
||||
|
||||
auto mouse_pos_ipair = GetMouseCoordinates();
|
||||
auto resolution_ipair = GetSize();
|
||||
auto mouse_pos = Vector2(mouse_pos_ipair.x, mouse_pos_ipair.y);
|
||||
auto resolution = Vector2(resolution_ipair.x, resolution_ipair.y);
|
||||
|
||||
auto mp_norm = mouse_pos / resolution;
|
||||
mp_norm -= {.5f, .5f};
|
||||
mp_norm *= 2.f;
|
||||
mp_norm = {-mp_norm.x, mp_norm.y};
|
||||
|
||||
if (e.WheelMovement > 0) {
|
||||
ZoomOut(0.1);
|
||||
ZoomOutTowards(mp_norm, 0.1f);
|
||||
}
|
||||
if (e.WheelMovement < 0) {
|
||||
ZoomIn(0.1);
|
||||
ZoomInTowards(mp_norm, 0.1f);
|
||||
}
|
||||
}
|
||||
|
||||
|
2
main.cpp
2
main.cpp
@@ -5,6 +5,8 @@
|
||||
|
||||
#include <FractalApp.hpp>
|
||||
|
||||
// TODO: Parse command-line args.
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
ReWindow::Logger::Debug.EnableConsole(false);
|
||||
|
||||
|
@@ -39,6 +39,8 @@ void FractalInspectorApp::ReloadShader() {
|
||||
LoadShaders();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FractalInspectorApp::PositionCmd(const CmdArgs &args) {
|
||||
if (args.empty()) { // Output position + scale
|
||||
console->Log(std::format("Pos: {}, {}, Zoom: {}", u_translation.x, u_translation.y, u_scale));
|
||||
@@ -46,15 +48,21 @@ void FractalInspectorApp::PositionCmd(const CmdArgs &args) {
|
||||
}
|
||||
|
||||
if (args.size() >= 2) { // Set Position
|
||||
u_translation.x = std::stof(args[0]);
|
||||
u_translation.y = std::stof(args[1]);
|
||||
u_translation_goal.x = std::stof(args[0]);
|
||||
u_translation_goal.y = std::stof(args[1]);
|
||||
if (args.size() >= 3) { // Also set scale
|
||||
u_scale = std::stof(args[2]);
|
||||
u_scale_goal = std::stof(args[2]);
|
||||
}
|
||||
}
|
||||
console->Log(std::format("{}", args.size()));
|
||||
}
|
||||
|
||||
void FractalInspectorApp::ZoomCmd(const CmdArgs& args) {
|
||||
if (args.empty()) {
|
||||
console->Log(std::format("Zoom: {}", u_scale)); return;
|
||||
}
|
||||
}
|
||||
|
||||
void FractalInspectorApp::ParseCmdLineMessage(const std::string &message) {
|
||||
auto tokens = misc::string_expand(message);
|
||||
|
||||
@@ -68,13 +76,23 @@ void FractalInspectorApp::ParseCmdLineMessage(const std::string &message) {
|
||||
// Remove 0th element from tokens before passing to command delegates.
|
||||
tokens.erase(tokens.begin());
|
||||
|
||||
if (cmd == "r" || cmd == "reload") {
|
||||
ReloadShader();
|
||||
} else if (cmd == "pos") {
|
||||
return PositionCmd(tokens);
|
||||
} else {
|
||||
console->Log(std::format("No such command: {}", cmd), Colors::Red);
|
||||
if (misc::string_matches(cmd, {"r", "reload", "refresh"})) {
|
||||
return ReloadShader();
|
||||
}
|
||||
|
||||
if (misc::string_matches(cmd, {"zoom"})) {
|
||||
return ZoomCmd(tokens);
|
||||
}
|
||||
|
||||
if (misc::string_matches(cmd, {"pos", "position", "tp"})) {
|
||||
return PositionCmd(tokens);
|
||||
}
|
||||
|
||||
if (misc::string_matches(cmd, {"reset"})) {
|
||||
|
||||
}
|
||||
|
||||
console->Log(std::format("No such command: {}", cmd), Colors::Red);
|
||||
}
|
||||
|
||||
void FractalInspectorApp::LoadJulia() {
|
||||
@@ -352,7 +370,6 @@ bool FractalInspectorApp::Open() {
|
||||
JGL::Update(vec_size);
|
||||
|
||||
|
||||
|
||||
glClearColor(0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
@@ -364,7 +381,11 @@ bool FractalInspectorApp::Open() {
|
||||
scene = new JUI::Scene();
|
||||
CreateMenu();
|
||||
|
||||
canvas = new RenderTarget(vec_size);
|
||||
|
||||
SampleRate canvas_samples = SampleRate::X16;
|
||||
FilteringMode canvas_filtering = FilteringMode::MIPMAP_NEAREST;
|
||||
|
||||
canvas = new RenderTarget(vec_size, Colors::Transparent, false, canvas_samples, canvas_filtering);
|
||||
LoadShaders();
|
||||
|
||||
console->Log(std::format("OpenGL Renderer: {}", GetGLRenderer()));
|
||||
@@ -409,28 +430,46 @@ void FractalInspectorApp::ZoomIn(float rate) {
|
||||
|
||||
rate = rate * u_scale;
|
||||
|
||||
u_scale -= rate;
|
||||
u_scale_goal -= rate;
|
||||
// Stupid hack to make zoom originate at the center of the screen.
|
||||
u_translation -= Vector2(0.5f, 0.5f)*rate;
|
||||
u_translation_goal -= Vector2(0.5f, 0.5f)*rate;
|
||||
}
|
||||
|
||||
void FractalInspectorApp::ZoomInTowards(const Vector2& dir, float rate) {}
|
||||
void FractalInspectorApp::ZoomInTowards(const Vector2& dir, float rate) {
|
||||
rate = rate * u_scale;
|
||||
|
||||
u_scale_goal -= rate;
|
||||
|
||||
u_translation_goal -= Vector2(0.5f, 0.5f)*rate;
|
||||
|
||||
u_translation_goal += dir*rate;
|
||||
}
|
||||
|
||||
void FractalInspectorApp::ZoomOutTowards(const Vector2& dir, float rate) {
|
||||
rate = rate * u_scale;
|
||||
|
||||
u_scale_goal += rate;
|
||||
// Stupid hack to make zoom originate at the center of the screen.
|
||||
u_translation_goal += Vector2(0.5f, 0.5f)*rate;
|
||||
|
||||
u_translation_goal -= dir*rate;
|
||||
}
|
||||
|
||||
void FractalInspectorApp::ZoomOut(float rate) {
|
||||
|
||||
rate = rate * u_scale;
|
||||
|
||||
u_scale += rate;
|
||||
u_scale_goal += rate;
|
||||
// Stupid hack to make zoom originate at the center of the screen.
|
||||
u_translation += Vector2(0.5f, 0.5f)*rate;
|
||||
u_translation_goal += Vector2(0.5f, 0.5f)*rate;
|
||||
}
|
||||
|
||||
void FractalInspectorApp::Update(float elapsed) {
|
||||
scene->Update(elapsed);
|
||||
|
||||
if (IsKeyDown(Keys::F6)) {
|
||||
u_scale = 2.f;
|
||||
u_translation = {.4, 0};
|
||||
u_scale_goal = 2.f;
|
||||
u_translation_goal = {.4, 0};
|
||||
}
|
||||
|
||||
// TODO: Vary the rate appropriately.
|
||||
@@ -450,19 +489,25 @@ void FractalInspectorApp::Update(float elapsed) {
|
||||
|
||||
|
||||
if (IsKeyDown(Keys::DownArrow))
|
||||
u_translation.y += rate;
|
||||
u_translation_goal.y += rate;
|
||||
if (IsKeyDown(Keys::UpArrow))
|
||||
u_translation.y -= rate;
|
||||
u_translation_goal.y -= rate;
|
||||
|
||||
if (IsKeyDown(Keys::LeftArrow))
|
||||
u_translation.x += rate;
|
||||
u_translation_goal.x += rate;
|
||||
if (IsKeyDown(Keys::RightArrow))
|
||||
u_translation.x -= rate;
|
||||
u_translation_goal.x -= rate;
|
||||
|
||||
|
||||
u_time += elapsed;
|
||||
|
||||
u_julia_value = Vector2::Lerp(u_julia_value, u_julia_set, 0.001f);
|
||||
float lerp_rate = 0.1f;
|
||||
float julia_lerp_rate = 0.01f;
|
||||
|
||||
u_translation = Vector2::Lerp(u_translation, u_translation_goal, lerp_rate);
|
||||
u_scale = Math::Lerp(u_scale, u_scale_goal, lerp_rate);
|
||||
|
||||
u_julia_value = Vector2::Lerp(u_julia_value, u_julia_set, julia_lerp_rate);
|
||||
|
||||
UpdateShaderUniforms(elapsed);
|
||||
|
||||
@@ -576,7 +621,6 @@ void FractalInspectorApp::OnMouseButtonDown(const ReWindow::MouseButtonDownEvent
|
||||
|
||||
void FractalInspectorApp::OnMouseButtonUp(const ReWindow::MouseButtonUpEvent &e) {
|
||||
|
||||
|
||||
auto btn = ToJUIEnum(e.Button);
|
||||
|
||||
if (scene->ObserveMouseInput(btn, false))
|
||||
@@ -612,7 +656,7 @@ void FractalInspectorApp::OnMouseMove(const ReWindow::MouseMoveEvent &e) {
|
||||
|
||||
|
||||
if (panning)
|
||||
u_translation += pan_direction*pan_rate;
|
||||
u_translation_goal += pan_direction*pan_rate;
|
||||
|
||||
last = nmp;
|
||||
}
|
||||
|
Reference in New Issue
Block a user