EmscriptenとSDL2でSDL_LockTextureを使ったピクセル描画

SDL2で、SDL_LockTextureを使ってピクセル書き込み時にロックすることで、ゲームなどでも高速にピクセル描画ができます。このサンプルでは、Context->pixelsはバッファとして用意しましたが、memcopyなどで使う事はしていませんん。CreateTextureでテクスチャーオブジェクトを作るとメモリーも確保されるので、SDL_LockTextureでロックをして、for文で直接値を書き換えています。

ピクセルは、RGBAを8+8+8+8=4bytesで保持しています。ですがCreateTextureは単純なメモリブロックなので、そのままfor文でループすると、1バイト単位つまり、R,G,B,Aを別々に処理します。通常色を変更したい場合は、ピクセル単位で操作したいので、一度キャストをしています。

 

 

EmscriptenでSDL_UpdateTextureを使ったピクセル描画

SDL 1.2から2.0への移行(http://sdl2referencejp.osdn.jp/MigrationGuide.html) に、SDL_UpdateTextureを使ったピクセル描画について書かれていたので試してみました。こちらも問題なく動作しましたが、本来は静的画像ファイルを表示するときに使うようです。頻繁に更新する場合は、Emscriptenでピクセル描画とスケーリング で使ったSDL_LockSurfaceでロックをして書き込む方式が良いようです。

 

Emscriptenでピクセル描画とスケーリング

サンプルなどを調べて、一部分のみメモリー上の配列を、ピクセルとして描画して、さらにそれをスケーリングする方法が分かったのでコードをgistにアップしました。

スケーリングする方法

まず、640×480の画面サイズでWindowを作成しました。ピクセルを描画するときに、出力先のサイズ指定を1280*960にすることで2倍にスケーリングできます。実際にウィンドウのサイズを大きくするのではなく、このSDL_RenderCopyの値を変更するだけです。描画元の画像サイズを疑似的に1/2にすることでもスケーリングが可能と思われます。SDL_LockSurface(screen);でロックをします。

ピクセル描画

SDL_CreateRGBSurfaceで、サーフェスを作るとpixels属性が用意されるので、そこに書き込むことでピクセル操作が可能です。また書き込む際は、

 

EmscriptenのSDL2のライブラリ指定方法などのメモ

Emscriptenを試してみたので初歩的なメモを残しておきます。

インストールと最初のチュートリアル

Emscriptenは、Windowsでもインストーラーがあるのですぐに開発環境が構築できます。最初にhttp://kripken.github.io/emscripten-site/docs/getting_started/index.html を使うとemccの使い方が分かります。

サンプルソースコード

Emscriptenをインストールするとテストスイートもインストールされてそれがサンプルとなります。とくにSDL2を始めるときの参考になります。

そのままでは動かない。

Emscriptenは、emccコマンドを実行するとC/C++のソースコードをトランスパイルして、JavaScriptとHTMLを出力します。SDL2の場合は、通常のループ処理などを修正する必要があるようです。SDL_Delayを使ったループ処理は使えないので、ifdefマクロで分岐する必要があります。emscripten_set_main_loopのサンプルは以下が参考になります。

http://kripken.github.io/emscripten-site/docs/porting/emscripten-runtime-environment.html

http://stackoverflow.com/questions/29335510/using-sdl2-renderdraw-functions-with-emscripten

コンパイル時のSDL2ライブラリーの指定方法

https://kripken.github.io/emscripten-site/docs/compiling/Building-Projects.html

チュートリアルにはこの記述がなく、Google検索をしているときに見つけました。またemcc –show-portsでemscriptenに移植されたライブラリー一覧が確認できます。

ゲームのチュートリアル

EmscriptenとSDLでゲームを作るチュートリアルです。

https://lyceum-allotments.github.io/2016/06/emscripten-and-sdl-2-tutorial-part-1/

開発時の問題の切り分けに注意

EmscriptenとSDL2など何かライブラリーを使って開発する際は、C/C++の経験が豊富でない場合は、Visual Studio 2017 + SDL2でアプリを開発後に、Emscriptenに移植するという2段階で行ったほうがよさそうです。はじめからEmscriptenで開発するとプラットフォームに依存しなくなるのですが、SDL2ライブラリーの使い方が悪いのか、Emscripten特有の問題なのかの切り分けがしづらくなります。

 

Debian8(Ubuntu)でxtermのフォントを大きくして、Molokaiテーマにする方法

Xlibやglutを触るために仮想環境のDebian8.7のGUIを使いました。xtermの初期設定はフォントが小さく、初期設定では青が濃すぎてとても見づらかったです。またxtermやvimなど各種設定を調べるとかなり面倒でした。

設定方法

.vimrcに set t_Co=256を追加。

.bashrc、.profile、.bash_profileのどれかにexport TERM=xterm-256colorを追加

このTERM環境変数は、vimやgrepなどが256色使えるのか判断するために使われています。xterm自体の設定ではないです。

.Xresourcesを作成して、以下をコピペし、xrdb -merge ~/.Xresourcesを実行して反映します。

参考資料

xtermが256色をサポートしているか、vimが256色を表示できているかは、http://www.robmeerman.co.uk/unix/256colours をやってみるとよいです。

Debian8.7でopenbox

 

仮想環境のUbuntuが重すぎる の記事で、DebianのCUIインストールからX環境をインストールしました。その後日本語入力に挑戦してなかなかうまくいかず、https://7me.oji.0j0.jp/2016/virtualbox-debian-workspace.html を見つけたので、openboxをインストールしました。

キーボード設定1

/etc/default/keyboardをjp106に変更。

これで、ibus-mozcをインストールしたら、なぜかstartxでopenboxを起動すると、GUI上では英語版のキーボードになってしまいました。

https://wiki.archlinuxjp.org/index.php/Xorg_でのキーボード設定 を参考に、setxkbmap -print -verbose 10を実行したところlocaleがCでlayoutがusになっていました。

pc(pc104)も気になりますがひとまず、以下で変更できるようです。

いろいろ試していますがなかなか日本語入力ができない。

 

仮想環境のUbuntuが重すぎる

Ubuntu16.04をHyper-V環境に入れて、openboxに切り替えたのですがxtermのvimで日本語入力の挙動が安定していなくてどうしようもない状態なので、Debian8.7+twmの環境をひとまず用意しました。

Debianのインストール

https://www.debian.org/distrib/ から 64ビット PC netinst.isoをダウンロードして、デスクトップ環境をインストールしない状態でCUIのみのインストールにしました。後でインストールも可能ですが、SSHサーバはこの時に有効にしました。Windows10のHyper-Vにインストールする場合は、http://www.lowefamily.com.au/2016/08/05/how-to-run-debian-on-hyper-v/が参考になります。

マルチメディア

debianは初期設定でロイヤリティーフリーなので、マルチメディア関係を有効にするために、debian-multimediaのリポジトリを追加しました。apt-get install deb-multimedia-keyringが必要になると思います。

最小のX環境構成

https://www.xmisao.com/2014/01/16/debian-initial-settings.html

X環境を用意するには、xserver-xorgをインストールします。xinitコマンドとそのフロントエンドスクリプトのstartxを実行するためにxinitをインストールします。ウィンドウマネージャーは、twmをインストールします。X標準なのでxserver-xorgとともにインストールされると思ったのですが別途必要でした。x11-appsはxclockなどです。とりあえずxterm以外も動作確認できるようにインストールしました。xclock -d -update 1&で起動したら漢字の表記も問題ありませんでした。xtermは、xserver-xorgと同時にインストールされるので、個別にapt-getする必要はありません。x11-xserver-utilsをインストールするとxrdbコマンドが使えるようになります。

情報の整理

GNOMEやKDEやopenboxやtwmはXウィンドウマネージャーと言います。これが画面の見た目を左右します。もうひとつ重要な概念としてXディスプレイマネージャーというがあります。これは単純にGUIのログイン画面です。最もシンプルなのはX11ができたころからのxdmがあります。GNOME環境だとgdmです。

DebianをCUIの構成でインストールすると、グラフィックなログイン画面(Xディスプレイマネージャー)を使わず、CUIでログインして、startxコマンドでGUI環境を起動することも可能です。私のXの最小構成もXディスプレイマネージャーをインストールしていません。(apt-get install gdmで簡単にインストールできます。)

initxとstartxとxinitrcの関係

Xの最小構成の場合、WindowsやOSXなどのように優しくありません。単純にstartxをするとXが立ち上がりますが、何も表示されず何も動かせない状態になり、他の環境からSSHで接続してkillするなどが必要になります。なのでinitxとそれを呼び出すstartxシェルスクリプトをこの機会にすこし調べてみるとよいです。

initxの全体の設定ファイルは、/etc/X11/xinit/xinitrcになります。見てもらえば分かるように/etc/X11/Xsessionを読み込む以外は何も書かれていません。そのためstartxやinitxをやると、GUI画面にはなるけど真っ黒な状態で何もできなくなってしまいます。

GNOMEやKDEのようにやさしくはありませんが、ユーザー用の数行の設定ファイルを書けばよいだけです。

ユーザー用の.xinitrcを作成

startxはシェルスクリプトで内部でinitxを呼び出します。initxのユーザー単位の設定ファイルは、$HOME/.xinitrcになります。とりあえず以下をコピペして使えばよいです。

一行目のユーザーの.Xresourcesを読み込んでデータベースを更新します。まだ.Xresourcesを使ってませんが、ここにxterm端末エミュレータのフォント設定などを書き込みます。.Xresourcesをすぐに反映したい場合は、以下のコマンドで出来るようです。ですが私の場合は以下のコマンドがうまくいかない場合があるので、ログアウト・再ログインをしています。

二行目は、xtermを起動しています。 -geometry +X座標+y座標で起動します。三行目でexecコマンドでウィンドウマネージャーを起動します。

GUI(twm)の停止の仕方

GNOMEやKDEはログアウトなどがありますが、twmは本当にウインドウ表示とリサイズなどシンプルなことしかできないです。twmをkillすると、ウィンドウマネージャーも停止できるので、起動したxterm上で、killall twmでGUI環境を終了します。

 

まとめ

Ubuntu16.04をHyper-Vで動かしていたので大変つらかったのですが、恐ろしく軽いGUI環境が手に入りました。あとは日本語IMEとopenboxウィンドウマネージャーに切り替えればかなりいい感じになりそうです。

 

 

ShellScript(Bash)でのx$VER=xyesを使ったテクニック

configure.acは、m4マクロとシェルスクリプトが書けます。libsixelのconfigure.acを元にautotoolsの勉強をしていたら、以下のように、x$varname = xyesというシェルスクリプトを見つけました。

はじめは、唐突にxが出てくるのかが分からなくて、autoscanやm4マクロの決まった仕組みと思っていましたが、シェルスクリプトのテクニックでした。

上記で、have_gl=yesの場合は以下に置換されます。

例えば、have_gl=のように空の場合は、以下に置換されます。この場合、文字xが残っているので、シェルスクリプトの文法として問題ありません。

 

上記のように、もし、testの引数が”$have_gl”で、$have_gl=のように、値がからの場合は、変数の置換のみが起こり、testの引数が以下のように足りなくなってしまいます。つまり、変数の値が空の時に、シェルが動かなくなります。そのためtestを使うときに、xとxyesを使ったテクニックがあるようです。

 

http://stackoverflow.com/questions/174119/why-do-shell-script-comparisons-often-use-xvar-xyes

https://github.com/saitoha/libsixel/blob/master/examples/opengl/configure.ac

libsixelのOpenGLのデモからXlibのコードを削除してみる

前回の記事、「libsixelのOpenGLのデモを調べるためOpenGLとXlibでアニメーション 」でXlibとOpenGLの基本が分かりました。

改めてサンプルソースコードを見てみると、Xlibは使っていないので、その部分とOSXの部分を削除して、ビルドして無事に動作できました。

表示だけなら純粋なOpenGLなので、ひとまず何か作れそうなところまで来ました。

 

libsixelのOpenGLのデモを調べるためOpenGLとXlibでアニメーション

https://www.khronos.org/opengl/wiki/Programming_OpenGL_in_Linux:_Programming_Animations_with_GLX_and_Xlib を参考に、FPSの計算などを無視してとりあえず、count += 0.01のようにしてOpenGLのアニメーションをしてみました。

このプログラムを書いてみて、Xlibはselect関数を使ったりするのかと思っていたのですが、単純なOpenGLプログラムの場合は、ループ文とusleepでよいようです。

libsixelのOpenGLのselect

https://github.com/saitoha/libsixel/blob/master/examples/opengl/main.c

改めてソースコードを確認すると、selectは、端末エミュレータのカーソル位置に関係して使っているようです。もしかするとこのサンプルはXlibの依存をなくすことができるのかもしれません。