dotzuki-cli 0.7.1

dotzuki CLI: scaffold (dotzuki new), compile-check (dotzuki check) and play (dotzuki run) zero-Rust JRPG projects
#ifndef DOTZUKI_HARMONY_HOST_H
#define DOTZUKI_HARMONY_HOST_H

#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl3.h>
#include <ace/xcomponent/native_interface_xcomponent.h>
#include <atomic>
#include <cstdint>
#include <js_native_api.h>
#include <mutex>
#include <ohaudio/native_audiorenderer.h>
#include <ohaudio/native_audiostreambuilder.h>
#include <vector>

#include "dotzuki_runner_mobile.h"

class DotzukiHost {
public:
    static DotzukiHost &Instance();
    bool RegisterXComponent(napi_env env, napi_value exports);
    void ExportFunctions(napi_env env, napi_value exports);

private:
    DotzukiHost() = default;
    ~DotzukiHost();
    DotzukiHost(const DotzukiHost &) = delete;
    DotzukiHost &operator=(const DotzukiHost &) = delete;

    static napi_value Start(napi_env env, napi_callback_info info);
    static napi_value SetInput(napi_env env, napi_callback_info info);
    static napi_value Pause(napi_env env, napi_callback_info info);
    static napi_value Resume(napi_env env, napi_callback_info info);
    static napi_value ExportSave(napi_env env, napi_callback_info info);

    static void SurfaceCreated(OH_NativeXComponent *component, void *window);
    static void SurfaceChanged(OH_NativeXComponent *component, void *window);
    static void SurfaceDestroyed(OH_NativeXComponent *component, void *window);
    static void TouchEvent(OH_NativeXComponent *component, void *window);
    static void Frame(
        OH_NativeXComponent *component, uint64_t timestamp, uint64_t targetTimestamp);

    static OH_AudioData_Callback_Result AudioWrite(
        OH_AudioRenderer *renderer, void *userData, void *data, int32_t size);
    static int32_t AudioInterrupt(OH_AudioRenderer *renderer, void *userData,
        OH_AudioInterrupt_ForceType type, OH_AudioInterrupt_Hint hint);
    static int32_t AudioError(
        OH_AudioRenderer *renderer, void *userData, OH_AudioStream_Result error);
    static int32_t AudioEvent(
        OH_AudioRenderer *renderer, void *userData, OH_AudioStream_Event event);

    bool InitializeEgl(void *window, uint64_t width, uint64_t height);
    bool InitializeProgram();
    bool InitializeAudio();
    void RenderFrame(uint64_t timestamp);
    void Resize(uint64_t width, uint64_t height);
    void ShutdownAudio();
    void ShutdownEgl();
    void ReplaceRunner(const uint8_t *pack, size_t packLen, const char *save, size_t saveLen);

    DotzukiMobileRunner *runner_ = nullptr;
    OH_NativeXComponent *component_ = nullptr;
    std::atomic<uint8_t> input_ { 0 };
    std::atomic<bool> paused_ { false };
    std::mutex gameMutex_;
    uint64_t lastTimestamp_ = 0;
    double accumulator_ = 0;
    uint64_t surfaceWidth_ = 0;
    uint64_t surfaceHeight_ = 0;

    EGLDisplay display_ = EGL_NO_DISPLAY;
    EGLSurface surface_ = EGL_NO_SURFACE;
    EGLContext context_ = EGL_NO_CONTEXT;
    GLuint program_ = 0;
    GLuint texture_ = 0;
    std::vector<uint8_t> frame_;

    OH_AudioStreamBuilder *audioBuilder_ = nullptr;
    OH_AudioRenderer *audioRenderer_ = nullptr;
};

#endif