GLSL #2: コールバック関数の登録
目標
GLFWを使って作成したウィンドウ(下記の前回記事参照)にコールバック関数を用いた,エラーハンドリング,キー操作,スクロール操作を追加する.
実装環境
- GLEW 3.2.1
- Windows 10 64bit
- Visual Studio 2015
サンプルプログラム
window.h
ウィンドウの基底クラスを記述したヘッダファイル.前回から,コールバック関数を追加.
// // window.h // #pragma once #include <iostream> using namespace std; #include <GLFW/glfw3.h> namespace gl { class window { protected: GLFWwindow *wnd; int width; int height; const string name; int keyID; double xoffset; double yoffset; public: window( int w, // Width int h, // Height const string &name // Name ); ~window(); virtual void render() = 0; // ----- Callbacks virtual void setCallbacks(); // Error static void errorCallback( int err, // Error ID const char *desc // Description ); // Key static void keyCallback( GLFWwindow* window, int key, int scancode, int action, int mods ); // Scroll static void scrollCallback( GLFWwindow* window, double xoffset, double yoffset ); }; }
window.cpp
ウィンドウの基底クラスを記述したソースファイル.ヘッダファイルに書いたコールバック関数の具体的な処理を追加.デフォルトの機能として,Escキーを押すとプログラムが終了する,スクロールするとメンバ変数にオフセット値を保存するようにした.
// // window.cpp // #include "window.h" namespace gl { window::window( int w, int h, const string &name ) : name(name) { width = w; height = h; try { // ----- Initialize the library if (!glfwInit()) { throw "Failed to initialize GLFW 3..."; } // ----- Create a window wnd = glfwCreateWindow(w, h, name.c_str(), NULL, NULL); if (!wnd) { throw "Failed to create a window..."; glfwTerminate(); } } catch (string e) { cerr << "Error: " << e.c_str() << endl; exit(EXIT_FAILURE); } glfwMakeContextCurrent(wnd); setCallbacks(); } window::~window() { if (wnd) { glfwTerminate(); } } // ----- Callbacks void window::setCallbacks() { // Register this pointer glfwSetWindowUserPointer(wnd, this); // Error glfwSetErrorCallback(errorCallback); // Key glfwSetKeyCallback(wnd, keyCallback); // Scroll glfwSetScrollCallback(wnd, scrollCallback); } // Error void window::errorCallback( int err, const char *desc ) { cerr << desc << endl; } // Key void window::keyCallback( GLFWwindow* window, int key, int scancode, int action, int mods ) { int keyID = key; if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) { glfwSetWindowShouldClose(window, GL_TRUE); } } // Scroll void window::scrollCallback( GLFWwindow* window, double xoffset, double yoffset ) { // Get arbitrary pointer gl::window* _this = static_cast<gl::window*>(glfwGetWindowUserPointer(window)); _this->xoffset = xoffset; _this->yoffset = yoffset; } }
main.cpp
メインのソースファイル.gl::windowを継承して,自分のウィンドウを作る想定です.MyWindowクラスでは,変更したいコールバック関数を記述した上で,gl::windowクラスで設定されていたコールバック関数を上書きすることで機能を追加する.今回はキー操作を行うコールバック関数に「1」キーを押すと,コマンドプロンプトに「Hello!」の文字列を表示する機能を追加した.
// // main.cpp // #include "window.h" class MyWindow : gl::window { public: MyWindow( int w, int h, const string name ): window(w, h, name) { setCallbacks(); } // ----- Callbacks // Override the setCallbacks() function void setCallbacks() { // Key glfwSetKeyCallback(wnd, keyCallback); } // Define a new key callback static void keyCallback( GLFWwindow* window, int key, int scancode, int action, int mods ) { if (key == GLFW_KEY_ESCAPE && action == GLFW_RELEASE) { glfwSetWindowShouldClose(window, GL_TRUE); } if (key == GLFW_KEY_1 && action == GLFW_RELEASE) { cout << "Hello!!" << endl; } } void render() { // Rendering loop while (!glfwWindowShouldClose(wnd)) { // Swap front and back buffers glfwSwapBuffers(wnd); // Poll for and process events glfwPollEvents(); } } }; int main() { MyWindow wnd(640, 480, "GLFW 3 Window"); wnd.render(); return 0; }
結果
動いた!目標達成です.このプログラムでは,単に真っ黒なウィンドウが作成されるだけで,何も表示されません.右上の×ボタンを押すか,Escキーを押すことで,プログラムを終了します.
