導入
必要なもの
C++17 対応コンパイラ (GCC、Clang、Emscripten で確認)。 ライブラリのソースだけでなく、ヘッダをインクルードする利用側のコードも C++17 でコンパイルしてください。
ビルドに CMake 3.13 以降を使う場合は CMake。使わなくても構いません。
ツール (
bin/) とドキュメント生成には Python 3 とrequirements.txtの依存パッケージ。
インストール
リポジトリを一度 clone し、環境変数 SHAPOGFX_PATH でその場所を指すのが標準的な使い方です。
ビルドファイルからはパスを直接書かず、CMake では $ENV{SHAPOGFX_PATH}、PlatformIO では
${sysenv.SHAPOGFX_PATH} としてこの変数を参照します。
${HOME}/sgfx/を作成し、そこに移動します。mkdir -p ${HOME}/sgfx cd ${HOME}/sgfx
リポジトリを clone します。
git clone https://github.com/shapoco/shapo-gfx.git
環境変数
SHAPOGFX_PATHに${HOME}/sgfx/shapo-gfxを設定します。 新しいシェルでも有効にするには~/.bashrc(使っているシェルの設定ファイル) にも同じ行を追加してください。export SHAPOGFX_PATH=${HOME}/sgfx/shapo-gfx echo 'export SHAPOGFX_PATH=${HOME}/sgfx/shapo-gfx' >> ~/.bashrc
CMake で使う
自分のプロジェクトから add_subdirectory で取り込み、ターゲット shapoco::gfx にリンクします。
Pico SDK のプロジェクトでも同じです。
add_subdirectory($ENV{SHAPOGFX_PATH} shapo-gfx)
target_link_libraries(your_target PRIVATE shapoco::gfx)
ライブラリ単体でビルドしてサンプルとテストを実行するには次のようにします。
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
./build/example/wasm/demo2d/demo2d out2d.ppm # 1 フレームを PPM に書き出す
./build/example/wasm/demo3d/demo3d out3d.ppm
ctest --test-dir build --output-on-failure
オプション |
既定値 |
説明 |
|---|---|---|
|
空 (ライブラリ既定の 1) |
透視補正レベル 0 / 1 / 2 (3D レンダラの概念 参照) |
|
トップレベル時 ON |
ネイティブ版サンプルをビルドする |
|
トップレベル時 ON |
テストをビルドする |
PlatformIO で使う
リポジトリのルートに library.json があるので、PlatformIO のライブラリとしてそのまま利用できます。
[env:my_board]
platform = espressif32
board = seeed_xiao_esp32s3
framework = arduino
lib_deps = symlink://${sysenv.SHAPOGFX_PATH}
; ヘッダが C++17 を要求する。多くのコアは既定が gnu++11 のため上書きする
build_unflags = -std=gnu++11
build_flags = -std=gnu++17
lib_deps には GitHub の URL (https://github.com/shapoco/shapo-gfx.git、ブランチやタグは ...git#v0.1.0)
や相対パス (symlink://../shapo-gfx) も指定できます。
build_unflags / build_flags は 利用側のコード のためのものです。
ライブラリ自身のソースは library.json が -std=gnu++17 を指定するので、これがなくてもビルドできますが、
ヘッダをインクルードする側のコードは C++17 でコンパイルする必要があります
(C++17 未満の場合は config.hpp が分かりやすいエラーメッセージを出します)。
既定の規格はコアによって異なるため、build_unflags には -std=gnu++11 -std=gnu++14 のように
複数列挙しても構いません (存在しないフラグは無視されます)。
ピクセルフォーマットの無効化などのコンパイル時オプションも build_flags に書きます。
build_flags =
-std=gnu++17
-D SHAPOGFX_FORMAT_GRAY1=0
-D SHAPOGFX_FORMAT_RGB444=0
CMake も PlatformIO も使わない
include/ をインクルードパスに加え、src/gfx2d/*.cpp と src/gfx3d/*.cpp を C++17 でコンパイルします。
コンパイル時オプションは全て単純なマクロです。
コンパイル時オプション
マクロ |
既定値 |
効果 |
|---|---|---|
|
1 |
0 にするとそのピクセルフォーマットのコードを 2D・3D 両方から除去する。無効化したフォーマットの Surface / Texture は無視される |
|
0 |
1 でネイティブバイト順の RGB565 を有効にする |
|
1 |
テクスチャ座標の透視補正レベル ( |
|
16 |
レベル 2 でテクスチャ座標を正確に求める間隔 (ピクセル、2 の冪。 |
|
1 (RP2040 / RP2350 では 4) |
テクスチャ付き・グーロー補間の線分で、テクセルに乗じる頂点色を更新する間隔 (ピクセル、16 以下の 2 の冪)。4 にするとテクスチャ付きピクセルの処理が少し軽くなり、色は 4 ピクセル単位で一定になる ( |
|
11 |
スクリーン座標と Surface の幅・高さのビット数 (1〜15)。 |
|
RP2 で 1、他は 0 |
RP2040 / RP2350 (Pico SDK) で 16 ビットテクセルの参照とグーロー補間の色の歩進に SIO interpolator ( |
|
RP2 で 1、他は 0 |
RP2040 / RP2350 (Pico SDK) で、回転・せん断した |
|
FPU があれば 1、他は 0 |
軸に平行な楕円の各行の幅を求める整数平方根を FPU の |
|
1 |
0 で 2D の変換行列を除去する。 |
|
1 |
0 で 2D のブレンドモード ( |
|
1 |
0 で |
|
16 |
2D のステートスタックの段数 ( |
|
1 |
0 でボーンアニメーション ( |
|
Cortex-M0/M0+ と ESP8266 で 1、他は 0 |
1 にすると 32x32→64 ビットの積をライブラリ呼び出しでなく 16x16 ビットの積 4 つで作る (乗算器が下位 32 ビットしか出さないコア向け。固定小数点の頂点段・セットアップ・透視補正除算)。結果は同じ |
|
32 |
レコードの深度の精度 (32 または 16)。16 で深度付きレコードが 4 バイト小さくなる ( |
|
1 |
0 でテクスチャ/環境マッピングを除去 ( |
|
1 |
0 でフラットシェーディングになる ( |
|
1 |
0 で半透明を除去し、全て不透明に描く ( |
|
1 |
0 で線分 / 点のプリミティブを除去 ( |
|
16 |
行列スタックの段数 ( |
|
64 |
頂点キャッシュのエントリ数 (2 の冪。 |
|
8 |
1 シーンに持てるレイヤ数 (1〜128。 |
gfx3d.cpp / src/gfx2d のみに影響するマクロは公開型を変えないので、翻訳単位ごとに食い違っても壊れません。
2D の機能を無効にした場合も、その関数は残り (何もしないだけ)、同じアプリケーションコードがそのままコンパイルできます。
機能を無効にするとそのコードと作業メモリが減り、同じアリーナにより多くの形状を保持できます
(3D レンダラの概念 の「省略できる機能」参照)。
3D レンダラの出力フォーマット 1 つにつき、ピクセルループが約 14 KB (Cortex-M33) / 20 KB (Cortex-M0+) 増えます。
このため RGB565 (ネイティブ順) は既定で無効です。SHAPOGFX_FORMAT_RGB565=1 で使う場合、RGB565_SWAPPED を使わないなら SHAPOGFX_FORMAT_RGB565_SWAPPED=0 にしてください。
フォーマットのマクロと SHAPOGFX_COORD_BITS は、ヘッダを含む全ての翻訳単位で同じ値にしてください
(CMake のオプションで指定した SHAPOGFX_COORD_BITS はライブラリの利用側にも伝わります)。
バージョン
ライブラリのバージョンは include/shapoco/gfx2d/version.hpp で定義され、config.hpp 経由で
gfx2d.hpp / gfx3d.hpp のどちらからも見えます。2D と 3D は同時にリリースされ、番号は一つです。
名前 |
内容 |
|---|---|
|
バージョンの各成分 |
|
|
|
|
|
上記と同じ値の |
#if SHAPOGFX_VERSION < SHAPOGFX_MAKE_VERSION(1, 0, 0)
#error "ShapoGFX 1.0.0 or later is required"
#endif
printf("ShapoGFX %s\n", shapoco::gfx::VERSION_STRING);
library.json の version も同じ番号で、リリースごとに git で v<version> のタグを打ちます。
プラットフォーム別の設定
ライブラリはアーキテクチャに依存しませんが、次の設定が各ターゲットに向いています (クロスコンパイルとホストでの検証によるもので、実機では未確認です)。
ターゲット |
推奨 |
|---|---|
RP2350 (Cortex-M33 + FPU) |
既定の float ビルド。 |
RP2040 (Cortex-M0+、FPU なし) |
|
ESP32-S3 (Xtensa LX7 + FPU) |
float ビルド。アリーナは PSRAM ではなく内部 SRAM に置く。 |
ESP32-P4 (RISC-V + FPU、2 コア) |
S3 と同様。アリーナは内部メモリ (L2MEM) に。大きな 2D の転送や塗りはアプリ側で PPA / 2D-DMA に任せられる (3D レンダラでは使えない) |
最小のサンプル: 2D
#include "shapoco/gfx2d/gfx2d.hpp"
#include "shapoco/gfx2d/fonts.hpp"
namespace g2 = shapoco::gfx2d;
static uint16_t fb[320 * 240]; // RGB565_SWAPPED のフレームバッファ
static const g2::Surface screen = {g2::PixelFormat::RGB565_SWAPPED, 320, 240, 320 * 2, fb};
void draw() {
g2::Graphics2D g(screen);
g.clear(g2::makeColor(20, 24, 40));
g.fillRoundRect(20, 20, 200, 100, 12, g2::makeColor(255, 255, 255, 40)); // 半透明
g.drawCircle(260, 120, 40, g2::Colors::CYAN);
g.setFont(&ShapoSansP_s12c09a01w02);
g.setTextColor(g2::Colors::WHITE);
g.drawString(32, 32, "Hello, ShapoGFX");
// ... fb をディスプレイへ転送 ...
}
最小のサンプル: 3D
#include "shapoco/gfx3d/gfx3d.hpp"
namespace g2 = shapoco::gfx2d;
namespace g3 = shapoco::gfx3d;
static uint8_t arena[64 * 1024]; // 3D レンダラの作業メモリ
static uint16_t band[320 * 40]; // 40 ライン分の転送バッファ (RGB565_SWAPPED)
static const g2::Surface bandSurface = {g2::PixelFormat::RGB565_SWAPPED, 320, 40, 320 * 2, band};
static g3::Graphics3D g3d;
static const g3::Material matRed = {
{0.9f, 0.15f, 0.1f, 1.0f}, {0.9f, 0.15f, 0.1f, 1.0f}, nullptr, g3::BlendMode::NONE, 0,
};
void setup() {
g3d.init(320, 240, arena, sizeof(arena));
g3d.setPerspectiveProjection(60.0f * 3.14159f / 180.0f, 320.0f / 240.0f, 0.3f, 100.0f);
g3d.setClearColor({0.05f, 0.05f, 0.1f, 1.0f});
}
void drawFrame(float t) {
g3d.beginScene();
g3d.lookAt({0, 2, 5}, {0, 0, 0}); // カメラ
g3d.enableParallelLight({-0.5f, -1, -0.6f}, {1, 1, 1, 1});
g3d.enableEnvironmentLight({0.2f, 0.2f, 0.3f, 1});
g3d.pushState();
g3d.rotate(t, 0.3f, 1, 0);
g3d.setMaterial(matRed);
g3d.putCube({0, 0, 0}, {1.5f, 1.5f, 1.5f});
g3d.popState();
g3d.putTorus({0, -1.5f, 0}, 1.5f, 0.3f);
g3d.endScene();
g3d.beginRender();
for (int y = 0; y < 240; y += 40) {
g3d.render(0, y, 320, 40, bandSurface); // 画面の領域 -> band の (0, 0)
// ... band をディスプレイの (0, y) へ転送 ...
}
g3d.endRender();
}
3D シーンの構築 (beginScene() 〜 endScene()) では頂点処理まで行い、render() で領域ごとにラスタライズします。
そのためフレームバッファを持たずに帯状の転送が可能です。詳しくは 3D レンダラの概念 を参照してください。
ツールとドキュメントの依存パッケージ
python3 -m pip install -r requirements.txt
bin/requirements.txt (Pillow, numpy, pygltflib) と Sphinx 関連が入ります。
bin/ のツールはインライン依存宣言 (PEP 723) を持つので uv run bin/img2cpp ... でも実行できます。