diff --git a/bin/assetzip/main.cpp b/bin/assetzip/main.cpp index 77d03902..6de27d40 100644 --- a/bin/assetzip/main.cpp +++ b/bin/assetzip/main.cpp @@ -2,36 +2,21 @@ #include #include #include -#include +#include #include -#include -std::vector parseAssetFileNames(const std::string &yamlFilePath) { - const auto node = YAML::LoadFile(yamlFilePath); - - std::vector paths; - paths.push_back(yamlFilePath); - - if (!node["assets"]) { - return paths; - } - if (!node["assets"].IsSequence()) { - throw std::runtime_error("YAML must contain 'assets' as a sequence."); - } - - for (const auto &n: node["assets"]) { - paths.push_back(n.as()); - } - - std::set pathSet; - for (const auto &n: paths) { - if (pathSet.contains(n)) { - throw std::runtime_error(std::format("'{}' duplicated.", n)); +std::vector collectAssetNames(int argc, char *argv[]) { + std::vector result; + std::unordered_set checkSet; + result.reserve(argc - 1); + checkSet.reserve(argc - 1); + for (int i = 1; i < argc; ++i) { + if (!checkSet.contains(argv[i])) { + result.emplace_back(argv[i]); + checkSet.insert(argv[i]); } - pathSet.emplace(n); } - - return paths; + return result; } std::vector loadFile(const std::string &path) { @@ -50,12 +35,7 @@ std::vector loadFile(const std::string &path) { return data; } -void run(const std::string &yamlFilePath) { - const auto fileNames = parseAssetFileNames(yamlFilePath); - if (fileNames.empty()) { - throw std::runtime_error("no asset files specified in config."); - } - +void run(const std::vector &fileNames) { // .dat出力開始 std::ofstream out(".dat", std::ios::binary); if (!out) { @@ -91,19 +71,20 @@ void run(const std::string &yamlFilePath) { } int main(int argc, char *argv[]) { - if (argc != 2) { - std::cerr << "usage: assetzip " << std::endl; - return 1; + const auto fileNames = collectAssetNames(argc, argv); + if (fileNames.empty()) { + std::cout << "usage: assetzip ..." << std::endl; + std::cout << "nothing generated." << std::endl; + return 0; } try { - run(argv[1]); - } catch (const YAML::Exception &e) { + run(fileNames); + } catch (const std::exception &e) { std::cerr << e.what() << std::endl; std::cerr << "failed to zip asset files." << std::endl; return 1; - } catch (const std::exception &e) { - std::cerr << e.what() << std::endl; + } catch (...) { std::cerr << "failed to zip asset files." << std::endl; return 1; } diff --git a/examples/simple/.dat b/examples/simple/.dat deleted file mode 100644 index 2466a733..00000000 Binary files a/examples/simple/.dat and /dev/null differ diff --git a/examples/simple/config.yml b/examples/simple/config.yml deleted file mode 100644 index 13155b1a..00000000 --- a/examples/simple/config.yml +++ /dev/null @@ -1,13 +0,0 @@ -title: simple -width: 640 -height: 480 -attachments: - - id: RT - format: render-target - clear-value: [0.894, 0.619, 0.38, 1.0] -render-passes: - - id: RP - subpasses: - - id: SP - outputs: [RT] - pipelines: [] diff --git a/examples/simple/main.cpp b/examples/simple/main.cpp index a647d2c9..f201d230 100644 --- a/examples/simple/main.cpp +++ b/examples/simple/main.cpp @@ -1,34 +1,52 @@ #include -#include +#include -#define TRY(n) \ - if (!(n)) { \ - std::cout << orgeGetErrorMessage() << std::endl; \ - return 1; \ - } - -#define CHECK(n) \ - if (!(n)) { \ - std::cout << orgeGetErrorMessage() << std::endl; \ - continue; \ - } +#define TRY(type, param) if (orgeApiCall((type), (param)) != ORGE_OK) return 1; +#define CHECK(type, param) if (orgeApiCall((type), (param)) != ORGE_OK) continue; int main() { - TRY(orgeInitialize()); + const char *renderTargetId = "RT"; + OrgeAttachmentConfig attachmentConfig{}; + attachmentConfig.id = renderTargetId; + attachmentConfig.format = ORGE_FORMAT_RENDER_TARGET; + attachmentConfig.clearValueType = ORGE_CLEAR_VALUE_TYPE_COLOR; + attachmentConfig.clearValue[0] = 0.894f; + attachmentConfig.clearValue[1] = 0.619f; + attachmentConfig.clearValue[2] = 0.38f; + attachmentConfig.clearValue[3] = 1.0f; + OrgeSubpassConfig subpassConfig{}; + subpassConfig.id = "SP"; + subpassConfig.outputCount = 1; + subpassConfig.outputs = &renderTargetId; + OrgeRenderPassConfig renderPassConfig{}; + renderPassConfig.id = "RP"; + renderPassConfig.subpassCount = 1; + renderPassConfig.subpasses = &subpassConfig; + OrgeInitializeParam config{}; + config.title = "simple"; + config.width = 640; + config.height = 480; + config.attachmentCount = 1; + config.attachments = &attachmentConfig; + config.renderPassCount = 1; + config.renderPasses = &renderPassConfig; - int count = 0; - while (orgeUpdate()) { - CHECK(orgeBeginRender()); - CHECK(orgeBeginRenderPass("RP")); - CHECK(orgeEndRenderPass()); - CHECK(orgeEndRender()); + TRY(ORGE_INITIALIZE, &config); + + OrgeBeginRenderPassParam beginRenderPassParam{"RP"}; + int count = 0; + while (orgeApiCall(ORGE_UPDATE, nullptr) != ORGE_WINDOW_CLOSED) { + CHECK(ORGE_BEGIN_RENDER, nullptr); + CHECK(ORGE_BEGIN_RENDER_PASS, &beginRenderPassParam); + CHECK(ORGE_END_RENDER_PASS, nullptr); + CHECK(ORGE_END_RENDER, nullptr); if (count % 60 == 0) { std::cout << count / 60 << std::endl; } count += 1; } - orgeTerminate(); + TRY(ORGE_TERMINATE, nullptr); return 0; } diff --git a/include/orge.h b/include/orge.h deleted file mode 100644 index 5a8453c8..00000000 --- a/include/orge.h +++ /dev/null @@ -1,571 +0,0 @@ -//! orgeのAPIが網羅されたヘッダーファイル -//! -//! 原則bit数固定の型を使っている。 -//! 文字列のみ例外的にconst char *を使っている。 -//! 尚、文字列の長さは指定されないため、null文字終端でなければ壊れるかもしれない。 - -#pragma once - -#ifdef _WIN32 -# ifdef ORGE_BUILD_SHARED -# define API_EXPORT __declspec(dllexport) -# elif ORGE_USE_SHARED -# define API_EXPORT __declspec(dllimport) -# else -# define API_EXPORT -# endif -#else -# define API_EXPORT -#endif - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// ================================================================================================================== // -// Information // -// ================================================================================================================== // - -enum OrgeDialogType { - ORGE_DIALOG_TYPE_ERROR = 0, - ORGE_DIALOG_TYPE_WARNING, - ORGE_DIALOG_TYPE_INFORMATION, -}; - -/// ダイアログを表示する関数 -/// -/// - dtype: ダイアログの種類 (OrgeDialogType) -/// - title: ダイアログのタイトル -/// - message: ダイアログのメッセージ -/// -/// ダイアログが閉じられるまでスレッドを停止する。 -API_EXPORT void orgeShowDialog(uint32_t dtype, const char *title, const char *message); - -/// orgeの直近のエラーメッセージを取得する関数 -API_EXPORT const char *orgeGetErrorMessage(void); - -// ================================================================================================================== // -// Lifetime Managiment // -// ================================================================================================================== // - -/// orgeを初期化する関数 -API_EXPORT uint8_t orgeInitialize(void); - -/// orgeを終了する関数 -API_EXPORT void orgeTerminate(void); - -/// orgeを更新する関数 -/// -/// 毎フレーム初めに必ず呼ぶこと。 -/// -/// 0以外であればウィンドウが閉じられていないことを意味する。 -API_EXPORT uint8_t orgeUpdate(void); - -// ================================================================================================================== // -// Window // -// ================================================================================================================== // - -/// フルスクリーン状態を取得する関数 -API_EXPORT uint8_t orgeIsFullscreen(void); - -/// フルスクリーン状態を設定する関数 -API_EXPORT void orgeSetFullscreen(uint8_t toFullscreen); - -// ================================================================================================================== // -// Graphics Resources // -// ================================================================================================================== // - -/// orgeにバッファを追加する関数 -/// -/// - id: バッファID -/// - size: バッファのサイズ (バイト数) -/// - isStorage: ストレージバッファか (falseの場合ユニフォームバッファとみなされる) -API_EXPORT uint8_t orgeCreateBuffer(const char *id, uint64_t size, uint8_t isStorage, uint8_t isHostCoherent); - -/// バッファを破棄する関数 -API_EXPORT void orgeDestroyBuffer(const char *id); - -/// バッファを更新する関数 -/// -/// dataはバッファ作成時に指定したサイズ分データを持つこと。 -API_EXPORT uint8_t orgeUpdateBuffer(const char *id, const uint8_t *data); - -/// バッファをローカルバッファにコピーする関数 -/// -/// dataはバッファ作成時に指定したサイズ分データを持つこと。 -API_EXPORT uint8_t orgeCopyBufferTo(const char *id, uint8_t *data); - -/// バッファディスクリプタを更新する関数 -/// -/// - renderPassId: レンダーパスID -/// - pipelineId: パイプラインID -/// - id: バッファID -/// - set: ディスクリプタセット番号 -/// - index: 何個目のディスクリプタセットか -/// - binding: バインディング番号 -/// - offset: 配列上のオフセット (ディスクリプタが配列でないなら0) -API_EXPORT uint8_t orgeUpdateBufferDescriptor( - const char *renderPassId, - const char *pipelineId, - const char *id, - uint32_t set, - uint32_t index, - uint32_t binding, - uint32_t offset -); - -/// バッファディスクリプタを更新する関数 (コンピュートパイプライン) -/// -/// - pipelineId: パイプラインID -/// - id: バッファID -/// - set: ディスクリプタセット番号 -/// - index: 何個目のディスクリプタセットか -/// - binding: バインディング番号 -/// - offset: 配列上のオフセット (ディスクリプタが配列でないなら0) -API_EXPORT uint8_t orgeUpdateComputeBufferDescriptor( - const char *pipelineId, - const char *id, - uint32_t set, - uint32_t index, - uint32_t binding, - uint32_t offset -); - -/// orgeにイメージを追加する関数 -/// -/// - file: アセットファイル名 -API_EXPORT uint8_t orgeLoadImage(const char *file); - -/// イメージを破棄する関数 -API_EXPORT void orgeDestroyImage(const char *file); - -/// orgeにストレージイメージを追加する関数 -/// -/// - id: ストレージイメージID -/// - width: 幅 -/// - height: 高さ -/// - format: フォーマット (0: RGBA8, 1: RG32F, 2: R32F) -API_EXPORT uint8_t orgeCreateStorageImage(const char *id, uint32_t width, uint32_t height, uint32_t format); - -/// ストレージイメージを破棄する関数 -API_EXPORT void orgeDestroyStorageImage(const char *id); - -/// イメージディスクリプタを更新する関数 -/// -/// - renderPassId: レンダーパスID -/// - pipelineId: パイプラインID -/// - id: イメージID (アセットファイル名) -/// - set: ディスクリプタセット番号 -/// - index: 何個目のディスクリプタセットか -/// - binding: バインディング番号 -/// - offset: 配列上のオフセット (ディスクリプタが配列でないなら0) -API_EXPORT uint8_t orgeUpdateImageDescriptor( - const char *renderPassId, - const char *pipelineId, - const char *id, - uint32_t set, - uint32_t index, - uint32_t binding, - uint32_t offset -); - -/// イメージディスクリプタを更新する関数 (コンピュートパイプライン) -/// -/// - pipelineId: パイプラインID -/// - id: イメージID (アセットファイル名) -/// - set: ディスクリプタセット番号 -/// - index: 何個目のディスクリプタセットか -/// - binding: バインディング番号 -/// - offset: 配列上のオフセット (ディスクリプタが配列でないなら0) -API_EXPORT uint8_t orgeUpdateComputeImageDescriptor( - const char *pipelineId, - const char *id, - uint32_t set, - uint32_t index, - uint32_t binding, - uint32_t offset -); - -/// ストレージイメージディスクリプタを更新する関数 (コンピュートパイプライン) -/// -/// - pipelineId: パイプラインID -/// - id: ストレージイメージID -/// - set: ディスクリプタセット番号 -/// - index: 何個目のディスクリプタセットか -/// - binding: バインディング番号 -/// - offset: 配列上のオフセット (ディスクリプタが配列でないなら0) -API_EXPORT uint8_t orgeUpdateComputeStorageImageDescriptor( - const char *pipelineId, - const char *id, - uint32_t set, - uint32_t index, - uint32_t binding, - uint32_t offset -); - -/// orgeにサンプラを追加する関数 -/// -/// - id: サンプラID -/// - linearMagFilter: 拡大時のフィルタリング設定 -/// - 0以外なら線形補間 -/// - 0なら最も近いテクセルを参照 -/// - linearMinFilter: 縮小時のフィルタリング設定 -/// - 0以外なら線形補間 -/// - 0なら最も近いテクセルを参照 -/// - repeat: [0-1]の範囲外のUV座標における設定 -/// - 0以外ならテクスチャを繰り返して参照 -/// - 0なら0あるいは1の境界値を参照 -API_EXPORT uint8_t orgeCreateSampler(const char *id, uint8_t linearMagFilter, uint8_t linearMinFilter, uint8_t repeat); - -/// サンプラを破棄する関数 -API_EXPORT void orgeDestroySampler(const char *id); - -/// サンプラディスクリプタを更新する関数 -/// -/// - renderPassId: レンダーパスID -/// - pipelineId: パイプラインID -/// - id: サンプラID -/// - set: ディスクリプタセット番号 -/// - index: 何個目のディスクリプタセットか -/// - binding: バインディング番号 -/// - offset: 配列上のオフセット (ディスクリプタが配列でないなら0) -API_EXPORT uint8_t orgeUpdateSamplerDescriptor( - const char *renderPassId, - const char *pipelineId, - const char *id, - uint32_t set, - uint32_t index, - uint32_t binding, - uint32_t offset -); - -/// サンプラディスクリプタを更新する関数 (コンピュート) -/// -/// - pipelineId: パイプラインID -/// - id: サンプラID -/// - set: ディスクリプタセット番号 -/// - index: 何個目のディスクリプタセットか -/// - binding: バインディング番号 -/// - offset: 配列上のオフセット (ディスクリプタが配列でないなら0) -API_EXPORT uint8_t orgeUpdateComputeSamplerDescriptor( - const char *pipelineId, - const char *id, - uint32_t set, - uint32_t index, - uint32_t binding, - uint32_t offset -); - -/// アタッチメントディスクリプタを更新する関数 -/// -/// - renderPassId: レンダーパスID -/// - pipelineId: パイプラインID -/// - id: アタッチメントID -/// - set: ディスクリプタセット番号 -/// - index: 何個目のディスクリプタセットか -/// - binding: バインディング番号 -/// - offset: 配列上のオフセット (ディスクリプタが配列でないなら0) -/// -/// 更新先のディスクリプタがtexture2DでもsubpassInputでも構わない。 -/// アタッチメントをディスクリプタに関連づけるときにこの関数を用いる。 -/// -/// WARN: 描画が開始されていること。 -API_EXPORT uint8_t orgeUpdateInputAttachmentDescriptor( - const char *renderPassId, - const char *pipelineId, - const char *id, - uint32_t set, - uint32_t index, - uint32_t binding, - uint32_t offset -); - -/// orgeにメッシュを追加する関数 -/// -/// - id: メッシュID -API_EXPORT uint8_t orgeLoadMesh(const char *id); - -/// メッシュを破棄する関数 -API_EXPORT void orgeDestroyMesh(const char *id); - -// ================================================================================================================== // -// Text Rendering // -// ================================================================================================================== // - -enum OrgeTextLocationHorizontal { - ORGE_TEXT_LOCATION_HORIZONTAL_LEFT = 0, - ORGE_TEXT_LOCATION_HORIZONTAL_CENTER, - ORGE_TEXT_LOCATION_HORIZONTAL_RIGHT, -}; - -enum OrgeTextLocationVertical { - ORGE_TEXT_LOCATION_VERTICAL_TOP = 0, - ORGE_TEXT_LOCATION_VERTICAL_MIDDLE, - ORGE_TEXT_LOCATION_VERTICAL_BOTTOM, -}; - -/// 文字をラスタライズする関数 -/// -/// - id: フォントID -/// - s: UTF-8文字列 -/// -/// sの各文字がラスタライズされる。 -/// 結合文字は結合されず、別々の文字として扱われる。 -API_EXPORT uint8_t orgeRasterizeCharacters(const char *id, const char *s); - -/// このフレームで描画する文字列を追加する関数 -/// -/// - renderPassId: この文字列を描画するレンダーパスのID -/// - subpassId: この文字列を描画するサブパスのID -/// - fontId: フォントID -/// - text: UTF-8文字列 -/// - x: 基準点X座標 -/// - y: 基準点Y座標 -/// - height: 文字の基準高 -/// - horizontal: 水平方向の配置位置 (OrgeTextLocationHorizontal) -/// - vertical: 垂直方向の配置位置 (OrgeTextLocationVertical) -/// -/// 存在しない文字はスキップされる。 -/// -/// WARN: 毎フレームorgeBeginRender()の前に呼ぶこと。 -API_EXPORT uint8_t orgeLayoutText( - const char *renderPassId, - const char *subpassId, - const char *fontId, - const char *text, - float x, - float y, - float height, - uint32_t horizontal, - uint32_t vertical -); - -/// orgeLayoutText()で追加された文字列をすべて描画する関数 -/// -/// WARN: レンダーパスが開始されていること。 -/// WARN: 正しいサブパスに移動されていること。 -API_EXPORT uint8_t orgeDrawTexts(); - -// ================================================================================================================== // -// Rendering // -// ================================================================================================================== // - -/// orgeの描画を開始する関数 -API_EXPORT uint8_t orgeBeginRender(void); - -/// orgeの描画を終了する関数 -API_EXPORT uint8_t orgeEndRender(void); - -/// メッシュをバインドする関数 -/// -/// 既に同一のメッシュがバインドされている場合、処理はスキップされる。 -/// -/// WARN: 描画が開始されていること。 -API_EXPORT uint8_t orgeBindMesh(const char *meshId); - -/// レンダーパスを開始する関数 -/// -/// WARN: 描画が開始されていること。 -/// WARN: レンダーパスがまだ開始されていない・あるいは既に終了されていること。 -API_EXPORT uint8_t orgeBeginRenderPass(const char *renderPassId); - -/// レンダーパスを開始する関数 -/// -/// レンダーパスが開始されていない場合、処理はスキップされる。 -/// -/// WARN: 描画が開始されていること。 -API_EXPORT uint8_t orgeEndRenderPass(void); - -/// 次のサブパスへ移るための関数 -/// -/// WARN: レンダーパスが開始されていること。 -/// WARN: orgeはサブパスを移行できるかを検証しない。 -/// 実際のレンダーパスに即して呼ぶこと。 -API_EXPORT uint8_t orgeNextSubpass(void); - -/// パイプラインをバインドする関数 -/// -/// - pipelineId: パイプラインID -/// - indices: 各ディスクリプタセットにおいて何個目のセットを使うか。 -/// ディスクリプタセットの個数分データを持つこと。 -/// 例えば、set = 0とset = 1があり、それぞれ3個と4個確保されている場合、 -/// indicesの要素数は2、indicesの各要素は0-2と0-3を取る。 -/// -/// WARN: レンダーパスが開始されていること。 -API_EXPORT uint8_t orgeBindPipeline(const char *pipelineId, uint32_t const *indices); - -/// 描画関数 -/// -/// - instanceCount: 描画するインスタンスの個数 -/// - instanceOffset: 参照するインスタンスバッファのオフセット -/// -/// WARN: パイプラインがバインドされていること。 -/// WARN: メッシュがバインドされていること。 -API_EXPORT uint8_t orgeDraw(uint32_t instanceCount, uint32_t instanceOffset); - -/// 描画関数 (メッシュをシェーダ内で構築する場合) -/// -/// - vertexCount: メッシュの頂点数 -/// - instanceCount: 描画するインスタンスの個数 -/// - instanceOffset: 参照するインスタンスバッファのオフセット -/// -/// WARN: パイプラインがバインドされていること。 -API_EXPORT uint8_t orgeDrawDirectly(uint32_t vertexCount, uint32_t instanceCount, uint32_t instanceOffset); - -// ================================================================================================================== // -// Compute // -// ================================================================================================================== // - -/// コンピュートパイプラインをバインドする関数 -/// -/// WARN: 描画が開始されていること。 -/// WARN: レンダーパスがバインドされていないこと。 -API_EXPORT uint8_t orgeBindComputePipeline(const char *pipelineId, uint32_t const *indices); - -/// コンピュートパイプラインを実行する関数 -/// -/// WARN: パイプラインがバインドされていること。 -API_EXPORT uint8_t orgeDispatch(uint32_t x, uint32_t y, uint32_t z); - -// ================================================================================================================== // -// Input // -// ================================================================================================================== // - -enum OrgeScancode { - ORGE_SCANCODE_A = 0, - ORGE_SCANCODE_B, - ORGE_SCANCODE_C, - ORGE_SCANCODE_D, - ORGE_SCANCODE_E, - ORGE_SCANCODE_F, - ORGE_SCANCODE_G, - ORGE_SCANCODE_H, - ORGE_SCANCODE_I, - ORGE_SCANCODE_J, - ORGE_SCANCODE_K, - ORGE_SCANCODE_L, - ORGE_SCANCODE_M, - ORGE_SCANCODE_N, - ORGE_SCANCODE_O, - ORGE_SCANCODE_P, - ORGE_SCANCODE_Q, - ORGE_SCANCODE_R, - ORGE_SCANCODE_S, - ORGE_SCANCODE_T, - ORGE_SCANCODE_U, - ORGE_SCANCODE_V, - ORGE_SCANCODE_W, - ORGE_SCANCODE_X, - ORGE_SCANCODE_Y, - ORGE_SCANCODE_Z, - ORGE_SCANCODE_1, - ORGE_SCANCODE_2, - ORGE_SCANCODE_3, - ORGE_SCANCODE_4, - ORGE_SCANCODE_5, - ORGE_SCANCODE_6, - ORGE_SCANCODE_7, - ORGE_SCANCODE_8, - ORGE_SCANCODE_9, - ORGE_SCANCODE_0, - ORGE_SCANCODE_RETURN, - ORGE_SCANCODE_ESCAPE, - ORGE_SCANCODE_BACKSPACE, - ORGE_SCANCODE_TAB, - ORGE_SCANCODE_SPACE, - ORGE_SCANCODE_MINUS, - ORGE_SCANCODE_EQUALS, - ORGE_SCANCODE_LEFTBRACKET, - ORGE_SCANCODE_RIGHTBRACKET, - ORGE_SCANCODE_BACKSLASH, - ORGE_SCANCODE_NONUSHASH, - ORGE_SCANCODE_SEMICOLON, - ORGE_SCANCODE_APOSTROPHE, - ORGE_SCANCODE_GRAVE, - ORGE_SCANCODE_COMMA, - ORGE_SCANCODE_PERIOD, - ORGE_SCANCODE_SLASH, - ORGE_SCANCODE_RIGHT, - ORGE_SCANCODE_LEFT, - ORGE_SCANCODE_DOWN, - ORGE_SCANCODE_UP, -}; - -enum OrgeMouseButton { - ORGE_MOUSE_BUTTON_LEFT = 0, - ORGE_MOUSE_BUTTON_MIDDLE, - ORGE_MOUSE_BUTTON_RIGHT, -}; - -/// キー入力状態を取得する関数 -/// -/// 返戻値: -/// - = -1: キーアップ -/// - = 0: ニュートラル -/// - > 0: キーダウン (押されているフレーム数) -API_EXPORT int32_t orgeGetKeyState(uint32_t scancode); - -/// マウスカーソルのX座標を取得する関数 -/// -/// 座標系はウィンドウの左上が0、右端が幅。 -/// ウィンドウ外の場合は最後に記録されたウィンドウ内の座標を返す。 -API_EXPORT uint32_t orgeGetCursorX(void); - -/// マウスカーソルのY座標を取得する関数 -/// -/// 座標系はウィンドウの上端が0、下端が高さ。 -/// ウィンドウ外の場合は最後に記録されたウィンドウ内の座標を返す。 -API_EXPORT uint32_t orgeGetCursorY(void); - -/// マウスボタンの押下状態を取得する関数 -/// -/// - button: マウスボタン (OrgeMouseButton) -/// -/// 返戻値: -/// - = -1: ボタンアップ -/// - = 0: ニュートラル -/// - > 0: ボタンダウン (押されているフレーム数) -API_EXPORT int32_t orgeGetMouseButtonState(uint32_t button); - -// ================================================================================================================== // -// Audio // -// ================================================================================================================== // - -/// 音声チャンネルの音量を取得する関数 -/// -/// - index: 音声チャンネルのインデックス -/// -/// 不明なindexが指定された場合や、内部で予期せぬ例外が発生した場合は-1.0fが返る。 -API_EXPORT float orgeGetAudioChannelVolume(uint32_t index); - -/// 音声チャンネルの音量を設定する関数 -/// -/// - index: 音声チャンネルのインデックス -/// - volume: 音量 ([0.0, 1.0]) -API_EXPORT uint8_t orgeSetAudioChannelVolume(uint32_t index, float volume); - -/// orgeにWAVEを追加する関数 -/// -/// - file: アセットファイル名 -/// - startPosition: ループ開始位置 -API_EXPORT uint8_t orgeLoadWave(const char *file, uint32_t startPosition); - -/// WAVEを破棄する関数 -API_EXPORT void orgeDestroyWave(const char *file); - -/// WAVEを再生する関数 -/// -/// - file: アセットファイル名 -/// - index: 音声チャンネルのインデックス -/// - loop: ループ再生するか -/// -/// 初めてindex番目の音声チャンネルで音声が再生されるとき、音声ストリームが作成される。 -/// index番目の音声チャンネルとfileのWAVEの音声互換性がない場合、音声ストリームが再作成される。 -/// index番目の音声チャンネルが音声を再生している場合、その音声を中断してfileのWAVEを再生する。 -API_EXPORT uint8_t orgePlayWave(const char *file, uint32_t index, uint8_t loop); - -#ifdef __cplusplus -} -#endif diff --git a/include/orge/audio.h b/include/orge/audio.h new file mode 100644 index 00000000..0e31a2cc --- /dev/null +++ b/include/orge/audio.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +struct OrgeGetAudioChannelVolumeParam { + uint32_t index; + float *out; +}; + +struct OrgeSetAudioChannelVolumeParam { + uint32_t index; + float volume; +}; + +struct OrgeLoadWaveParam { + const char *file; + uint32_t startPosition; +}; + +struct OrgeDestroyWaveParam { + const char *file; +}; + +struct OrgePlayWaveParam { + const char *file; + uint32_t index; + uint8_t loop; +}; diff --git a/include/orge/compute.h b/include/orge/compute.h new file mode 100644 index 00000000..cfd91129 --- /dev/null +++ b/include/orge/compute.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +struct OrgeBindComputePipelineParam { + const char *pipelineId; + const uint32_t *indices; +}; + +struct OrgeDispatchParam { + uint32_t x; + uint32_t y; + uint32_t z; +}; diff --git a/include/orge/config.h b/include/orge/config.h new file mode 100644 index 00000000..f74fe395 --- /dev/null +++ b/include/orge/config.h @@ -0,0 +1,149 @@ +#pragma once + +#include + +struct OrgeFontConfig { + const char *id; + // .ttfファイル名 + const char *file; + uint32_t charSize; + uint32_t charAtlusCol; + uint32_t charAtlusRow; +}; + +enum OrgeFormat { + ORGE_FORMAT_RENDER_TARGET = 0, + ORGE_FORMAT_DEPTH_BUFFER, + ORGE_FORMAT_SHARE_COLOR_ATTACHMENT, + ORGE_FORMAT_SIGNED_SHARE_COLOR_ATTACHMENT, +}; + +enum OrgeClearValueType { + ORGE_CLEAR_VALUE_TYPE_COLOR = 0, + ORGE_CLEAR_VALUE_TYPE_DEPTH, +}; + +struct OrgeAttachmentConfig { + const char *id; + OrgeFormat format; + uint8_t discard; + OrgeClearValueType clearValueType; + // clearValueType == ORGE_CLEAR_VALUE_TYPE_DEPTHの場合、 + // 最初の要素だけ使用される + float clearValue[4]; +}; + +enum OrgeDescriptorType { + ORGE_DESCRIPTOR_TYPE_TEXTURE = 0, + ORGE_DESCRIPTOR_TYPE_SAMPLER, + ORGE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + ORGE_DESCRIPTOR_TYPE_STORAGE_BUFFER, + ORGE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, +}; + +enum OrgeShaderStages { + ORGE_SHADER_STAGES_VERTEX = 0, + ORGE_SHADER_STAGES_FRAGMENT, + ORGE_SHADER_STAGES_VERTEX_AND_FRAGMENT, +}; + +struct OrgeDescriptorBindingConfig { + OrgeDescriptorType type; + uint32_t count; + OrgeShaderStages stage; +}; + +struct OrgeDescriptorSetConfig { + uint32_t count; + uint32_t bindingCount; + OrgeDescriptorBindingConfig *bindings; +}; + +struct OrgeGraphicsPipelineConfig { + const char *id; + const char *vertexShaderFile; + const char *fragmentShaderFile; + uint32_t descSetCount; + OrgeDescriptorSetConfig *descSets; + uint32_t vertexInputAttributeCount; + uint32_t *vertexInputAttributes; + uint8_t meshInShader; + uint8_t culling; + uint8_t depthTest; + uint32_t colorBlendCount; + uint8_t *colorBlends; +}; + +struct OrgeSubpassDepthConfig { + const char *depth; + uint8_t readOnly; +}; + +struct OrgeSubpassConfig { + const char *id; + uint32_t inputCount; + const char **inputs; + uint32_t outputCount; + const char **outputs; + OrgeSubpassDepthConfig *depth; + uint32_t dependCount; + const char **depends; + uint32_t pipelineCount; + const char **pipelines; +}; + +struct OrgeRenderPassConfig { + const char *id; + uint32_t subpassCount; + OrgeSubpassConfig *subpasses; +}; + +enum OrgeComputeDescriptorType { + ORGE_COMPUTE_DESCRIPTOR_TYPE_TEXTURE = 0, + ORGE_COMPUTE_DESCRIPTOR_TYPE_SAMPLER, + ORGE_COMPUTE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + ORGE_COMPUTE_DESCRIPTOR_TYPE_STORAGE_BUFFER, + ORGE_COMPUTE_DESCRIPTOR_TYPE_STORAGE_IMAGE, +}; + +struct OrgeComputeDescriptorBindingConfig { + OrgeComputeDescriptorType type; + uint32_t count; +}; + +struct OrgeComputeDescriptorSetConfig { + uint32_t count; + uint32_t bindingCount; + OrgeComputeDescriptorBindingConfig *bindings; +}; + +struct OrgeComputePipelineConfig { + const char *id; + const char *shaderFile; + uint32_t descSetCount; + OrgeComputeDescriptorSetConfig *descSets; +}; + +struct OrgeInitializeParam { + const char *title; + uint32_t width; + uint32_t height; + uint8_t fullscreen; + uint8_t disableFullscreenShortcut; + uint8_t disableVsync; + uint32_t audioChannelCount; + uint32_t charCount; + const char *assetsPath; + uint32_t assetCount; + const char **assets; + uint32_t fontCount; + OrgeFontConfig *fonts; + uint32_t attachmentCount; + OrgeAttachmentConfig *attachments; + uint32_t graphicsPipelineCount; + OrgeGraphicsPipelineConfig *graphicsPipelines; + uint32_t renderPassCount; + OrgeRenderPassConfig *renderPasses; + uint32_t computePipelineCount; + OrgeComputePipelineConfig *computePipelines; +}; diff --git a/include/orge/dialog.h b/include/orge/dialog.h new file mode 100644 index 00000000..b571c73e --- /dev/null +++ b/include/orge/dialog.h @@ -0,0 +1,13 @@ +#pragma once + +enum OrgeDialogType { + ORGE_DIALOG_TYPE_ERROR = 0, + ORGE_DIALOG_TYPE_WARNING, + ORGE_DIALOG_TYPE_INFORMATION, +}; + +struct OrgeShowDialogParam { + OrgeDialogType dtype; + const char *title; + const char *message; +}; diff --git a/include/orge/input.h b/include/orge/input.h new file mode 100644 index 00000000..b85e7fdd --- /dev/null +++ b/include/orge/input.h @@ -0,0 +1,84 @@ +#pragma once + +#include + +enum OrgeScancode { + ORGE_SCANCODE_A = 0, + ORGE_SCANCODE_B, + ORGE_SCANCODE_C, + ORGE_SCANCODE_D, + ORGE_SCANCODE_E, + ORGE_SCANCODE_F, + ORGE_SCANCODE_G, + ORGE_SCANCODE_H, + ORGE_SCANCODE_I, + ORGE_SCANCODE_J, + ORGE_SCANCODE_K, + ORGE_SCANCODE_L, + ORGE_SCANCODE_M, + ORGE_SCANCODE_N, + ORGE_SCANCODE_O, + ORGE_SCANCODE_P, + ORGE_SCANCODE_Q, + ORGE_SCANCODE_R, + ORGE_SCANCODE_S, + ORGE_SCANCODE_T, + ORGE_SCANCODE_U, + ORGE_SCANCODE_V, + ORGE_SCANCODE_W, + ORGE_SCANCODE_X, + ORGE_SCANCODE_Y, + ORGE_SCANCODE_Z, + ORGE_SCANCODE_1, + ORGE_SCANCODE_2, + ORGE_SCANCODE_3, + ORGE_SCANCODE_4, + ORGE_SCANCODE_5, + ORGE_SCANCODE_6, + ORGE_SCANCODE_7, + ORGE_SCANCODE_8, + ORGE_SCANCODE_9, + ORGE_SCANCODE_0, + ORGE_SCANCODE_RETURN, + ORGE_SCANCODE_ESCAPE, + ORGE_SCANCODE_BACKSPACE, + ORGE_SCANCODE_TAB, + ORGE_SCANCODE_SPACE, + ORGE_SCANCODE_MINUS, + ORGE_SCANCODE_EQUALS, + ORGE_SCANCODE_LEFTBRACKET, + ORGE_SCANCODE_RIGHTBRACKET, + ORGE_SCANCODE_BACKSLASH, + ORGE_SCANCODE_NONUSHASH, + ORGE_SCANCODE_SEMICOLON, + ORGE_SCANCODE_APOSTROPHE, + ORGE_SCANCODE_GRAVE, + ORGE_SCANCODE_COMMA, + ORGE_SCANCODE_PERIOD, + ORGE_SCANCODE_SLASH, + ORGE_SCANCODE_RIGHT, + ORGE_SCANCODE_LEFT, + ORGE_SCANCODE_DOWN, + ORGE_SCANCODE_UP, +}; + +enum OrgeMouseButton { + ORGE_MOUSE_BUTTON_LEFT = 0, + ORGE_MOUSE_BUTTON_MIDDLE, + ORGE_MOUSE_BUTTON_RIGHT, +}; + +struct OrgeGetKeyStateParam { + OrgeScancode scancode; + int32_t *out; +}; + +struct OrgeGetCursorParam { + uint32_t *outX; + uint32_t *outY; +}; + +struct OrgeGetMouseButtonStateParam { + OrgeMouseButton button; + int32_t *out; +}; diff --git a/include/orge/orge.h b/include/orge/orge.h new file mode 100644 index 00000000..d742bdda --- /dev/null +++ b/include/orge/orge.h @@ -0,0 +1,97 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "audio.h" +#include "compute.h" +#include "config.h" +#include "dialog.h" +#include "input.h" +#include "rendering.h" +#include "resource.h" +#include "text.h" +#include "window.h" + +enum OrgeApiCallType { + ORGE_SHOW_DIALOG = 0, + ORGE_SHOW_ERROR_DIALOG, + + ORGE_INITIALIZE, + ORGE_TERMINATE, + ORGE_UPDATE, + + ORGE_IS_FULLSCREEN, + ORGE_SET_FULLSCREEN, + + ORGE_CREATE_BUFFER, + ORGE_DESTROY_BUFFER, + ORGE_UPDATE_BUFFER, + ORGE_COPY_BUFFER_TO, + ORGE_UPDATE_BUFFER_DESCRIPTOR, + ORGE_UPDATE_COMPUTE_BUFFER_DESCRIPTOR, + ORGE_LOAD_IMAGE, + ORGE_DESTROY_IMAGE, + ORGE_CREATE_STORAGE_IMAGE, + ORGE_DESTROY_STORAGE_IMAGE, + ORGE_UPDATE_IMAGE_DESCRIPTOR, + ORGE_UPDATE_COMPUTE_IMAGE_DESCRIPTOR, + ORGE_UPDATE_COMPUTE_STORAGE_IMAGE_DESCRIPTOR, + ORGE_CREATE_SAMPLER, + ORGE_DESTROY_SAMPLER, + ORGE_UPDATE_SAMPLER_DESCRIPTOR, + ORGE_UPDATE_COMPUTE_SAMPLER_DESCRIPTOR, + ORGE_UPDATE_INPUT_ATTACHMENT_DESCRIPTOR, + ORGE_LOAD_MESH, + ORGE_DESTROY_MESH, + + ORGE_RASTERIZE_CHARACTERS, + ORGE_LAYOUT_TEXT, + ORGE_DRAW_TEXTS, + + ORGE_BEGIN_RENDER, + ORGE_END_RENDER, + ORGE_BIND_MESH, + ORGE_BEGIN_RENDER_PASS, + ORGE_END_RENDER_PASS, + ORGE_NEXT_SUBPASS, + ORGE_BIND_PIPELINE, + ORGE_DRAW, + ORGE_DRAW_DIRECTLY, + + ORGE_BIND_COMPUTE_PIPELINE, + ORGE_DISPATCH, + + ORGE_GET_KEY_STATE, + ORGE_GET_CURSOR, + ORGE_GET_MOUSE_BUTTON_STATE, + + ORGE_GET_AUDIO_CHANNEL_VOLUME, + ORGE_SET_AUDIO_CHANNEL_VOLUME, + ORGE_LOAD_WAVE, + ORGE_DESTROY_WAVE, + ORGE_PLAY_WAVE, +}; + +enum OrgeApiResult { + ORGE_OK = 0, + ORGE_ERROR, + ORGE_WINDOW_CLOSED, + ORGE_SWAPCHAIN_RECREATED, + ORGE_SURFACE_RECREATED, + ORGE_AUDIO_CHANNEL_NOT_INITIALIZED, +}; + +#ifdef _WIN32 +# ifdef ORGE_BUILD_SHARED +# __declspec(dllexport) +# elif ORGE_USE_SHARED +# __declspec(dllimport) +# endif +#endif +OrgeApiResult orgeApiCall(OrgeApiCallType type, void *param); + +#ifdef __cplusplus +} +#endif diff --git a/include/orge/rendering.h b/include/orge/rendering.h new file mode 100644 index 00000000..4b1ecd7b --- /dev/null +++ b/include/orge/rendering.h @@ -0,0 +1,27 @@ +#pragma once + +#include + +struct OrgeBindMeshParam { + const char *meshId; +}; + +struct OrgeBeginRenderPassParam { + const char *renderPassId; +}; + +struct OrgeBindPipelineParam { + const char *pipelineId; + const uint32_t *indices; +}; + +struct OrgeDrawParam { + uint32_t instanceCount; + uint32_t instanceOffset; +}; + +struct OrgeDrawDirectlyParam { + uint32_t vertexCount; + uint32_t instanceCount; + uint32_t instanceOffset; +}; diff --git a/include/orge/resource.h b/include/orge/resource.h new file mode 100644 index 00000000..bf131b2d --- /dev/null +++ b/include/orge/resource.h @@ -0,0 +1,138 @@ +#pragma once + +#include + +struct OrgeCreateBufferParam { + const char *id; + uint64_t size; + uint8_t isStorage; + uint8_t isHostCoherent; +}; + +struct OrgeDestroyBufferParam { + const char *id; +}; + +struct OrgeUpdateBufferParam { + const char *id; + const uint8_t *data; +}; + +struct OrgeCopyBufferToParam { + const char *id; + uint8_t *data; +}; + +struct OrgeUpdateBufferDescriptorParam { + const char *renderPassId; + const char *pipelineId; + const char *id; + uint32_t set; + uint32_t index; + uint32_t binding; + uint32_t offset; +}; + +struct OrgeUpdateComputeBufferDescriptorParam { + const char *pipelineId; + const char *id; + uint32_t set; + uint32_t index; + uint32_t binding; + uint32_t offset; +}; + +struct OrgeLoadImageParam { + const char *file; +}; + +struct OrgeDestroyImageParam { + const char *file; +}; + +struct OrgeCreateStorageImageParam { + const char *id; + uint32_t width; + uint32_t height; + uint32_t format; +}; + +struct OrgeDestroyStorageImageParam { + const char *id; +}; + +struct OrgeUpdateImageDescriptorParam { + const char *renderPassId; + const char *pipelineId; + const char *id; + uint32_t set; + uint32_t index; + uint32_t binding; + uint32_t offset; +}; + +struct OrgeUpdateComputeImageDescriptorParam { + const char *pipelineId; + const char *id; + uint32_t set; + uint32_t index; + uint32_t binding; + uint32_t offset; +}; + +struct OrgeUpdateComputeStorageImageDescriptorParam { + const char *pipelineId; + const char *id; + uint32_t set; + uint32_t index; + uint32_t binding; + uint32_t offset; +}; + +struct OrgeCreateSamplerParam { + const char *id; + uint8_t linearMagFilter; + uint8_t linearMinFilter; + uint8_t repeat; +}; + +struct OrgeDestroySamplerParam { + const char *id; +}; + +struct OrgeUpdateSamplerDescriptorParam { + const char *renderPassId; + const char *pipelineId; + const char *id; + uint32_t set; + uint32_t index; + uint32_t binding; + uint32_t offset; +}; + +struct OrgeUpdateComputeSamplerDescriptorParam { + const char *pipelineId; + const char *id; + uint32_t set; + uint32_t index; + uint32_t binding; + uint32_t offset; +}; + +struct OrgeUpdateInputAttachmentDescriptorParam { + const char *renderPassId; + const char *pipelineId; + const char *id; + uint32_t set; + uint32_t index; + uint32_t binding; + uint32_t offset; +}; + +struct OrgeLoadMeshParam { + const char *id; +}; + +struct OrgeDestroyMeshParam { + const char *id; +}; diff --git a/include/orge/text.h b/include/orge/text.h new file mode 100644 index 00000000..f62b54e0 --- /dev/null +++ b/include/orge/text.h @@ -0,0 +1,30 @@ +#pragma once + +enum OrgeTextLocationHorizontal { + ORGE_TEXT_LOCATION_HORIZONTAL_LEFT = 0, + ORGE_TEXT_LOCATION_HORIZONTAL_CENTER, + ORGE_TEXT_LOCATION_HORIZONTAL_RIGHT, +}; + +enum OrgeTextLocationVertical { + ORGE_TEXT_LOCATION_VERTICAL_TOP = 0, + ORGE_TEXT_LOCATION_VERTICAL_MIDDLE, + ORGE_TEXT_LOCATION_VERTICAL_BOTTOM, +}; + +struct OrgeRasterizeCharactersParam { + const char *id; + const char *s; +}; + +struct OrgeLayoutTextParam { + const char *renderPassId; + const char *subpassId; + const char *fontId; + const char *text; + float x; + float y; + float height; + OrgeTextLocationHorizontal horizontal; + OrgeTextLocationVertical vertical; +}; diff --git a/include/orge/window.h b/include/orge/window.h new file mode 100644 index 00000000..f70b71c9 --- /dev/null +++ b/include/orge/window.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +struct OrgeIsFullscreenParam { + uint8_t *out; +}; + +struct OrgeSetFullscreenParam { + uint8_t fullscreen; +}; diff --git a/meson.build b/meson.build index 4cc4e066..330e516c 100644 --- a/meson.build +++ b/meson.build @@ -183,7 +183,7 @@ orge = library('orge', # =================================================================================================================== # # include/orge.hをインストール対象に追加 -install_headers(['include/orge.h']) +install_headers(['include/orge/orge.h']) # 依存ライブラリのビルドディレクトリを取得 # diff --git a/src/api/audio.hpp b/src/api/audio.hpp new file mode 100644 index 00000000..5ddd7569 --- /dev/null +++ b/src/api/audio.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include "../audio/audio.hpp" + +namespace api { + +inline OrgeApiResult getAudioChannelVolume(OrgeGetAudioChannelVolumeParam *param) { + try { + *param->out = audio::audio().getVolume(param->index); + return ORGE_OK; + } catch (...) { + return ORGE_AUDIO_CHANNEL_NOT_INITIALIZED; + } +} + +inline void setAudioChannelVolume(OrgeSetAudioChannelVolumeParam *param) { + audio::audio().setVolume(param->index, param->volume); +} + +inline void loadWave(OrgeLoadWaveParam *param) { + audio::audio().loadWaveFromFile(param->file, param->startPosition); +} + +inline void destroyWave(OrgeDestroyWaveParam *param) { + audio::audio().destroyWave(param->file); +} + +inline void playWave(OrgePlayWaveParam *param) { + audio::audio().play(param->file, param->index, static_cast(param->loop)); +} + +} // namespace api diff --git a/src/api/compute.hpp b/src/api/compute.hpp new file mode 100644 index 00000000..cf991126 --- /dev/null +++ b/src/api/compute.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include + +#include "../graphics/renderer/renderer.hpp" + +namespace api { + +inline void bindComputePipeline(OrgeBindComputePipelineParam *param) { + graphics::renderer::renderer().getContext().bindComputePipeline(param->pipelineId, param->indices); +} + +inline void dispatch(OrgeDispatchParam *param) { + graphics::renderer::renderer().getContext().dispatch(param->x, param->y, param->z); +} + +} // namespace api diff --git a/src/api/dialog.hpp b/src/api/dialog.hpp new file mode 100644 index 00000000..a3a7a08c --- /dev/null +++ b/src/api/dialog.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include "../error/error.hpp" + +#include + +namespace api { + +inline void showDialog(OrgeShowDialogParam *param) { + SDL_MessageBoxFlags flags = SDL_MESSAGEBOX_ERROR; + switch (param->dtype) { + case ORGE_DIALOG_TYPE_WARNING: + flags = SDL_MESSAGEBOX_WARNING; + break; + case ORGE_DIALOG_TYPE_INFORMATION: + flags = SDL_MESSAGEBOX_INFORMATION; + break; + default: + break; + } + SDL_ShowSimpleMessageBox(flags, param->title, param->message, nullptr); +} + +inline void showErrorDialog() { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "error", error::getMessage().c_str(), nullptr); +} + +} // namespace api diff --git a/src/api/dispatch.hpp b/src/api/dispatch.hpp new file mode 100644 index 00000000..1c680ab9 --- /dev/null +++ b/src/api/dispatch.hpp @@ -0,0 +1,180 @@ +#pragma once + +#include + +#include "audio.hpp" +#include "compute.hpp" +#include "dialog.hpp" +#include "input.hpp" +#include "lifetime.hpp" +#include "rendering.hpp" +#include "resource.hpp" +#include "text.hpp" +#include "window.hpp" + +namespace api { + +inline OrgeApiResult dispatchApi(OrgeApiCallType type, void *param) { + switch (type) { + case ORGE_SHOW_DIALOG: + showDialog(static_cast(param)); + break; + case ORGE_SHOW_ERROR_DIALOG: + showErrorDialog(); + break; + + case ORGE_INITIALIZE: + initialize(static_cast(param)); + break; + case ORGE_TERMINATE: + terminate(); + break; + case ORGE_UPDATE: + return update(); + + case ORGE_IS_FULLSCREEN: + isFullscreen(static_cast(param)); + break; + case ORGE_SET_FULLSCREEN: + setFullscreen(static_cast(param)); + break; + + case ORGE_CREATE_BUFFER: + createBuffer(static_cast(param)); + break; + case ORGE_DESTROY_BUFFER: + destroyBuffer(static_cast(param)); + break; + case ORGE_UPDATE_BUFFER: + updateBuffer(static_cast(param)); + break; + case ORGE_COPY_BUFFER_TO: + copyBufferTo(static_cast(param)); + break; + case ORGE_UPDATE_BUFFER_DESCRIPTOR: + updateBufferDescriptor(static_cast(param)); + break; + case ORGE_UPDATE_COMPUTE_BUFFER_DESCRIPTOR: + updateComputeBufferDescriptor(static_cast(param)); + break; + case ORGE_LOAD_IMAGE: + loadImage(static_cast(param)); + break; + case ORGE_DESTROY_IMAGE: + destroyImage(static_cast(param)); + break; + case ORGE_CREATE_STORAGE_IMAGE: + createStorageImage(static_cast(param)); + break; + case ORGE_DESTROY_STORAGE_IMAGE: + destroyStorageImage(static_cast(param)); + break; + case ORGE_UPDATE_IMAGE_DESCRIPTOR: + updateImageDescriptor(static_cast(param)); + break; + case ORGE_UPDATE_COMPUTE_IMAGE_DESCRIPTOR: + updateComputeImageDescriptor(static_cast(param)); + break; + case ORGE_UPDATE_COMPUTE_STORAGE_IMAGE_DESCRIPTOR: + updateComputeStorageImageDescriptor(static_cast(param)); + break; + case ORGE_CREATE_SAMPLER: + createSampler(static_cast(param)); + break; + case ORGE_DESTROY_SAMPLER: + destroySampler(static_cast(param)); + break; + case ORGE_UPDATE_SAMPLER_DESCRIPTOR: + updateSamplerDescriptor(static_cast(param)); + break; + case ORGE_UPDATE_COMPUTE_SAMPLER_DESCRIPTOR: + updateComputeSamplerDescriptor(static_cast(param)); + break; + case ORGE_UPDATE_INPUT_ATTACHMENT_DESCRIPTOR: + updateInputAttachmentDescriptor(static_cast(param)); + break; + case ORGE_LOAD_MESH: + loadMesh(static_cast(param)); + break; + case ORGE_DESTROY_MESH: + destroyMesh(static_cast(param)); + break; + + case ORGE_RASTERIZE_CHARACTERS: + rasterizeCharacters(static_cast(param)); + break; + case ORGE_LAYOUT_TEXT: + layoutText(static_cast(param)); + break; + case ORGE_DRAW_TEXTS: + drawTexts(); + break; + + case ORGE_BEGIN_RENDER: + beginRender(); + break; + case ORGE_END_RENDER: + endRender(); + break; + case ORGE_BIND_MESH: + bindMesh(static_cast(param)); + break; + case ORGE_BEGIN_RENDER_PASS: + beginRenderPass(static_cast(param)); + break; + case ORGE_END_RENDER_PASS: + endRenderPass(); + break; + case ORGE_NEXT_SUBPASS: + nextSubpass(); + break; + case ORGE_BIND_PIPELINE: + bindPipeline(static_cast(param)); + break; + case ORGE_DRAW: + draw(static_cast(param)); + break; + case ORGE_DRAW_DIRECTLY: + drawDirectly(static_cast(param)); + break; + + case ORGE_BIND_COMPUTE_PIPELINE: + bindComputePipeline(static_cast(param)); + break; + case ORGE_DISPATCH: + dispatch(static_cast(param)); + break; + + case ORGE_GET_KEY_STATE: + getKeyState(static_cast(param)); + break; + case ORGE_GET_CURSOR: + getCursor(static_cast(param)); + break; + case ORGE_GET_MOUSE_BUTTON_STATE: + getMouseButtonState(static_cast(param)); + break; + + case ORGE_GET_AUDIO_CHANNEL_VOLUME: + return getAudioChannelVolume(static_cast(param)); + case ORGE_SET_AUDIO_CHANNEL_VOLUME: + setAudioChannelVolume(static_cast(param)); + break; + case ORGE_LOAD_WAVE: + loadWave(static_cast(param)); + break; + case ORGE_DESTROY_WAVE: + destroyWave(static_cast(param)); + break; + case ORGE_PLAY_WAVE: + playWave(static_cast(param)); + break; + + default: + throw std::format("invalid api type: {}", static_cast(type)); + } + + return ORGE_OK; +} + +} // namespace api diff --git a/src/api/input.hpp b/src/api/input.hpp new file mode 100644 index 00000000..e01e269a --- /dev/null +++ b/src/api/input.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include "../input/input.hpp" + +namespace api { + +inline void getKeyState(OrgeGetKeyStateParam *param) { + *param->out = input::input().getState(param->scancode); +} + +inline void getCursor(OrgeGetCursorParam *param) { + *param->outX = input::input().getCursorX(); + *param->outY = input::input().getCursorY(); +} + +inline void getMouseButtonState(OrgeGetMouseButtonStateParam *param) { + *param->out = input::input().getMouseButtonState(param->button); +} + +} // namespace api diff --git a/src/api/lifetime.hpp b/src/api/lifetime.hpp new file mode 100644 index 00000000..b7c84890 --- /dev/null +++ b/src/api/lifetime.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include + +#include "../asset/asset.hpp" +#include "../config/config.hpp" +#include "../graphics/graphics.hpp" +#include "../graphics/core/core.hpp" +#include "../graphics/window/swapchain.hpp" +#include "../audio/audio.hpp" +#include "../input/input.hpp" + +#include +#include + +#ifdef __APPLE__ +# define MODKEY SDL_KMOD_GUI +#else +# define MODKEY SDL_KMOD_ALT +#endif + +namespace api { + +inline void initialize(OrgeInitializeParam *param) { + if (!SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO)) { + throw std::format("failed to prepare for creating a window: {}", SDL_GetError()); + } + if (!SDL_Vulkan_LoadLibrary(nullptr)) { + throw std::format("failed to load Vulkan: {}", SDL_GetError()); + } + if (param->assetsPath) { + asset::initialize(param->assetsPath); + } + config::initialize(param); + graphics::initialize(); + audio::initialize(); + input::initialize(); +} + +inline void terminate() { + graphics::terminate(); + audio::destroy(); + input::destroy(); +} + +inline OrgeApiResult update() { + SDL_Event event; + while (SDL_PollEvent(&event)) { + if (event.type == SDL_EVENT_QUIT) { + return ORGE_WINDOW_CLOSED; + } + if ( + !config::config().disableFullscreenShortcut + && event.type == SDL_EVENT_KEY_DOWN + && event.key.key == SDLK_RETURN + && (event.key.mod & MODKEY) + ) { + const auto &swapchain = graphics::window::swapchain(); + graphics::core::device().waitIdle(); + swapchain.setFullscreen(!swapchain.isFullscreen()); + } + } + audio::audio().update(); + input::input().update(); + return ORGE_OK; +} + +} // namespace api diff --git a/src/api/rendering.hpp b/src/api/rendering.hpp new file mode 100644 index 00000000..fc3739e2 --- /dev/null +++ b/src/api/rendering.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include + +#include "../graphics/renderer/renderer.hpp" + +namespace api { + +inline void beginRender() { + graphics::renderer::renderer().begin(); +} + +inline void endRender() { + graphics::renderer::renderer().end(); +} + +inline void bindMesh(OrgeBindMeshParam *param) { + graphics::renderer::renderer().getContext().bindMesh(param->meshId); +} + +inline void beginRenderPass(OrgeBeginRenderPassParam *param) { + graphics::renderer::renderer().getContext().beginRenderPass(param->renderPassId); +} + +inline void endRenderPass() { + graphics::renderer::renderer().getContext().endRenderPass(); +} + +inline void nextSubpass() { + graphics::renderer::renderer().getContext().nextSubpass(); +} + +inline void bindPipeline(OrgeBindPipelineParam *param) { + graphics::renderer::renderer().getContext().bindPipeline(param->pipelineId, param->indices); +} + +inline void draw(OrgeDrawParam *param) { + graphics::renderer::renderer().getContext().draw(param->instanceCount, param->instanceOffset); +} + +inline void drawDirectly(OrgeDrawDirectlyParam *param) { + graphics::renderer::renderer() + .getContext() + .drawDirectly(param->vertexCount, param->instanceCount, param->instanceOffset); +} + +} // namespace api diff --git a/src/api/resource.hpp b/src/api/resource.hpp new file mode 100644 index 00000000..f2e6981c --- /dev/null +++ b/src/api/resource.hpp @@ -0,0 +1,166 @@ +#pragma once + +#include + +#include "../graphics/renderer/renderer.hpp" +#include "../graphics/renderpass/renderpass.hpp" +#include "../graphics/resource/buffer.hpp" +#include "../graphics/resource/image-storage.hpp" +#include "../graphics/resource/image-user.hpp" +#include "../graphics/resource/mesh.hpp" +#include "../graphics/resource/sampler.hpp" + +namespace api { + +inline void createBuffer(OrgeCreateBufferParam *param) { + graphics::resource::addBuffer( + param->id, + param->size, + static_cast(param->isStorage), + static_cast(param->isHostCoherent) + ); +} + +inline void destroyBuffer(OrgeDestroyBufferParam *param) { + graphics::resource::destroyBuffer(param->id); +} + +inline void updateBuffer(OrgeUpdateBufferParam *param) { + graphics::resource::getBuffer(param->id).update(param->data); +} + +inline void copyBufferTo(OrgeCopyBufferToParam *param) { + graphics::resource::getBuffer(param->id).copyTo(param->data); +} + +inline void updateBufferDescriptor(OrgeUpdateBufferDescriptorParam *param) { + graphics::renderpass::getRenderPass(param->renderPassId) + .getPipeline(param->pipelineId) + .updateBufferDescriptor( + param->id, + param->set, + param->index, + param->binding, + param->offset + ); +} + +inline void updateComputeBufferDescriptor(OrgeUpdateComputeBufferDescriptorParam *param) { + graphics::compute::getComputePipeline(param->pipelineId) + .updateBufferDescriptor( + param->id, + param->set, + param->index, + param->binding, + param->offset + ); +} + +inline void loadImage(OrgeLoadImageParam *param) { + graphics::resource::addUserImageFromFile(param->file); +} + +inline void destroyImage(OrgeDestroyImageParam *param) { + graphics::resource::destroyUserImage(param->file); +} + +inline void createStorageImage(OrgeCreateStorageImageParam *param) { + graphics::resource::addStorageImage(param->id, param->width, param->height, param->format); +} + +inline void destroyStorageImage(OrgeDestroyStorageImageParam *param) { + graphics::resource::destroyStorageImage(param->id); +} + +inline void updateImageDescriptor(OrgeUpdateImageDescriptorParam *param) { + graphics::renderpass::getRenderPass(param->renderPassId) + .getPipeline(param->pipelineId) + .updateUserImageDescriptor( + param->id, + param->set, + param->index, + param->binding, + param->offset + ); +} + +inline void updateComputeImageDescriptor(OrgeUpdateComputeImageDescriptorParam *param) { + graphics::compute::getComputePipeline(param->pipelineId) + .updateImageDescriptor( + param->id, + param->set, + param->index, + param->binding, + param->offset + ); +} + +inline void updateComputeStorageImageDescriptor(OrgeUpdateComputeStorageImageDescriptorParam *param) { + graphics::compute::getComputePipeline(param->pipelineId) + .updateStorageImageDescriptor( + param->id, + param->set, + param->index, + param->binding, + param->offset + ); +} + +inline void createSampler(OrgeCreateSamplerParam *param) { + graphics::resource::addSampler( + param->id, + static_cast(param->linearMagFilter), + static_cast(param->linearMinFilter), + static_cast(param->repeat) + ); +} + +inline void destroySampler(OrgeDestroySamplerParam *param) { + graphics::resource::destroySampler(param->id); +} + +inline void updateSamplerDescriptor(OrgeUpdateSamplerDescriptorParam *param) { + graphics::renderpass::getRenderPass(param->renderPassId) + .getPipeline(param->pipelineId) + .updateSamplerDescriptor( + param->id, + param->set, + param->index, + param->binding, + param->offset + ); +} + +inline void updateComputeSamplerDescriptor(OrgeUpdateComputeSamplerDescriptorParam *param) { + graphics::compute::getComputePipeline(param->pipelineId) + .updateSamplerDescriptor( + param->id, + param->set, + param->index, + param->binding, + param->offset + ); +} + +inline void updateInputAttachmentDescriptor(OrgeUpdateInputAttachmentDescriptorParam *param) { + graphics::renderpass::getRenderPass(param->renderPassId) + .getPipeline(param->pipelineId) + .updateInputAttachmentDescriptor( + param->id, + param->set, + param->index, + param->binding, + param->offset, + graphics::renderer::renderer().getContext().currentIndex() + ); +} + +inline void loadMesh(OrgeLoadMeshParam *param) { + graphics::resource::addMesh(param->id); +} + +inline void destroyMesh(OrgeDestroyMeshParam *param) { + graphics::resource::destroyMesh(param->id); +} + +} // namespace api diff --git a/src/api/text.hpp b/src/api/text.hpp new file mode 100644 index 00000000..f54f570b --- /dev/null +++ b/src/api/text.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include "../graphics/text/text.hpp" +#include "../graphics/renderer/renderer.hpp" + +namespace api { + +inline void rasterizeCharacters(OrgeRasterizeCharactersParam *param) { + graphics::text::rasterizeText(param->id, param->s); +} + +inline void layoutText(OrgeLayoutTextParam *param) { + graphics::text::layoutText( + param->renderPassId, + param->subpassId, + param->fontId, + param->text, + param->x, + param->y, + param->height, + static_cast(param->horizontal), + static_cast(param->vertical) + ); +} + +inline void drawTexts() { + graphics::renderer::renderer().getContext().drawTexts(); +} + +} // namespace api diff --git a/src/api/window.hpp b/src/api/window.hpp new file mode 100644 index 00000000..887046cf --- /dev/null +++ b/src/api/window.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include "../graphics/window/swapchain.hpp" + +namespace api { + +inline void isFullscreen(OrgeIsFullscreenParam *param) { + *param->out = static_cast(graphics::window::swapchain().isFullscreen()); +} + +inline void setFullscreen(OrgeSetFullscreenParam *param) { + // NOTE: 発生する例外はすべて致命的であり、TRY_DISCARDで強制終了されるので、返戻型はvoid。 + graphics::window::swapchain().setFullscreen(static_cast(param->fullscreen)); +} + +} // namespace api diff --git a/src/asset/asset.cpp b/src/asset/asset.cpp index 2b4d1030..f197ad81 100644 --- a/src/asset/asset.cpp +++ b/src/asset/asset.cpp @@ -1,6 +1,7 @@ #include "asset.hpp" #include +#include #include #include #include @@ -10,10 +11,10 @@ namespace asset { std::vector g_dat; std::unordered_map g_assetMap; -void loadDatFile() { - std::ifstream file(".dat", std::ios::binary); +void loadDatFile(const std::string &path) { + std::ifstream file(path, std::ios::binary); if (!file) { - throw ".dat not found."; + throw std::format("assets data file not found: {}", path); } file.seekg(0, std::ios::end); @@ -51,20 +52,13 @@ void analyzeDat() { } } -void initialize() { - loadDatFile(); +void initialize(const std::string &path) { + loadDatFile(path); analyzeDat(); } -std::span getConfigData() { - const auto &entry = g_assetMap[0]; - const unsigned char *data = g_dat.data() + entry.offset; - return std::span(data, entry.size); -} - std::span getAsset(uint32_t id) { - // NOTE: 0はconfigファイルに予約されているので+1する。 - const auto &entry = g_assetMap[id + 1]; + const auto &entry = g_assetMap[id]; const unsigned char *data = g_dat.data() + entry.offset; return std::span(data, entry.size); } diff --git a/src/asset/asset.hpp b/src/asset/asset.hpp index be0b394c..127626fe 100644 --- a/src/asset/asset.hpp +++ b/src/asset/asset.hpp @@ -2,12 +2,11 @@ #include #include +#include namespace asset { -void initialize(); - -std::span getConfigData(); +void initialize(const std::string &path); std::span getAsset(uint32_t id); diff --git a/src/config/attachment.cpp b/src/config/attachment.cpp deleted file mode 100644 index 07ab5c07..00000000 --- a/src/config/attachment.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "attachment.hpp" - -#include "utils.hpp" - -#include - -namespace config { - -Format parseFormat(const std::string& s) { - return s == "render-target" - ? Format::RenderTarget - : s == "depth-buffer" - ? Format::DepthBuffer - : s == "share-color-attachment" - ? Format::ShareColorAttachment - : s == "signed-share-color-attachment" - ? Format::SignedShareColorAttachment - : throw std::format("config error: format '{}' is invalid.", s); -} - -ClearValueConfig parseClearValueConfig(const YAML::Node &node) { - const bool isColor = node["clear-value"] && node["clear-value"].IsSequence(); - return isColor - ? ClearValueConfig(get>(node, "clear-value", "float[4]")) - : ClearValueConfig(f(node, "clear-value")); -} - -AttachmentConfig::AttachmentConfig(const YAML::Node &node): - format(parseFormat(s(node, "format"))), - discard(b(node, "discard", false)), - clearValue(parseClearValueConfig(node)) -{ - checkUnexpectedKeys(node, {"id", "format", "discard", "clear-value"}); -} - -std::unordered_map parseAttachmentConfigs(const YAML::Node &node) { - std::unordered_map attachments; - for (const auto &n: node["attachments"]) { - const auto id = s(n, "id"); - if (attachments.contains(id)) { - throw std::format("config error: attachments '{}' duplicated.", id); - } - attachments.emplace(id, AttachmentConfig(n)); - } - return attachments; -} - -} // namespace config diff --git a/src/config/attachment.hpp b/src/config/attachment.hpp deleted file mode 100644 index 04b10b0c..00000000 --- a/src/config/attachment.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include - -#include - -namespace config { - -enum class Format: uint8_t { - RenderTarget, - DepthBuffer, - ShareColorAttachment, - SignedShareColorAttachment, -}; - -using ColorClearValue = std::array; -using DepthClearValue = float; -using ClearValueConfig = std::variant; - -struct AttachmentConfig { - const Format format; - const bool discard; - const ClearValueConfig clearValue; - - AttachmentConfig(const YAML::Node &node); -}; - -std::unordered_map parseAttachmentConfigs(const YAML::Node &node); - -} // namespace config diff --git a/src/config/compute.cpp b/src/config/compute.cpp deleted file mode 100644 index cfbdcf2f..00000000 --- a/src/config/compute.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "compute.hpp" - -#include "utils.hpp" - -namespace config { - -inline ComputeDescriptorType parseComputeDescriptorType(const std::string& s) { - return s == "texture" - ? ComputeDescriptorType::Texture - : s == "sampler" - ? ComputeDescriptorType::Sampler - : s == "uniform-buffer" - ? ComputeDescriptorType::UniformBuffer - : s == "storage-buffer" - ? ComputeDescriptorType::StorageBuffer - : s == "storage-image" - ? ComputeDescriptorType::StorageImage - : throw std::format("config error: type '{}' is invalid.", s); -} - -ComputeDescriptorBindingConfig::ComputeDescriptorBindingConfig(const YAML::Node &node): - type(parseComputeDescriptorType(s(node, "type"))), - count(u(node, "count", 1)) -{ - checkUnexpectedKeys(node, {"type", "count"}); -} - -ComputeDescriptorSetConfig::ComputeDescriptorSetConfig(const YAML::Node &node): - count(u(node, "count")), - bindings(parseConfigs(node, "bindings")) -{ - checkUnexpectedKeys(node, {"count", "bindings"}); -} - -ComputePipelineConfig::ComputePipelineConfig(const YAML::Node &node): - shader(s(node, "shader")), - descSets(parseConfigs(node, "desc-sets")) -{ - checkUnexpectedKeys(node, {"id", "shader", "desc-sets"}); -} - -std::unordered_map parseComputePipelineConfigs(const YAML::Node &node) { - std::unordered_map pipelines; - for (const auto &n: node["compute-pipelines"]) { - const auto id = s(n, "id"); - if (pipelines.contains(id)) { - throw std::format("config error: compute pipeline '{}' duplicated.", id); - } - pipelines.emplace(id, n); - } - return pipelines; -} - -} // namespace config diff --git a/src/config/compute.hpp b/src/config/compute.hpp deleted file mode 100644 index 29ab26c3..00000000 --- a/src/config/compute.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include - -namespace config { - -enum class ComputeDescriptorType: uint8_t { - Texture, - Sampler, - UniformBuffer, - StorageBuffer, - StorageImage, -}; - -struct ComputeDescriptorBindingConfig { - const ComputeDescriptorType type; - const uint32_t count; - - ComputeDescriptorBindingConfig(const YAML::Node &node); -}; - -struct ComputeDescriptorSetConfig { - const uint32_t count; - const std::vector bindings; - - ComputeDescriptorSetConfig(const YAML::Node &node); -}; - -struct ComputePipelineConfig { - const std::string shader; - const std::vector descSets; - - ComputePipelineConfig(const YAML::Node &node); -}; - -std::unordered_map parseComputePipelineConfigs(const YAML::Node &node); - -} // namespace config diff --git a/src/config/config.cpp b/src/config/config.cpp index b08f47bb..2d8cce30 100644 --- a/src/config/config.cpp +++ b/src/config/config.cpp @@ -1,129 +1,346 @@ #include "config.hpp" -#include "../asset/asset.hpp" -#include "utils.hpp" +#include namespace config { -std::optional g_config; - -std::unordered_map collectAssetMap(const YAML::Node &node) { - if (!node["assets"]) { - return {}; +std::unordered_map createFonts(OrgeInitializeParam *param) { + std::unordered_map fonts; + fonts.reserve(param->fontCount); + for (uint32_t i = 0; i < param->fontCount; ++i) { + const auto &font = param->fonts[i]; + fonts.try_emplace(font.id, font.file, font.charSize, font.charAtlusCol, font.charAtlusRow); } - if (!node["assets"].IsSequence()) { - throw "config error: assets must be a string sequence."; + return fonts; +} + +std::unordered_map createAttachments(OrgeInitializeParam *param) { + std::unordered_map attachments; + attachments.reserve(param->attachmentCount); + for (uint32_t i = 0; i < param->attachmentCount; ++i) { + const auto &n = param->attachments[i]; + + ClearValueConfig clearValue; + switch (n.clearValueType) { + case ORGE_CLEAR_VALUE_TYPE_COLOR: + clearValue = ColorClearValue{n.clearValue[0], n.clearValue[1], n.clearValue[2], n.clearValue[3]}; + break; + case ORGE_CLEAR_VALUE_TYPE_DEPTH: + clearValue = DepthClearValue{n.clearValue[0]}; + break; + default: + throw std::format("invalid clear value type passed: {}", static_cast(n.clearValueType)); + } + + Format format; + switch (n.format) { + case ORGE_FORMAT_RENDER_TARGET: + format = Format::RenderTarget; + break; + case ORGE_FORMAT_DEPTH_BUFFER: + format = Format::DepthBuffer; + break; + case ORGE_FORMAT_SHARE_COLOR_ATTACHMENT: + format = Format::ShareColorAttachment; + break; + case ORGE_FORMAT_SIGNED_SHARE_COLOR_ATTACHMENT: + format = Format::SignedShareColorAttachment; + break; + default: + throw std::format("invalid attachment format passed: {}", static_cast(n.format)); + } + + attachments.try_emplace(n.id, format, static_cast(n.discard), clearValue); } + return attachments; +} - const auto assets = ss(node, "assets"); +std::vector createDescriptorBindings( + uint32_t bindingCount, + OrgeDescriptorBindingConfig *bindings +) { + std::vector result; + result.reserve(bindingCount); + for (uint32_t i = 0; i < bindingCount; ++i) { + const auto& n = bindings[i]; - std::unordered_map assetMap; - for (const auto &n: assets) { - if (assetMap.contains(n)) { - throw std::format("config error: asset '{}' is duplicated.", n); + DescriptorType type; + switch (n.type) { + case ORGE_DESCRIPTOR_TYPE_TEXTURE: + type = DescriptorType::Texture; + break; + case ORGE_DESCRIPTOR_TYPE_SAMPLER: + type = DescriptorType::Sampler; + break; + case ORGE_DESCRIPTOR_TYPE_UNIFORM_BUFFER: + type = DescriptorType::UniformBuffer; + break; + case ORGE_DESCRIPTOR_TYPE_STORAGE_BUFFER: + type = DescriptorType::StorageBuffer; + break;; + case ORGE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: + break; + default: + throw std::format("invalid descriptor binding type passed: {}", static_cast(n.type)); + } + + ShaderStages stage; + switch (n.stage) { + case ORGE_SHADER_STAGES_VERTEX: + stage = ShaderStages::Vertex; + break; + case ORGE_SHADER_STAGES_FRAGMENT: + stage = ShaderStages::Fragment; + break; + case ORGE_SHADER_STAGES_VERTEX_AND_FRAGMENT: + stage = ShaderStages::VertexAndFragment; + break; } - const auto size = assetMap.size(); - assetMap.emplace(n, static_cast(size)); + + result.emplace_back(type, n.count, stage); } + return result; +} - return assetMap; +std::vector createDescriptorSets(uint32_t descSetCount, const OrgeDescriptorSetConfig *descSets) { + std::vector result; + result.reserve(descSetCount); + for (uint32_t i = 0; i < descSetCount; ++i) { + const auto &n = descSets[i]; + auto bindings = createDescriptorBindings(n.bindingCount, n.bindings); + result.emplace_back(n.count, std::move(bindings)); + } + return result; } -// NOTE: 文字アトラスの順番は実行時に決めて良い。 -std::unordered_map collectFontMap(const std::unordered_map &fonts) { - std::unordered_map fontMap; - fontMap.reserve(fonts.size()); - uint32_t i = 0; - for (const auto &[n, _]: fonts) { - fontMap.emplace(n, i); - i += 1; +std::unordered_map createPipelines(OrgeInitializeParam *param) { + std::unordered_map result; + result.reserve(static_cast(param->graphicsPipelineCount)); + for (uint32_t i = 0; i < param->graphicsPipelineCount; ++i) { + const auto &n = param->graphicsPipelines[i]; + + auto descSets = createDescriptorSets(n.descSetCount, n.descSets); + + std::vector vertexInputAttributes; + vertexInputAttributes.reserve(n.vertexInputAttributeCount); + for (uint32_t j = 0; j < n.vertexInputAttributeCount; ++j) { + vertexInputAttributes.push_back(n.vertexInputAttributes[j]); + } + + std::vector colorBlends; + colorBlends.reserve(n.colorBlendCount); + for (uint32_t j = 0; j < n.colorBlendCount; ++j) { + colorBlends.push_back(n.colorBlends[j]); + } + + result.try_emplace( + n.id, + n.vertexShaderFile, + n.fragmentShaderFile, + std::move(descSets), + std::move(vertexInputAttributes), + n.meshInShader, + n.culling, + n.depthTest, + std::move(colorBlends) + ); } - return fontMap; + return result; } -Config::Config(const YAML::Node &node): - title(s(node, "title")), - width(u(node, "width")), - height(u(node, "height")), - fullscreen(b(node, "fullscreen", false)), - disableVsync(b(node, "disable-vsync", false)), - altReturnToggleFullscreen(b(node, "alt-return-toggle-fullscreen", true)), - audioChannelCount(u(node, "audio-channel-count", 16)), - charCount(u(node, "char-count", 256)), - meshes(parseMeshConfigs(node)), - fonts(parseFontConfigs(node)), - attachments(parseAttachmentConfigs(node)), - pipelines(parsePipelineConfigs(node)), - renderPasses(parseRenderPassConfigs(node)), - computePipelines(parseComputePipelineConfigs(node)), - assetMap(collectAssetMap(node)), - fontMap(collectFontMap(fonts)) -{ - checkUnexpectedKeys( - node, - { - "title", - "width", - "height", - "fullscreen", - "disable-vsync", - "alt-return-toggle-fullscreen", - "audio-channel-count", - "char-count", - "assets", - "meshes", - "fonts", - "attachments", - "pipelines", - "render-passes", - "compute-pipelines", +std::unordered_set createStringSet(uint32_t count, const char **strings) { + std::unordered_set result; + result.reserve(static_cast(count)); + for (uint32_t i = 0; i < count; ++i) { + result.insert(strings[i]); + } + return result; +} + +std::vector createSubpasses(uint32_t subpassCount, const OrgeSubpassConfig *subpasses) { + std::vector result; + result.reserve(static_cast(subpassCount)); + for (uint32_t i = 0; i < subpassCount; ++i) { + const auto &n = subpasses[i]; + + auto inputs = createStringSet(n.inputCount, n.inputs); + auto outputs = createStringSet(n.outputCount, n.outputs); + + std::optional depth; + if (n.depth) { + depth.emplace(n.depth->depth, n.depth->readOnly); } - ); - std::set renderPassIds; - for (const auto &[_, r]: renderPasses) { - for (const auto &n: r.subpasses) { - // 各アタッチメントの確認 - for (const auto &m: n.inputs) { - if (!attachments.contains(m)) { - throw std::format("config error: attachment '{}' not defined.", m); - } - switch (attachments.at(m).format) { - case Format::DepthBuffer: - case Format::ShareColorAttachment: - case Format::SignedShareColorAttachment: - break; - default: - throw "config error: the attachment format of a subpass input must be 'depth-buffer', 'share-color-attachment' or 'signed-share-color-attachment'."; - }; - } - for (const auto &m: n.outputs) { - if (!attachments.contains(m)) { - throw std::format("config error: attachment '{}' not defined.", m); + auto depends = createStringSet(n.dependCount, n.depends); + auto pipelines = createStringSet(n.pipelineCount, n.pipelines); + + result.emplace_back( + n.id, + std::move(inputs), + std::move(outputs), + std::move(depth), + std::move(depends), + std::move(pipelines) + ); + } + return result; +} + +std::unordered_map createRenderPasses(OrgeInitializeParam *param) { + std::unordered_map result; + result.reserve(param->renderPassCount); + for (uint32_t i = 0; i < param->renderPassCount; ++i) { + const auto &n = param->renderPasses[i]; + + auto subpasses = createSubpasses(n.subpassCount, n.subpasses); + + std::vector attachments; + std::unordered_set attachmentSet; + for (const auto &m: subpasses) { + for (const auto &o: m.inputs) { + if (!attachmentSet.contains(o)) { + attachments.push_back(o); + attachmentSet.insert(o); } - // TODO: ヴァリデーション。 } - if (n.depth.has_value()) { - const auto &id = n.depth->id; - if (!attachments.contains(id)) { - throw std::format("config error: attachment '{}' not defined.", id); + for (const auto &o: m.outputs) { + if (!attachmentSet.contains(o)) { + attachments.push_back(o); + attachmentSet.insert(o); } - // TODO: ヴァリデーション。 } - // パイプラインの存在確認 - for (const auto &m: n.pipelines) { - if (m != "@text@" && !pipelines.contains(m)) { - throw std::format("config error: pipeline '{}' not defined.", m); + if (m.depth.has_value()) { + const auto &o = m.depth.value(); + if (!attachmentSet.contains(o.id)) { + attachments.push_back(o.id); + attachmentSet.insert(o.id); } } } + + std::unordered_map attachmentMap; + attachmentMap.reserve(attachments.size()); + for (uint32_t j = 0; j < attachments.size(); ++j) { + attachmentMap.emplace(param->attachments[j].id, j); + } + + std::unordered_map subpassMap; + subpassMap.reserve(subpasses.size()); + for (uint32_t j = 0; j < subpasses.size(); ++j) { + subpassMap.emplace(subpasses[j].id, j); + } + + result.try_emplace( + n.id, + std::move(subpasses), + std::move(attachments), + std::move(attachmentMap), + std::move(subpassMap) + ); } + return result; } -void initialize() { - const auto data = asset::getConfigData(); - const auto yaml = std::string(reinterpret_cast(data.data()), data.size()); - g_config.emplace(YAML::Load(yaml)); +std::vector createComputeDescriptorBindings( + uint32_t bindingCount, + const OrgeComputeDescriptorBindingConfig *bindings +) { + std::vector result; + result.reserve(bindingCount); + for (uint32_t i = 0; i < bindingCount; ++i) { + const auto &n = bindings[i]; + + ComputeDescriptorType type; + switch (n.type) { + case ORGE_COMPUTE_DESCRIPTOR_TYPE_TEXTURE: + type = ComputeDescriptorType::Texture; + break; + case ORGE_COMPUTE_DESCRIPTOR_TYPE_SAMPLER: + type = ComputeDescriptorType::Sampler; + break; + case ORGE_COMPUTE_DESCRIPTOR_TYPE_UNIFORM_BUFFER: + type = ComputeDescriptorType::UniformBuffer; + break; + case ORGE_COMPUTE_DESCRIPTOR_TYPE_STORAGE_BUFFER: + type = ComputeDescriptorType::StorageBuffer; + break; + case ORGE_COMPUTE_DESCRIPTOR_TYPE_STORAGE_IMAGE: + type = ComputeDescriptorType::StorageImage; + break; + default: + throw std::format("invalid compute descriptor binding type passed: {}", static_cast(n.type)); + } + + result.emplace_back(type, n.count); + } + return result; +} + +std::vector createComputeDescriptorSets( + uint32_t descSetCount, + const OrgeComputeDescriptorSetConfig *descSets +) { + std::vector result; + result.reserve(descSetCount); + for (uint32_t i = 0; i < descSetCount; ++i) { + const auto &n = descSets[i]; + auto bindings = createComputeDescriptorBindings(n.bindingCount, n.bindings); + result.emplace_back(n.count, std::move(bindings)); + } + return result; +} + +std::unordered_map createComputePipelines(OrgeInitializeParam *param) { + std::unordered_map result; + result.reserve(param->computePipelineCount); + for (uint32_t i = 0; i < param->computePipelineCount; ++i) { + const auto& n = param->computePipelines[i]; + auto descSets = createComputeDescriptorSets(n.descSetCount, n.descSets); + result.try_emplace( + n.id, + n.shaderFile, + std::move(descSets) + ); + } + return result; +} + +std::optional g_config; + +void initialize(OrgeInitializeParam *param) { + auto fonts = createFonts(param); + auto attachments = createAttachments(param); + auto pipelines = createPipelines(param); + auto renderPasses = createRenderPasses(param); + auto computePipelines = createComputePipelines(param); + std::unordered_map assetMap; + assetMap.reserve(param->assetCount); + for (uint32_t i = 0; i < param->assetCount; ++i) { + assetMap.emplace(param->assets[i], i); + } + std::unordered_map fontMap; + fontMap.reserve(param->fontCount); + for (uint32_t i = 0; i < param->fontCount; ++i) { + fontMap.emplace(param->fonts[i].id, i); + } + + g_config.emplace( + param->title, + param->width, + param->height, + static_cast(param->fullscreen), + static_cast(param->disableFullscreenShortcut), + static_cast(param->disableVsync), + param->audioChannelCount, + param->charCount, + std::move(fonts), + std::move(attachments), + std::move(pipelines), + std::move(renderPasses), + std::move(computePipelines), + std::move(assetMap), + std::move(fontMap) + ); } const Config &config() { diff --git a/src/config/config.hpp b/src/config/config.hpp index 07fb33aa..0d2fb73b 100644 --- a/src/config/config.hpp +++ b/src/config/config.hpp @@ -1,37 +1,254 @@ #pragma once -#include "attachment.hpp" -#include "compute.hpp" -#include "font.hpp" -#include "mesh.hpp" -#include "pipeline.hpp" -#include "renderpass.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace config { +struct FontConfig { + const std::string file; + const uint32_t charSize; + const uint32_t charAtlusCol; + const uint32_t charAtlusRow; + + FontConfig(const char *file, uint32_t size, uint32_t col, uint32_t row): + file(file), charSize(size), charAtlusCol(col), charAtlusRow(row) + {} +}; + +enum class Format { + RenderTarget, + DepthBuffer, + ShareColorAttachment, + SignedShareColorAttachment, +}; + +using ColorClearValue = std::array; +using DepthClearValue = float; +using ClearValueConfig = std::variant; + +struct AttachmentConfig { + const Format format; + const bool discard; + const ClearValueConfig clearValue; + + AttachmentConfig(Format format, bool discard, ClearValueConfig clearValue): + format(format), discard(discard), clearValue(clearValue) + {} +}; + +enum class DescriptorType: uint8_t { + Texture, + Sampler, + UniformBuffer, + StorageBuffer, + InputAttachment, +}; + +enum class ShaderStages: uint8_t { + Vertex, + Fragment, + VertexAndFragment, +}; + +struct DescriptorBindingConfig { + const DescriptorType type; + const uint32_t count; + const ShaderStages stage; + + DescriptorBindingConfig(DescriptorType type, uint32_t count, ShaderStages stage): + type(type), count(count), stage(stage) + {} +}; + +struct DescriptorSetConfig { + const uint32_t count; + const std::vector bindings; + + DescriptorSetConfig(uint32_t count, std::vector &&bindings): + count(count), bindings(std::move(bindings)) + {} +}; + +struct GraphicsPipelineConfig { + const std::string vertexShader; + const std::string fragmentShader; + const std::vector descSets; + const std::vector vertexInputAttributes; + const bool meshInShader; + const bool culling; + const bool depthTest; + const std::vector colorBlends; + + GraphicsPipelineConfig( + const char *vertexShader, + const char *fragmentShader, + std::vector &&descSets, + std::vector &&vertexInputAttributes, + bool meshInShader, + bool culling, + bool depthTest, + std::vector &&colorBlends + ): + vertexShader(vertexShader), + fragmentShader(fragmentShader), + descSets(std::move(descSets)), + vertexInputAttributes(std::move(vertexInputAttributes)), + meshInShader(meshInShader), + culling(culling), + depthTest(depthTest), + colorBlends(std::move(colorBlends)) + {} +}; + +struct SubpassDepthConfig { + const std::string id; + const bool readOnly; + + SubpassDepthConfig(const char *id, bool readOnly): id(id), readOnly(readOnly) {} +}; + +struct SubpassConfig { + const std::string id; + const std::unordered_set inputs; + const std::unordered_set outputs; + const std::optional depth; + const std::unordered_set depends; + const std::unordered_set pipelines; + + SubpassConfig( + const char *id, + std::unordered_set &&inputs, + std::unordered_set &&outputs, + std::optional &&depth, + std::unordered_set &&depends, + std::unordered_set &&pipelines + ): + id(id), + inputs(std::move(inputs)), + outputs(std::move(outputs)), + depth(std::move(depth)), + depends(std::move(depends)), + pipelines(std::move(pipelines)) + {} +}; + +struct RenderPassConfig { + const std::vector subpasses; + + const std::vector attachments; + const std::unordered_map attachmentMap; + const std::unordered_map subpassMap; + + RenderPassConfig( + std::vector &&subpasses, + std::vector &&attachments, + std::unordered_map &&attachmentMap, + std::unordered_map &&subpassMap + ): + subpasses(std::move(subpasses)), + attachments(std::move(attachments)), + attachmentMap(std::move(attachmentMap)), + subpassMap(std::move(subpassMap)) + {} +}; + +enum class ComputeDescriptorType { + Texture, + Sampler, + UniformBuffer, + StorageBuffer, + StorageImage, +}; + +struct ComputeDescriptorBindingConfig { + const ComputeDescriptorType type; + const uint32_t count; + + ComputeDescriptorBindingConfig(ComputeDescriptorType type, uint32_t count): + type(type), count(count) + {} +}; + +struct ComputeDescriptorSetConfig { + const uint32_t count; + const std::vector bindings; + + ComputeDescriptorSetConfig(uint32_t count, std::vector &&bindings): + count(count), bindings(std::move(bindings)) + {} +}; + +struct ComputePipelineConfig { + const std::string shader; + const std::vector descSets; + + ComputePipelineConfig(const char *shader, std::vector &&descSets): + shader(shader), descSets(std::move(descSets)) + {} +}; + struct Config { const std::string title; const uint32_t width; const uint32_t height; const bool fullscreen; + const bool disableFullscreenShortcut; const bool disableVsync; - const bool altReturnToggleFullscreen; const uint32_t audioChannelCount; const uint32_t charCount; - const std::unordered_map meshes; const std::unordered_map fonts; const std::unordered_map attachments; - const std::unordered_map pipelines; + const std::unordered_map pipelines; const std::unordered_map renderPasses; const std::unordered_map computePipelines; const std::unordered_map assetMap; const std::unordered_map fontMap; - Config(const YAML::Node &node); + Config( + const char *title, + uint32_t width, + uint32_t height, + bool fullscreen, + bool disableFullscreenShortcut, + bool disableVsync, + uint32_t audioChannelCount, + uint32_t charCount, + std::unordered_map &&fonts, + std::unordered_map &&attachments, + std::unordered_map &&pipelines, + std::unordered_map &&renderPasses, + std::unordered_map &&computePipelines, + std::unordered_map &&assetMap, + std::unordered_map &&fontMap + ): + title(title), + width(width), + height(height), + fullscreen(fullscreen), + disableFullscreenShortcut(disableFullscreenShortcut), + disableVsync(disableVsync), + audioChannelCount(audioChannelCount), + charCount(charCount), + fonts(std::move(fonts)), + attachments(std::move(attachments)), + pipelines(std::move(pipelines)), + renderPasses(std::move(renderPasses)), + computePipelines(std::move(computePipelines)), + assetMap(std::move(assetMap)), + fontMap(std::move(fontMap)) + {} }; -void initialize(); +void initialize(OrgeInitializeParam *param); const Config &config(); diff --git a/src/config/enumconvert.hpp b/src/config/enumconvert.hpp index 1bcaef4d..b6359f1d 100644 --- a/src/config/enumconvert.hpp +++ b/src/config/enumconvert.hpp @@ -1,8 +1,6 @@ #pragma once -#include "attachment.hpp" -#include "compute.hpp" -#include "pipeline.hpp" +#include "config.hpp" #include diff --git a/src/config/font.cpp b/src/config/font.cpp deleted file mode 100644 index 193c6056..00000000 --- a/src/config/font.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "font.hpp" - -#include "utils.hpp" - -namespace config { - -FontConfig::FontConfig(const YAML::Node &node): - file(s(node, "file")), - charSize(u(node, "char-size")), - charAtlusCol(u(node, "char-atlus-col")), - charAtlusRow(u(node, "char-atlus-row")) -{ - checkUnexpectedKeys(node, {"id", "file", "char-size", "char-atlus-col", "char-atlus-row"}); - - if (charSize == 0) { - throw "config error: 'char-size' must be greater than 0."; - } - if (charAtlusCol == 0) { - throw "config error: 'char-atlus-col' must be greater than 0."; - } - if (charAtlusRow == 0) { - throw "config error: 'char-atlus-row' must be greater than 0."; - } -} - -std::unordered_map parseFontConfigs(const YAML::Node &node) { - std::unordered_map fonts; - for (const auto &n: node["fonts"]) { - const auto id = s(n, "id"); - if (fonts.contains(id)) { - throw std::format("config error: font '{}' duplicated.", id); - } - fonts.emplace(id, n); - } - return fonts; -} - -} // namespace config diff --git a/src/config/font.hpp b/src/config/font.hpp deleted file mode 100644 index b1731482..00000000 --- a/src/config/font.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include - -namespace config { - -struct FontConfig { - const std::string file; - const uint32_t charSize; - const uint32_t charAtlusCol; - const uint32_t charAtlusRow; - - FontConfig(const YAML::Node &node); -}; - -std::unordered_map parseFontConfigs(const YAML::Node &node); - -} // namespace config diff --git a/src/config/mesh.cpp b/src/config/mesh.cpp deleted file mode 100644 index 5348e136..00000000 --- a/src/config/mesh.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "mesh.hpp" - -#include "utils.hpp" - -namespace config { - -MeshConfig::MeshConfig(const YAML::Node &node): vertices(s(node, "vertices")), indices(s(node, "indices")) { - checkUnexpectedKeys(node, {"id", "vertices", "indices"}); -} - -std::unordered_map parseMeshConfigs(const YAML::Node &node) { - std::unordered_map meshes; - for (const auto &n: node["meshes"]) { - const auto id = s(n, "id"); - if (meshes.contains(id)) { - throw std::format("config error: mesh '{}' duplicated.", id); - } - meshes.emplace(id, MeshConfig(n)); - } - return meshes; -} - -} // namespace diff --git a/src/config/mesh.hpp b/src/config/mesh.hpp deleted file mode 100644 index f2ef9697..00000000 --- a/src/config/mesh.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include -#include - -namespace config { - -struct MeshConfig { - const std::string vertices; - const std::string indices; - - MeshConfig(const YAML::Node &node); -}; - -std::unordered_map parseMeshConfigs(const YAML::Node &node); - -} // namespace config diff --git a/src/config/pipeline.cpp b/src/config/pipeline.cpp deleted file mode 100644 index 74d0ec92..00000000 --- a/src/config/pipeline.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "pipeline.hpp" - -#include "utils.hpp" - -namespace config { - -inline DescriptorType parseDescriptorType(const std::string& s) { - return s == "texture" - ? DescriptorType::Texture - : s == "sampler" - ? DescriptorType::Sampler - : s == "uniform-buffer" - ? DescriptorType::UniformBuffer - : s == "storage-buffer" - ? DescriptorType::StorageBuffer - : s == "input-attachment" - ? DescriptorType::InputAttachment - : throw std::format("config error: type '{}' is invalid.", s); -} - -inline ShaderStages parseShaderStages(const std::string& s) { - return s == "vertex" - ? ShaderStages::Vertex - : s == "fragment" - ? ShaderStages::Fragment - : s == "vertex-and-fragment" - ? ShaderStages::VertexAndFragment - : throw std::format("config error: stages '{}' is invalid.", s); -} - -DescriptorBindingConfig::DescriptorBindingConfig(const YAML::Node &node): - type(parseDescriptorType(s(node, "type"))), - count(u(node, "count", 1)), - stage(parseShaderStages(s(node, "stage"))) -{ - checkUnexpectedKeys(node, {"type", "count", "stage"}); -} - -DescriptorSetConfig::DescriptorSetConfig(const YAML::Node &node): - count(u(node, "count")), - bindings(parseConfigs(node, "bindings")) -{ - checkUnexpectedKeys(node, {"count", "bindings"}); -} - -PipelineConfig::PipelineConfig(const YAML::Node &node): - vertexShader(s(node, "vertex-shader")), - fragmentShader(s(node, "fragment-shader")), - descSets(parseConfigs(node, "desc-sets")), - vertexInputAttributes(us(node, "vertex-input-attributes", std::vector{})), - meshInShader(b(node, "mesh-in-shader", false)), - culling(b(node, "culling", false)), - depthTest(b(node, "depth-test", false)), - colorBlends(bs(node, "color-blends")) -{ - checkUnexpectedKeys( - node, - { - "id", "vertex-shader", "fragment-shader", "desc-sets", "vertex-input-attributes", - "mesh-in-shader", "culling", "depth-test", "color-blends" - } - ); - - for (const auto &n: vertexInputAttributes) { - validateValue(n, {1, 2, 3, 4}, "vertex input attribute"); - } -} - -std::unordered_map parsePipelineConfigs(const YAML::Node &node) { - std::unordered_map pipelines; - for (const auto &n: node["pipelines"]) { - const auto id = s(n, "id"); - if (id == "@text@") { - throw "config error: pipeline id must not be '@text@'."; - } - if (pipelines.contains(id)) { - throw std::format("config error: pipeline '{}' duplicated.", id); - } - pipelines.emplace(id, n); - } - return pipelines; -} - -} // namespace config diff --git a/src/config/pipeline.hpp b/src/config/pipeline.hpp deleted file mode 100644 index c00777bc..00000000 --- a/src/config/pipeline.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include - -namespace config { - -enum class DescriptorType: uint8_t { - Texture, - Sampler, - UniformBuffer, - StorageBuffer, - InputAttachment, -}; - -enum class ShaderStages: uint8_t { - Vertex, - Fragment, - VertexAndFragment, -}; - -struct DescriptorBindingConfig { - const DescriptorType type; - const uint32_t count; - const ShaderStages stage; - - DescriptorBindingConfig(const YAML::Node &node); - DescriptorBindingConfig(DescriptorType type, uint32_t count, ShaderStages stage): - type(type), count(count), stage(stage) - {} -}; - -struct DescriptorSetConfig { - const uint32_t count; - const std::vector bindings; - - DescriptorSetConfig(const YAML::Node &node); - DescriptorSetConfig(uint32_t count, const std::vector &&bindings): - count(count), bindings(bindings) - {} -}; - -struct PipelineConfig { - const std::string vertexShader; - const std::string fragmentShader; - const std::vector descSets; - const std::vector vertexInputAttributes; - const bool meshInShader; - const bool culling; - const bool depthTest; - const std::vector colorBlends; - - PipelineConfig(const YAML::Node &node); -}; - -std::unordered_map parsePipelineConfigs(const YAML::Node &node); - -} // namespace config diff --git a/src/config/renderpass.cpp b/src/config/renderpass.cpp deleted file mode 100644 index a737c62c..00000000 --- a/src/config/renderpass.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "renderpass.hpp" - -#include "utils.hpp" - -namespace config { - -SubpassDepthConfig::SubpassDepthConfig(const YAML::Node &node): id(s(node, "id")), readOnly(b(node, "read-only")) { - checkUnexpectedKeys(node, {"id", "read-only"}); -} - -SubpassConfig::SubpassConfig(const YAML::Node &node): - id(s(node, "id")), - inputs(sus(node, "inputs", std::make_optional>({}))), - outputs(sus(node, "outputs")), - depth(node["depth"] ? std::make_optional(node["depth"]) : std::nullopt), - depends(sus(node, "depends", std::make_optional>({}))), - pipelines(sus(node, "pipelines")) -{ - checkUnexpectedKeys(node, {"id", "inputs", "outputs", "depth", "depends", "pipelines"}); -} - -std::vector collectAttachments(const std::vector &subpasses) { - std::unordered_set attachments; - for (const auto &n: subpasses) { - for (const auto &m: n.inputs) { - attachments.emplace(m); - } - for (const auto &m: n.outputs) { - attachments.emplace(m); - } - if (n.depth) { - attachments.emplace(n.depth.value().id); - } - } - std::vector result; - result.reserve(attachments.size()); - result.assign(std::make_move_iterator(attachments.begin()), std::make_move_iterator(attachments.end())); - return result; -} - -RenderPassConfig::RenderPassConfig(const YAML::Node &node): - subpasses(parseConfigs(node, "subpasses")), - attachments(collectAttachments(subpasses)), - attachmentMap(collectMap(attachments)), - subpassMap(collectMap(subpasses)) -{ - checkUnexpectedKeys(node, {"id", "subpasses"}); - - // TODO: 順番もバリデーションしたい。 - for (const auto &n: subpasses) { - for (const auto &m: n.depends) { - if (!subpassMap.contains(m)) { - throw std::format("config error: subpass '{}' not defined.", m); - } - } - } -} - -std::unordered_map parseRenderPassConfigs(const YAML::Node &node) { - std::unordered_map renderPasses; - for (const auto &n: node["render-passes"]) { - const auto id = s(n, "id"); - if (renderPasses.contains(id)) { - throw std::format("config error: render pass '{}' duplicated.", id); - } - renderPasses.emplace(id, RenderPassConfig(n)); - } - return renderPasses; -} - -} // namespace config diff --git a/src/config/renderpass.hpp b/src/config/renderpass.hpp deleted file mode 100644 index d8f25698..00000000 --- a/src/config/renderpass.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace config { - -struct SubpassDepthConfig { - const std::string id; - const bool readOnly; - - SubpassDepthConfig(const YAML::Node &node); -}; - -struct SubpassConfig { - const std::string id; - const std::unordered_set inputs; - const std::unordered_set outputs; - const std::optional depth; - const std::unordered_set depends; - const std::unordered_set pipelines; - - SubpassConfig(const YAML::Node &node); -}; - -struct RenderPassConfig { - const std::vector subpasses; - - const std::vector attachments; - const std::unordered_map attachmentMap; - const std::unordered_map subpassMap; - - RenderPassConfig(const YAML::Node &node); -}; - -std::unordered_map parseRenderPassConfigs(const YAML::Node &node); - -} // namespace config diff --git a/src/config/utils.hpp b/src/config/utils.hpp deleted file mode 100644 index c78f06bd..00000000 --- a/src/config/utils.hpp +++ /dev/null @@ -1,136 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace config { - -inline void checkUnexpectedKeys(const YAML::Node &n, const std::set &ks) { - for (const auto &p: n) { - const auto k = p.first.as(); - if (!ks.contains(k)) { - throw std::format("config error: unexpected key '{}' found.", k); - } - } -} - -template -void validateValue(const T &v, const std::set &cs, const std::string &s) { - if (!cs.contains(v)) { - throw std::format("config error: {} '{}' is invalid.", s, v); - } -} - -template -T get(const YAML::Node &n, const std::string &k, const std::string &t, std::optional d = std::nullopt) { - if (!n[k]) { - if (d) { - return d.value(); - } else { - throw std::format("config error: '{}' not found.", k); - } - } - try { - return n[k].as(); - } catch (...) { - throw std::format("config error: '{}' is not a {}.", k, t); - } -} - -inline bool b(const YAML::Node &n, const std::string &k, std::optional d = std::nullopt) { - return get(n, k, "bool", d); -} - -inline float f(const YAML::Node &n, const std::string &k) { - return get(n, k, "float"); -} - -inline uint32_t u(const YAML::Node &n, const std::string &k, std::optional d = std::nullopt) { - return get(n, k, "unsigned int", d); -} - -inline std::string s(const YAML::Node &n, const std::string &k, std::optional d = std::nullopt) { - return get(n, k, "string", d); -} - -inline std::vector bs(const YAML::Node &n, const std::string &k) { - return get>(n, k, "bool[]"); -} - -inline std::vector us( - const YAML::Node &n, - const std::string &k, - std::optional> d = std::nullopt -) { - return get>(n, k, "unsigned int[]", d); -} - -inline std::vector ss( - const YAML::Node &n, - const std::string &k, - std::optional> d = std::nullopt -) { - return get>(n, k, "string[]", d); -} - -inline std::unordered_set sus( - const YAML::Node &n, - const std::string &k, - std::optional> d = std::nullopt -) { - if (!n[k]) { - if (d) { - return d.value(); - } else { - throw std::format("config error: '{}' not found.", k); - } - } - std::unordered_set results; - for (const auto &m: n[k]) { - try { - results.emplace(m.as()); - } catch (...) { - throw std::format("config error: '{}' is not a string.", k); - } - } - return results; -} - -template -std::vector parseConfigs(const YAML::Node &node, const std::string &k) { - std::vector results; - for (const auto &n: node[k]) { - results.emplace_back(n); - } - return results; -} - -template -std::unordered_map collectMap(const std::vector &v) { - std::unordered_map map; - for (const auto &n: v) { - // TODO: サブジェクトを追加したい。 - if (map.contains(n.id)) { - throw std::format("config error: '{}' duplicated.", n.id); - } - map.emplace(n.id, static_cast(map.size())); - } - return map; -} - -template<> -inline std::unordered_map collectMap(const std::vector &v) { - std::unordered_map map; - for (const auto &n: v) { - // TODO: サブジェクトを追加したい。 - if (map.contains(n)) { - throw std::format("config error: '{}' duplicated.", n); - } - map.emplace(n, static_cast(map.size())); - } - return map; -} - -} // namespace config diff --git a/src/error/vulkan.hpp b/src/error/vulkan.hpp new file mode 100644 index 00000000..512103aa --- /dev/null +++ b/src/error/vulkan.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include "../graphics/graphics.hpp" +#include "error.hpp" + +#include +#include +#include + +#define ABORT_WITH_ERROR_DIALOG(msg) \ + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "fatal error", (msg), nullptr); \ + abort(); \ + break; + +namespace error { + +inline OrgeApiResult handleVkResult(const vk::Result &e) { + switch (e) { + case vk::Result::eErrorInitializationFailed: + ABORT_WITH_ERROR_DIALOG("Failed to initialize Vulkan. Is Vulkan availabe and latest?"); + case vk::Result::eErrorLayerNotPresent: + ABORT_WITH_ERROR_DIALOG("Some Vulkan layers required are unavailable. Is Vulkan availabe and latest?"); + case vk::Result::eErrorExtensionNotPresent: + ABORT_WITH_ERROR_DIALOG("Some Vulkan extensions required are unavailable. Is Vulkan availabe and latest?"); + case vk::Result::eErrorDeviceLost: + ABORT_WITH_ERROR_DIALOG("Graphics device has been lost."); + case vk::Result::eErrorOutOfHostMemory: + ABORT_WITH_ERROR_DIALOG("Host memory limit has been reached."); + case vk::Result::eErrorOutOfDeviceMemory: + ABORT_WITH_ERROR_DIALOG("Graphics device memory limit has been reached."); + case vk::Result::eErrorInvalidVideoStdParametersKHR: + ABORT_WITH_ERROR_DIALOG("Video Std parameter is invalid."); + case vk::Result::eSuboptimalKHR: + case vk::Result::eErrorOutOfDateKHR: + graphics::recreateSwapchain(); + return ORGE_SWAPCHAIN_RECREATED; + case vk::Result::eErrorSurfaceLostKHR: + graphics::recreateSurface(); + return ORGE_SURFACE_RECREATED; + default: + error::setMessage("vulkan error: " + vk::to_string(e) + " (" + std::to_string(static_cast(e)) + ")"); + break; + } + return ORGE_ERROR; +} + +} // namespace error diff --git a/src/graphics/graphics.cpp b/src/graphics/graphics.cpp index 265ebf26..2c1e0857 100644 --- a/src/graphics/graphics.cpp +++ b/src/graphics/graphics.cpp @@ -45,4 +45,32 @@ void terminate() noexcept { core::destroyCore(); } +void recreateSwapchain() { + graphics::core::device().waitIdle(); + graphics::renderer::renderer().recreateSemaphoreForImageEnabled(); + graphics::renderpass::destroyAllFramebuffersAndPipelines(); + graphics::compute::destroyAllComputePipelines(); + graphics::resource::destroyAllAttachmentImages(); + graphics::resource::destroyDescriptorPool(); + graphics::window::swapchain().recreateSwapchain(); + graphics::resource::initializeDescriptorPool(); + graphics::resource::initializeAllAttachmentImages(); + graphics::compute::initializeComputePipelines(); + graphics::renderpass::createAllFramebuffersAndPipelines(); +} + +void recreateSurface() { + graphics::core::device().waitIdle(); + graphics::renderer::renderer().recreateSemaphoreForImageEnabled(); + graphics::renderpass::destroyAllFramebuffersAndPipelines(); + graphics::compute::destroyAllComputePipelines(); + graphics::resource::destroyAllAttachmentImages(); + graphics::resource::destroyDescriptorPool(); + graphics::window::swapchain().recreateSurface(); + graphics::resource::initializeDescriptorPool(); + graphics::resource::initializeAllAttachmentImages(); + graphics::compute::initializeComputePipelines(); + graphics::renderpass::createAllFramebuffersAndPipelines(); +} + } // namespace graphics diff --git a/src/graphics/graphics.hpp b/src/graphics/graphics.hpp index f7019a72..81d30578 100644 --- a/src/graphics/graphics.hpp +++ b/src/graphics/graphics.hpp @@ -6,4 +6,8 @@ void initialize(); void terminate() noexcept; +void recreateSwapchain(); + +void recreateSurface(); + } // namespace graphics diff --git a/src/graphics/resource/mesh.cpp b/src/graphics/resource/mesh.cpp index 6a875d76..da2a270b 100644 --- a/src/graphics/resource/mesh.cpp +++ b/src/graphics/resource/mesh.cpp @@ -10,29 +10,23 @@ namespace graphics::resource { -const std::span getVerticesData(const std::string &id) { - const auto vertices = error::at(config::config().meshes, id, "meshes").vertices; - const auto assetId = error::at(config::config().assetMap, vertices, "assets"); - return asset::getAsset(assetId); -} - -const std::span getIndicesData(const std::string &id) { - const auto indices = error::at(config::config().meshes, id, "meshes").indices; - const auto assetId = error::at(config::config().assetMap, indices, "assets"); +const std::span getData(const std::string &id, const std::string &ext) { + const auto fileName = std::format("{}.{}", id, ext); + const auto assetId = error::at(config::config().assetMap, fileName, "assets"); return asset::getAsset(assetId); } Mesh::Mesh(const std::string &id): _id(id), - _iCount(static_cast(getIndicesData(id).size() / sizeof(uint32_t))), + _iCount(static_cast(getData(id, "i").size() / sizeof(uint32_t))), _vb(core::device().createBufferUnique( vk::BufferCreateInfo() - .setSize(static_cast(getVerticesData(id).size())) + .setSize(static_cast(getData(id, "v").size())) .setUsage(vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eTransferDst) )), _ib(core::device().createBufferUnique( vk::BufferCreateInfo() - .setSize(static_cast(getIndicesData(id).size())) + .setSize(static_cast(getData(id, "i").size())) .setUsage(vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eTransferDst) )), _vbMemory(allocateMemory(_vb.get(), vk::MemoryPropertyFlagBits::eDeviceLocal)), @@ -40,14 +34,14 @@ Mesh::Mesh(const std::string &id): { uploadBuffer( _vb.get(), - static_cast(getVerticesData(id).data()), - getVerticesData(id).size(), + static_cast(getData(id, "v").data()), + getData(id, "v").size(), vk::PipelineStageFlagBits::eVertexShader ); uploadBuffer( _ib.get(), - static_cast(getIndicesData(id).data()), - getIndicesData(id).size(), + static_cast(getData(id, "i").data()), + getData(id, "i").size(), vk::PipelineStageFlagBits::eVertexShader ); } diff --git a/src/graphics/text/text.hpp b/src/graphics/text/text.hpp index ae3c34ed..3be12a83 100644 --- a/src/graphics/text/text.hpp +++ b/src/graphics/text/text.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/src/input/input.hpp b/src/input/input.hpp index ed090484..7722b831 100644 --- a/src/input/input.hpp +++ b/src/input/input.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include namespace input { diff --git a/src/orge-audio.cpp b/src/orge-audio.cpp deleted file mode 100644 index 2386de9c..00000000 --- a/src/orge-audio.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include - -#include "audio/audio.hpp" -#include "orge-private.hpp" - -float orgeGetAudioChannelVolume(uint32_t index) { - try { - return audio::audio().getVolume(index); - } catch (...) { - return -1.0f; - } -} - -uint8_t orgeSetAudioChannelVolume(uint32_t index, float volume) { - TRY(audio::audio().setVolume(index, volume)); -} - -uint8_t orgeLoadWave(const char *file, uint32_t startPosition) { - TRY(audio::audio().loadWaveFromFile(file, startPosition)); -} - -void orgeDestroyWave(const char *file) { - audio::audio().destroyWave(file); -} - -uint8_t orgePlayWave(const char *file, uint32_t index, uint8_t loop) { - TRY(audio::audio().play(file, index, static_cast(loop))); -} diff --git a/src/orge-compute.cpp b/src/orge-compute.cpp deleted file mode 100644 index ff13cfd9..00000000 --- a/src/orge-compute.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include - -#include "graphics/compute/pipeline.hpp" -#include "graphics/renderer/renderer.hpp" -#include "orge-private.hpp" - -#define DEFINE_UPDATE_DESC_FUNC(n) \ - uint8_t orgeUpdateCompute##n##Descriptor( \ - const char *pipelineId, \ - const char *id, \ - uint32_t set, \ - uint32_t index, \ - uint32_t binding, \ - uint32_t offset \ - ) { \ - TRY( \ - graphics::compute::getComputePipeline(pipelineId) \ - .update##n##Descriptor(id, set, index, binding, offset) \ - ); \ - } - -DEFINE_UPDATE_DESC_FUNC(Buffer) -DEFINE_UPDATE_DESC_FUNC(Image) -DEFINE_UPDATE_DESC_FUNC(StorageImage) -DEFINE_UPDATE_DESC_FUNC(Sampler) - -#define TRY_OR(n) \ - bool result = false; \ - CHECK(n); \ - if (!result) graphics::renderer::renderer().reset(); \ - return static_cast(result); - -uint8_t orgeBindComputePipeline(const char *pipelineId, uint32_t const *indices) { - TRY_OR(graphics::renderer::renderer().getContext().bindComputePipeline(pipelineId, indices)); -} - -uint8_t orgeDispatch(uint32_t x, uint32_t y, uint32_t z) { - TRY_OR(graphics::renderer::renderer().getContext().dispatch(x, y, z)); -} diff --git a/src/orge-graphics.cpp b/src/orge-graphics.cpp deleted file mode 100644 index 6a769dd1..00000000 --- a/src/orge-graphics.cpp +++ /dev/null @@ -1,193 +0,0 @@ -#include - -#include "graphics/renderer/renderer.hpp" -#include "graphics/renderpass/renderpass.hpp" -#include "graphics/resource/buffer.hpp" -#include "graphics/resource/image-storage.hpp" -#include "graphics/resource/image-user.hpp" -#include "graphics/resource/mesh.hpp" -#include "graphics/resource/sampler.hpp" -#include "graphics/text/text.hpp" -#include "graphics/window/swapchain.hpp" -#include "orge-private.hpp" - -#define DECLARE_UPDATE_DESC_FUNC(n) \ - uint8_t orgeUpdate##n##Descriptor( \ - const char *renderPassId, \ - const char *pipelineId, \ - const char *id, \ - uint32_t set, \ - uint32_t index, \ - uint32_t binding, \ - uint32_t offset \ - ) -#define DEFINE_UPDATE_DESC_FUNC(n, m) \ - DECLARE_UPDATE_DESC_FUNC(n) { \ - TRY( \ - graphics::renderpass::getRenderPass(renderPassId) \ - .getPipeline(pipelineId) \ - .update##m##Descriptor(id, set, index, binding, offset) \ - ); \ - } -#define TRY_OR(n) \ - bool result = false; \ - CHECK(n); \ - if (!result) graphics::renderer::renderer().reset(); \ - return static_cast(result); - -// ================================================================================================================== // -// Window // -// ================================================================================================================== // - -uint8_t orgeIsFullscreen(void) { - return static_cast(graphics::window::swapchain().isFullscreen()); -} - -void orgeSetFullscreen(uint8_t toFullscreen) { - // NOTE: 発生する例外はすべて致命的であり、TRY_DISCARDで強制終了されるので、返戻型はvoid。 - TRY_DISCARD(graphics::window::swapchain().setFullscreen(static_cast(toFullscreen))); -} - -// ================================================================================================================== // -// Graphics Resources // -// ================================================================================================================== // - -uint8_t orgeCreateBuffer(const char *id, uint64_t size, uint8_t isStorage, uint8_t isHostCoherent) { - TRY(graphics::resource::addBuffer(id, size, static_cast(isStorage), static_cast(isHostCoherent))); -} - -void orgeDestroyBuffer(const char *id) { - graphics::resource::destroyBuffer(id); -} - -uint8_t orgeUpdateBuffer(const char *id, const uint8_t *data) { - TRY(graphics::resource::getBuffer(id).update(data)); -} - -API_EXPORT uint8_t orgeCopyBufferTo(const char *id, uint8_t *data) { - TRY(graphics::resource::getBuffer(id).copyTo(data)); -} - -DEFINE_UPDATE_DESC_FUNC(Buffer, Buffer) - -uint8_t orgeLoadImage(const char *file) { - TRY(graphics::resource::addUserImageFromFile(file)); -} - -void orgeDestroyImage(const char *file) { - graphics::resource::destroyUserImage(file); -} - -API_EXPORT uint8_t orgeCreateStorageImage(const char *id, uint32_t width, uint32_t height, uint32_t format) { - TRY(graphics::resource::addStorageImage(id, width, height, format)); -} - -API_EXPORT void orgeDestroyStorageImage(const char *id) { - graphics::resource::destroyStorageImage(id); -} - -DEFINE_UPDATE_DESC_FUNC(Image, UserImage) - -uint8_t orgeCreateSampler(const char *id, uint8_t linearMagFilter, uint8_t linearMinFilter, uint8_t repeat) { - TRY(graphics::resource::addSampler( - id, - static_cast(linearMagFilter), - static_cast(linearMinFilter), - static_cast(repeat) - )); -} - -void orgeDestroySampler(const char *id) { - graphics::resource::destroySampler(id); -} - -DEFINE_UPDATE_DESC_FUNC(Sampler, Sampler) - -DECLARE_UPDATE_DESC_FUNC(InputAttachment) { - TRY( - const auto &context = graphics::renderer::renderer().getContext(); - graphics::renderpass::getRenderPass(renderPassId) - .getPipeline(pipelineId) - .updateInputAttachmentDescriptor(id, set, index, binding, offset, context.currentIndex()); - ); -} - -uint8_t orgeLoadMesh(const char *id) { - TRY(graphics::resource::addMesh(id)); -} - -// ================================================================================================================== // -// Text Rendering // -// ================================================================================================================== // - -uint8_t orgeRasterizeCharacters(const char *id, const char *s) { - TRY(graphics::text::rasterizeText(id, s)); -} - -API_EXPORT uint8_t orgeLayoutText( - const char *renderPassId, - const char *subpassId, - const char *fontId, - const char *text, - float x, - float y, - float height, - uint32_t horizontal, - uint32_t vertical -) { - TRY(graphics::text::layoutText( - renderPassId, - subpassId, - fontId, - text, - x, - y, - height, - static_cast(horizontal), - static_cast(vertical) - )); -} - -uint8_t orgeDrawTexts() { - TRY(graphics::renderer::renderer().getContext().drawTexts()); -} - -// ================================================================================================================== // -// Rendering // -// ================================================================================================================== // - -uint8_t orgeBeginRender(void) { - TRY_OR(graphics::renderer::renderer().begin()); -} - -uint8_t orgeEndRender(void) { - TRY_OR(graphics::renderer::renderer().end()); -} - -uint8_t orgeBindMesh(const char *meshId) { - TRY_OR(graphics::renderer::renderer().getContext().bindMesh(meshId)); -} - -uint8_t orgeBeginRenderPass(const char *renderPassId) { - TRY_OR(graphics::renderer::renderer().getContext().beginRenderPass(renderPassId)); -} - -uint8_t orgeEndRenderPass(void) { - TRY_OR(graphics::renderer::renderer().getContext().endRenderPass()); -} - -uint8_t orgeNextSubpass(void) { - TRY_OR(graphics::renderer::renderer().getContext().nextSubpass()); -} - -uint8_t orgeBindPipeline(const char *pipelineId, uint32_t const *indices) { - TRY_OR(graphics::renderer::renderer().getContext().bindPipeline(pipelineId, indices)); -} - -uint8_t orgeDraw(uint32_t instanceCount, uint32_t instanceOffset) { - TRY_OR(graphics::renderer::renderer().getContext().draw(instanceCount, instanceOffset)); -} - -uint8_t orgeDrawDirectly(uint32_t vertexCount, uint32_t instanceCount, uint32_t instanceOffset) { - TRY_OR(graphics::renderer::renderer().getContext().drawDirectly(vertexCount, instanceCount, instanceOffset)); -} diff --git a/src/orge-input.cpp b/src/orge-input.cpp deleted file mode 100644 index 1724cd70..00000000 --- a/src/orge-input.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include - -#include "input/input.hpp" - -int32_t orgeGetKeyState(uint32_t scancode) { - return input::input().getState(static_cast(scancode)); -} - -uint32_t orgeGetCursorX(void) { - return input::input().getCursorX(); -} - -uint32_t orgeGetCursorY(void) { - return input::input().getCursorY(); -} - -int32_t orgeGetMouseButtonState(uint32_t button) { - return input::input().getMouseButtonState(static_cast(button)); -} diff --git a/src/orge-private.cpp b/src/orge-private.cpp deleted file mode 100644 index 8a2c6f3b..00000000 --- a/src/orge-private.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "orge-private.hpp" - -#include "graphics/core/core.hpp" -#include "graphics/compute/pipeline.hpp" -#include "graphics/renderpass/renderpass.hpp" -#include "graphics/renderer/renderer.hpp" -#include "graphics/resource/descpool.hpp" -#include "graphics/resource/image-attachment.hpp" -#include "graphics/window/swapchain.hpp" - -#include - -#define ABORT_WITH_ERROR_DIALOG(msg) \ - SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "fatal error", (msg), nullptr); \ - abort() -#define RECREATE_SWAPCHAIN_OR_SURFACE(which) \ - graphics::core::device().waitIdle(); \ - graphics::renderer::renderer().recreateSemaphoreForImageEnabled(); \ - graphics::renderpass::destroyAllFramebuffersAndPipelines(); \ - graphics::compute::destroyAllComputePipelines(); \ - graphics::resource::destroyAllAttachmentImages(); \ - graphics::resource::destroyDescriptorPool(); \ - graphics::window::swapchain().recreate##which(); \ - graphics::resource::initializeDescriptorPool(); \ - graphics::resource::initializeAllAttachmentImages(); \ - graphics::compute::initializeComputePipelines(); \ - graphics::renderpass::createAllFramebuffersAndPipelines() - -namespace orge { - -void handleVkResult(const vk::Result &e) { - switch (e) { - case vk::Result::eErrorInitializationFailed: - ABORT_WITH_ERROR_DIALOG("Failed to initialize Vulkan. Is Vulkan availabe and latest?"); - case vk::Result::eErrorLayerNotPresent: - ABORT_WITH_ERROR_DIALOG("Some Vulkan layers required are unavailable. Is Vulkan availabe and latest?"); - case vk::Result::eErrorExtensionNotPresent: - ABORT_WITH_ERROR_DIALOG("Some Vulkan extensions required are unavailable. Is Vulkan availabe and latest?"); - case vk::Result::eErrorDeviceLost: - ABORT_WITH_ERROR_DIALOG("Graphics device has been lost."); - case vk::Result::eErrorOutOfHostMemory: - ABORT_WITH_ERROR_DIALOG("Host memory limit has been reached."); - case vk::Result::eErrorOutOfDeviceMemory: - ABORT_WITH_ERROR_DIALOG("Graphics device memory limit has been reached."); - case vk::Result::eErrorInvalidVideoStdParametersKHR: - ABORT_WITH_ERROR_DIALOG("Video Std parameter is invalid."); - case vk::Result::eSuboptimalKHR: - case vk::Result::eErrorOutOfDateKHR: - error::setMessage("swapchain is out of date, performing recreation."); - RECREATE_SWAPCHAIN_OR_SURFACE(Swapchain); - break; - case vk::Result::eErrorSurfaceLostKHR: - error::setMessage("surface is out of date, performing recreation."); - RECREATE_SWAPCHAIN_OR_SURFACE(Surface); - break; - default: - error::setMessage("vulkan error: " + vk::to_string(e) + " (" + std::to_string(static_cast(e)) + ")"); - break; - } -} - -} // namespace orge diff --git a/src/orge-private.hpp b/src/orge-private.hpp deleted file mode 100644 index ff42caa2..00000000 --- a/src/orge-private.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include "error/error.hpp" - -#include - -#define CHECK(n) \ - try { \ - n; \ - result = true; \ - } catch (const char *e) { \ - error::setMessage(std::string(e)); \ - } catch (const std::string &e) { \ - error::setMessage(e); \ - } catch (const vk::Result &e) { \ - orge::handleVkResult(e); \ - } catch (const vk::SystemError &e) { \ - orge::handleVkResult(static_cast(e.code().value())); \ - } catch (const std::exception &e) { \ - error::setMessage(e.what()); \ - } catch (...) { \ - error::setMessage("unbound error."); \ - } -#define TRY(n) bool result = false; CHECK(n); return static_cast(result); -#define TRY_DISCARD(n) bool result = false; CHECK(n); (void)result; - -namespace orge { - -void handleVkResult(const vk::Result &e); - -} // namespace orge diff --git a/src/orge.cpp b/src/orge.cpp index dcb3e057..2b2e77c5 100644 --- a/src/orge.cpp +++ b/src/orge.cpp @@ -1,94 +1,21 @@ -#include - -#include "asset/asset.hpp" -#include "audio/audio.hpp" -#include "config/config.hpp" -#include "error/error.hpp" -#include "graphics/core/core.hpp" -#include "graphics/graphics.hpp" -#include "graphics/window/swapchain.hpp" -#include "input/input.hpp" -#include "orge-private.hpp" - -#include -#include -#include - -#ifdef __APPLE__ -# define MODKEY SDL_KMOD_GUI -#else -# define MODKEY SDL_KMOD_ALT -#endif - -// ================================================================================================================== // -// Information // -// ================================================================================================================== // - -void orgeShowDialog(uint32_t dtype, const char *title, const char *message) { - SDL_MessageBoxFlags flags = SDL_MESSAGEBOX_ERROR; - switch (static_cast(dtype)) { - case ORGE_DIALOG_TYPE_WARNING: - flags = SDL_MESSAGEBOX_WARNING; - break; - case ORGE_DIALOG_TYPE_INFORMATION: - flags = SDL_MESSAGEBOX_INFORMATION; - break; - default: - break; - } - SDL_ShowSimpleMessageBox(flags, title, message, nullptr); -} - -const char *orgeGetErrorMessage(void) { - return error::getMessage().c_str(); -} - -// ================================================================================================================== // -// Lifetime Managiment // -// ================================================================================================================== // - -uint8_t orgeInitialize(void) { - TRY( - if (!SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO)) { - throw std::format("failed to prepare for creating a window: {}", SDL_GetError()); - } - if (!SDL_Vulkan_LoadLibrary(nullptr)) { - throw std::format("failed to load Vulkan: {}", SDL_GetError()); - } - asset::initialize(); - config::initialize(); - graphics::initialize(); - audio::initialize(); - input::initialize(); - ) -} - -void orgeTerminate(void) { - graphics::terminate(); - audio::destroy(); - input::destroy(); -} - -uint8_t orgeUpdate(void) { - SDL_Event event; - while (SDL_PollEvent(&event)) { - if (event.type == SDL_EVENT_QUIT) { - return 0; - } - if ( - config::config().altReturnToggleFullscreen - && event.type == SDL_EVENT_KEY_DOWN - && event.key.key == SDLK_RETURN - && (event.key.mod & MODKEY) - ) { - // TODO: 例外どうしよう。 - const auto &swapchain = graphics::window::swapchain(); - graphics::core::device().waitIdle(); - swapchain.setFullscreen(!swapchain.isFullscreen()); - } +#include "api/dispatch.hpp" +#include "error/vulkan.hpp" + +OrgeApiResult orgeApiCall(OrgeApiCallType type, void *param) { + try { + return api::dispatchApi(type, param); + } catch (const char *e) { + error::setMessage(std::string(e)); + } catch (const std::string &e) { + error::setMessage(e); + } catch (const vk::Result &e) { + return error::handleVkResult(e); + } catch (const vk::SystemError &e) { + return error::handleVkResult(static_cast(e.code().value())); + } catch (const std::exception &e) { + error::setMessage(e.what()); + } catch (...) { + error::setMessage("unbound error."); } - // TODO: 例外どうしよう。 - audio::audio().update(); - input::input().update(); - return 1; + return ORGE_ERROR; }