こんにちは!
本記事はコネヒト Advent Calendar 2017の24日目の記事になります。
こんにちは!Androidエンジニアの富田です。今回はKotlin/NativeのOpenGLのサンプルコードを触ってみましたので紹介したいと思います。
Kotlin/Nativeとは?
LLVMを用いてネイティブコードを生成してくれるコンパイラで、各プラットフォームのコンパイルを可能にするように設計されています。先日v0.5がリリースされてSwiftからKotlinコードを利用できたり、Python Extensionサンプルが追加されました。
Kotlin/Nativeについては以下の記事でも紹介されておりますので、興味のある方はご覧ください。
Kotlin/Nativeを使ってiOSアプリを作ってみる
Kotlin/Nativeを使ってXcode + CLionでiOSアプリを書く
Kotlin/Nativeのサンプルについて
Kotlin/Nativeのリポジトリには、たくさんのサンプルコードがありますので、いくつか紹介します。
| サンプル | 内容 |
|---|---|
| csvparser | csvのファイルをparseする |
| gitchurn | gitリポジトリの統計情報を表示する |
| libcurl | HTTPクライアント |
| nonBlockingEchoServer | コルーチンを利用したマルチクライアント |
| opengl | OpenGLのティーポットサンプル |
| python_extension | Python Extension |
| tensorflow | TensorFlowのデモ |
| socket | Socketサーバ |
| tetris | テトリスアプリケーション |
| videoplayer | ビデオプレイヤー |
| win32 | Win32のHello World |
プラットフォームライブラリ
各プラットフォーム毎にネイティブコードを利用できるようにするため、ビルド時にライブラリが含まれるようになっています。このライブラリをプラットフォームライブラリと呼ばれています。
実際にビルドをしてもらうと、dist/klib/platform以下にプラットフォームライブラリが含まれているのがわかります。さらにdist/klib/platform/macbook以下を見ると、以下のネイティブライブラリがあることがわかりました。今回はOpenGLを使いたいので、Kotlin側でimport platform.OpenGLと記述すると利用できます。
| ライブラリ | パッケージ |
|---|---|
| AppKit | platform.ApplicationServices |
| CFNetwork | platform.CFNetwork |
| CoreData | platform.CoreData |
| CoreFoundation | platform.CoreFoundation |
| CoreGraphics | platform.CoreGraphics |
| CoreImage | platform.CoreImage |
| CoreServices | platform.CoreServices |
| CoreText | platform.CoreText |
| CoreVideo | platform.CoreVideo |
| DiskArbitration | platform.DiskArbitration |
| Foundation | platform.Foundation |
| CoreVideo | platform.CoreVideo |
| GLUT | platform.GLUT |
| IOKit | platform.IOKit |
| IOSurface | platform.IOSurface |
| ImageIO | platform.ImageIO |
| Metal | platform.Metal |
| OpenGL | platform.OpenGL |
| OpenGL3 | platform.OpenGL3 |
| OpenGLCommon | platform.OpenGLCommon |
| QuartzCore | platform.QuartzCore |
| Security | platform.Security |
| libkern | platform.libkern |
| objc | platform.objc |
| osx | platform.osx |
| posix | platform.posix |
| zlib | platform.zlib |
OpenGLのサンプルを書いてみる
こちらのOpenGL GLUT TriangleサンプルをKotlin/Nativeを用いてKotlinで書いてみたいと思います。
提供されているcppのサンプルコードは以下の通りです。
# include <stdio.h>
# include <windows.h>
# include <GL/gl.h>
# include <GL/glut.h>
typedef struct {
int width;
int height;
char* title;
float field_of_view_angle;
float z_near;
float z_far;
} glutWindow;
glutWindow win;
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f,0.0f,-3.0f);
glBegin(GL_TRIANGLES);
glColor3f(0.0f,0.0f,1.0f);
glVertex3f( 0.0f, 1.0f, 0.0f);
glColor3f(0.0f,1.0f,0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glColor3f(1.0f,0.0f,0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glEnd();
glutSwapBuffers();
}
void initialize ()
{
glMatrixMode(GL_PROJECTION);
glViewport(0, 0, win.width, win.height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
GLfloat aspect = (GLfloat) win.width / win.height;
gluPerspective(win.field_of_view_angle, aspect, win.z_near, win.z_far);
glMatrixMode(GL_MODELVIEW);
glShadeModel( GL_SMOOTH );
glClearDepth( 1.0f );
glEnable( GL_DEPTH_TEST );
glDepthFunc( GL_LEQUAL );
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
glClearColor(0.0, 0.0, 0.0, 1.0);
}
int main(int argc, char **argv)
{
win.width = 640;
win.height = 480;
win.title = "OpenGL/GLUT Example. Visit http://openglsamples.sf.net ";
win.field_of_view_angle = 45;
win.z_near = 1.0f;
win.z_far = 500.0f;
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
glutInitWindowSize(win.width,win.height);
glutCreateWindow(win.title);
glutDisplayFunc(display);
glutIdleFunc(display);
initialize();
glutMainLoop();
return 0;
}
こちらをKotlinで書いてみると次のようになります。
import kotlinx.cinterop.*
import platform.GLUT.*
import platform.OpenGL.*
import platform.OpenGLCommon.*
private val windowWidth = 640
private val windowHeight = 480
private fun display() {
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT)
glLoadIdentity()
glTranslatef(0.0f, 0.0f, -3.0f)
glBegin(GL_TRIANGLES);
glColor3f(0.0f, 0.0f, 1.0f)
glVertex3f(0.0f, 1.0f, 0.0f)
glColor3f(0.0f, 1.0f, 0.0f)
glVertex3f(-1.0f, -1.0f, 0.0f)
glColor3f(1.0f, 0.0f, 0.0f)
glVertex3f(1.0f, -1.0f, 0.0f)
glEnd()
glutSwapBuffers()
}
private fun initialize() {
glMatrixMode(GL_PROJECTION)
glViewport(0, 0, windowWidth, windowHeight)
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
val aspect = windowWidth.toDouble() / windowHeight
gluPerspective(45.0, aspect, 1.0, 500.0)
glMatrixMode(GL_MODELVIEW)
glShadeModel(GL_SMOOTH)
glClearDepth(1.0)
glEnable(GL_DEPTH_TEST)
glDepthFunc(GL_LEQUAL)
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
}
fun main(args: Array<String>) {
memScoped {
val argc = alloc<IntVar>().apply { value = 0 }
glutInit(argc.ptr, null)
}
glutInitDisplayMode(GLUT_RGB or GLUT_DOUBLE or GLUT_DEPTH)
glutInitWindowSize(windowWidth, windowHeight)
glutCreateWindow("Triangle")
glutDisplayFunc(staticCFunction(::display))
glutIdleFunc(staticCFunction(::display))
initialize()
glutMainLoop()
}
アプリケーションの実行結果は以下となります。ビルドや実行方法に関しては、こちらのOpenGLサンプルをご確認ください。
最後に
まとめ
Kotlin/Nativeを用いて、OpenGLのネイティブライブラリをKotlinから呼び出してみました。Kotlin/Nativeリポジトリにはtensorflow、python_extentionなど面白そうなサンプルがたくさんありますので、興味のある方は触ってみると良いかもしれません。個人的な目標として、来年はKotlin/Nativeのサンプルを送ってみたいと思います!
明日の予告
コネヒト Advent Calendar 2017の最終日はitoshoさんの記事です!!メリークリスマス!!!
