EmscriptenとLDCを使えばD言語のSDLゲームがブラウザで動かせる、かも

とりあえずひどく簡単なサンプルは動いたけど、D言語でclassを書いたらLLVMからJavaScriptへの変換が失敗したので、まだ実用までは壁がありそう。

EmscriptenLLVMからJavaScriptへのコンパイラ

LDCD言語からLLVMへのコンパイラ

なので、D言語LDCLLVMコンパイルし、LLVMEmscriptenJavaScriptコンパイルすれば、ブラウザ上でD言語が動かせる。原理的には。EmscriptenD言語SDLに対応しているのでSDLも動く。原理的には。

Windowsで動かす場合、例えば以下のコードを書く。

import SDL;

immutable width = 640, height = 480;
SDL_Surface *screen;
int ticks = 0;

void update() {
  SDL_LockSurface(screen);
  for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
            *(cast(char*)screen.pixels + i*width*4 + j*4 + 0) = cast(char)(j + ticks) % 255;
            *(cast(char*)screen.pixels + i*width*4 + j*4 + 1) = cast(char)(i + ticks) % 255;
            *(cast(char*)screen.pixels + i*width*4 + j*4 + 2) = cast(char)((255-i) + ticks) % 255;
    }
  }
  SDL_UnlockSurface(screen);
  SDL_Flip(screen);
  ticks++;
}

extern(C):
void mainLoop() {
  update();
}

void emscripten_set_main_loop(void function(), int fps, int simulate_infinite_loop);

int main() {
  SDL_Init(SDL_INIT_VIDEO);
  screen = SDL_SetVideoMode(width, height, 32, SDL_SWSURFACE);
  emscripten_set_main_loop(&mainLoop, 60, 1);
  return 0;
}

emscripten_set_main_loopってのは、各フレームごとに呼ぶ出される関数を指定するためのもの。Emscripten使う場合は、SDL_Delayではなく、これを使う必要があるらしい。

あとは以下のようにコンパイルすれば、

ldc2 -O -ISDL hello.d -output-ll

LLVMコンパイルされたhello.llができる。次はこれを、

python emcc -O2 -s ASM_JS=1 hello.ll -o hello.html

とすれば、LLVMから変換されたJavaScriptを含むHTMLファイルができる。'-s ASM_JS=1'オプションをつければ、asm.jsを使ったJavaScriptが生成されるので、せっかくだからasm.jsに対応したFirefox22で動かしたほうが楽しいかも。残念ながらこんくらいの単純なサンプルだとChrome26と比べて別段速くはないが。

とりあえずの問題は、最初にも書いたようにclass書くとEmscriptenがコケるところ。何も含まない空のclass書くだけでコケるのがなんとも困る。LDCとClangでclassの扱いが違うのかね。

あと、Windows上でコンパイルのためのツールを整備するのがかなり面倒。Emscriptenについては、

にある長い手順をこなさないといかんし、LDCは、

というさらに面倒な手順が必要。しかもうちの環境だと5.の最後のninja叩く前に、build.ninjaの'-D NDEBUG'をすべて消さないと、7.のLDCのビルドがコケた。

D言語ブラウザゲームが書けるようになるとかなり便利なので、このまま順当に進化してもらって実用になって欲しいところ。とりあえずclass問題がなんとかなるといいな。あと音周りもだぶんまだだよね?SDL_Mixer対応とか。

追記:

Emscripten自体はSDL_Mixer対応しているらしい。