数日前にDUBにしれっと登録した「NanoVG.d(http://code.dlang.org/packages/nanovg-d )」の紹介をします。
NanoVGについて
検索すればたぶんだいたいの情報は出てくるかと思いますが簡単に紹介しておきます。
NanoVG(memononen/nanovg)とはMikko Mononen氏制作の2Dベクターグラフィックスライブラリです。HTML5のcanvas APIをもとに設計されており、コンパクトながら綺麗なベクターグラフィックスを簡単に利用することができます。
NanoVG.dについて
上記NanoVGですが、C言語インターフェイスで提供されているので基本的にはextern(C)で持ってくるだけで使用することができます。ただ、C言語インターフェイスなので基本的に開放処理は自前で明示的に書くことになり、若干手間で多分殆どの人は忘れるでしょうからD言語用にラップしたインターフェイスを用意しました。
また、NanoVG単体では描画情報およびソフトウェアテッセレーション機能のみを実装しているため、(この手のライブラリではもはや当たり前ですが)別途NanoVGの仕様に合わせたレンダラを実装するか持ってくる必要があります。NanoVG本家にはOpenGL2,3,ES2,ES3に対応したレンダラが標準で実装されており、またDirectXで再実装されたレンダラもあるのでC/C++で使う上では困りませんが、Dでは使えないので(外部ライブラリとしてではなくソースコードとして組み込むことになるため)OpenGL3バージョンのみ移植しました。
ライセンス形態はzlib/libpngライセンスとなります。動作確認は、現在のところGNU/Linux(Arch Linux+GNOME Shell)でのみ確認できております(たぶんWindowsでも動くかと思いますが、確認は取れてないので自己責任でおねがいします)。
サンプル
README.mdの丸写しですが
import derelict.glfw3.glfw3;
import derelict.opengl3.gl;
import std.string;
// import nanovg-d package
import nanovg;
void main()
{
// Load/InitLibrary
DerelictGL3.load();
DerelictGLFW3.load();
if(glfwInit() != GL_TRUE) throw new Exception("GLFW initialization failed.");
scope(exit) glfwTerminate();
// For Intel Graphics(Forced to use OpenGL 3.3 Core Profile)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// CreateWindow
auto pWindow = glfwCreateWindow(640, 480, "NanoVG.d Example", null, null);
if(pWindow is null) throw new Exception("GLFW Window creation failed.");
pWindow.glfwMakeContextCurrent();
// LazyLoading GL3
DerelictGL3.reload();
// CenteringWindow
auto vm = glfwGetVideoMode(glfwGetPrimaryMonitor());
pWindow.glfwSetWindowPos((vm.width - 640) / 2, (vm.height - 480) / 2);
// CreateNanoVGContext/Font
// (Download and place NotoSans font)
auto context = new NanoVG.ContextGL3();
auto fontid = context.createFont("font", "./NotoSans-Regular.ttf");
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
while(!glfwWindowShouldClose(pWindow))
{
int w, h;
pWindow.glfwGetFramebufferSize(&w, &h);
glViewport(0, 0, w, h);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
with(context)
{
beginFrame(w, h, cast(float)w / cast(float)h);
scope(exit) endFrame();
// Initialize
fontFace = fontid;
fontSize = 18.0f;
fontBlur = 0;
// Title Text
textAlign = NanoVG.TextAlign.LEFT | NanoVG.TextAlign.TOP;
fillColor = nvgRGBAf(0.0f, 0.0f, 0.0f, 1.0f);
text(8, 8, "NanoVG.d Sample");
// Rect1
beginPath();
rect(100, 100, 150, 30);
fillColor = nvgRGBAf(1.0f, 0.75f, 0.0f, 0.5f);
fill();
// Rect2
beginPath();
rect(130, 120, 50, 50);
fillColor = nvgRGBAf(0.0f, 0.5f, 1.0f, 0.75f);
fill();
// Rounded Rect
beginPath();
roundedRect(50, 50, 250, 250, 8.0f);
fillColor = nvgRGBAf(0.0f, 0.0f, 0.0f, 0.25f);
fill();
// Centered Text
textAlign = NanoVG.TextAlign.CENTER | NanoVG.TextAlign.TOP;
fillColor = nvgRGBAf(1.0f, 1.0f, 1.0f, 1.0f);
text(50 + 250 / 2, 50 + 4, "TextWindow Modoki");
// Beizer Curve
beginPath();
moveTo(200, 200);
bezierTo(200, 300, 200, 300, 300, 300);
strokeColor = nvgRGBAf(0.0f, 0.0f, 0.0f, 1.0f);
stroke();
}
pWindow.glfwSwapBuffers();
glfwPollEvents();
}
}
基本的にD言語向けインターフェイスは全部NanoVG名前空間(nanovg/package.dでRenamed Importしてる)に詰めてあります。C言語インターフェイスもグローバル空間にそのままおいてあるので、Cで書いたコードをそのままもってくることも可能です(文字列はtoStringzで変換しないといけませんが)。また、OpenGL3レンダラを使用する場合はバージョン指定にUseGL3Rendererを追加する必要があります。
C言語で書かれたコードをインターフェイスを用いて書きなおす場合、テキスト関連関数のendパラメータが省略可能だったり(nullになります)しますが基本的には関数名のnvgプレフィクスを除いたものがNanoVG.Contextのメソッド名になっているのでほぼそのまま書き換えることが可能です。一部関数はsetterになっていたりTransform系関数がNanoVG.Matrix3x2の中に移動していたりしますが。
(後々ドキュメントを整備する予定です。)
以上で(すごく短いですが)NanoVG.dの紹介はおしまいです。簡単に使える割に比較的ハイパフォーマンスなので、ゲームに使用したりUI作成に使用したりできて(D言語自体も割とハイパフォーマンスなので)いい感じです。