NDKサンプルのhello-gl2をビルドして実行してみる

今回は前回の続きでNDKを導入してみる。

Android NDK | Android Developersから「Linux 32/64-bit (x86)」をダウンロードして展開する。(今回は~/android-ndk-r8b/)

ndk-buildにパスを通す。

> export PATH=~/android-ndk-r8b:${PATH}

サンプルのhello-gl2をndk-buildする。

> cd ~/android-ndk-r8b/samples/hello-gl2
> ndk-build

libgl2jni.soが生成された。

Eclipseを起動して、[File]-[import]を選択し「Android」-「Existing Android Code Into Workspace」でRoot Directoryに"~/android-ndk-r8b/samples/hello-gl2"を指定してインポートする。([Help]-[Install New Software...]から「NDK Plugins」がインストールできるがapkを作成するだけならまだ不要)

前回同様に[Run As]からapkをし、生成された~/android-ndk-r8b/samples/hello-gl2/bin/com.android.gl2jni.GL2JNIActivity.apkを実機で確認すると三角形と画面全体のフェードのリピートが確認できた。

Ubuntuでandroid開発環境

ここら辺を参考にUbuntu12.04上にandroid開発環境を構築する。

とりあえずはhello, world!が出ればいいということでJavaはdefault(OpenJDK)でやってみる。
まず、Eclipseをインストール。

$ sudo apt-get install eclipse

ここでは3.7.2がインストールされた。

ADTのインストール。
Eclipseを起動して「Help」 -> 「Install New Software…」を選択。
「Add…」ボタンをクリックし、「Location」に
https://dl-ssl.google.com/android/eclipse/
と入力してOKをクリック。
「Developer Tools」が選べるようになるので選択してインストール。
(途中出てきたSecurity WarningはOKを選択。)
インストールが終了すると再起動を促されるので「Restart Now」をクリックして再起動。

Eclipseを再起動すると「Welcome to Android Development」ダイアログがでる。
今回は動作確認をバージョン2.3.6の実機で行うので「Install Android 2.2, a version which is supported by ~93% phones and tablets」をチェック入れてインストール。

インストールが終わったら早速ビルドしてみる。

  • [File]-[New]-[Project...]を選択
  • Android」の「Android Application Project」を選択。
  • Application Nameを「Hello」と入力して「Next」ボタンをクリック。
  • 以下、デフォルトで設定していくと、「Install Dependencies」といわれたので「Install/Upgrade」ボタンを押してインストール。
  • 「Finish」ボタンが押せるようになるのでクリックして終了。

「Project Explorer」から「Hello」プロジェクトを右クリック。
[Run As]-[Android Application]としてapkを生成させる。エミュレーターなどのtarget設定していないため「Android AVD Error」ダイアログが出てVirtual Deviceを作成するか聞かれるがここでは「No」を選択しキャンセル。

~/workspace/Hello/bin/Hello.apkを実機にコピー。(ここではDropbox(ubuntu,android)を使用。)
インストールして実行。(Androidのアプリケーション設定で「提供元不明のアプリ」をチェックする必要がある。)

とりあえず"Hello, world!"は出た。

SDLとOpenGLでhello, world(Windows版)

さて、前回の続きで今回はWindows+SDL+OpenGLでhello, world。

環境は、

まず、GLEWを用意。
ここからWindows 32-bit版をダウンロードして展開。今回はC:\libs\glew-1.9.0に展開。

次にSDLを用意。
ここからをSDL-devel-1.2.15-VC.zipダウンロード。やはり、C:\libs\SDL-1.2.15に展開。
このまま使ってもいいのだけれど、前回の#includeのファイルパスそのまま使うためにレイアウトを変更する。

> md C:\libs\SDL-1.2.15\include\SDL
> move C:\libs\SDL-1.2.15\include\*.h C:\libs\SDL-1.2.15\include\SDL

スタートメニューから「Microsoft Visual C++ 2008 Express Edition」>「Visual Studio Tools」>「Visual Studio 2008 コマンド プロンプト」を選んで起動。

前回のhello.cをhello.cppとして作成。(C89では通らないため。今回はC:\Users\simpgに)

同じディレクトリにCMakeLists.txtを作成。

[CMakeLists.txt]

set(CMAKE_EXE_LINKER_FLAGS "/NODEFAULTLIB:\"msvcrt.lib\" /MACHINE:x86")
include_directories(C:\\libs\\SDL-1.2.15\\include C:\\libs\\glew-1.9.0\\include)
link_directories(C:\\libs\\SDL-1.2.15\\lib\\x86 C:\\libs\\glew-1.9.0\\lib)
link_libraries(hello SDLmain SDL glew32 opengl32)
add_executable(hello hello.cpp)

cmake、nmakeでビルド。

> cd \Users\simpg
> cmake -G "NMake Makefiles"
> nmake

実行のために必要なDLLをカレントにコピーしてから実行。

> copy C:\libs\SDL-1.2.15\lib\x86\SDL.dll
> copy C:\libs\glew-1.9.0\bin\glew32.dll
> hello.exe

無事表示できた。

SDLとOpenGLでhello, world

これこれフュージョンしてhello, world。

テスト環境は、Ubuntu12.04。

まずは、ネイティブなSDL+OpenGL開発環境を構築。

$ sudo apt-get install libsdl1.2-dev libglew1.6-dev

glut用のコードをSDL用に修正。(記事の最後のhello.c)
ビルドして実行。

$ gcc hello.c -lGLEW -lSDL -o hello
$ ./hello

問題なし。

emscriptenでもやってみる。

$ emscripten/emcc hello.c -o hello.html

(Chrome20,Firefox13で確認。見た目はglut版とまったく一緒。。。表示を確認するにはブラウザの設定が「WebGL有効」である必要があります。)

(2012/08/11追記:どうやらemscriptenのSDL_Delayは期待した動作をしてくれないみたい。)
[hello.c]

#ifdef EMSCRIPTEN
#define GL_GLEXT_PROTOTYPES
#define EGL_EGLEXT_PROTOTYPES
#else // glew
#include
#endif // EMSCRIPTEN

#include
#define NO_SDL_GLEXT
#include

#include

#define TEX_W (128)

typedef struct
{
GLuint programObject;
GLuint vertexShader, fragmentShader;
GLuint textureId;
} glhandle;

static const char s_vShaderStr[] =
"attribute vec4 a_position; \n"
"attribute vec2 a_texCoord; \n"
"varying vec2 v_texCoord; \n"
"void main() \n"
"{ \n"
" gl_Position = a_position; \n"
" v_texCoord = a_texCoord; \n"
"} \n";


static const char s_fShaderStr[] =
"#ifdef GL_ES\n"
"precision mediump float; \n"
"#endif\n"
"varying vec2 v_texCoord; \n"
"uniform sampler2D s_texture; \n"
"void main() \n"
"{ \n"
" gl_FragColor = texture2D( s_texture, v_texCoord );\n"
"} \n";


static const unsigned char s_acDotImg[8][12] =
{
0x63,0x3f,0x30,0x30,0x3e,0x00,0x00,0x63,0x3e,0x7e,0x30,0x7c,
0x63,0x30,0x30,0x30,0x63,0x00,0x00,0x63,0x63,0x63,0x30,0x66,
0x63,0x30,0x30,0x30,0x63,0x00,0x00,0x6b,0x63,0x63,0x30,0x63,
0x7f,0x3e,0x30,0x30,0x63,0x00,0x00,0x7f,0x63,0x67,0x30,0x63,
0x63,0x30,0x30,0x30,0x63,0x30,0x00,0x7f,0x63,0x7c,0x30,0x63,
0x63,0x30,0x30,0x30,0x63,0x10,0x00,0x77,0x63,0x6e,0x30,0x66,
0x63,0x3f,0x3f,0x3f,0x3e,0x20,0x00,0x63,0x3e,0x67,0x3f,0x7c,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};

static const GLfloat s_vertices[] = {
-1.0f, 1.0f, 0.0f, // Position 0
0.0f, 0.0f, // TexCoord 0
-1.0f, -1.0f, 0.0f,
0.0f, 0.0625f,
1.0f, -1.0f, 0.0f,
0.75f, 0.0625f,
1.0f, 1.0f, 0.0f,
0.75f, 0.0f,
};
static const GLushort s_indices[] = { 0, 1, 3, 2 };

static GLuint load_shader( GLenum type, const char *src )
{
GLuint shader;

shader = glCreateShader( type );
glShaderSource( shader, 1, &src, NULL );
glCompileShader( shader );

return shader;
}

static GLuint setup_tex()
{
int i, j, k;
GLuint textureId;
GLubyte pixels[TEX_W*TEX_W * 3]; // ちょっと大きいけど

glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glGenTextures( 1, &textureId );
glBindTexture( GL_TEXTURE_2D, textureId );

// ドットイメージテクスチャ化
for( i = 0; i < 8; i++ )
{
for( j = 0; j < 12; j++ )
{
for( k = 0; k < 8; k++ )
{
GLubyte val = ( (s_acDotImg[i][j] & (1<<(7-k))) ? 0xff : 0 );
int index = (i*128+j*8+k)*3;
pixels[index+0] = val;
pixels[index+1] = val;
pixels[index+2] = val;
}
}
}

glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, TEX_W, TEX_W, 0, GL_RGB, GL_UNSIGNED_BYTE, pixels );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, textureId );

return textureId;
}

static void setup_vtx( glhandle *handle, GLuint positionLoc, GLuint texCoordLoc, GLuint samplerLoc )
{
GLuint s_vertexPosObject, s_indexObject;
glGenBuffers(1, &s_vertexPosObject);
glBindBuffer(GL_ARRAY_BUFFER, s_vertexPosObject );
glBufferData(GL_ARRAY_BUFFER, sizeof(s_vertices), s_vertices, GL_STATIC_DRAW );

glGenBuffers(1, &s_indexObject);
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, s_indexObject );
glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(s_indices), s_indices, GL_STATIC_DRAW );

glBindBuffer(GL_ARRAY_BUFFER, s_vertexPosObject);
glVertexAttribPointer( positionLoc, 3, GL_FLOAT, GL_FALSE, 5 * 4, 0 );
glVertexAttribPointer( texCoordLoc, 2, GL_FLOAT, GL_FALSE, 5 * 4, (const GLvoid *)(3 * 4) );
glEnableVertexAttribArray( positionLoc );
glEnableVertexAttribArray( texCoordLoc );

glUniform1i( samplerLoc, 0 );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, s_indexObject );
}

static void initialize( glhandle *handle )
{
GLuint positionLoc, texCoordLoc, samplerLoc;

handle->vertexShader = load_shader( GL_VERTEX_SHADER, s_vShaderStr );
handle->fragmentShader = load_shader( GL_FRAGMENT_SHADER, s_fShaderStr );

handle->programObject = glCreateProgram();
glAttachShader( handle->programObject, handle->vertexShader );
glAttachShader( handle->programObject, handle->fragmentShader );
glLinkProgram( handle->programObject );
glUseProgram( handle->programObject );

positionLoc = glGetAttribLocation( handle->programObject, "a_position" );
texCoordLoc = glGetAttribLocation( handle->programObject, "a_texCoord" );
samplerLoc = glGetUniformLocation( handle->programObject, "s_texture" );

handle->textureId = setup_tex();
setup_vtx(handle, positionLoc, texCoordLoc, samplerLoc);
}

static void release( glhandle *handle )
{
glDeleteTextures(1, &handle->textureId);
glDeleteShader(handle->fragmentShader);
glDeleteShader(handle->vertexShader);
glDeleteProgram(handle->programObject);
}

static void display()
{
glClear(GL_COLOR_BUFFER_BIT);

glDrawElements( GL_TRIANGLE_STRIP, sizeof(s_indices)/sizeof(s_indices[0]), GL_UNSIGNED_SHORT, 0 );

SDL_GL_SwapBuffers();
}

int main(int argc, char *argv[])
{
glhandle handle;

SDL_Init(SDL_INIT_VIDEO);
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
SDL_SetVideoMode(96*2, 8*2, 32, SDL_OPENGL);
#ifndef EMSCRIPTEN
glewInit();
#endif

initialize(&handle);

display();

SDL_Event ev;
int bExit = 0;
while(bExit == 0)
{
while(SDL_PollEvent(&ev))
{
if(ev.type == SDL_QUIT)
{
bExit = 1;
break;
}
}
SDL_Delay(20);
}
SDL_Quit();

release(&handle);

return 0;
}

Ubuntuでboost

Ubuntu12.04にboostをapt-getでインストール。

$ sudo apt-get install libboost-dev build-essential

BOOST_VERSIONは104601となっている。

[hello.cpp]

#include 
#include

int main()
{
std::cout << boost::format("%s\n") % "hello, world";
return 0;
}

ビルド。

$ gcc hello.cpp -lstdc++ -o hello

実行

$ ./hello

hello, world
無事表示された。

Ubuntu+eclipse+CDTでhello, world

まず、eclipseをインストール。環境はUbuntu12.04。

$ sudo apt-get install eclipse

eclipse起動。(日本語にするのが面倒なので英語のまま)
[Help]-[About Eclipse Platform]メニューを選択すると「Version: 3.7.2」と表示されている。

[Help]-[Install New Software...]メニューを選択。
「Work with」のコンボボックスから「Indigo Update Site-http://download.eclipse.org/releases/indigo」を選択する。
「Programming Languages」-「C/C++ Development Tools」にチェックを入れ、「Next」ボタンをクリック、以下指示に従ってインストール。

再起動を促すダイアログが出るので「Restart」ボタンで再起動。

[File]-[New]-[Project...]メニューを選択。
C/C++」-「C Project」を選択して「Next」ボタンをクリック。

「Project name」に「hello」と入力。
「Executable」-「Hello World ANSI C Project」を選択し「Finish」ボタンをクリックしてプロジェクト作成。

[Project]-[Build Project]メニューを選択してビルド。
[Run]-[Run]メニューを選択して実行。

Consoleビューに

!!!Hello World!!!
と表示された。

MinGW(+CMake)でhello, world

Windows上でもちょっとしたコードはコマンドラインのほうが便利じゃね?ということでMinGW(+CMake)をWindowsXPにインストールしてみる。

まずは、MinGWとCMakeをダウンロード。
ここここからmingw-get-inst-20120426.exeとcmake-2.8.8-win32-x86.exeをダウンロード。

どちらもインストーラーなので指示に従いインストール。
基本デフォルトのままだが、MinGWインストーラーのデフォルトでは"C++ Compiler"が選択されていないのでチェックを入れて追加した。(今回の手順では本来必要ないが、定番なので"MinGW Developer Toolkit"もチェックを入れて追加した。)
CMakeは今回コマンドラインで使うので"Add CMake to the system PATH for current users"にチェックを入れる。

いつもの。
[hello.cpp]

#include 
int main()
{
printf("hello, world\n");
return 0;
}

CMake用にCMakeLists.txtを作成。
[CMakeLists.txt]

add_executable(hello hello.cpp)

MinGWのbinディレクトリにパスを通してからビルド。

>PATH=C:\MinGW\bin;%PATH%
>cmake -G "MinGW Makefiles"
>mingw32-make

実行。

>hello.exe

無事

hello, world
と表示された。