概要

ShapoGFX とは

ShapoGFX は組み込みシステム向けの 2D/3D グラフィックスライブラリです。 RP2350 や ESP32 のような MCU から、SPI やパラレルバスで接続された小型の RGB565 / RGB444 ディスプレイに 描画することを想定しています。

  • ピュア C++17: 特定のプラットフォームや外部ライブラリに依存しません。 PC 上でもそのままビルドでき、WebAssembly でブラウザ上でも動作します。

  • ライブラリ内で動的メモリ確保をしない: 描画先バッファは利用者が用意し、 3D レンダラの作業メモリと 2D のステートスタックは利用者が渡すアリーナから切り出します。 モデルデータ (頂点配列、テクスチャ、フォント) は参照されるだけなので Flash 上の const データとして置けます。

  • フレームバッファなしの 3D: 3D レンダラはスキャンライン法で描画し、フレームバッファも Z バッファも持ちません。 画面の任意の矩形領域を描けるので、小さな転送バッファへ帯状に描いてディスプレイへ順次転送できます。

  • 2D と 3D の共通基盤: ピクセルフォーマット、色、Surface / Texture は 2D と 3D で共通です。 2D で描いた背景の上に 3D シーンを重ねる、3D の出力を 2D の画像として貼る、といった組み合わせが自然にできます。

名前空間と構成

名前空間 / ディレクトリ

内容

shapoco::gfx2d (include/shapoco/gfx2d/)

ピクセルフォーマット、色、Surface / Texture、Graphics2D 描画 API、フォント

shapoco::gfx3d (include/shapoco/gfx3d/)

Graphics3D レンダラ、基本形状、静的シーン (Mesh / Node / Scene)、ベクトル・行列

src/gfx2d/, src/gfx3d/

実装 (C++17 でコンパイルするソース)

bin/

画像と glTF を C++ コードに変換する Python ツール (img2cpp, gltf2cpp)

example/wasm/, docs/example/

サンプル (demo2d, demo3d) とブラウザ用ページ

test/

自己検査テスト (CTest)

対応ピクセルフォーマット

PixelFormat

ビット/px

メモリ上の配置

用途

GRAY1

1

MSB ファースト、1 = 白

マスク、モノクロ画像、フォント

RGB444

12

2 ピクセルを 3 バイトに詰める (R1G1 B1R2 G2B2、ディスプレイ転送順)

12bit カラーディスプレイ

ARGB4444

16

ネイティブ uint16_t、0xARGB、A = 15 で不透明

α付きスプライト、合成用

RGB565_SWAPPED

16

CPU のバイト順に対してバイトスワップして格納 (リトルエンディアンの CPU では上位バイトが先になり、ディスプレイ転送順と一致)

16bit カラーディスプレイ、フレームバッファ

RGB565

16

ネイティブ uint16_t (CPU のバイト順)

16 ビット単位で転送するディスプレイ (RP2 の SPI 16 ビットモードや PIO、ESP32 の esp_lcd i80 など)

RGB565_SWAPPED はバイトスワップ済みで格納するので、SPI / パラレルのディスプレイコントローラへ 8 ビット単位のまま変換なしで DMA 転送できます。 16 ビット単位で MSB から送るインターフェースなら RGB565 を使うと、ピクセルの読み書きのたびのバイトスワップが不要になります。

  • 2D API (Graphics2D) は 5 フォーマット全てを描画先・画像として扱えます。

  • 3D レンダラの 出力 は RGB565_SWAPPED、RGB565、RGB444、テクスチャ は 5 フォーマット全てに対応します。

  • 不要なフォーマットはコンパイル時マクロ SHAPOGFX_FORMAT_* で無効化してコードサイズを削減できます (導入 を参照)。

主要な制約

利用前に知っておくべき制約を挙げます。

3D レンダラ

  • テクスチャの幅と高さは 2 の冪 でなければなりません (座標のラップをビットマスクで行うため)。 2 の冪でないテクスチャは繰り返しがずれます。

  • 出力フォーマットは RGB565_SWAPPED、RGB565、RGB444 のみです。他のフォーマットの Surface へ render() しても何も描かれません。

  • ニア平面をまたぐ、またはニア平面より手前にある三角形は クリップされず破棄 されます。 カメラに極端に近いポリゴンは消えます。

  • 状態スタック (pushState()) の深さは 16 です。超過すると pushState() は false を返し、 putNode() はその部分木を飛ばします。

  • 三角形バッファの容量はアリーナのサイズで決まります (プリミティブごとに必要な属性だけを持つ 可変長のレコードで保持されるので、個数ではなくバイト数の予算です)。線分プールは既定でアリーナから 決まりますが Config::spanCapacity で指定できます。あふれた分はそのフレームでは描かれません (getStats() で使用量、ピーク、破棄数を確認できます)。

  • 1 プリミティブの頂点数は 65535 以下、添字は uint16_t です。

  • 頂点色 (Vertex::color) の α は無視されます。半透明はマテリアル単位です。

  • 線の太さは 1 px 固定です。点は setPointSize() で 1〜64 px の正方形になります。線と点にはライティングとテクスチャが適用されません。

  • ピクセル処理は固定小数点で、色は切り捨てで量子化されます (float 実装との差は概ね 1 LSB 以内)。

  • テクスチャ座標の透視補正は既定で「垂直方向のみ」です。水平方向に奥行きが変わる大きな面 (横に伸びる壁など) では線分内部にアフィン歪みが残ります。完全補正はコンパイルオプションで選べます。

2D API

  • fillPolygon() は 1 スキャンラインあたり最大 32 個の交点までを扱います。

  • 変換行列はアフィン変換のみです。拡大・回転した図形や画像は最近傍で描かれ、アンチエイリアスはありません。

  • Graphics2D は Surface 構造体のコピーを保持します。ピクセルバッファの寿命は利用者が管理します。

  • 色は ARGB8888 で受け取り、描画呼び出しごとに描画先フォーマットへ変換します。 ブレンドモードと不透明度はステートで指定します (既定は α < 255 でブレンド)。

共通

  • スレッドセーフではありません。Graphics2D / Graphics3D はスレッドごとに 1 つ使います。

  • SHAPOGFX_FORMAT_* などのマクロは、ヘッダを含む全ての翻訳単位で同じ値にする必要があります (コンパイラのグローバル定義で与えるのが確実です)。

  • ライブラリ本体はヒープを使いません。唯一の例外は任意ヘッダ surface_alloc.hpp の OwnedSurface です。

性能の目安

480x320 のデモシーン (トーラス、キューブ 4 個、風車モデル。半透明・テクスチャ・環境マップ込み) の 1 フレーム:

  • WebAssembly、デスクトップ PC (Node.js、シングルスレッド): 1 ms 未満

  • RP2350 @ 312 MHz、シングルコア: render() 約 55 ms (15〜18 fps)。 ピクセル処理の固定小数点化前、透視補正レベル 0 での測定値です。

ライセンス

MIT ライセンスです。同梱の Adafruit gfxfont.h は BSD ライセンスで、表記は LICENSE に含まれています。