#include "kernel.h" #include "egl_context.h" #include "render_target.h" #include "logger.h" #include "assets_manager.h" #include "aidl/com/omixlab/mosis/IMosisListener.h" #include #include #include #include #include #include "RmlUi_Renderer_GL3.h" #include #include #include #include // Global state for Lua access static Rml::Context* g_context = nullptr; static Rml::ElementDocument* g_document = nullptr; using namespace aidl::com::omixlab::mosis; using namespace aidl::android::hardware; class AssetFilesInterface : public Rml::FileInterface { public: static AssetFilesInterface& Instance() { static AssetFilesInterface instance; return instance; } Rml::FileHandle Open(const Rml::String &path) override { AAssetManager* am = AssetsManager::Native(); AAsset* asset = AAssetManager_open(am, path.c_str(), AASSET_MODE_BUFFER); return reinterpret_cast(asset); } void Close(Rml::FileHandle file) override { AAsset* asset = reinterpret_cast(file); AAsset_close(asset); } size_t Read(void *buffer, size_t size, Rml::FileHandle file) override { AAsset* asset = reinterpret_cast(file); return AAsset_read(asset, buffer, size); } bool Seek(Rml::FileHandle file, long offset, int origin) override { AAsset* asset = reinterpret_cast(file); off_t new_cursor = AAsset_seek(asset, offset, origin); return new_cursor != -1; } size_t Tell(Rml::FileHandle file) override { AAsset* asset = reinterpret_cast(file); return AAsset_seek(asset, 0, SEEK_CUR); } size_t Length(Rml::FileHandle file) override { AAsset* asset = reinterpret_cast(file); return AAsset_getLength(asset); } bool LoadFile(const Rml::String &path, Rml::String &out_data) override { AAssetManager* am = AssetsManager::Native(); AAsset* asset = AAssetManager_open(am, path.c_str(), AASSET_MODE_BUFFER); if (!asset) return false; out_data.resize(AAsset_getLength(asset)); auto data_ptr = static_cast(AAsset_getBuffer(asset)); std::span data = std::span(data_ptr, out_data.size()); std::ranges::copy(data, out_data.begin()); return true; } }; class SystemInterface : public Rml::SystemInterface { public: static SystemInterface& Instance() { static SystemInterface instance; return instance; } bool LogMessage(Rml::Log::Type type, const Rml::String &message) override { Logger::Log(std::format("RMLUI: {}", message)); return true; } }; // Lua function to load a screen document static int LuaLoadScreen(lua_State* L) { if (!g_context) { lua_pushboolean(L, false); return 1; } const char* path = luaL_checkstring(L, 1); Logger::Log(std::format("Loading screen: {}", path)); // Check if asset exists AAssetManager* am = AssetsManager::Native(); AAsset* asset = AAssetManager_open(am, path, AASSET_MODE_BUFFER); if (!asset) { Logger::Log(std::format("Screen not found: {}", path)); lua_pushboolean(L, false); return 1; } AAsset_close(asset); // Unload current document if (g_document) { g_context->UnloadDocument(g_document); g_document = nullptr; } // Load new document g_document = g_context->LoadDocument(path); if (g_document) { g_document->Show(); Logger::Log(std::format("Loaded screen: {}", path)); lua_pushboolean(L, true); } else { Logger::Log(std::format("Failed to load screen: {}", path)); lua_pushboolean(L, false); } return 1; } // Register Lua functions for navigation static void RegisterLuaFunctions() { lua_State* L = Rml::Lua::Interpreter::GetLuaState(); lua_pushcfunction(L, LuaLoadScreen); lua_setglobal(L, "loadScreen"); Logger::Log("Registered Lua loadScreen function"); } void Kernel::main_loop() { m_egl_context = std::make_unique(); if (!m_egl_context->create()) { Logger::Log("failed to create EGL context"); return; } m_render_target = std::make_unique(); if (!m_render_target->create_exported(540, 960)) { Logger::Log("failed to create render target"); return; } m_render_target->bind(); for (const auto& [pid, l] : m_listeners) l->onServiceInitialized(true); m_aidl_buffer = std::make_unique(); m_aidl_buffer->reset(m_render_target->hardware_buffer()); for (const auto& [pid, l] : m_listeners) l->onBufferAvailable(*m_aidl_buffer); RenderInterface_GL3 rmlui_render_interface; if (!rmlui_render_interface) { Logger::Log("failed to create render interface"); return; } Rml::SetRenderInterface(&rmlui_render_interface); Rml::SetFileInterface(&AssetFilesInterface::Instance()); Rml::SetSystemInterface(&SystemInterface::Instance()); Rml::Initialise(); Rml::Lua::Initialise(); Logger::Log("RmlUi Lua bindings initialized"); // Register navigation functions with Lua RegisterLuaFunctions(); g_context = Rml::CreateContext("default", Rml::Vector2i(540, 960)); if (!g_context) { Logger::Log("RMLUI failed to create a context"); Rml::Shutdown(); return; } // Load fonts from assets/fonts/ Rml::LoadFontFace("fonts/LatoLatin-Bold.ttf"); Rml::LoadFontFace("fonts/LatoLatin-BoldItalic.ttf"); Rml::LoadFontFace("fonts/LatoLatin-Italic.ttf"); Rml::LoadFontFace("fonts/LatoLatin-Regular.ttf"); Rml::LoadFontFace("fonts/NotoEmoji-Regular.ttf", true); Rml::LoadFontFace("fonts/Roboto/Roboto-VariableFont_wdth,wght.ttf"); Rml::LoadFontFace("fonts/Roboto/Roboto-Italic-VariableFont_wdth,wght.ttf"); // Load home screen document g_document = g_context->LoadDocument("apps/home/home.rml"); if (!g_document) { Logger::Log("Failed to load home.rml document"); Rml::Shutdown(); return; } g_document->Show(); while (true) { if (!m_tasks.empty()) { std::lock_guard _lock(m_mutex); for (const auto &task: m_tasks) task(g_context); m_tasks.clear(); } m_render_target->bind(); glClearColor(0.f, 0.f, 0.f, 1.f); glClear(GL_COLOR_BUFFER_BIT); glViewport(0, 0, 540, 960); g_context->Update(); rmlui_render_interface.SetViewport(540, 960); rmlui_render_interface.BeginFrame(); g_context->Render(); rmlui_render_interface.EndFrame(m_render_target->framebuffer()); glFinish(); { std::lock_guard _lock(m_mutex); for (const auto& [pid, l] : m_listeners) l->onFrameAvailable(); } std::this_thread::sleep_for(std::chrono::milliseconds(16)); // ~60 FPS } Rml::Shutdown(); } Kernel::Kernel(const std::shared_ptr &listener) { m_listeners.emplace(AIBinder_getCallingPid(), listener); m_main_loop_thread = std::thread(&Kernel::main_loop, this); } void Kernel::add_listener(const std::shared_ptr &listener) { std::lock_guard _lock(m_mutex); m_listeners.emplace(AIBinder_getCallingPid(), listener); listener->onServiceInitialized(true); listener->onBufferAvailable(*m_aidl_buffer); } void Kernel::on_touch_down(float x, float y) { Logger::Log(std::format("on_touch_down {} - {}", x, y)); std::lock_guard _lock(m_mutex); m_tasks.emplace_back([x, y](Rml::Context* context){ context->ProcessMouseMove(static_cast(x * 540), static_cast(y * 960), 0); context->ProcessMouseButtonDown(0, 0); }); } void Kernel::on_touch_move(float x, float y) { Logger::Log(std::format("on_touch_move {} - {}", x, y)); std::lock_guard _lock(m_mutex); m_tasks.emplace_back([x, y](Rml::Context* context){ context->ProcessMouseMove(static_cast(x * 540), static_cast(y * 960), 0); }); } void Kernel::on_touch_up(float x, float y) { Logger::Log(std::format("on_touch_up {} - {}", x, y)); std::lock_guard _lock(m_mutex); m_tasks.emplace_back([x, y](Rml::Context* context){ context->ProcessMouseMove(static_cast(x * 540), static_cast(y * 960), 0); context->ProcessMouseButtonUp(0, 0); }); } Kernel::~Kernel() = default;