こんにちは!
本記事はコネヒト 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さんの記事です!!メリークリスマス!!!