Added camera!
- Can be translated locally or moved to a point in the world - Rotates locally around local x- and z-axis and around global y-axis. Added key checks to test camera movement. Added Quaternions (Inherits from CoordinatesVector<double,4>) with a view to handling the camera orientation. Added equality operators for CoordinatesVectors. Removed slow `glutGet()` calls. Added custom reshape callback as we now store the window parameters to avoid some `glutGet()` calls. Renamed `KeyStateManager` to `InputStatus` as it handles more than key states now. Mouse movement callback now captures the cursor, handles its re-centering and when the cursor enters the window far away from its last position. TODO : Consider limiting rotations for the camera (Prevents flipping the head around)
This commit is contained in:
parent
e79f88bb9b
commit
4a5b0f5829
11 changed files with 494 additions and 174 deletions
|
@ -19,8 +19,12 @@ add_executable(tests_opengl
|
||||||
src/DataHandling/Model3D.cpp
|
src/DataHandling/Model3D.cpp
|
||||||
src/DataHandling/Model3D.h
|
src/DataHandling/Model3D.h
|
||||||
src/Vectors.h
|
src/Vectors.h
|
||||||
src/KeyStateManager.cpp
|
src/InputStatus.cpp
|
||||||
src/KeyStateManager.h)
|
src/InputStatus.h
|
||||||
|
src/Camera.cpp
|
||||||
|
src/Camera.h
|
||||||
|
src/Quaternion.cpp
|
||||||
|
src/Quaternion.h)
|
||||||
|
|
||||||
target_link_directories(tests_opengl PRIVATE
|
target_link_directories(tests_opengl PRIVATE
|
||||||
src)
|
src)
|
||||||
|
|
14
README.md
14
README.md
|
@ -2,15 +2,23 @@
|
||||||
|
|
||||||
The goal of the course is to introduce us to the OpenGL render pipeline and how to use the library.
|
The goal of the course is to introduce us to the OpenGL render pipeline and how to use the library.
|
||||||
|
|
||||||
The code here was, in part, inspired by the code which was given as part of the course but could not run on windows.
|
The code here was, in part, inspired by the code which was given as part of the course but could not run elsewhere than Windows.
|
||||||
It is aimed to replace it and serve as a base for my own project as part of the course.
|
It is aimed to replace it and serve as a base for my own project as part of the course.
|
||||||
|
|
||||||
|
As this project evolves I am thinking more and more about making it a "complete" minimalist game-engine if I have the time.
|
||||||
|
|
||||||
## TODOs
|
## TODOs
|
||||||
|
|
||||||
- [ ] Camera movement
|
- [x] Camera movement
|
||||||
- [ ] Entities
|
- [ ] Entities
|
||||||
- [ ] Quaternion computations? Maybe use OpenGLMathematics
|
- [x] Quaternion computations? ~~Maybe use OpenGLMathematics~~ Ended up doing it from scratch.
|
||||||
|
|
||||||
|
### Possible expansions
|
||||||
|
|
||||||
- [ ] Loading other file types
|
- [ ] Loading other file types
|
||||||
|
- [ ] Asset manager
|
||||||
|
- [ ] Detect key press' edges ?
|
||||||
|
- [ ] Switch from GLUT to GLFW
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
|
|
70
src/Camera.cpp
Normal file
70
src/Camera.cpp
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
//
|
||||||
|
// Created by trotfunky on 19/10/2019.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Camera.h"
|
||||||
|
|
||||||
|
|
||||||
|
Camera::Camera(const Vec3d& eye_pos, const Vec3d& look_direction, const Vec3d& up_vector) :
|
||||||
|
eye(eye_pos),
|
||||||
|
gaze(look_direction),
|
||||||
|
gaze_up(up_vector)
|
||||||
|
{
|
||||||
|
// Normalize the gaze vectors as they form the base for the local coordinates
|
||||||
|
gaze.normalize();
|
||||||
|
gaze_up.normalize();
|
||||||
|
|
||||||
|
compute_base_change();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::translate(const Vec3d& translation)
|
||||||
|
{
|
||||||
|
eye = eye + translation * rotation_quaternion;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::rotate(const Vec3d& rotation)
|
||||||
|
{
|
||||||
|
Quaternion x_rotation{gaze*sin(rotation.x/2)};
|
||||||
|
x_rotation.w = cos(rotation.x/2);
|
||||||
|
x_rotation.normalize();
|
||||||
|
gaze_up = x_rotation * gaze_up;
|
||||||
|
|
||||||
|
Quaternion z_rotation{gaze.cross_product(gaze_up)*sin(rotation.z/2)};
|
||||||
|
z_rotation.w = cos(rotation.z/2);
|
||||||
|
z_rotation.normalize();
|
||||||
|
gaze = z_rotation * gaze;
|
||||||
|
gaze_up = z_rotation * gaze_up;
|
||||||
|
|
||||||
|
Quaternion y_rotation{0,sin(rotation.y),0,cos(rotation.y)};
|
||||||
|
y_rotation.normalize();
|
||||||
|
gaze = y_rotation * gaze;
|
||||||
|
gaze_up = y_rotation * gaze_up;
|
||||||
|
|
||||||
|
compute_base_change();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::look()
|
||||||
|
{
|
||||||
|
gluLookAt(eye.x,eye.y,eye.z,
|
||||||
|
eye.x+gaze.x,eye.y+gaze.y,eye.z+gaze.z,
|
||||||
|
gaze_up.x,gaze_up.y,gaze_up.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::set_position(const Vec3d& eye_pos)
|
||||||
|
{
|
||||||
|
gaze = eye_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::compute_base_change()
|
||||||
|
{
|
||||||
|
// Third vector of the base, should already be normalized
|
||||||
|
Vec3d gaze_normal = gaze.cross_product(gaze_up);
|
||||||
|
|
||||||
|
double quaternion_w = std::sqrt(1 + gaze.x + gaze_up.y + gaze_normal.z) / 2;
|
||||||
|
|
||||||
|
rotation_quaternion = {(gaze_normal.y - gaze_up.z)/(4*quaternion_w),
|
||||||
|
(gaze.z - gaze_normal.x)/(4*quaternion_w),
|
||||||
|
(gaze_up.x - gaze.y)/(4*quaternion_w),
|
||||||
|
quaternion_w};
|
||||||
|
rotation_quaternion.normalize();
|
||||||
|
}
|
44
src/Camera.h
Normal file
44
src/Camera.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
//
|
||||||
|
// Created by trotfunky on 19/10/2019.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef TESTS_OPENGL_CAMERA_H
|
||||||
|
#define TESTS_OPENGL_CAMERA_H
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <GL/glu.h>
|
||||||
|
|
||||||
|
#include "Quaternion.h"
|
||||||
|
#include "Vectors.h"
|
||||||
|
|
||||||
|
class Camera {
|
||||||
|
public:
|
||||||
|
Camera(const Vec3d& eye_pos,const Vec3d& look_direction,const Vec3d& up_vector);
|
||||||
|
|
||||||
|
/// Translates the camera relative to its current position and look direction.
|
||||||
|
/// \param translation Translation where x is pointing in the direction of vision.
|
||||||
|
void translate(const Vec3d& translation);
|
||||||
|
/// Rotates the gaze around its local x and z but around global y, relatively to the current orientation.
|
||||||
|
/// This is to provide a coherent movement in regards to mouse movement.
|
||||||
|
/// \param rotation Angles are radians to rotate about each axis.
|
||||||
|
void rotate(const Vec3d& rotation);
|
||||||
|
|
||||||
|
/// Calls the gluLookAt function for the camera.
|
||||||
|
void look();
|
||||||
|
|
||||||
|
void set_position(const Vec3d& eye_pos);
|
||||||
|
private:
|
||||||
|
Vec3d eye;
|
||||||
|
Vec3d gaze;
|
||||||
|
Vec3d gaze_up;
|
||||||
|
|
||||||
|
/// Quaternion from the world coordinates to the local coordinates
|
||||||
|
Quaternion rotation_quaternion;
|
||||||
|
|
||||||
|
/// Compute rotation quaternion from the global coordinates to the local coordinates.
|
||||||
|
/// As per https://math.stackexchange.com/questions/2122668/calculate-orientation-quaternion-given-two-axes-of-a-coordinate-system
|
||||||
|
void compute_base_change();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //TESTS_OPENGL_CAMERA_H
|
165
src/InputStatus.cpp
Normal file
165
src/InputStatus.cpp
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
//
|
||||||
|
// Created by trotfunky on 07/10/2019.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "InputStatus.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// Initialize static members
|
||||||
|
|
||||||
|
Vec2i InputStatus::window_center;
|
||||||
|
Vec2f InputStatus::mouse_sensitivity{100, 100};
|
||||||
|
|
||||||
|
std::map<unsigned char,bool> InputStatus::ascii_keys_status = {};
|
||||||
|
std::map<int,bool> InputStatus::special_keys_status = {};
|
||||||
|
std::map<int,bool> InputStatus::mouse_button_status = {};
|
||||||
|
|
||||||
|
Vec2i InputStatus::current_mouse_delta;
|
||||||
|
Vec2i InputStatus::last_mouse_delta;
|
||||||
|
Vec2i InputStatus::last_mouse_position;
|
||||||
|
|
||||||
|
void InputStatus::register_glut_callbacks()
|
||||||
|
{
|
||||||
|
glutKeyboardFunc(InputStatus::key_press);
|
||||||
|
glutKeyboardUpFunc(InputStatus::key_up);
|
||||||
|
glutSpecialFunc(InputStatus::special_key_press);
|
||||||
|
glutSpecialUpFunc(InputStatus::special_key_up);
|
||||||
|
|
||||||
|
glutMouseFunc(InputStatus::mouse_click);
|
||||||
|
glutPassiveMotionFunc(InputStatus::mouse_movement);
|
||||||
|
glutMotionFunc(InputStatus::mouse_movement);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================
|
||||||
|
// Keyboard
|
||||||
|
// ==================
|
||||||
|
|
||||||
|
bool InputStatus::is_key_pressed(unsigned char key)
|
||||||
|
{
|
||||||
|
if (ascii_keys_status.find(key) == ascii_keys_status.end())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ascii_keys_status.at(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InputStatus::is_special_key_pressed(int key)
|
||||||
|
{
|
||||||
|
if (special_keys_status.find(key) == special_keys_status.end())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return special_keys_status.at(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputStatus::key_press(unsigned char event_key, int mouse_x, int mouse_y)
|
||||||
|
{
|
||||||
|
update_key(event_key,true);
|
||||||
|
mouse_movement(mouse_x,mouse_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputStatus::key_up(unsigned char event_key, int mouse_x, int mouse_y)
|
||||||
|
{
|
||||||
|
update_key(event_key,false);
|
||||||
|
mouse_movement(mouse_x,mouse_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputStatus::special_key_press(int event_key, int mouse_x, int mouse_y)
|
||||||
|
{
|
||||||
|
update_special_key(event_key,true);
|
||||||
|
mouse_movement(mouse_x,mouse_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputStatus::special_key_up(int event_key, int mouse_x, int mouse_y)
|
||||||
|
{
|
||||||
|
update_special_key(event_key,false);
|
||||||
|
mouse_movement(mouse_x,mouse_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputStatus::update_key(unsigned char event_key, bool new_status)
|
||||||
|
{
|
||||||
|
if (ascii_keys_status.find(event_key) != ascii_keys_status.end())
|
||||||
|
{
|
||||||
|
ascii_keys_status.at(event_key) = new_status;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ascii_keys_status.insert({event_key,new_status});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputStatus::update_special_key(int event_key, bool new_status)
|
||||||
|
{
|
||||||
|
if (special_keys_status.find(event_key) != special_keys_status.end())
|
||||||
|
{
|
||||||
|
special_keys_status.at(event_key) = new_status;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
special_keys_status.insert({event_key,new_status});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================
|
||||||
|
// Mouse
|
||||||
|
// ==================
|
||||||
|
|
||||||
|
void InputStatus::mouse_movement(int mouse_x, int mouse_y)
|
||||||
|
{
|
||||||
|
Vec2i current_frame;
|
||||||
|
current_frame.x = mouse_x;
|
||||||
|
current_frame.y = mouse_y;
|
||||||
|
|
||||||
|
// Prevent counting the glutWarpPointer movement into account
|
||||||
|
if (current_frame != window_center)
|
||||||
|
{
|
||||||
|
Vec2i frame_delta = current_frame - last_mouse_position;
|
||||||
|
// Prevent jumping around when entering the window
|
||||||
|
if (frame_delta.magnitude() < window_center.magnitude()/10)
|
||||||
|
{
|
||||||
|
current_mouse_delta.x += frame_delta.x;
|
||||||
|
current_mouse_delta.y += frame_delta.y;
|
||||||
|
|
||||||
|
// Re-center mouse
|
||||||
|
glutWarpPointer(window_center.x, window_center.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
last_mouse_position = current_frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputStatus::mouse_click(int mouse_button, int button_state, int mouse_x, int mouse_y)
|
||||||
|
{
|
||||||
|
bool new_status = button_state == GLUT_DOWN;
|
||||||
|
|
||||||
|
if (mouse_button_status.find(mouse_button) != mouse_button_status.end())
|
||||||
|
{
|
||||||
|
mouse_button_status.at(mouse_button) = new_status;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mouse_button_status.insert({mouse_button,new_status});
|
||||||
|
}
|
||||||
|
mouse_movement(mouse_x,mouse_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InputStatus::is_mouse_button_pressed(int mouse_button)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (mouse_button_status.find(mouse_button) == mouse_button_status.end())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mouse_button_status.at(mouse_button);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Vec2i& InputStatus::get_mouse_delta(bool update)
|
||||||
|
{
|
||||||
|
if (update)
|
||||||
|
{
|
||||||
|
last_mouse_delta = current_mouse_delta;
|
||||||
|
current_mouse_delta.x = 0;
|
||||||
|
current_mouse_delta.y = 0;
|
||||||
|
}
|
||||||
|
return last_mouse_delta;
|
||||||
|
}
|
|
@ -2,8 +2,8 @@
|
||||||
// Created by trotfunky on 07/10/2019.
|
// Created by trotfunky on 07/10/2019.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef TESTS_OPENGL_KEYSTATEMANAGER_H
|
#ifndef TESTS_OPENGL_INPUTSTATUS_H
|
||||||
#define TESTS_OPENGL_KEYSTATEMANAGER_H
|
#define TESTS_OPENGL_INPUTSTATUS_H
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <GL/glut.h>
|
#include <GL/glut.h>
|
||||||
|
@ -13,9 +13,9 @@
|
||||||
|
|
||||||
/// Handles the key and mouse events from glut and keep their status up to date.
|
/// Handles the key and mouse events from glut and keep their status up to date.
|
||||||
/// "Static class"
|
/// "Static class"
|
||||||
class KeyStateManager {
|
class InputStatus {
|
||||||
public:
|
public:
|
||||||
KeyStateManager() = delete;
|
InputStatus() = delete;
|
||||||
|
|
||||||
static void register_glut_callbacks();
|
static void register_glut_callbacks();
|
||||||
|
|
||||||
|
@ -40,6 +40,9 @@ public:
|
||||||
/// Accumulates the movements of the mouse
|
/// Accumulates the movements of the mouse
|
||||||
static void mouse_movement(int mouse_x, int mouse_y);
|
static void mouse_movement(int mouse_x, int mouse_y);
|
||||||
|
|
||||||
|
static Vec2i window_center;
|
||||||
|
|
||||||
|
static Vec2f mouse_sensitivity;
|
||||||
private:
|
private:
|
||||||
// The maps are used to keep track of the keys which were pressed or released during runtime.
|
// The maps are used to keep track of the keys which were pressed or released during runtime.
|
||||||
static std::map<unsigned char,bool> ascii_keys_status;
|
static std::map<unsigned char,bool> ascii_keys_status;
|
||||||
|
@ -58,4 +61,4 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif //TESTS_OPENGL_KEYSTATEMANAGER_H
|
#endif //TESTS_OPENGL_INPUTSTATUS_H
|
|
@ -1,151 +0,0 @@
|
||||||
//
|
|
||||||
// Created by trotfunky on 07/10/2019.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "KeyStateManager.h"
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
// Initialize static members
|
|
||||||
|
|
||||||
std::map<unsigned char,bool> KeyStateManager::ascii_keys_status = {};
|
|
||||||
std::map<int,bool> KeyStateManager::special_keys_status = {};
|
|
||||||
std::map<int,bool> KeyStateManager::mouse_button_status = {};
|
|
||||||
|
|
||||||
Vec2i KeyStateManager::current_mouse_delta;
|
|
||||||
Vec2i KeyStateManager::last_mouse_delta;
|
|
||||||
Vec2i KeyStateManager::last_mouse_position;
|
|
||||||
|
|
||||||
void KeyStateManager::register_glut_callbacks()
|
|
||||||
{
|
|
||||||
glutKeyboardFunc(KeyStateManager::key_press);
|
|
||||||
glutKeyboardUpFunc(KeyStateManager::key_up);
|
|
||||||
glutSpecialFunc(KeyStateManager::special_key_press);
|
|
||||||
glutSpecialUpFunc(KeyStateManager::special_key_up);
|
|
||||||
|
|
||||||
glutMouseFunc(KeyStateManager::mouse_click);
|
|
||||||
glutPassiveMotionFunc(KeyStateManager::mouse_movement);
|
|
||||||
glutMotionFunc(KeyStateManager::mouse_movement);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================
|
|
||||||
// Keyboard
|
|
||||||
// ==================
|
|
||||||
|
|
||||||
bool KeyStateManager::is_key_pressed(unsigned char key)
|
|
||||||
{
|
|
||||||
if (ascii_keys_status.find(key) == ascii_keys_status.end())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return ascii_keys_status.at(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool KeyStateManager::is_special_key_pressed(int key)
|
|
||||||
{
|
|
||||||
if (special_keys_status.find(key) == special_keys_status.end())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return special_keys_status.at(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyStateManager::key_press(unsigned char event_key, int mouse_x, int mouse_y)
|
|
||||||
{
|
|
||||||
update_key(event_key,true);
|
|
||||||
mouse_movement(mouse_x,mouse_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyStateManager::key_up(unsigned char event_key, int mouse_x, int mouse_y)
|
|
||||||
{
|
|
||||||
update_key(event_key,false);
|
|
||||||
mouse_movement(mouse_x,mouse_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyStateManager::special_key_press(int event_key, int mouse_x, int mouse_y)
|
|
||||||
{
|
|
||||||
update_special_key(event_key,true);
|
|
||||||
mouse_movement(mouse_x,mouse_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyStateManager::special_key_up(int event_key, int mouse_x, int mouse_y)
|
|
||||||
{
|
|
||||||
update_special_key(event_key,false);
|
|
||||||
mouse_movement(mouse_x,mouse_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyStateManager::update_key(unsigned char event_key, bool new_status)
|
|
||||||
{
|
|
||||||
if (ascii_keys_status.find(event_key) != ascii_keys_status.end())
|
|
||||||
{
|
|
||||||
ascii_keys_status.at(event_key) = new_status;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ascii_keys_status.insert({event_key,new_status});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyStateManager::update_special_key(int event_key, bool new_status)
|
|
||||||
{
|
|
||||||
if (special_keys_status.find(event_key) != special_keys_status.end())
|
|
||||||
{
|
|
||||||
special_keys_status.at(event_key) = new_status;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
special_keys_status.insert({event_key,new_status});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================
|
|
||||||
// Mouse
|
|
||||||
// ==================
|
|
||||||
|
|
||||||
void KeyStateManager::mouse_movement(int mouse_x, int mouse_y)
|
|
||||||
{
|
|
||||||
Vec2i current_frame;
|
|
||||||
current_frame.x = mouse_x;
|
|
||||||
current_frame.y = mouse_y;
|
|
||||||
|
|
||||||
Vec2i frame_delta = current_frame - last_mouse_position;
|
|
||||||
current_mouse_delta.x += frame_delta.x;
|
|
||||||
current_mouse_delta.y += frame_delta.y;
|
|
||||||
|
|
||||||
last_mouse_position = current_frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyStateManager::mouse_click(int mouse_button, int button_state, int mouse_x, int mouse_y)
|
|
||||||
{
|
|
||||||
bool new_status = button_state == GLUT_DOWN;
|
|
||||||
|
|
||||||
if (mouse_button_status.find(mouse_button) != mouse_button_status.end())
|
|
||||||
{
|
|
||||||
mouse_button_status.at(mouse_button) = new_status;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mouse_button_status.insert({mouse_button,new_status});
|
|
||||||
}
|
|
||||||
mouse_movement(mouse_x,mouse_y);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool KeyStateManager::is_mouse_button_pressed(int mouse_button)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (mouse_button_status.find(mouse_button) == mouse_button_status.end())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return mouse_button_status.at(mouse_button);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Vec2i& KeyStateManager::get_mouse_delta(bool update)
|
|
||||||
{
|
|
||||||
if (update)
|
|
||||||
{
|
|
||||||
last_mouse_delta = current_mouse_delta;
|
|
||||||
current_mouse_delta.x = 0;
|
|
||||||
current_mouse_delta.y = 0;
|
|
||||||
}
|
|
||||||
return last_mouse_delta;
|
|
||||||
}
|
|
80
src/Quaternion.cpp
Normal file
80
src/Quaternion.cpp
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
//
|
||||||
|
// Created by trotfunky on 18/10/2019.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Quaternion.h"
|
||||||
|
|
||||||
|
|
||||||
|
Quaternion::Quaternion(double axis_x, double axis_y, double axis_z, double w_value) : CoordinatesVector<double,4>()
|
||||||
|
{
|
||||||
|
x = axis_x;
|
||||||
|
y = axis_y;
|
||||||
|
z = axis_z;
|
||||||
|
w = w_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Quaternion::Quaternion(const Quaternion& original) : x(coordinates[0]), y(coordinates[1]), z(coordinates[2]), w(coordinates[3])
|
||||||
|
{
|
||||||
|
std::copy(std::begin(original.coordinates),std::end(original.coordinates),std::begin(coordinates));
|
||||||
|
}
|
||||||
|
|
||||||
|
Quaternion::Quaternion(const CoordinatesVector<double, 4>& original)
|
||||||
|
{
|
||||||
|
if (this != &original)
|
||||||
|
{
|
||||||
|
std::copy(std::begin(original.coordinates),std::end(original.coordinates),std::begin(coordinates));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Quaternion::Quaternion(const CoordinatesVector<double, 3>& original)
|
||||||
|
{
|
||||||
|
std::copy(std::begin(original.coordinates),std::end(original.coordinates),std::begin(coordinates));
|
||||||
|
w = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Quaternion::operator Vec3d() const
|
||||||
|
{
|
||||||
|
Vec3d result;
|
||||||
|
std::copy(std::begin(coordinates),std::begin(coordinates)+3,std::begin(result.coordinates));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Quaternion Quaternion::inverse() const
|
||||||
|
{
|
||||||
|
Quaternion inverse = *this;
|
||||||
|
inverse.x *= -1;
|
||||||
|
inverse.y *= -1;
|
||||||
|
inverse.z *= -1;
|
||||||
|
return inverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
Quaternion Quaternion::operator*(const Quaternion& op) const
|
||||||
|
{
|
||||||
|
Quaternion result;
|
||||||
|
result.w = w*op.w - x*op.x - y*op.y - z*op.z;
|
||||||
|
result.x = w*op.x + x*op.w + y*op.z - z*op.y;
|
||||||
|
result.y = w*op.y - x*op.z + y*op.w + z*op.x;
|
||||||
|
result.z = w*op.z + x*op.y - y*op.x + z*op.w;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3d operator*(const Quaternion& rot, const Vec3d& op)
|
||||||
|
{
|
||||||
|
Quaternion originalPosition = op;
|
||||||
|
return static_cast<Vec3d>(rot * originalPosition * rot.inverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3d operator*(const Vec3d& op,const Quaternion& rot)
|
||||||
|
{
|
||||||
|
Quaternion originalPosition = op;
|
||||||
|
return static_cast<Vec3d>(rot.inverse() * originalPosition * rot);
|
||||||
|
}
|
||||||
|
|
||||||
|
Quaternion& Quaternion::operator=(const Quaternion& original)
|
||||||
|
{
|
||||||
|
if (this != &original)
|
||||||
|
{
|
||||||
|
std::copy(std::begin(original.coordinates),std::end(original.coordinates),std::begin(coordinates));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
39
src/Quaternion.h
Normal file
39
src/Quaternion.h
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
//
|
||||||
|
// Created by trotfunky on 18/10/2019.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef TESTS_OPENGL_QUATERNION_H
|
||||||
|
#define TESTS_OPENGL_QUATERNION_H
|
||||||
|
|
||||||
|
#include "Vectors.h"
|
||||||
|
|
||||||
|
struct Quaternion : CoordinatesVector<double,4>{
|
||||||
|
double& x = coordinates[0];
|
||||||
|
double& y = coordinates[1];
|
||||||
|
double& z = coordinates[2];
|
||||||
|
double& w = coordinates[3];
|
||||||
|
|
||||||
|
Quaternion() = default;
|
||||||
|
Quaternion(double axis_x, double axis_y, double axis_z, double w_value);
|
||||||
|
Quaternion(const Quaternion& original);
|
||||||
|
Quaternion(const CoordinatesVector<double,4>& original);
|
||||||
|
Quaternion(const CoordinatesVector<double,3>& original);
|
||||||
|
|
||||||
|
/// Returns the inverse of a *unit-quaternion*.
|
||||||
|
Quaternion inverse() const;
|
||||||
|
|
||||||
|
/// Quaterion multiplication. See also https://en.wikipedia.org/wiki/Quaternion#Hamilton_product
|
||||||
|
Quaternion operator*(const Quaternion& op) const;
|
||||||
|
|
||||||
|
/// Performs the rotation associated to the *unit-quaternion* on the Vec3 operand.
|
||||||
|
Vec3d friend operator*(const Quaternion& rot, const Vec3d& op);
|
||||||
|
Vec3d friend operator*(const Vec3d& op, const Quaternion& rot);
|
||||||
|
|
||||||
|
Quaternion& operator=(const Quaternion& original);
|
||||||
|
|
||||||
|
/// Cast operator
|
||||||
|
explicit operator Vec3d() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //TESTS_OPENGL_QUATERNION_H
|
|
@ -6,6 +6,7 @@
|
||||||
#define TESTS_OPENGL_VECTORS_H
|
#define TESTS_OPENGL_VECTORS_H
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
/// Group of coordinates with the input operator overloaded.
|
/// Group of coordinates with the input operator overloaded.
|
||||||
|
@ -99,6 +100,23 @@ struct CoordinatesVector
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool operator==(const CoordinatesVector<T,N>& op)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0;i<N;i++)
|
||||||
|
{
|
||||||
|
if (coordinates[i] != op.coordinates[i])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const CoordinatesVector<T,N>& op)
|
||||||
|
{
|
||||||
|
return !(*this == op);
|
||||||
|
}
|
||||||
|
|
||||||
friend std::fstream& operator>>(std::fstream& stream, CoordinatesVector<T,N>& vector)
|
friend std::fstream& operator>>(std::fstream& stream, CoordinatesVector<T,N>& vector)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0;i<N;i++)
|
for (unsigned int i = 0;i<N;i++)
|
||||||
|
|
66
src/main.cpp
66
src/main.cpp
|
@ -4,24 +4,27 @@
|
||||||
#include "displayers.h"
|
#include "displayers.h"
|
||||||
#include "DataHandling/Texture.h"
|
#include "DataHandling/Texture.h"
|
||||||
#include "DataHandling/Model3D.h"
|
#include "DataHandling/Model3D.h"
|
||||||
#include "KeyStateManager.h"
|
#include "InputStatus.h"
|
||||||
|
#include "Camera.h"
|
||||||
|
|
||||||
volatile unsigned long long int timer_ticks = 0;
|
volatile unsigned long long int timer_ticks = 0;
|
||||||
|
static double aspect_ratio;
|
||||||
static Texture tree_texture;
|
static Texture tree_texture;
|
||||||
static Model3D raptor;
|
static Model3D raptor;
|
||||||
static Texture raptor_texture;
|
static Texture raptor_texture;
|
||||||
|
static Camera camera({10,0,10},{-10,0,-10},{0,1,0});
|
||||||
|
|
||||||
void manage_inputs()
|
void manage_inputs()
|
||||||
{
|
{
|
||||||
if (KeyStateManager::is_mouse_button_pressed(GLUT_LEFT_BUTTON))
|
if (InputStatus::is_mouse_button_pressed(GLUT_LEFT_BUTTON))
|
||||||
{
|
{
|
||||||
glClearColor(0,0,0.5,1);
|
glClearColor(0,0,0.5,1);
|
||||||
}
|
}
|
||||||
else if (KeyStateManager::is_key_pressed(' '))
|
else if (InputStatus::is_key_pressed(' '))
|
||||||
{
|
{
|
||||||
glClearColor(0.5,0,0,1);
|
glClearColor(0.5,0,0,1);
|
||||||
}
|
}
|
||||||
else if (KeyStateManager::is_key_pressed(0x1B))
|
else if (InputStatus::is_key_pressed(0x1B))
|
||||||
{
|
{
|
||||||
glutDestroyWindow(glutGetWindow());
|
glutDestroyWindow(glutGetWindow());
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
|
@ -31,13 +34,43 @@ void manage_inputs()
|
||||||
glClearColor(0,0,0,1);
|
glClearColor(0,0,0,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (KeyStateManager::is_special_key_pressed(GLUT_KEY_RIGHT))
|
if (InputStatus::is_special_key_pressed(GLUT_KEY_RIGHT))
|
||||||
{
|
{
|
||||||
timer_ticks += 5;
|
timer_ticks += 5;
|
||||||
|
camera.translate({0,0,1});
|
||||||
}
|
}
|
||||||
if (KeyStateManager::is_special_key_pressed(GLUT_KEY_LEFT))
|
if (InputStatus::is_special_key_pressed(GLUT_KEY_LEFT))
|
||||||
{
|
{
|
||||||
timer_ticks -= 5;
|
timer_ticks -= 5;
|
||||||
|
camera.translate({0,0,-1});
|
||||||
|
}
|
||||||
|
if (InputStatus::is_key_pressed(' '))
|
||||||
|
{
|
||||||
|
camera.translate({0,1,0});
|
||||||
|
}
|
||||||
|
if (InputStatus::is_special_key_pressed(GLUT_KEY_PAGE_DOWN))
|
||||||
|
{
|
||||||
|
camera.translate({0,-1,0});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InputStatus::is_special_key_pressed(GLUT_KEY_UP))
|
||||||
|
{
|
||||||
|
camera.translate({1,0,0});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (InputStatus::is_special_key_pressed(GLUT_KEY_DOWN))
|
||||||
|
{
|
||||||
|
camera.translate({-1,0,0});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get mouse delta since last frame
|
||||||
|
static Vec2i mouse_delta;
|
||||||
|
mouse_delta = InputStatus::get_mouse_delta(true);
|
||||||
|
if (mouse_delta.x != 0 || mouse_delta.y != 0)
|
||||||
|
{
|
||||||
|
camera.rotate({0,
|
||||||
|
-mouse_delta.x / InputStatus::mouse_sensitivity.x,
|
||||||
|
-mouse_delta.y / InputStatus::mouse_sensitivity.y});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,14 +84,11 @@ void display()
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
// Prepare view
|
// Prepare view
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
gluPerspective(60,(double)glutGet(GLUT_WINDOW_WIDTH)/(double)glutGet(GLUT_WINDOW_HEIGHT),10,30000);
|
gluPerspective(60,aspect_ratio,0.1,30000);
|
||||||
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
gluLookAt(10, 7.5, 10,
|
camera.look();
|
||||||
0, 0, 1,
|
|
||||||
0, 1, 0);
|
|
||||||
|
|
||||||
|
|
||||||
display_rotating_pyramid(-5,-2,-5,2,4,angleY);
|
display_rotating_pyramid(-5,-2,-5,2,4,angleY);
|
||||||
display_rotating_pyramid(5,-2,0,1,5,angleY);
|
display_rotating_pyramid(5,-2,0,1,5,angleY);
|
||||||
|
@ -74,6 +104,15 @@ void display()
|
||||||
glutSwapBuffers();
|
glutSwapBuffers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reshape(int new_x, int new_y)
|
||||||
|
{
|
||||||
|
glViewport(0,0,new_x,new_y);
|
||||||
|
|
||||||
|
aspect_ratio = (double)new_x/new_y;
|
||||||
|
InputStatus::window_center.x = new_x / 2;
|
||||||
|
InputStatus::window_center.y = new_y / 2;
|
||||||
|
}
|
||||||
|
|
||||||
void update_angle(int value)
|
void update_angle(int value)
|
||||||
{
|
{
|
||||||
timer_ticks++;
|
timer_ticks++;
|
||||||
|
@ -85,7 +124,7 @@ int main(int argc, char** argv)
|
||||||
glutInit(&argc,argv);
|
glutInit(&argc,argv);
|
||||||
// Generate window with GLUT
|
// Generate window with GLUT
|
||||||
glutInitDisplayMode(GLUT_RGB| GLUT_DEPTH | GLUT_DOUBLE);
|
glutInitDisplayMode(GLUT_RGB| GLUT_DEPTH | GLUT_DOUBLE);
|
||||||
glutCreateWindow("Hello");
|
glutCreateWindow("OpenGL custom engine tests");
|
||||||
glutIgnoreKeyRepeat(true);
|
glutIgnoreKeyRepeat(true);
|
||||||
|
|
||||||
// Init OpenGL
|
// Init OpenGL
|
||||||
|
@ -129,8 +168,9 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
glutDisplayFunc(display);
|
glutDisplayFunc(display);
|
||||||
glutIdleFunc(display);
|
glutIdleFunc(display);
|
||||||
|
glutReshapeFunc(reshape);
|
||||||
glutTimerFunc(50,update_angle,0);
|
glutTimerFunc(50,update_angle,0);
|
||||||
KeyStateManager::register_glut_callbacks();
|
InputStatus::register_glut_callbacks();
|
||||||
|
|
||||||
// Enters main loop, managed by GLUT
|
// Enters main loop, managed by GLUT
|
||||||
glutMainLoop();
|
glutMainLoop();
|
||||||
|
|
Loading…
Add table
Reference in a new issue