Skip to content

Commit

Permalink
add mouse binding support for camera ctl
Browse files Browse the repository at this point in the history
  • Loading branch information
archibate committed Jul 22, 2023
1 parent 8eff93a commit 27134cd
Show file tree
Hide file tree
Showing 9 changed files with 503 additions and 80 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.10)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

project(opengltutor
Expand Down
13 changes: 7 additions & 6 deletions include/Game.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@

#include "check_gl.hpp"
#include <memory>
#include "InputCtl.hpp"

struct Game {
struct Private;
std::unique_ptr<Private> const m_private;
GLFWwindow *const m_window;

Game(GLFWwindow *window);
InputCtl m_inputCtl;
GLFWwindow *m_window;

Game();
~Game();

Game(Game &&) = delete;

static Game &get();
void set_window(GLFWwindow *window);
void initialize();
void render();
void cursor_pos_callback(double xpos, double ypos);
void mouse_button_callback(int button, int action, int mods);
void scroll_callback(double xoffset, double yoffset);
void key_callback(int key, int scancode, int action, int mods);
};
48 changes: 48 additions & 0 deletions include/InputCtl.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#pragma once

#include "check_gl.hpp"
#include <memory>
#include <glm/glm.hpp>
#include "KeyBinding.hpp"

struct InputCtl {
struct Private;
std::unique_ptr<Private> const m_private;

struct InputPreference {
float zoom_speed = 0.2f;
float orbit_speed = 1.0f;
float drift_speed = 1.0f;
float pan_speed = 1.0f;
MouseBinding orbit_binding = {Modifier::kNone, MouseButton::kLMB};
MouseBinding drift_binding = {Modifier::kCtrl, MouseButton::kLMB};
MouseBinding pan_binding = {Modifier::kShift, MouseButton::kLMB};
MouseBinding zoom_binding = {Modifier::kNone, MouseButton::kWheel};
MouseBinding hitchcock_binding = {Modifier::kShift, MouseButton::kWheel};
// Familiar binding for Blender and Zeno users:
/* MouseBinding orbit_binding = {Modifier::kNone, MouseButton::kMMB}; */
/* MouseBinding drift_binding = {Modifier::kCtrl, MouseButton::kMMB}; */
/* MouseBinding pan_binding = {Modifier::kShift, MouseButton::kMMB}; */
/* MouseBinding zoom_binding = {Modifier::kNone, MouseButton::kWheel}; */
/* MouseBinding hitchcock_binding = {Modifier::kShift, MouseButton::kWheel}; */
int zoom_axis = 1;
bool clamp_cursor = true;
} m_inputPref;

private:
void cursor_pos_callback(double xpos, double ypos);
void mouse_button_callback(int button, int action, int mods);
void scroll_callback(double xoffset, double yoffset);
void key_callback(int key, int scancode, int action, int mods);
void framebuffer_size_callback(int width, int height);

public:
InputCtl();
~InputCtl();
InputCtl(InputCtl &&) = delete;

void register_callbacks(GLFWwindow *window);

glm::mat4x4 get_view_matrix();
glm::mat4x4 get_projection_matrix();
};
91 changes: 91 additions & 0 deletions include/KeyBinding.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#pragma once

#include "check_gl.hpp"
#include <cmath>

enum class Modifier {
kNone,
kCtrl,
kShift,
kAlt,
};

enum class MouseButton {
kLMB,
kRMB,
kMMB,
kWheel,
kNone,
};

struct MouseBinding {
Modifier modifier = Modifier::kNone;
MouseButton mouseBtn = MouseButton::kLMB;

bool check_is_scrolled(GLFWwindow *window) {
bool modPressed = true;
bool shift = glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS;
bool ctrl = glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS;
bool alt = glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS;
auto mods = (shift ? GLFW_MOD_SHIFT : 0) | (ctrl ? GLFW_MOD_CONTROL : 0) | (alt ? GLFW_MOD_ALT : 0);
switch (modifier) {
case Modifier::kShift: modPressed = mods == GLFW_MOD_SHIFT; break;
case Modifier::kCtrl: modPressed = mods == GLFW_MOD_CONTROL; break;
case Modifier::kAlt: modPressed = mods == GLFW_MOD_ALT; break;
default: modPressed = mods == 0; break;
}
bool wheelScrolled = false;
switch (mouseBtn) {
case MouseButton::kWheel: wheelScrolled = true; break;
default: break;
}
return wheelScrolled && modPressed;
}

/* bool check_is_pressed(GLFWwindow *window, int button, int action, int mods) { */
/* bool modPressed = true; */
/* mods &= GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT; */
/* switch (modifier) { */
/* case Modifier::kShift: modPressed = mods == GLFW_MOD_SHIFT; break; */
/* case Modifier::kCtrl: modPressed = mods == GLFW_MOD_CONTROL; break; */
/* case Modifier::kAlt: modPressed = mods == GLFW_MOD_ALT; break; */
/* default: modPressed = mods == 0; break; */
/* } */
/* bool btnPressed = false; */
/* switch (mouseBtn) { */
/* case MouseButton::kNone: btnPressed = false; break; */
/* case MouseButton::kLMB: btnPressed = button == GLFW_MOUSE_BUTTON_LEFT; break; */
/* case MouseButton::kMMB: btnPressed = button == GLFW_MOUSE_BUTTON_MIDDLE; break; */
/* case MouseButton::kRMB: btnPressed = button == GLFW_MOUSE_BUTTON_RIGHT; break; */
/* default: break; */
/* } */
/* return btnPressed && modPressed && action == GLFW_PRESS; */
/* } */

bool check_is_pressed(GLFWwindow *window) {
bool modPressed = true;
bool shift = glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS;
bool ctrl = glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS;
bool alt = glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS;
auto mods = (shift ? GLFW_MOD_SHIFT : 0) | (ctrl ? GLFW_MOD_CONTROL : 0) | (alt ? GLFW_MOD_ALT : 0);
switch (modifier) {
case Modifier::kShift: modPressed = mods == GLFW_MOD_SHIFT; break;
case Modifier::kCtrl: modPressed = mods == GLFW_MOD_CONTROL; break;
case Modifier::kAlt: modPressed = mods == GLFW_MOD_ALT; break;
default: modPressed = mods == 0; break;
}
int button = GLFW_MOUSE_BUTTON_LEFT;
switch (mouseBtn) {
case MouseButton::kLMB: button = GLFW_MOUSE_BUTTON_LEFT; break;
case MouseButton::kMMB: button = GLFW_MOUSE_BUTTON_MIDDLE; break;
case MouseButton::kRMB: button = GLFW_MOUSE_BUTTON_RIGHT; break;
case MouseButton::kNone: return modPressed
&& glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) != GLFW_PRESS
&& glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_MIDDLE) != GLFW_PRESS
&& glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) != GLFW_PRESS
;
default: return false;
}
return modPressed && glfwGetMouseButton(window, button) == GLFW_PRESS;
}
};
74 changes: 74 additions & 0 deletions include/print.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <optional>
#include <variant>

/* namespace conutils { */

namespace _print_details {
template <class T, class = void>
struct _printer {
Expand Down Expand Up @@ -52,6 +54,42 @@ namespace _print_details {
using type = U;
};

template <class T, class U = void, class = void>
struct _enable_if_glmvec {
using not_type = U;
};

template <class T, class U>
struct _enable_if_glmvec<T, U, std::enable_if_t<
std::is_same_v<decltype(T()[0] * T()), T> &&
std::is_same_v<decltype(T() * T()[0]), T> &&
std::is_same_v<decltype(T().x + T()), T> &&
std::is_same_v<decltype(T().x), typename T::value_type> &&
std::is_same_v<decltype(T()[0]), typename T::value_type &> &&
std::is_same_v<decltype(T() == T()), bool> &&
std::is_same_v<decltype(T(T()[0])), T> &&
std::is_same_v<decltype(T().length()), typename T::length_type> &&
std::is_same_v<decltype(std::declval<typename T::bool_type>().x), bool>
>> {
using type = U;
};

template <class T, class U = void, class = void>
struct _enable_if_glmmat {
using not_type = U;
};

template <class T, class U>
struct _enable_if_glmmat<T, U, typename _enable_if_glmvec<typename T::col_type,
typename _enable_if_glmvec<typename T::row_type, std::enable_if_t<
std::is_same_v<decltype(T()[0] * T()), typename T::row_type> &&
std::is_same_v<decltype(T() * T()[0]), typename T::col_type> &&
std::is_same_v<decltype(T()[0][0] * T()), T> &&
std::is_same_v<decltype(T()[0][0]), typename T::value_type &>
>>::type>::type> {
using type = U;
};

template <class T, class U = void, class = void>
struct _enable_if_map {
using not_type = U;
Expand Down Expand Up @@ -188,6 +226,40 @@ namespace _print_details {
}
};

template <class T>
struct _printer<T, typename _enable_if_has_print<T, typename _enable_if_glmvec<T>::type>::not_type> {
static void print(std::ostream &os, T const &t) {
os << "{";
bool once = false;
for (typename T::length_type i = 0; i < t.length(); i++) {
if (once) {
os << ", ";
} else {
once = true;
}
_printer<_rmcvref_t<typename T::value_type>>::print(os, t[i]);
}
os << "}";
}
};

template <class T>
struct _printer<T, typename _enable_if_has_print<T, typename _enable_if_glmmat<T>::type>::not_type> {
static void print(std::ostream &os, T const &t) {
os << "{";
bool once = false;
for (typename T::length_type i = 0; i < t.length(); i++) {
if (once) {
os << ",\n ";
} else {
once = true;
}
_printer<_rmcvref_t<typename T::col_type>>::print(os, t[i]);
}
os << "}";
}
};

template <class T>
struct _printer<T, typename _enable_if_has_print<T, typename _enable_if_map<T>::type>::not_type> {
static void print(std::ostream &os, T const &t) {
Expand Down Expand Up @@ -370,3 +442,5 @@ using _print_details::is_printable;
//
// map<string, optional<int>> m = {{"hello", 42}, {"world", nullopt}};
// print(m); // {"hello": 42, "world": nullopt}

/* } */
83 changes: 31 additions & 52 deletions src/Game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,31 @@
#include <glm/ext.hpp>
#include "OBJ.hpp"

struct Game::Private {
struct Game::Private { // P-IMPL pattern
glm::mat4x4 viewMat;
glm::mat4x4 projMat;

OBJ monkey;
};

Game::Game(GLFWwindow *window) : m_private(new Private), m_window(window) {
glfwSetWindowUserPointer(window, this);
}
Game::Game() : m_private(std::make_unique<Private>()) {}

Game::~Game() = default;

Game &Game::get() {
static Game game; // singleton
return game;
}

void Game::set_window(GLFWwindow *window) {
m_window = window;
glfwSetWindowUserPointer(window, this);
m_inputCtl.register_callbacks(window);
}

void Game::initialize() {
m_private->monkey.load_obj("/home/bate/Codes/opengltutor/assets/monkey.obj");
/* m_private->monkey.load_obj("/home/bate/Codes/opengltutor/assets/monkey.obj"); */
m_private->monkey.load_obj("/home/bate/Codes/opengltutor/assets/cube.obj");
CHECK_GL(glEnable(GL_DEPTH_TEST));
CHECK_GL(glEnable(GL_MULTISAMPLE));
CHECK_GL(glEnable(GL_BLEND));
Expand All @@ -35,59 +48,25 @@ void Game::render() {

CHECK_GL(glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT));

glm::mat4x4 projection = glm::perspective(glm::radians(40.0f), (float)width / height, 0.01f, 100.0f);
/* projection = glm::ortho(-2.0f, 2.0f, -2.0f, 2.0f, 0.0f, 100.0f); */
/* projection = glm::frustum(-0.005f, 0.005f, -0.005f, 0.005f, 0.01f, 100.0f); */
auto projection = m_inputCtl.get_projection_matrix();

CHECK_GL(glMatrixMode(GL_PROJECTION));
CHECK_GL(glLoadMatrixf(glm::value_ptr(projection)));

glm::vec3 eye(0, 0, 5);
glm::vec3 center(0, 0, 0);
glm::vec3 up(0, 1, 0);
glm::mat4x4 view = glm::lookAt(eye, center, up);


/* glm::vec3 eye(0, 0, 5); */
/* glm::vec3 center(0, 0, 0); */
/* glm::vec3 up(0, 1, 0); */
/* glm::mat4x4 view = glm::lookAt(eye, center, up); */
auto view = m_inputCtl.get_view_matrix();

static float angle = 0.0f;
glm::mat4x4 model(1.0f);
model = glm::rotate(model, glm::radians(angle), glm::vec3(0.0f, 1.0f, 0.0f));
model = glm::translate(model, glm::vec3(0.0f, 0.0f, 0.0f));
angle += 0.5f;

/* model = glm::rotate(model, glm::radians(angle), glm::vec3(0.0f, 1.0f, 0.0f)); */
/* model = glm::translate(model, glm::vec3(0.0f, 0.12f * glm::sin(glm::radians(angle) * 2.718f), 0.0f)); */
/* angle += 0.5f; */
CHECK_GL(glMatrixMode(GL_MODELVIEW));
CHECK_GL(glLoadMatrixf(glm::value_ptr(view * model)));

m_private->monkey.draw_obj();
}

void Game::cursor_pos_callback(double xpos, double ypos) {
int width, height;
glfwGetWindowSize(m_window, &width, &height);

float x = (float)(2 * xpos / width - 1);
float y = (float)(2 * (height - ypos) / height - 1);

if (glfwGetMouseButton(m_window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) {
// TODO: when left mouse button is dragged
}
}

void Game::mouse_button_callback(int button, int action, int mods) {
double xpos, ypos;
glfwGetCursorPos(m_window, &xpos, &ypos);
int width, height;
glfwGetWindowSize(m_window, &width, &height);

float x = (float)(2 * xpos / width - 1);
float y = (float)(2 * (height - ypos) / height - 1);

if ( button == GLFW_MOUSE_BUTTON_LEFT
&& action == GLFW_PRESS
) {
// TODO: when left mouse button is pressed
}
}

void Game::scroll_callback(double xoffset, double yoffset) {
}

void Game::key_callback(int key, int scancode, int action, int mods) {
}
Loading

0 comments on commit 27134cd

Please sign in to comment.