Tutorial 00.1: System Interface (GLFW3)

To be able to make our code independent from the windowing-sytem like GLFW or SDL2, we will use from now on an abstract System class.

To be able to access different subsystems in different parts of the code, we will use a static main class singleton.

The Scene (a struct) will be simulated using a member function void AnimateNextFrame(float timestep).

The visual representation of this scene will be rendered in a separate (abstract) class called Renderer, using a member function void Render(const Scene& scene).

The Main Loop:

int main(int argc, char* argv[])

{

System_GLFW& system = System_GLFW::Instance();

return Main::Instance(&system).MainLoop();

}

...

int Main::MainLoop()

{

double tnow = 0, tframe = 0, tlastframe = 0;

unsigned int tlastrenamed = 0, fpscounter = 0;

m_renderer = std::unique_ptr<Renderer>(new Renderer_OpenGL(800, 600));

Scene scene;

while (!Framework->IsCloseRequested())

{

// limit the FPS

tnow = Framework->Time();

tframe = tnow - tlastframe;

if (tframe < 1.0 / m_fps_goal)

continue;

tlastframe = tnow;

// rename the window title each second, show current FPS

fpscounter++;

if ((unsigned int)tnow != tlastrenamed)

{

tlastrenamed = (unsigned int)tnow;

Framework->SetWindowTitle("OpenGL FPS: " + std::to_string(fpscounter));

fpscounter = 0;

}

// simulate scene

scene.AnimateNextFrame(tframe);

// render scene

if (m_renderer.get())

m_renderer->Render(scene);

Framework->SwapBuffers();

Framework->Update();

}

return EXIT_SUCCESS;

}

The main() function is very simple: we only create a system instance (using GLFW implementation), and pass it to the main class.

Then we call the main loop member function which runs the whole application.

To be able to use different Renderer instances in the same application, we just store a Renderer pointer in Main.

If the window is resized for example, we can create a new Renderer (dynamically) and destroy the old one.

Each frame we check if the current FPS, if it exceeds the upper limit (60 FPS for now), we pause the loop 1 ms.

We also pass the dime difference between now and the last frame to the animation function, and finally render the scene.

The Update() function makes sure that we can detect events like keys pressed, clicks or cursor moved etc.

Complete Source Code:

Main.h

#pragma once

#include <memory>

#include "System.h"

#include "Renderer.h"

#define Framework (Main::Instance().system())

class Main

{

public:

static Main& Instance(System* system = nullptr);

~Main();

int MainLoop();

System* system();

private:

Main(System* system);

Main(const Main& other) = delete;

Main& operator=(const Main& other) = delete;

System* m_system{ nullptr };

unsigned int m_fps_goal{ 60 };

std::unique_ptr<Renderer> m_renderer;

};

Main.cpp

#include "Main.h"

#include "System_GLFW.h"

#include "Renderer_OpenGL.h"

int main(int argc, char* argv[])

{

System_GLFW& system = System_GLFW::Instance();

return Main::Instance(&system).MainLoop();

}

Main & Main::Instance(System* system)

{

static Main instance(system);

return instance;

}

Main::Main(System* system)

: m_system(system)

{

if (!m_system)

exit(EXIT_FAILURE);

}

Main::~Main()

{}

int Main::MainLoop()

{

double tnow = 0, tframe = 0, tlastframe = 0;

unsigned int tlastrenamed = 0, fpscounter = 0;

m_renderer = std::unique_ptr<Renderer>(new Renderer_OpenGL(800, 600));

Scene scene;

while (!Framework->IsCloseRequested())

{

// limit the FPS

tnow = Framework->Time();

tframe = tnow - tlastframe;

if (tframe < 1.0 / m_fps_goal)

continue;

tlastframe = tnow;

// rename the window title each second, show current FPS

fpscounter++;

if ((unsigned int)tnow != tlastrenamed)

{

tlastrenamed = (unsigned int)tnow;

Framework->SetWindowTitle("OpenGL FPS: " + std::to_string(fpscounter));

fpscounter = 0;

}

// simulate scene

scene.AnimateNextFrame(tframe);

// render scene

if (m_renderer.get())

m_renderer->Render(scene);

Framework->SwapBuffers();

Framework->Update();

}

return EXIT_SUCCESS;

}

System * Main::system()

{

return m_system;

}

Math.h

#pragma once

#include <glm/glm.hpp>

#include <glm/gtx/transform.hpp>

#include <glm/gtc/matrix_transform.hpp>

#include <glm/gtc/quaternion.hpp>

#include <glm/gtx/quaternion.hpp>

#include <glm/gtx/rotate_vector.hpp>

#include <glm/gtc/type_ptr.hpp>

#include <iostream>

using namespace glm;

#define PI 3.14159265358979323846264338327950288419716939937510f

#define min2(arg1, arg2) (arg1 < arg2 ? arg1 : arg2) // minimum of 2 values

#define max2(arg1, arg2) (arg1 > arg2 ? arg1 : arg2) // maximum of 2 values

#define abs2(arg) (arg > 0 ? arg : -arg)) // positive value

Math.cpp

#include "Math.h"

// empty

Renderer.h

#pragma once

#include "Scene.h"

class Renderer

{

public:

virtual ~Renderer() {}

virtual void Render(const Scene& scene) = 0;

};

Renderer_OpenGL.h

#pragma once

#include "Renderer.h"

#include <GL/glew.h>

class Renderer_OpenGL : public Renderer

{

public:

Renderer_OpenGL(unsigned int width, unsigned int height);

virtual ~Renderer_OpenGL();

virtual void Render(const Scene& scene);

protected:

unsigned int m_width{ 0 }, m_height{ 0 };

};

Renderer_OpenGL.cpp

#include "Renderer_OpenGL.h"

#include <iostream>

Renderer_OpenGL::Renderer_OpenGL(unsigned int width, unsigned int height)

{

}

Renderer_OpenGL::~Renderer_OpenGL()

{

}

void Renderer_OpenGL::Render(const Scene & scene)

{

glClearColor(0, 1, 0, 0);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// ...

}

Scene.h

#pragma once

#include "Math.h"

struct Scene

{

struct {

float FoV{ radians(45.0f) };

float ZNear{ 0.1f }, ZFar{ 100.0f };

} Camera;

Scene();

void AnimateNextFrame(float timestep);

};

Scene.cpp

#include "Scene.h"

Scene::Scene()

{

}

void Scene::AnimateNextFrame(float timestep)

{

}

System.h

#pragma once

#include <map>

#include <string>

#include "System_Input.h"

#include "Math.h"

struct InputState

{

struct {

ivec2 position;

bool button[MOUSE_BUTTON_COUNT_MAX]{ 0 };

int scroll;

} cursor;

struct {

bool key[KEY_COUNT_MAX]{ 0 };

} keyboard;

};

class System

{

public:

virtual ~System();

// update 1 frame

virtual void Update() = 0;

// window

virtual void SwapBuffers() const = 0;

virtual bool IsCloseRequested() const = 0;

virtual void SetWindowTitle(const std::string& name) = 0;

virtual ivec2 WindowPosition() const;

virtual ivec2 WindowSize() const;

// cursor

virtual ivec2 CursorPosition() const;

virtual ivec2 EventCursorMoved() const;

virtual bool IsClicked(unsigned int button) const;

virtual bool EventClicked(unsigned int button) const;

virtual bool EventClickReleased(unsigned int button) const;

virtual bool ScrolledUp() const;

virtual bool ScrolledDown() const;

// keyboard

virtual bool IsKeyPressed(unsigned int key) const;

virtual bool EventKeyPressed(unsigned int key) const;

virtual bool EventKeyReleased(unsigned int key) const;

// time

virtual double Time() const;

virtual void Sleep(unsigned int milli_seconds) const;

protected:

ivec2 m_windowsize, m_windowpos;

InputState m_current, m_previous;

std::map<unsigned int, unsigned int> m_keyindex;

std::map<unsigned int, unsigned int> m_mousebuttonindex;

virtual void SetupInputMap() = 0;

};

System.cpp

#include "System.h"

#include <chrono>

#include <thread>

System::~System()

{}

ivec2 System::WindowPosition() const

{

return m_windowpos;

}

ivec2 System::WindowSize() const

{

return m_windowsize;

}

ivec2 System::CursorPosition() const

{

return m_current.cursor.position;

}

ivec2 System::EventCursorMoved() const

{

return m_current.cursor.position - m_previous.cursor.position;

}

bool System::IsClicked(unsigned int button) const

{

if (button >= MOUSE_BUTTON_COUNT_MAX)

{

std::cout << "WARNING: Input::IsClicked(...) out of range" << std::endl;

return false;

}

return m_current.cursor.button[button];

}

bool System::EventClicked(unsigned int button) const

{

if (button >= MOUSE_BUTTON_COUNT_MAX)

{

std::cout << "WARNING: Input::EventClicked(...) out of range" << std::endl;

return false;

}

return m_current.cursor.button[button] && !m_previous.cursor.button[button];

}

bool System::EventClickReleased(unsigned int button) const

{

if (button >= MOUSE_BUTTON_COUNT_MAX)

{

std::cout << "WARNING: Input::EventClickReleased(...) out of range" << std::endl;

return false;

}

return !m_current.cursor.button[button] && m_previous.cursor.button[button];

}

bool System::ScrolledUp() const

{

return m_current.cursor.scroll == +1;

}

bool System::ScrolledDown() const

{

return m_current.cursor.scroll == -1;

}

bool System::IsKeyPressed(unsigned int key) const

{

if (key >= KEY_COUNT_MAX)

{

std::cout << "WARNING: Input::IsKeyPressed(...) out of range" << std::endl;

return false;

}

return m_current.keyboard.key[key];

}

bool System::EventKeyPressed(unsigned int key) const

{

if (key >= KEY_COUNT_MAX)

{

std::cout << "WARNING: Input::EventKeyPressed(...) out of range" << std::endl;

return false;

}

return m_current.keyboard.key[key] && !m_previous.keyboard.key[key];

}

bool System::EventKeyReleased(unsigned int key) const

{

if (key >= KEY_COUNT_MAX)

{

std::cout << "WARNING: Input::EventKeyReleased(...) out of range" << std::endl;

return false;

}

return !m_current.keyboard.key[key] && m_previous.keyboard.key[key];

}

double System::Time() const

{

static std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now();

std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now();

std::chrono::duration<double> time_span = std::chrono::duration_cast<std::chrono::duration<double>>(t2 - t1);

return time_span.count();

}

void System::Sleep(unsigned int milli_seconds) const

{

std::this_thread::sleep_for(std::chrono::milliseconds(milli_seconds));

}

System_GLFW.h

#pragma once

#include "System.h"

#include <GL/glew.h>

#include <GLFW/glfw3.h>

class System_GLFW : public System

{

public:

// singelton

static System_GLFW& Instance(unsigned int width = 0, unsigned int height = 0);

virtual ~System_GLFW();

// update 1 frame

virtual void Update();

// window

virtual void SwapBuffers() const;

virtual bool IsCloseRequested() const;

virtual void SetWindowTitle(const std::string& name);

private:

friend void mouse_button_callback(GLFWwindow* window, int button, int action, int mods);

friend void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods);

virtual void SetupInputMap();

GLFWwindow* m_window{ nullptr };

System_GLFW(unsigned int width, unsigned int height);

// NOT ALLOWED TO BE COPIED OR ASSIGNED TO

System_GLFW(const System_GLFW& other) = delete;

System_GLFW& operator=(const System_GLFW& other) = delete;

};

System_GLFW.cpp

#include "System_GLFW.h"

#include <iostream>

// callback functions

// ----------------------------------------------------------------------------------------------------------------

// this variable will be updated by the callback functions and will be used to update the current frame

InputState glfw_events_catched_globally;

ivec2 windowpos, windowsize;

void cursor_position_callback(GLFWwindow* window, double xpos, double ypos)

{

glfw_events_catched_globally.cursor.position = ivec2(xpos, windowsize.y - ypos); // origin set to lower left window corner

}

void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)

{

glfw_events_catched_globally.cursor.button[System_GLFW::Instance().m_mousebuttonindex[button]] = action != GLFW_RELEASE;

}

void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)

{

glfw_events_catched_globally.cursor.scroll = yoffset > 0 ? +1 : -1;

}

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)

{

glfw_events_catched_globally.keyboard.key[System_GLFW::Instance().m_keyindex[key]] = action != GLFW_RELEASE;

}

void window_pos_callback(GLFWwindow* window, int xpos, int ypos)

{

windowpos = ivec2(xpos, ypos);

}

void window_size_callback(GLFWwindow* window, int width, int height)

{

windowsize = ivec2(width, height);

}

// ----------------------------------------------------------------------------------------------------------------

System_GLFW::System_GLFW(unsigned int width, unsigned int height)

{

/* Initialize the library */

if (!glfwInit())

exit(EXIT_FAILURE);

if (width == 0 || height == 0)

{

width = 1200;

height = 900;

}

/* Create a windowed mode window and its OpenGL context */

m_window = glfwCreateWindow(width, height, "OpenGL ", NULL, NULL);

if (!m_window)

{

glfwTerminate();

exit(EXIT_FAILURE);

}

/* Make the window's context current */

glfwMakeContextCurrent(m_window);

// initialize GLEW

if (glewInit() != GLEW_OK)

exit(EXIT_FAILURE);

// set callback functions

glfwSetCursorPosCallback(m_window, cursor_position_callback);

glfwSetMouseButtonCallback(m_window, mouse_button_callback);

glfwSetScrollCallback(m_window, scroll_callback);

glfwSetKeyCallback(m_window, key_callback);

glfwSetWindowPosCallback(m_window, window_pos_callback);

glfwSetWindowSizeCallback(m_window, window_size_callback);

// initial value for window pos / size

glfwGetWindowPos(m_window, &windowpos.x, &windowpos.y);

glfwGetWindowSize(m_window, &windowsize.x, &windowsize.y);

SetupInputMap();

Update();

}

System_GLFW& System_GLFW::Instance(unsigned int width, unsigned int height)

{

static System_GLFW instance(width, height);

return instance;

}

System_GLFW::~System_GLFW()

{

glfwTerminate();

}

void System_GLFW::Update()

{

glfwPollEvents();

// window

m_windowpos = windowpos;

m_windowsize = windowsize;

// input

m_previous = m_current;

m_current = glfw_events_catched_globally;

// reset scroll event

glfw_events_catched_globally.cursor.scroll = 0;

}

void System_GLFW::SwapBuffers() const

{

glfwSwapBuffers(m_window);

}

bool System_GLFW::IsCloseRequested() const

{

return glfwWindowShouldClose(m_window);

}

void System_GLFW::SetWindowTitle(const std::string & name)

{

glfwSetWindowTitle(m_window, name.c_str());

}

void System_GLFW::SetupInputMap()

{

/* Printable keys */

m_keyindex[GLFW_KEY_SPACE] = KEY_SPACE;

m_keyindex[GLFW_KEY_APOSTROPHE] = KEY_APOSTROPHE;

m_keyindex[GLFW_KEY_COMMA] = KEY_COMMA;

m_keyindex[GLFW_KEY_MINUS] = KEY_MINUS;

m_keyindex[GLFW_KEY_PERIOD] = KEY_PERIOD;

m_keyindex[GLFW_KEY_SLASH] = KEY_SLASH;

m_keyindex[GLFW_KEY_0] = KEY_0;

m_keyindex[GLFW_KEY_1] = KEY_1;

m_keyindex[GLFW_KEY_2] = KEY_2;

m_keyindex[GLFW_KEY_3] = KEY_3;

m_keyindex[GLFW_KEY_4] = KEY_4;

m_keyindex[GLFW_KEY_5] = KEY_5;

m_keyindex[GLFW_KEY_6] = KEY_6;

m_keyindex[GLFW_KEY_7] = KEY_7;

m_keyindex[GLFW_KEY_8] = KEY_8;

m_keyindex[GLFW_KEY_9] = KEY_9;

m_keyindex[GLFW_KEY_SEMICOLON] = KEY_SEMICOLON;

m_keyindex[GLFW_KEY_EQUAL] = KEY_EQUAL;

m_keyindex[GLFW_KEY_A] = KEY_A;

m_keyindex[GLFW_KEY_B] = KEY_B;

m_keyindex[GLFW_KEY_C] = KEY_C;

m_keyindex[GLFW_KEY_D] = KEY_D;

m_keyindex[GLFW_KEY_E] = KEY_E;

m_keyindex[GLFW_KEY_F] = KEY_F;

m_keyindex[GLFW_KEY_G] = KEY_G;

m_keyindex[GLFW_KEY_H] = KEY_H;

m_keyindex[GLFW_KEY_I] = KEY_I;

m_keyindex[GLFW_KEY_J] = KEY_J;

m_keyindex[GLFW_KEY_K] = KEY_K;

m_keyindex[GLFW_KEY_L] = KEY_L;

m_keyindex[GLFW_KEY_M] = KEY_M;

m_keyindex[GLFW_KEY_N] = KEY_N;

m_keyindex[GLFW_KEY_O] = KEY_O;

m_keyindex[GLFW_KEY_P] = KEY_P;

m_keyindex[GLFW_KEY_Q] = KEY_Q;

m_keyindex[GLFW_KEY_R] = KEY_R;

m_keyindex[GLFW_KEY_S] = KEY_S;

m_keyindex[GLFW_KEY_T] = KEY_T;

m_keyindex[GLFW_KEY_U] = KEY_U;

m_keyindex[GLFW_KEY_V] = KEY_V;

m_keyindex[GLFW_KEY_W] = KEY_W;

m_keyindex[GLFW_KEY_X] = KEY_X;

m_keyindex[GLFW_KEY_Y] = KEY_Y;

m_keyindex[GLFW_KEY_Z] = KEY_Z;

m_keyindex[GLFW_KEY_LEFT_BRACKET] = KEY_LEFT_BRACKET;

m_keyindex[GLFW_KEY_BACKSLASH] = KEY_BACKSLASH;

m_keyindex[GLFW_KEY_RIGHT_BRACKET] = KEY_RIGHT_BRACKET;

m_keyindex[GLFW_KEY_GRAVE_ACCENT] = KEY_GRAVE_ACCENT;

m_keyindex[GLFW_KEY_WORLD_1] = KEY_WORLD_1;

m_keyindex[GLFW_KEY_WORLD_2] = KEY_WORLD_2;

/* Function keys */

m_keyindex[GLFW_KEY_ESCAPE] = KEY_ESCAPE;

m_keyindex[GLFW_KEY_ENTER] = KEY_ENTER;

m_keyindex[GLFW_KEY_TAB] = KEY_TAB;

m_keyindex[GLFW_KEY_BACKSPACE] = KEY_BACKSPACE;

m_keyindex[GLFW_KEY_INSERT] = KEY_INSERT;

m_keyindex[GLFW_KEY_DELETE] = KEY_DELETE;

m_keyindex[GLFW_KEY_RIGHT] = KEY_RIGHT;

m_keyindex[GLFW_KEY_LEFT] = KEY_LEFT;

m_keyindex[GLFW_KEY_DOWN] = KEY_DOWN;

m_keyindex[GLFW_KEY_UP] = KEY_UP;

m_keyindex[GLFW_KEY_PAGE_UP] = KEY_PAGE_UP;

m_keyindex[GLFW_KEY_PAGE_DOWN] = KEY_PAGE_DOWN;

m_keyindex[GLFW_KEY_HOME] = KEY_HOME;

m_keyindex[GLFW_KEY_END] = KEY_END;

m_keyindex[GLFW_KEY_CAPS_LOCK] = KEY_CAPS_LOCK;

m_keyindex[GLFW_KEY_SCROLL_LOCK] = KEY_SCROLL_LOCK;

m_keyindex[GLFW_KEY_NUM_LOCK] = KEY_NUM_LOCK;

m_keyindex[GLFW_KEY_PRINT_SCREEN] = KEY_PRINT_SCREEN;

m_keyindex[GLFW_KEY_PAUSE] = KEY_PAUSE;

m_keyindex[GLFW_KEY_F1] = KEY_F1;

m_keyindex[GLFW_KEY_F2] = KEY_F2;

m_keyindex[GLFW_KEY_F3] = KEY_F3;

m_keyindex[GLFW_KEY_F4] = KEY_F4;

m_keyindex[GLFW_KEY_F5] = KEY_F5;

m_keyindex[GLFW_KEY_F6] = KEY_F6;

m_keyindex[GLFW_KEY_F7] = KEY_F7;

m_keyindex[GLFW_KEY_F8] = KEY_F8;

m_keyindex[GLFW_KEY_F9] = KEY_F9;

m_keyindex[GLFW_KEY_F10] = KEY_F10;

m_keyindex[GLFW_KEY_F11] = KEY_F11;

m_keyindex[GLFW_KEY_F12] = KEY_F12;

m_keyindex[GLFW_KEY_F13] = KEY_F13;

m_keyindex[GLFW_KEY_F14] = KEY_F14;

m_keyindex[GLFW_KEY_F15] = KEY_F15;

m_keyindex[GLFW_KEY_F16] = KEY_F16;

m_keyindex[GLFW_KEY_F17] = KEY_F17;

m_keyindex[GLFW_KEY_F18] = KEY_F18;

m_keyindex[GLFW_KEY_F19] = KEY_F19;

m_keyindex[GLFW_KEY_F20] = KEY_F20;

m_keyindex[GLFW_KEY_F21] = KEY_F21;

m_keyindex[GLFW_KEY_F22] = KEY_F22;

m_keyindex[GLFW_KEY_F23] = KEY_F23;

m_keyindex[GLFW_KEY_F24] = KEY_F24;

m_keyindex[GLFW_KEY_F25] = KEY_F25;

m_keyindex[GLFW_KEY_KP_0] = KEY_KP_0;

m_keyindex[GLFW_KEY_KP_1] = KEY_KP_1;

m_keyindex[GLFW_KEY_KP_2] = KEY_KP_2;

m_keyindex[GLFW_KEY_KP_3] = KEY_KP_3;

m_keyindex[GLFW_KEY_KP_4] = KEY_KP_4;

m_keyindex[GLFW_KEY_KP_5] = KEY_KP_5;

m_keyindex[GLFW_KEY_KP_6] = KEY_KP_6;

m_keyindex[GLFW_KEY_KP_7] = KEY_KP_7;

m_keyindex[GLFW_KEY_KP_8] = KEY_KP_8;

m_keyindex[GLFW_KEY_KP_9] = KEY_KP_9;

m_keyindex[GLFW_KEY_KP_DECIMAL] = KEY_KP_DECIMAL;

m_keyindex[GLFW_KEY_KP_DIVIDE] = KEY_KP_DIVIDE;

m_keyindex[GLFW_KEY_KP_MULTIPLY] = KEY_KP_MULTIPLY;

m_keyindex[GLFW_KEY_KP_SUBTRACT] = KEY_KP_SUBTRACT;

m_keyindex[GLFW_KEY_KP_ADD] = KEY_KP_ADD;

m_keyindex[GLFW_KEY_KP_ENTER] = KEY_KP_ENTER;

m_keyindex[GLFW_KEY_KP_EQUAL] = KEY_KP_EQUAL;

m_keyindex[GLFW_KEY_LEFT_SHIFT] = KEY_LEFT_SHIFT;

m_keyindex[GLFW_KEY_LEFT_CONTROL] = KEY_LEFT_CONTROL;

m_keyindex[GLFW_KEY_LEFT_ALT] = KEY_LEFT_ALT;

m_keyindex[GLFW_KEY_LEFT_SUPER] = KEY_LEFT_SUPER;

m_keyindex[GLFW_KEY_RIGHT_SHIFT] = KEY_RIGHT_SHIFT;

m_keyindex[GLFW_KEY_RIGHT_CONTROL] = KEY_RIGHT_CONTROL;

m_keyindex[GLFW_KEY_RIGHT_ALT] = KEY_RIGHT_ALT;

m_keyindex[GLFW_KEY_RIGHT_SUPER] = KEY_RIGHT_SUPER;

m_keyindex[GLFW_KEY_MENU] = KEY_MENU;

// mouse buttons

m_mousebuttonindex[GLFW_MOUSE_BUTTON_LEFT] = MOUSE_BUTTON_LEFT;

m_mousebuttonindex[GLFW_MOUSE_BUTTON_RIGHT] = MOUSE_BUTTON_RIGHT;

m_mousebuttonindex[GLFW_MOUSE_BUTTON_MIDDLE] = MOUSE_BUTTON_MIDDLE;

m_mousebuttonindex[GLFW_MOUSE_BUTTON_4] = MOUSE_BUTTON_4;

m_mousebuttonindex[GLFW_MOUSE_BUTTON_5] = MOUSE_BUTTON_5;

m_mousebuttonindex[GLFW_MOUSE_BUTTON_6] = MOUSE_BUTTON_6;

m_mousebuttonindex[GLFW_MOUSE_BUTTON_7] = MOUSE_BUTTON_7;

m_mousebuttonindex[GLFW_MOUSE_BUTTON_8] = MOUSE_BUTTON_8;

}

System_Input.h

#pragma once

enum

{

/* Printable keys */

KEY_SPACE,

KEY_APOSTROPHE,

KEY_COMMA,

KEY_MINUS,

KEY_PERIOD,

KEY_SLASH,

KEY_0,

KEY_1,

KEY_2,

KEY_3,

KEY_4,

KEY_5,

KEY_6,

KEY_7,

KEY_8,

KEY_9,

KEY_SEMICOLON,

KEY_EQUAL,

KEY_A,

KEY_B,

KEY_C,

KEY_D,

KEY_E,

KEY_F,

KEY_G,

KEY_H,

KEY_I,

KEY_J,

KEY_K,

KEY_L,

KEY_M,

KEY_N,

KEY_O,

KEY_P,

KEY_Q,

KEY_R,

KEY_S,

KEY_T,

KEY_U,

KEY_V,

KEY_W,

KEY_X,

KEY_Y,

KEY_Z,

KEY_LEFT_BRACKET,

KEY_BACKSLASH,

KEY_RIGHT_BRACKET,

KEY_GRAVE_ACCENT,

KEY_WORLD_1,

KEY_WORLD_2,

/* Function keys */

KEY_ESCAPE,

KEY_ENTER,

KEY_TAB,

KEY_BACKSPACE,

KEY_INSERT,

KEY_DELETE,

KEY_RIGHT,

KEY_LEFT,

KEY_DOWN,

KEY_UP,

KEY_PAGE_UP,

KEY_PAGE_DOWN,

KEY_HOME,

KEY_END,

KEY_CAPS_LOCK,

KEY_SCROLL_LOCK,

KEY_NUM_LOCK,

KEY_PRINT_SCREEN,

KEY_PAUSE,

KEY_F1,

KEY_F2,

KEY_F3,

KEY_F4,

KEY_F5,

KEY_F6,

KEY_F7,

KEY_F8,

KEY_F9,

KEY_F10,

KEY_F11,

KEY_F12,

KEY_F13,

KEY_F14,

KEY_F15,

KEY_F16,

KEY_F17,

KEY_F18,

KEY_F19,

KEY_F20,

KEY_F21,

KEY_F22,

KEY_F23,

KEY_F24,

KEY_F25,

KEY_KP_0,

KEY_KP_1,

KEY_KP_2,

KEY_KP_3,

KEY_KP_4,

KEY_KP_5,

KEY_KP_6,

KEY_KP_7,

KEY_KP_8,

KEY_KP_9,

KEY_KP_DECIMAL,

KEY_KP_DIVIDE,

KEY_KP_MULTIPLY,

KEY_KP_SUBTRACT,

KEY_KP_ADD,

KEY_KP_ENTER,

KEY_KP_EQUAL,

KEY_LEFT_SHIFT,

KEY_LEFT_CONTROL,

KEY_LEFT_ALT,

KEY_LEFT_SUPER,

KEY_RIGHT_SHIFT,

KEY_RIGHT_CONTROL,

KEY_RIGHT_ALT,

KEY_RIGHT_SUPER,

KEY_MENU,

// ...

KEY_COUNT_MAX,

};

enum

{

MOUSE_BUTTON_LEFT,

MOUSE_BUTTON_RIGHT,

MOUSE_BUTTON_MIDDLE,

MOUSE_BUTTON_4,

MOUSE_BUTTON_5,

MOUSE_BUTTON_6,

MOUSE_BUTTON_7,

MOUSE_BUTTON_8,

// ...

MOUSE_BUTTON_COUNT_MAX,

};