プライオリティ管理は、シンプルにOT(OrderingTable)でいくことにした。
これは各プライオリティ値に属するオブジェクトのリストを持ち、各リストを順に処理していくという方式。プライオリティが設定された段階で、各オブジェクトはそのプライオリティのリストに自身を登録するので、プライオリティ値によるソートが端的に不要となる。
このOTの考え方をもう一つ押し進めて、「テクスチャごとに独立したOTを持つ」という方式を採用。こうすると、同じテクスチャアトラスを用いるものは連続して描画できるし、間のプライオリティに異なるテクスチャアトラスを用いるものが登場しても正しく処理できる。描画そのものはキュー方式で行われるので、プライオリティをまたいでも同じアトラスが使われているものは同時に描画できる。固定の頂点バッファを用いて縦横1.0の正方形をスケーリングのかかったマトリクスで描画するのは昨日の構想通り。当然全オブジェクトで拡大縮小回転可能。キューに描画対象が32個溜まるか、テクスチャが切り替わるか、あるいは最後の余りもの処分かでのみGL描画をキックする。
2D描画系では左上原点が最も馴染み深いだろうということで、左上原点ピクセル単位座標系を採用。各オブジェクトも左上の頂点を原点とする。テクスチャクラスが3Dと兼用であるため左下原点になっているのは少々悩んだが、「左上原点とした場合のmethod」を用意することで吸収することにした。
残念ながら横方向に一定数以上並んだ時にちらつかせる機能は実装していないw *1
昨日のshaderは動作も確認していないだんかいで「こうかな?」というものだったので、実際に動いているものはこちら。
attribute highp vec2 a_vert; attribute mediump vec2 a_params; uniform highp mat4 u_projection; uniform mat3 u_mat[32]; uniform vec4 u_uv[32]; uniform vec4 u_rgba[32]; varying vec2 v_uv; varying vec4 v_rgba; void main(void) { int idx = int(a_params.x); vec2 lt = vec2(u_uv[idx].x, u_uv[idx].y); vec2 rb = vec2(u_uv[idx].z, u_uv[idx].w); v_uv = (rb - lt) * a_vert + lt; v_rgba = u_rgba[idx]; vec3 v = u_mat[idx] * vec3(a_vert, 1.0); gl_Position = u_projection * vec4(v, 1.0); }
precision mediump float; uniform vec4 u_bright; uniform sampler2D u_tex; varying vec2 v_uv; varying vec4 v_rgba; void main(void) { gl_FragColor = texture2D(u_tex, v_uv); // * v_rgba * u_bright; }
*1:フレームバッファ描画登場以前の時代のゲーム機はスプライトの映像信号をラスタ(走査線)単位で生成していたため、横方向に一定数を超えるスプライトが並ぶとそれ以降のものが描画されなくなるという仕様だった。ファミコンやMSXはもちろん、X68000まで。このため昔のゲーム機は横方向にいくつのスプライトを同時に表示できるかというのがゲーム機としての性能を示すステータスだったわけだが、フレームバッファ描画の登場以降そんな指標は全く意味を為さなくなったw 自分が最初に見たフレームバッファスプライト描画を行うハードウェアは、おそらく FM-TOWNS だったと記憶しているが、描画プロセッサによらないCPU描画であることを覗けば、X1やPC-8801,PC-9801などの「グラフィックRAM」も「フレームバッファ」と言えなくもない。違いはそこへの描画を行うのが描画プロセッサかCPUかだ。