SUU-Lab

プログラムに関するメモとかが多いです。

テストアプリケーション用テンプレートを作った

テスト用アプリケーションを作成しやすいように、テンプレート的なものを作りました。

アプリケーションクラスの作成

ウィンドウ作成などのWin32APIの面倒な処理をこのクラスが担当します。
一応、他プラットフォームでも対応できるようにインターフェイスクラスとして宣言しています。

KEY_CODE は列挙型で、別のヘッダーファイルで宣言されています。

AppMain関数がメインエントリポイントになります。

App.hpp

#pragma once

struct Position2D
{
    s32 x;
    s32 y;
};

struct Size2D
{
    u32 width;
    u32 height;
};

// コールバック登録用
struct AppCallbacks
{
    // リサイズ
    void(*pOnResize)(const Size2D& newSize, void* pUser);
    void* pOnResizeUser;

    // キーダウン
    void(*pOnKeyDown)(KEY_CODE key, void* pUser);
    void* pOnKeyDownUser;

    // キーアップ
    void(*pOnKeyUp)(KEY_CODE key, void* pUser);
    void* pOnKeyUpUser;

    // マウスキーダウン
    void(*pOnMouseKeyDown)(const Position2D& position, MOUSE_BUTTON button, void* pUser);
    void* pOnMouseKeyDownUser;

    // マウスキーアップ
    void(*pOnMouseKeyUp)(const Position2D& position, MOUSE_BUTTON button, void* pUser);
    void* pOnMouseKeyUpUser;

    // マウスホイール
    void(*pOnMouseWheel)(const Position2D& position, s32 delta, void* pUser);
    void* pOnMouseWheelUser;
};

// アプリケーションインターフェイス
class IApp
{
public:
    virtual ~IApp() = default;

    // コールバックを登録
    virtual void SetAppCallbacks(const AppCallbacks& callbacks) = 0;

    // true の間、メインループを実行
    virtual bool IsLoop() const = 0;

    // アプリケーションを終了
    virtual void PostQuit() = 0;

    // クライアント領域のサイズを取得
    virtual Size2D GetClientSize() const = 0;

    // ウィンドウハンドルを取得
    virtual void* GetWindowHandle() const = 0;

    // メッセージボックスを表示
    virtual void ShowMessageBox(const std::string& message, const std::string& caption) = 0;
};

// IApp ファクトリーメソッド
bool CreateApp(const Size2D& clientSize, const std::string& title, IApp ** ppOut);

// メインエントリポイント
void AppMain();

実装例

AppMain.cppではAppMain関数の定義と各種コールバックの登録を行っています。
AppMain関数内でコールバックの登録後、IApp::IsLoop()がtrueの間メインループを実行します。

AppMain.cpp

#define UNUSED(x) (x)

// リサイズ
void OnResize(const Size2D& newSize, void* pUser)
{
    UNUSED(newSize);
    UNUSED(pUser);
}

// キーダウン
void OnKeyDown(KEY_CODE key, void* pUser)
{
    IApp* pApp = reinterpret_cast<IApp*>(pUser);
    if (pApp == nullptr)
    {
        return;
    }

    if (key == KEY_CODE_ESCAPE)
    { // Escapeキーで終了
        pApp->PostQuit();
    }
}

// キーアップ
void OnKeyUp(KEY_CODE key, void* pUser)
{
    UNUSED(key);
    UNUSED(pUser);
}

// マウスキーダウン
void OnMouseKeyDown(const Position2D& position, MOUSE_BUTTON button, void* pUser)
{
    UNUSED(position);
    UNUSED(button);
    UNUSED(pUser);
}

// マウスキーアップ
void OnMouseKeyUp(const Position2D& position, MOUSE_BUTTON button, void* pUser)
{
    UNUSED(position);
    UNUSED(button);
    UNUSED(pUser);
}

// マウスホイール
void OnMouseWheel(const Position2D& position, s32 delta, void* pUser)
{
    UNUSED(position);
    UNUSED(delta);
    UNUSED(pUser);
}

// シーン更新処理
void UpdateScene()
{

}

// シーン描画処理
void RenderScene()
{

}

// エントリポイント
void AppMain()
{
    IApp* pApp = nullptr;
    Size2D clientSize = { 640, 480 };

    if (!CreateApp(clientSize, "Sample", &pApp))
    {
        return;
    }

    // コールバックの設定
    AppCallbacks callbacks = { 0 };
    // リサイズ
    callbacks.pOnResize = OnResize;
    callbacks.pOnResizeUser = pApp;
    // キーダウン
    callbacks.pOnKeyDown = OnKeyDown;
    callbacks.pOnKeyDownUser = pApp;
    // キーアップ
    callbacks.pOnKeyUp = OnKeyUp;
    callbacks.pOnKeyUpUser = pApp;
    // マウスキーダウン
    callbacks.pOnMouseKeyDown = OnMouseKeyDown;
    callbacks.pOnMouseKeyDownUser = pApp;
    // マウスキーアップ
    callbacks.pOnMouseKeyUp = OnMouseKeyUp;
    callbacks.pOnMouseKeyUpUser = pApp;
    // マウスホイール
    callbacks.pOnMouseWheel = OnMouseWheel;
    callbacks.pOnMouseWheelUser = pApp;

    pApp->SetAppCallbacks(callbacks);

    // メインループ
    while (pApp->IsLoop())
    {
        UpdateScene();
        RenderScene();
    }
    delete pApp;
}

できるだけ使いやすく作ったつもりですが、もう少しシンプルにできたかもしれません。
コードはGitHubにて公開していますので、ご自由にお使いください。

github.com