M5Stack:ガッツでC.G.!

最初にスイマセン。テスト時に使用していたナウシカのデータは「ガッツでC.G.!Vol.2」のプログラムデータを流用してたものなので、それについてのデータは配布できませんのでご了承ください。


M5Stackでのライン&ペイントによる描画プログラムが完成しました!

GitHub から取得してくださいー。

retroPCCG
https://github.com/shikarunochi/retroPCCG/tree/master/MicroPython

flashフォルダの下をプロジェクトに入れて、sdフォルダの下をmicroSDカードに入れてください。sdフォルダの下は、テスト用データです。

この絵が描けます。どうやって描いたかは、こちらの記事をどうぞ!

M5Stack:「くっ!ガッツが足りない!」…でも何とかなるツール


使用するデータファイル形式です。

320,240,0xffffff,0
-10,0,109,92,109,91,109,91,108,90,-1 
0,124,35,124,34,124,31,125,30,125,29,-1,-1
-20,0xf7cbd0,158,142,-1,0xe60136,149,43,-1,-1
(以降続く)

1行目:縦サイズ、横サイズ、背景色、枠色。
(枠色は縦横サイズが画面サイズより小さいときのみ使われます。)
2行目以降:描画命令です。LINE(-10)とPAINT(-20)があります。


-10:LINE
色、開始位置(x,y)、次の位置(x,y)、その次の位置(x,y)、と続きます。「-1」が来ると、いったん線を切ります。
線が切れている状態でさらに「-1」が来ると、LINEモードを終了します。色はRGB888コードで入力してください。画面表示はRGB565なので、微妙な色の違いは丸められちゃうと思います。


-20:PAINT
色、塗る位置(x,y)、色、塗る位置(x,y)、次の塗る位置…と続きます。
「-1」が来ると、色指定に戻り、さらに「-1」が来ると、PAINTモードを終了します。


これをSDファイルに適当な名前で保存してください。main.py からこういう感じで呼び出しです。

retroPCCGObj = RetroPCCG()
retroPCCGObj.executePaint("/sd/test.dat")

過去に発表されたFM-7等のレトロPC用CGデータをなるべくそのまま流用できるように、パラメータ設定ができるようにしてあります。必要であれば、executePaintの前に呼んでください。

retroPCCGObj.setParam(0.5, 0)

パラメータ1つ目は、X方向の縮小。0.5を指定すると、640ピクセルを320ピクセルで表示しします。
2つ目はLINEやPAINTでの区切り判定。通常は「-1」ですが、過去のCGデータでは「0」を使っていることも多いので、設定できるようになっています。

データの不整合チェックはあんまりしっかりやってないので、不整合があったら途中で止まると思います。


ペイント処理のためには、画面上でどこまで塗るか判定するために、画面ピクセルの状態を取得する必要があります。

M5Stackのドキュメントに、ピクセル取得関数(lcd.readPixel)が載っていたので、使えるのかと思ったのですが、どうやらこれは動作しないようです。(ハードウェア構成的に無理だったことがわかって、最新版のM5Cloud では命令も削除されているようです。)
(→ピクセル取得に関しては、後日、ハードウェアは問題なくて、ライブラリ側が未対応だっただけのことが判明しました。この時点では使えない前提で書いてます。)


画面上から色が取得できないのであれば、メモリ上に画面と同じ状態を保持しておくしかないです。320 x 240 x integer(4byte) = 307200 byte。うまく工夫して色を2byteで保持したとしても 320 x240 x 2byte = 153600byte。 …ちょっと厳しそうです。

いろいろ考えた結果、ピクセルONかOFFかの白黒データのみをバイナリ形式で保持することにしました。これなら、320 x 240 x 1bit(= 1/8byte) = 9600byteでいけます。その代わり、色の区別ができないので、一度塗ったところを再度塗ることはできません。


情報をビットとしてで保持するのがかなりめんどくさいところなのですが、@te3gameさん作成のロジックを使わせていただきました。これ、僕にはサクッと書けないところなので、すごく助かりました。

BARRAYクラス
https://qiita.com/rrii/items/0e83c143683e2abafe65

メモリ上で描画データを保持するのであれば、線の描画についても、lcd.line命令を使うわけにはいかず、自前でロジック書いて行う必要あります。ブレゼンハムのアルゴリズム を使いました。

Wikipedia
ブレゼンハムのアルゴリズム

ペイントのロジックはシードフィルアルゴリズムです。
以下のサイトを参考にしました。というか、ほぼそのまま使わせてもらいました。

Fussy’s Homepage : (1)シード・フィル アルゴリズム
http://fussy.web.fc2.com/algo/algo3-1.htm


ということで、動作はこういう感じ。MicroPythonでもメモリ不足にならずに処理できました。いけるもんですね。(でも時々落ちるみたいです。やっぱメモリ不足?)

実は、メモリ的に厳しいかと思って、ほぼ同様のロジックを、まずArduinoでも書いてみてました。さすがに早い。