emscriptenとOpenGL ES2.0でhello, world
emscriptenがOpenGL ES 2.0(WebGL)+GLUTをサポートしているので、OpenGL ES2.0で"hello, world"。emscriptenのセットアップはこちら。
- emscripten/tests/hello_world_gles.cpp
- emscripten/tests/glbook/Chanpter_9/Simple_Texture2D
を参考に作成。(200行くらいになってしまったので記事の最後にhello.cを貼りました。)
glutBitmapCharacterは使えるか不明だったのでテクスチャで"HELLO, WORLD"を表示する。
まずは、GLEWを使ってgccでビルド。
$ sodo apt-get install freeglut3-dev libglew1.6-dev
$ gcc hello.c -l glut -lGLEW -o hello
$ ./hello
ウインドウ上で"HELLO, WORLD"が表示された。
次にemscriptenでビルド。
$ emscripten/emcc hello.c -o hello.html
clang: warning: argument unused during compilation: '-nostdinc++'と出るがビルドはできた。
結果はこちら。いやいやすごい。(Chrome19,Firefox13で確認。表示を確認するにはブラウザの設定が「WebGL有効」である必要があります。)
[hello.c]
#ifdef EMSCRIPTEN
#define GL_GLEXT_PROTOTYPES
#define EGL_EGLEXT_PROTOTYPES
#else // glew
#include
#endif // EMSCRIPTEN#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 );
glutSwapBuffers();
}int main(int argc, char *argv[])
{
glhandle handle;glutInit(&argc, argv);
glutInitWindowSize(96*2, 8*2);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutCreateWindow("hello, world");#ifndef EMSCRIPTEN
glewInit();
#endif
initialize(&handle);glutDisplayFunc(display);
glutMainLoop();release(&handle);
return 0;
}