#pragma once #include #include #include #include #include #include #include "RenderTicker.hpp" #ifdef __EMSCRIPTEN__ #include #include #include #endif namespace thermion { /** * @brief A render loop implementation that manages rendering on a separate thread. * * This class handles frame rendering requests, viewer creation, and maintains * a task queue for rendering operations. */ class RenderThread { public: /** * @brief Constructs a new RenderThread and starts the render thread. */ explicit RenderThread(); /** * @brief Destroys the RenderThread and stops the render thread. */ ~RenderThread(); /** * @brief Requests a frame to be rendered. * * @param callback Callback function to be called after rendering completes */ void requestFrame(); /** * @brief Sets the render ticker used. */ void setRenderTicker(RenderTicker *renderTicker) { mRenderTicker = renderTicker; } /** * @brief Adds a task to the render thread's task queue. * * @param pt The packaged task to be executed * @return std::future Future for the task result */ template auto add_task(std::packaged_task& pt) -> std::future; /** * @brief Main iteration of the render loop. */ void iter(); /** * On emscripten builds, this breaks the current loop and * immediately exits, yielding to the main browser loop. * On other builds, this does nothing. */ void restart(); /** * */ bool mStop = false; /** * */ bool mRestart = false; #ifdef __EMSCRIPTEN__ emscripten::ProxyingQueue queue; pthread_t outer; #endif bool mRendered = false; bool mRender = false; private: std::mutex _taskMutex; std::condition_variable _cv; std::deque> _tasks; std::chrono::high_resolution_clock::time_point _lastFrameTime; int _frameCount = 0; float _accumulatedTime = 0.0f; float _fps = 0.0f; #ifdef __EMSCRIPTEN__ pthread_t t; #else std::thread* t = nullptr; #endif RenderTicker* mRenderTicker = nullptr; }; // Template implementation template auto RenderThread::add_task(std::packaged_task& pt) -> std::future { std::unique_lock lock(_taskMutex); auto ret = pt.get_future(); _tasks.push_back([pt = std::make_shared>( std::move(pt))] { (*pt)(); }); #ifndef __EMSCRIPTEN__ _cv.notify_one(); #endif return ret; } } // namespace thermion