ずっと前からMAMEでのATARI STARWARSの描画に納得がいってなかった。敵弾はもっとギラギラ光ってたし、被ダメージ時には画面がチカチカするし、デス・スター爆発は眩しかったし。そう思ってたけど、修正するのは大変そう。
ちょっと前に、あることがきっかけで「MAMEでSTARWARSを動かして描画されたベクターデータをファイルにダンプ」「そのダンプファイルをSVGに変換して1フレームずつ表示するWebアプリ」をClaude Codeに作ってもらったことを書いた。その時にいろいろ調べた結果、「敵弾がキラキラする理由」「被ダメージ時に画面が点滅する理由」「デス・スター爆発が眩しく見える理由」がおおよそ判明した。
ATARIのカラーベクターゲームに使用されているAVG(Analog Vector Generator)では、下記のコマンドで描画を行う。実際にはジャンプやコール・リターンなどもあるけど省略。
- CNTR 描画位置を画面中心にリセット
- SCAL 描画時のスケールを設定
- STAT 描画時の輝度・カラーを設定
- VCTR 指定されたX/Y方向に指定した輝度でベクターを描画、輝度が0だと描画位置の移動のみ
STARWARSだとSTATで指定するIntensity(輝度)が8bit、VCTRで指定するIntensityが3bitである。で、眩しく光ってる敵弾とデス・スター爆発の時のベクターは「STAT Intensity:0xff」「VCTR Intensity:0x7」と最大レベル。つまり最高輝度で何かが起こってる。
古くから存在しているドキュメント「The Secret Life of Vector Generators」を改めて読んでみると、今まで気づかなかった部分を発見した。
The Secret Life of Vector Generators
該当部分を翻訳して引用したのが下記の一節。
デス・スターを思い通りに爆発させるには、同心円をたくさん描くだけでは不十分でした。ビームをぼかして、画面を埋め尽くしたかったのです。フォーカス電圧を制御するために、モニターに真空管を追加することも検討しました。幸いなことに、その部品の納期が長すぎました。そこで、ベクトルジェネレーターにモニターのカラー入力をオーバードライブする機能を持たせることにしました。入力をオーバードライブすると、CRTは通常よりも多くの電流を消費し、高電圧が低下します。これにより、フォーカスグリッド電圧とアノード電圧の通常の比率が変化し、ビームがぼやけます。
つまり設計上、Intensityはオーバードライブ領域まで突っ込めるようになっていて、その時にビームがぼやけて太くなると。コレですわ。
先の「ベクターダンプデータを元に表示するWebアプリ」に、そのオーバードライブ時の処理を入れてみたらいい感じに表示された。ビンゴだ。被ダメージ時に画面が点滅するのは、画面外にこのオーバードライブ状態のベクターが描かれたら光らせればいい。これも良い感じ。
じゃあこれをリアルタイムでやればいいのか? MAMEの改造とかしんどすぎるよ、と思いつつClaude Codeに頼んでみると行けそうな感じ。マジか?
しかし上手く行かない。bgfxとか知らなかったので、Claudeに指示する方もふんわりした言葉でしか出せないのが原因。作って壊して勉強しての繰り返し。なんとか三回目で納得いくものが出来た。
ある時、Windows限定でMAMEを「-video d3d -hlsl_enable」で起動すると、Direct3D9を利用したレンダラがベクタースキャンゲームで有効になることに気づく。こっちの方が見た目がいい。じゃあこれを急遽マルチプラットフォーム対応のbgfxに移植して、先のオーバードライブと画面点滅を実装すればいいんじゃねと。
しかしそのまま移植するとかなり重たくなってしまった。たまたま40fpsのSTARWARSだとギリギリで動いてしまうので気づかなかったけど、60fpsのTEMPESTだと処理落ちする始末。慌てて軽量版を作って回避したり、RTXの自動輝度補正が悪さをして原因究明に時間がかかったり。
そしてなんとかなった。ソースコード・ドキュメントはほぼすべてClaude Codeによるもの。動画はNVIDIAツールで録画しただけの代物。敵弾と被ダメージ表現は我ながらいい感じだと思う。デス・スター爆発はもうちょいなんとかしたかったけど、改善するにはMAMEの表示周りを大改造しないとダメだと思う。
被ダメージ時のモニタ点滅のメカニズムを動画で再現、蛍光面の外に強いビームを出すとブラウン管内部で拡散されてモニタが光る。エミュレータでもちゃんと実物と同じ動きをするのは作った本人でも感動する。
TEMPESTデモアトラクトも出しておく。実機には負けるけどタイトルの眩しい感がポン出しで出せたのは嬉しい、実機だとモニタが焼けるほどの輝度だし。
Windows 64bitバイナリは下記からダウンロード出来るので、試せる人は試してください。当たり前だがROMイメージは付いてないので自分で用意する事。アーカイブ中のvector-mod.txtを読んでbgfxにしないと見た目が変わらないので注意。非力なマシンだとちょい厳しい。CPUよりグラボ依存。
Release MAME Vector CRT Mod (0.288, Windows x64) · okaz-code/mame
そしてMAME devにpull requestも出してしまった。ちゃんと規則を守って出してる。大丈夫なんかなコレ。
MAMEに元からあるD3D hlslから移植・改造した項目は下記の通り
- 蛍光体残像
- 色変換/コンバージェンス
- デフォーカス
- シャドウマスク
- 球面(樽)歪み
- 長いベクター線の輝度減少
- 多段BLOOM(8 段・RGBA16F 累積)、オリジナルの15段を軽量化
自分で設計して追加した項目は下記の通り
- ベクター線両端の円描画処理
- HALO平滑化(BLOOMの段数が少なくなった代わりの措置)
- 糸巻き歪み
- 縮小によるオーバースキャン領域の表示
- フレーム単位でのフリッカー処理
- RGBカラーの調整
- オーバードライブ(STARWARSのみ)
- モニター発光(STARWARSのみ)
その他いろいろあったかも。ありすぎて分からん。
非力なマシンではダメだと思ってはいたけど、手持ちのSurface Pro4でフレームレートガタ落ちになったのには笑えなかった。さすがに仕方がないか?
まだやりたいネタは色々あるけど、これ以上は流石に手間暇が大変そうなのでちょっと休もう。
お疲れ様でした。
スターウォーズのベクタースキャンのあのキラキラというかギラギラが再現されてて感動しました。
Hi! I am David (Seleuco), the developer of MAME4droid.
I recently saw your pull request on the upstream MAME repository, and following the thread brought me to your blog. Fantastic research on the Atari hardware and the “Secret Life of Vector Generators” document!
I’ve also been working recently on a major overhaul of the vector rendering pipeline for my Android port. Reading your posts, I noticed you have implemented some brilliant ideas (like the off-screen monitor glow) that I haven’t applied yet.
I wanted to invite you to take a look at my work and see if you’d be interested in bringing your improvements over. One thing I’ve recently implemented in MAME4droid—which I honestly think currently beats the desktop MAME pipeline (even with BGFX)—is true FP16 HDR rendering. If you have a modern Android phone with an HDR display (like a Google Pixel), the raw light energy of the vector neons looks absolutely incredible with real peak nits.
Since MAME4droid is a port, we have much more freedom to experiment and implement features than the strict upstream MAME guidelines allow. If your PR faces architectural hurdles getting merged into mainline, maybe we can easily integrate your improvements here.
As a strict rule for my port, I avoid modifying MAME’s core files, so I haven’t touched the core vector.cpp or the sigmoid function. Instead, all my physics, beam dynamics, and “Overbright” calculations are done entirely dynamically within my custom GLES3 renderer. I was thinking that maybe your monitor glow effect could be successfully reproduced purely on the renderer side by tracking and accumulating the overbright energy, even for off-screen vectors.
You can check out my recent releases, the HDR renderer, and the source code here:
https://github.com/seleuco/MAME4droid-Current/releases
Let me know what you think. Again, amazing work on the Star Wars physics!
Hi David, thanks so much — that means a lot coming from you, MAME4droid is fantastic work.
And of course, please feel free to explore and adapt the monitor-glow idea however you like. It’s all BSD-licensed, and honestly I’d be glad to see it live somewhere with fewer constraints than mainline.
Driving it in FP16 HDR seems like the right direction to me. In my experience, luminance has been one of the trickier parts of reproducing a vector scan faithfully, so a true HDR pipeline with real peak nits feels like a natural fit. I’d like to try MAME4droid myself, but I don’t own an Android device at the moment — if you have a recommendation for a good model to run it on, I’d appreciate it.
I’m also interested in how you implemented this, so once my current PR settles down I’d like to look at your approach as a reference. One small heads-up: I’m in the middle of rewriting things to address the feedback from the PR, so the vector-mod branch doesn’t currently contain all of the features — the source as it was when I first opened the PR is preserved in a separate branch, vector-mod-full. And thank you as well for the comment on the PR thread; I really appreciate it.
Would definitely be up for comparing notes. Thanks again, and great work on the port.
Hi okaz, thanks for the heads-up!
That explains why I couldn’t find the overdrive math when I took a quick glance at your repository earlier. I’ll make sure to check out the vector-mod-full branch to study your original Star Wars physics—thanks for saving me the headache!
Regarding your question about Android hardware: the truth is, the Android ecosystem is a total jungle. Fragmentation is a massive pain, and every OEM handles graphics drivers, color spaces, and HDR formats differently. Because of this, the only devices I can guarantee 100% that work beautifully with my FP16 HDR pipeline are the Google Pixel phones. Google keeps the display pipeline and drivers clean, so if you want to test MAME4droid with proper peak nits on an OLED screen, a recent Pixel is definitely the safest bet.
By the way, as you might have seen on the PR thread, rb6502 kindly suggested that we work together “off-tree” to build a combined approach for upstream MAME. I just politely declined the offer, haha. To be honest, I’m a bit of a lone wolf and I already have my hands completely full with the Android port. Mainline MAME development has to be extremely strict and rigid by design, and quite frankly, that level of upstream rigidity stresses me out! I much prefer the freedom of doing my own thing downstream.
I’ll be sticking around to see how your PR settles down, though. If you manage to get those beam-energy values exposed directly from vector.cpp as a pure data source, it will be a game-changer. I’ll definitely grab that code for my port to clean up my messy CPU-side bloom calculations.
Good luck rewriting the branch to please the reviewers, and let’s definitely compare notes when you have more breathing room!
Thanks Seleuco!
Good to know about the Pixel — I might pick one up at some point to give it a try. The Android fragmentation story sounds rough.
And no worries at all about the collaboration — I completely understand. You’ve got plenty on your plate, and doing your own thing downstream makes total sense. I’m happy to keep going solo on the upstream side.
The vector-mod-full branch will stay up, so feel free to dig through it whenever you like. Let’s compare notes once things calm down — thanks again, and good luck with MAME4droid!