glReadPixels GL_RGBAで動きました

こんな感じで動きました。

v_pixels_len = (int)Z_LVAL_P(width) * Z_LVAL_P(height)* sizeof(long);
v_pixels = emalloc(v_pixels_len);
glReadPixels((int)Z_LVAL_P(x),(int)Z_LVAL_P(y),(int)Z_LVAL_P(width),(int)Z_LVAL_P(height),(int)Z_LVAL_P(format),(int)Z_LVAL_P(type),v_pixels);
long_array_to_php_array(v_pixels, v_pixels_len, pixels);
  • 第7引数を参照渡しとして指定する
  • 第7引数を元にバッファを作るのをやめて、渡されたサイズを元に emalloc する
  • (C側の)glReadPixel の結果を第7引数に埋め込む。

glReadPixelsの使い方 (暫定)

  • 関数の呼び方
$pixels = array(); // 空配列を渡す
glReadPixels(0, 0, $width, $height, GL_RGBA, GL_UNSIGNED_BYTE, $pixels);
  • 画像ファイル保存

GD で画像を生成する為にピクセルデータを構築するのは、signed long を RGBA として解釈するので、ちょっと面倒だけど。
以下ので出来ました。

    // GD でキャンバスを作る
$im = imagecreatetruecolor($width, $height);
$i = 0;
// pixels 配列を R, G, B, A(無視) の順で解釈してイメージを作成
for ($y = $height ; $y >= 0; $y--) {
    for ($x = 0; $x < $width ; $x++) {
        $rgb = $pixels[$i];
        if ($rgb < 0) {
            $rgb += 4294967296; // integer => float
        }
        $blue  = $rgb % 0x100 ; $rgb /= 0x100;
        $green = $rgb % 0x100 ; $rgb /= 0x100;
        $red   = $rgb % 0x100 ; $rgb /= 0x100;
        $color = imagecolorallocate($im, $red, $green, $blue);
        imagesetpixel($im, $x, $y, $color); // pixel を埋めていく
        $i ++;
    }
}
imagepng($im, "output.png"); // PNG ファイルとして保存!!!

PHP の integer は 0x80000000 以上の正の値を扱えないので、
その場合は float に格上げして、ビット演算をあきらめて mod で処理してます。(unpack 使えって話ですね。すみません)

課題

PHP で無理やりバイト処理は心臓に悪いので、

array(array('red'=>..., 'green'=>..., 'blue'=>..., 'alpha'=>...))

の形式で返した方が良いと思いました。

メモリ使いすぎる問題は、それ以前に(パフォーマンス的に) PHP
こんなループ処理する事自体間違えてるので、extension の C 側の
ルーチンで全部処理するのが正しいですね。

yglImagePNG($filename); みたいにバッファ吸出し&画像出力を
C 言語側で閉じて処理する新規 function を作ってみよう。