読者です 読者をやめる 読者になる 読者になる

S.F. Page

Programming,Music,etc...

WebGL + GLSLで、レトロPC風の文字キャラクタを表示する - PCグラフィックスを懐かしむ。楽しむ。(10)

PCグラフィックス JavaScript WebGL HTML5 GLSL 古典的グラフィック技術を懐かしむ

プリミティブの描画の前に、この環境での文字表示を作るのを忘れていたので、作ることにした。 VRAMプレーンで行ったことを応用すればできるはずだ。

デモページ:

http://github.sfpgmr.net/graphics/devver/20160410/index.html

ソースコード: https://github.com/sfpgmr/graphics/tree/93af7591c70e70fe5df3f7115b07fcaf5d32558a

文字表示は以下の仕様となっている。

  • 文字は8x8ピクセルのサイズ、40桁×30行。
  • キャラクタVRAMおよびアトリビュートVRAMをそれぞれ1枚ずつテクスチャで持つ(64x32ピクセルのgl.LUMINANCEとして)。
  • アトリビュートVRAMの仕様はMZ-700とほぼ同じ。
  • キャラクタVRAM/アトリビュートVRAMに文字コード/アトリビュートコードを書きこむと文字が表示される。

文字データはMZ-700のエミュレータ(MZ700WIN)に入っていたフォントデータ(mz700fon.txt)を使わせていただいた。

シェーダーコードはちょっと複雑になってきた。

// パレットエミュレートシェーダー
var vshaderPSrc = 
`precision mediump float;
attribute vec2 position;
attribute vec2 texture_coord;
varying vec2 vtexture_coord;
 
void main(void) {
    gl_Position = vec4(position,0.0,1.0);
    vtexture_coord = texture_coord;
}
`;

var fshaderPSrc = 
`precision mediump float;

uniform sampler2D textureB;
uniform sampler2D textureG;
uniform sampler2D textureR;
uniform sampler2D pallet_color;
uniform sampler2D textureFont;
uniform sampler2D textureCharCode;
uniform sampler2D textureCharAttr;
uniform float time;

varying vec2 vtexture_coord;

// グラフィック表示
vec4 graphicPlane(void)
{
  //テクスチャ座標よりビット位置を求め、そのビットが立った2進数値を得る。
  float t = exp2(floor(mod(vtexture_coord.x * 512.0,8.0)));
  // RGB各プレーンの現在座標のバイトデータを読み込む
  vec4 rt = texture2D(textureR, vtexture_coord);
  vec4 gt = texture2D(textureG, vtexture_coord);
  vec4 bt = texture2D(textureB, vtexture_coord);
  
  // バイトデータの中でビットが立っているかどうかを調べる
  // Rプレーン
  float r = floor(mod(min(rt.x * 256.0,255.0) / t,2.0)) * 4.0;
  // Gプレーン
  float g = floor(mod(min(gt.x * 256.0,255.0) / t,2.0)) * 2.0;
  // Bプレーン
  float b = floor(mod(min(bt.x * 256.0,255.0) / t,2.0));

  // 各色の値を足して正規化を行い、パレットインデックスから実際の色を得る 
  vec4 p = texture2D(pallet_color,vec2((r + g + b) / 8.0 ,0.5));
  float i = min(p.x * 256.0,255.0);
  float ar = floor(mod(i * 0.5,2.0)); // bit3
  float ag = floor(mod(i * 0.25,2.0));  // bit2
  float ab = floor(mod(i,2.0)); // bit1
  return vec4(ar,ag,ab,1.0);
}

// 文字表示
vec4 textPlane(void){
  // キャラクタコードを読み出し
  vec4 cct = texture2D(textureCharCode, vtexture_coord);
  float cc = min(cct.x * 256.0,255.0);// キャラクターコード

  // アトリビュートを読み出し
  vec4 attrt = texture2D(textureCharAttr, vtexture_coord);
  
  // 表示対象の文字のビット位置を求める
  float x = exp2(floor(mod(vtexture_coord.x * 512.0,8.0)));
  // 表示対象の文字のY位置を求める
  float y = floor(mod(vtexture_coord.y * 256.0,8.0));
  
  // アトリビュートの評価 

  float i = min(attrt.x * 256.0,255.0);// アトリビュートデータ
  
  // キャラクタセット(0.0 .. セット0, 1.0 .. セット1 )
  float att = floor(mod(i / 128.0,2.0)) * 8.0;// bit 7

  // 文字色
  float ccg = floor(mod(i / 64.0,2.0));// bit 6
  float ccr = floor(mod(i / 32.0,2.0));// bit 5
  float ccb = floor(mod(i / 16.0,2.0));// bit 4

  // 背景色
  float bgg = floor(mod(i / 4.0,2.0));// bit 2
  float bgr = floor(mod(i / 2.0,2.0));// bit 1
  float bgb = floor(mod(i ,2.0));// bit 0
  

  // フォント読み出し位置
  vec2 fontpos = vec2(cc / 256.0,(y + att) / 16.0);
  // フォントデータの読み出し
  vec4 pixByte = texture2D(textureFont,fontpos);
  // 指定位置のビットが立っているかチェック
  float pixBit = floor(mod(min(pixByte.x * 256.0,255.0) / x,2.0));
  
  if(pixBit == 1.0){
    // ビットが立っているときは、文字色を設定
    return vec4(ccr,ccg,ccb,1.0);
  } 
  // ビットが立っていないときは背景色を設定
  return vec4(bgr,bgb,bgg,1.0);
}

void main(void){
  vec4 textColor = textPlane();
  if((textColor.r + textColor.g + textColor.b) > 0.0){
    gl_FragColor = textColor;  
  } else {
    vec4 color = graphicPlane();
    gl_FragColor = color;
  }
}
`;

そういうことで懐かしのキャラクターがWebGLで表示できた。。

https://41.media.tumblr.com/2ba6430e5fea782d8213188ef4cb01dd/tumblr_o5em2hzZU51s44dwzo1_1280.png

文字コードを見たらMZ-700が家に届いたときの興奮が蘇ってきた。急いでテレビにつないで、ベーマガのゲームを慣れないキーボードと格闘しながら入力したのを思い出したよ。最初は打ち込みミスでバグってちゃんと動かなかったんだよね。ゲーム向きなキャラクタも含まれていて、投稿作品によく使われていたな。

MZ-700の文字コードはASCIIやJIS8ではないんだよね。ディスプレイコードとかいうらしい。JSから打ち込んだ文字を表示させるには変換が必要だ。それはまあなんとかなるかな。