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:
Teo-CD 2019-10-28 23:45:44 +01:00 committed by trotFunky
parent e79f88bb9b
commit 4a5b0f5829
11 changed files with 494 additions and 174 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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