はじめに
この記事は”WindowsでGLFW3.1開発環境構築(Code::Blocks,MinGW)・その1”の続編です。
前回までの内容を踏まえて記述されているので、必要に応じて前回の記事を参照して下さい。
前回の記事でGLFW3.1を使ってウィンドウを開くところまで環境構築ができました。今回の記事では、そのウィンドウにOpenGLを使用して単純な図形を描画するまでを記述したいと思います。
ソースコード準備
この記事は開発環境の構築が目的なのでOpenGLのソースコードは”チュートリアル2:最初の三角形”で公開されているものをお借りすることにします。
1 . "Tutorials for modern OpenGL (3.3+) ダウンロードページ"から、**"OpenGL-tutorial_v0014_33通常版"**をダウンロードしてください。
- 注) グラフィックボードがOpenGL 3.3に対応していない場合、今回ビルドするプログラムの起動に失敗します。グラフィックボードがIntel製のオンボードだった場合、対応していない可能性があるので注意が必要です。
2 . ダウンロードしたzipファイル(OpenGL-tutorial_v0014_33.zip)を任意のフォルダへ解凍します。
3 . Code::Blocksで新しいプロジェクトを作成します。Code::Blocksを起動し、”Start here”ページの”Create a new project”をクリックしてプロジェクト作成ウィザードを起動します。
今回もプロジェクトも"Console application"テンプレートを使用して作成します。
言語を選択する項目では、ダウンロードしたソースコード(チュートリアル2:最初の三角形)に合わせて、**C++**を選択します。
プロジェクトの保存先等は自分の環境に合わせて適宜設定して下さい。(今後の説明は、以下は設定例を前提に進めます。自分の環境に合わせて読み替えて下さい。)
ウィザードが完了し、プロジェクトのひな形が作成されました。
4 . Code::BlocksウィンドウのProjectツリーに登録されているSourcesフォルダを開き、main.cppを右クリックし、”Remove file from project”を選択してプロジェクトからmain.cppを削除します。プロジェクトが保存されているフォルダを開き、main.cppファイルを削除してください。
(この画面は、”Remove file from project”クリック後、main.cpp削除前の状態をスクリーンキャプチャしたものです)
次に、2.で解凍したフォルダ内にある以下のファイルをプロジェクトフォルダへコピーします。
- OpenGL-tutorial_v0014_33\tutorial02_red_triangleフォルダ内
- tutorial02.cpp
- SimpleFragmentShader.fragmentshader
- SimpleVertexShader.vertexshader
- OpenGL-tutorial_v0014_33\commonフォルダ内
- shader.cpp
- shader.hpp
Code::Blocksのプロジェクトツリーに登録されているプロジェクト名(glfw-sample2)を右クリックし、"add files..."をクリックします。ファイル選択ダイアログが表示されるので、"tutorial02.cpp"と"shader.cpp"を選択してOKボタンをクリックして下さい。
"Multiple selection"ダイアログが表示されたらOKボタンをクリックして閉じます。
5 . 4.で追加したtutorial02.cppを若干変更します。Projectツリーの"tutorial02.cpp"をダブルクリックしてファイルを開きます。変更点は以下のようになります。
-
glfw3.hのインクルードの前にGLFW_DLLを定義(10行目)
#define GLFW_DLL
-
glfw3.hをGLFW/glfw3.hに変更(11行目)
#include <GLFW/glfw3.h>
-
glm.hppとshader.hppのincludeをコメントにする(14~19行目)
-
trueとfalseを定義する(21,22行目)
#define true 1
#define false (!true)
- LoadShaders関数のプロトタイプ宣言を追加する(24行目)
GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path);
以上で今回ビルドするソースコードの準備が完了しました。
tutorial02.cppのソースコード全体は、この記事の末尾に公開します。
外部依存ライブラリの準備
GLEW
"tutorial02.cpp"はGLEWというライブラリを使用しているので、ビルド前に用意します。
GLEWからSourceをダウンロードして任意のフォルダへ解凍してください。
- バイナリー(lib)形式も配布されていますが、MinGWではlibファイルをリンクできないので、自分でコンパイルする必要があります。
"MinGW Shell"(C:\MinGW\msys\1.0\msys.bat)を起動し、GLEWのソースを解凍したフォルダへ移動します。
以下のコマンドを実行し、libglew32.a,libglew32.dll.a,glew32.dllを作成します。
(コマンドはこちらを参考にしました。)
gcc -DGLEW_NO_GLU -O2 -Wall -W -Iinclude -DGLEW_BUILD -o src/glew.o -c src/glew.c
gcc -shared -Wl,-soname,libglew32.dll -Wl,--out-implib,lib/libglew32.dll.a -o lib/glew32.dll src/glew.o -L/mingw/lib -lglu32 -lopengl32 -lgdi32 -luser32 -lkernel32
ar cr lib/libglew32.a src/glew.o
(追記:2015/1/28)
GLEWのソースを解凍したフォルダでmakeを実行してもlibフォルダ内にlibglew32.a,libglew32.dll.a,glew32.dllが作成されます。
プロジェクトフォルダ内に"lib"フォルダを作成し**(GLEWを解凍したフォルダ)\lib\libglew32.a,libglew32.dll.aをコピーします。また、プロジェクトフォルダ直下にglew32.dll**をコピーします。
次に(GLEWを解凍したフォルダ)\includeフォルダごとプロジェクトフォルダ内にコピーします。
GLFW3.1
次に、GLFWのライブラリもプロジェクトフォルダへコピーします。
”その1”で使用した"libglfw3dll.a"をプロジェクトフォルダのlibフォルダ(GLEWのライブラリをコピーしたフォルダ)内にコピーしてください。
"glfw3.dll"はプロジェクトフォルダ内にコピーします。
同様に、GLFWの"include"フォルダもコピーします。(GLEWのインクルードフォルダと統合します)
- GLEWのフォルダと統合する必要はありませんが、統合しない場合は後述の"Search directories"にそれぞれ登録する必要があります。
ここまでの手順で、プロジェクトフォルダ内は以下のようなファイル構成になっていると思います。
プロジェクトのビルド設定
Code::Blocksの"Project build option"ダイアログを開きます。(その1を参考)
- "Search directories"タブの"Compiler"タブにincludeフォルダを登録します。
- "Search directories"タブの"Linker"タブにlibフォルダを登録します。
- "Linker setting"タブに以下の項目を追加します。
-
glewglew32 (2015/1/26:訂正) - glfw3dll
- opengl32
- gdi32
-
ここまででビルドに必要な環境はひと通り整いました。
実行
最後にCode::Blocksでビルドします。(その1を参照)
正常にビルドが完了した場合は実行してみてください。
正常に実行された場合は以下のようなウィンドウが表示されます。
もし何かのエラーがある場合は落ち着いて原因を探ってみてください。
どうしても分からない場合は、コメント欄に内容を書いてください。
何らかのアドバイスができるかもしれません。
今回まででOpenGLの開発環境として最低限整備できたと思います。
次の記事はこれをベースにOculus SDKを使って簡単なOculusアプリの開発環境を整備したいと思います。
付録
// Include standard headers
#include <stdio.h>
#include <stdlib.h>
// Include GLEW
#include <GL/glew.h>
// Include GLFW
#define GLFW_DLL
#include <GLFW/glfw3.h>
GLFWwindow* window;
/* Include GLM
#include <glm/glm.hpp>
using namespace glm;
#include <common/shader.hpp>
*/
#define true 1
#define false (!true)
GLuint LoadShaders(const char * vertex_file_path,const char * fragment_file_path);
int main( void )
{
// Initialise GLFW
if( !glfwInit() )
{
fprintf( stderr, "Failed to initialize GLFW\n" );
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// Open a window and create its OpenGL context
window = glfwCreateWindow( 1024, 768, "Tutorial 02 - Red triangle", NULL, NULL);
if( window == NULL ){
fprintf( stderr, "Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible. Try the 2.1 version of the tutorials.\n" );
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// Initialize GLEW
glewExperimental = true; // Needed for core profile
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
return -1;
}
// Ensure we can capture the escape key being pressed below
glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE);
// Dark blue background
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// Create and compile our GLSL program from the shaders
GLuint programID = LoadShaders( "SimpleVertexShader.vertexshader", "SimpleFragmentShader.fragmentshader" );
static const GLfloat g_vertex_buffer_data[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
do{
// Clear the screen
glClear( GL_COLOR_BUFFER_BIT );
// Use our shader
glUseProgram(programID);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the triangle !
glDrawArrays(GL_TRIANGLES, 0, 3); // 3 indices starting at 0 -> 1 triangle
glDisableVertexAttribArray(0);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
} // Check if the ESC key was pressed or the window was closed
while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0 );
// Cleanup VBO
glDeleteBuffers(1, &vertexbuffer);
glDeleteVertexArrays(1, &VertexArrayID);
glDeleteProgram(programID);
// Close OpenGL window and terminate GLFW
glfwTerminate();
return 0;
}