ここんところ、RaspberryPi Picoで遊ぶのが楽しくて仕方がない!ヽ(=´▽`=)ノ
半導体不足でRaspberryPiが手に入らない現在であっても、Picoは比較的簡単に手に入る。
しかも税込み550円!(ピンヘッダ付きは990円)
そして480x320ドットの大型液晶は税込みで2530円。
両方あわせて3000円ほどのマシンで、これほどまで遊べるなんてスゴイ!(^-^)
まだまだPicoを使いこなしてる感覚は無く、いまだに「あ、こんな速度で動いちゃうのね」と驚くことが多い。奥が深いぞ、Pico!(^o^)
さて、先日からRaspberryPi PicoにArduino BASICを移植してる!
前回のブログの最後にチョロっと書いた、グラフィック命令の追加をしてみる。
もはや移植というよりは拡張と言った方が良いのかも知れない(^^;;
追加できるのか検討
まずは想定しているグラフィック画面を定義をしてみる。
グラフィック画面の広さは480x320ドットとする
やっぱり画面全体をグラフィック画面として使えるようにしたい。
ただし下の12ドットはステータス表示がされてしまうので、基本は見えない。
CONSOLE命令でも追加して、ステータスのON/OFFでも入れようかな…?
カラーは256色にする
これは主にメモリの制限によるスペックダウン。
480x320ドットで65536色を表示させるために必要なメモリは300KB。
RAMが256KBしかないPicoには残念ながら入らない。
そこで、色数を256色に落とす事で必要なメモリは150KBとなる。
カラー番号と実際の色の対応は、MSXの256色モードを参考にさせていただいた。
テキスト画面とグラフィック画面は分離
テキストをスクロールさせてもグラフィックには影響が出ないような構造にしたい。
これはPC-8801を想像してもらえれば良いかなーと思う。
グラフィックとテキストの合成処理が必要となるが、これは難しくない。
BASICのコマンドは変更ではなく追加
今ある命令を拡張して機能を追加していくのは、いらぬバグを引き起こす可能性もある。
グラフィックを扱う命令は新規追加する方向で命令を考えてみる。
追加する命令はGCLS、PSET、LINEの3つのみ。
余裕があったらCIRCLEやPAINTも検討したい。
実装してみる!
方針は決まったので、さあやってみよう!
150KBのメモリ確保は、固定でしてしまえば良いので簡単としても…
やっぱり気になるのは、256色→65536色の変換が現実的な速度で行う事が出来るのだろうか…という事だ。
色数が256しかないので、ここは256個のテーブルを生成してメモリに置いておくのが良いかと思う。気をつけないといけないのは、メモリアクセスはキャッシュから外れると極端に遅くなる場合があり、計算で求められるデータはその都度計算した方が速い場合がある。
コードを想像してみよう。
uint8_t *gvram = グラフィックRAM;
uint16_t *buff = 変換後の格納バッファ;
for(int i = 0; i < 横幅; i++)
*buff++ = gColorTable[*gvram++];
うん、このくらいプログラムが局所的であればキャッシュの効果は期待できそう(^^)
出来上がったバッファの上に、テキストデータを合成していく。
現在のBASICは、テキスト文字が変更されると画面が更新される仕組みになっている。この仕組みを上手に利用しようと思う。
グラフィックデータが更新されたらテキストデータを更新しましたフラグを立て、テキストを更新するついでにグラフィックも表示するようにした!(意味通じる?^^;)
つまり、絵のデータが1ドット変更されたとしても、縦12ドット横480ドット更新されるw
これで現実的な速度が出るのかなぁ…と思ったが、やってみたら全然平気だった!(^^)
このテストをしていた時に表示していた画面が↑これだった。
矩形の色はBASICで書いたのではなく、C++プログラムで書いている。画面をクリアするとこの画面が出るようにしておき、テキストとの合成も同時にテストした。
よし!これでグラフィック画面が追加できそうな見込みが立った!(^o^)
グラフィック画面をRAMに保持する事で、RAMの使用状況は73%となった。
BASIC命令の追加
BASICの命令を追加してみるテストとして、まずはフォントデータ幅の切り替え命令を追加してみた。
FONT
とすればフォントサイズが横8ドットと6ドットが切り替わるだけの簡単な仕様(^^)
これでいちいちビルドオプションを変更してビルドし直さなくても、動かしながら動的に変更する事ができるようになった。引数もないので簡単実装(^^)
GCLS
グラフィック画面をクリアする命令を追加。引数はなし。
画面全てをクリアするためにはCLS:GCLSと2つ呼ぶ必要がある。
PSET(x, y),color
これで画面上にドットを打つことが出来る。ドットを消すPRESET命令はないが、PSETでカラーに0を指定すればドットは消える。
整数の引数を3つ取る命令が存在しなかったため、新たにParserを書くこととなった。なんか構造的にキレイに書けそうな雰囲気があったのだけど、どうにもうまくいかなかったので、べったりなコードを書くことになった(T-T)
1000個のドットを描画するのに一瞬!速すぎますよ!!(^^;;
そこで雰囲気を出すために、1ドット描くごとにグラフィック画面を更新するようにしたところ、ちゃんと遅くなったw
LINE(x1, y1)-(x2, y2),color
画面に指定色の線を引く。
うーん…このカッコとマイナスのある文法、BASIC特有かなーと思うけれど、Parser書くのが面倒だ(^^; 今回はソースをベタっと書いたけど、もう1つ命令を追加するチャンスがあったらキレイに直そうと思うほどのコードになった(^^;
LINEの描画は、有名なブレゼンハムのアルゴリズムを採用した。そのおかげもあってか、めちゃくちゃ速い!(^-^)
こちらも線を1本引くたびにグラフィック画面を更新したら、それっぽい表示になった!
おわりに
グラフィック命令が使えるようになると、昔テクノポリスという雑誌に載っていたBASICで描くグラフィック画像とかを試したくなる!
そのためにはPAINTが必要だし、プログラムによってはWINDOW / VIEWPORTなどが必要になりそうで大変だなー…。いや、やりませんよ?(^^;;
BASICが動くようになってくると、スプライト命令あったらゲーム作れそうだよね、とかPCG機能は簡単に入りそうだな…とか、もういろんな事を考えてしまう!(^^;
終わりがなさそうな気がするので、一旦キリにしようと思う!
ではまた次回!(^-^)ノ