diff --git a/src/animation/animation_scene.cpp b/src/animation/animation_scene.cpp index d9472e708..8e68703d5 100644 --- a/src/animation/animation_scene.cpp +++ b/src/animation/animation_scene.cpp @@ -357,11 +357,11 @@ struct AnimationSceneImpl final : public AnimationScene animator.resource->destroyRuntime(*animator.ctx); animator.ctx = nullptr; } - animator.resource->getObserverCb().unbind(this); + animator.resource->getObserverCb().unbind<&AnimationSceneImpl::onControllerResourceChanged>(this); } animator.resource = res; if (animator.resource != nullptr) { - animator.resource->onLoaded(this); + animator.resource->onLoaded<&AnimationSceneImpl::onControllerResourceChanged>(this); } } diff --git a/src/audio/editor/plugins.cpp b/src/audio/editor/plugins.cpp index b81600505..a96bb02e5 100644 --- a/src/audio/editor/plugins.cpp +++ b/src/audio/editor/plugins.cpp @@ -116,8 +116,8 @@ struct ClipManagerUI final : public StudioApp::GUIPlugin m_filter[0] = 0; m_is_open = false; Action* action = LUMIX_NEW(app.getWorldEditor().getAllocator(), Action)("Clip manager", "Toggle clip manager", "clip_manager"); - action->func.bind(this); - action->is_selected.bind(this); + action->func.bind<&ClipManagerUI::onAction>(this); + action->is_selected.bind<&ClipManagerUI::isOpen>(this); app.addWindowAction(action); } diff --git a/src/editor/asset_browser.cpp b/src/editor/asset_browser.cpp index ba5981bfe..a202ca08e 100644 --- a/src/editor/asset_browser.cpp +++ b/src/editor/asset_browser.cpp @@ -53,10 +53,10 @@ AssetBrowser::AssetBrowser(StudioApp& app) m_back_action = LUMIX_NEW(allocator, Action)("Back", "Back in asset history", "back"); m_back_action->is_global = false; - m_back_action->func.bind(this); + m_back_action->func.bind<&AssetBrowser::goBack>(this); m_forward_action = LUMIX_NEW(allocator, Action)("Forward", "Forward in asset history", "forward"); m_forward_action->is_global = false; - m_forward_action->func.bind(this); + m_forward_action->func.bind<&AssetBrowser::goForward>(this); m_app.addAction(m_back_action); m_app.addAction(m_forward_action); } diff --git a/src/editor/asset_compiler.cpp b/src/editor/asset_compiler.cpp index 23593a374..bbe90cf8f 100644 --- a/src/editor/asset_compiler.cpp +++ b/src/editor/asset_compiler.cpp @@ -96,7 +96,7 @@ struct AssetCompilerImpl : AssetCompiler { FileSystem& fs = app.getWorldEditor().getEngine().getFileSystem(); m_watcher = FileSystemWatcher::create(fs.getBasePath(), app.getWorldEditor().getAllocator()); - m_watcher->getCallback().bind(this); + m_watcher->getCallback().bind<&AssetCompilerImpl::onFileChanged>(this); m_task.create("Asset compiler", true); const char* base_path = m_app.getWorldEditor().getEngine().getFileSystem().getBasePath(); StaticString path(base_path, ".lumix/assets"); diff --git a/src/editor/editor_icon.cpp b/src/editor/editor_icon.cpp index 4eb423949..6711252bd 100644 --- a/src/editor/editor_icon.cpp +++ b/src/editor/editor_icon.cpp @@ -64,25 +64,25 @@ struct EditorIconsImpl final : public EditorIcons { m_render_interface = nullptr; m_icons.reserve(200); - editor.universeDestroyed().bind(this); - editor.universeCreated().bind(this); + editor.universeDestroyed().bind<&EditorIconsImpl::clear>(this); + editor.universeCreated().bind<&EditorIconsImpl::onUniverseCreated>(this); if (m_editor.getUniverse()) onUniverseCreated(); } ~EditorIconsImpl() { - m_editor.universeDestroyed().unbind(this); - m_editor.universeCreated().unbind(this); + m_editor.universeDestroyed().unbind<&EditorIconsImpl::clear>(this); + m_editor.universeCreated().unbind<&EditorIconsImpl::onUniverseCreated>(this); setRenderInterface(nullptr); if(m_editor.getUniverse()) { auto& universe = *m_editor.getUniverse(); - universe.entityCreated().unbind(this); - universe.entityDestroyed().unbind(this); - universe.componentAdded().unbind(this); - universe.componentDestroyed().unbind(this); + universe.entityCreated().unbind<&EditorIconsImpl::onEntityCreated>(this); + universe.entityDestroyed().unbind<&EditorIconsImpl::destroyIcon>(this); + universe.componentAdded().unbind<&EditorIconsImpl::refreshIcon>(this); + universe.componentDestroyed().unbind<&EditorIconsImpl::refreshIcon>(this); } } @@ -90,10 +90,10 @@ struct EditorIconsImpl final : public EditorIcons void onUniverseCreated() { auto& universe = *m_editor.getUniverse(); - universe.entityCreated().bind(this); - universe.entityDestroyed().bind(this); - universe.componentAdded().bind(this); - universe.componentDestroyed().bind(this); + universe.entityCreated().bind<&EditorIconsImpl::onEntityCreated>(this); + universe.entityDestroyed().bind<&EditorIconsImpl::destroyIcon>(this); + universe.componentAdded().bind<&EditorIconsImpl::refreshIcon>(this); + universe.componentDestroyed().bind<&EditorIconsImpl::refreshIcon>(this); } diff --git a/src/editor/gizmo.cpp b/src/editor/gizmo.cpp index 6aceae022..91ddd78e8 100644 --- a/src/editor/gizmo.cpp +++ b/src/editor/gizmo.cpp @@ -77,13 +77,13 @@ struct GizmoImpl final : public Gizmo m_steps[int(Mode::TRANSLATE)] = 10; m_steps[int(Mode::ROTATE)] = 45; m_steps[int(Mode::SCALE)] = 1; - editor.universeDestroyed().bind(this); + editor.universeDestroyed().bind<&GizmoImpl::onUniverseDestroyed>(this); } ~GizmoImpl() { - m_editor.universeDestroyed().unbind(this); + m_editor.universeDestroyed().unbind<&GizmoImpl::onUniverseDestroyed>(this); } diff --git a/src/editor/log_ui.cpp b/src/editor/log_ui.cpp index cea40a07a..da2c584ab 100644 --- a/src/editor/log_ui.cpp +++ b/src/editor/log_ui.cpp @@ -20,7 +20,7 @@ LogUI::LogUI(IAllocator& allocator) , m_are_notifications_hovered(false) , m_move_notifications_to_front(false) { - getLogCallback().bind(this); + getLogCallback().bind<&LogUI::onLog>(this); for (int i = 0; i < (int)LogLevel::COUNT; ++i) { @@ -31,7 +31,7 @@ LogUI::LogUI(IAllocator& allocator) LogUI::~LogUI() { - getLogCallback().unbind(this); + getLogCallback().unbind<&LogUI::onLog>(this); } diff --git a/src/editor/prefab_system.cpp b/src/editor/prefab_system.cpp index f1ec97b85..438baa5f1 100644 --- a/src/editor/prefab_system.cpp +++ b/src/editor/prefab_system.cpp @@ -172,18 +172,16 @@ public: , m_prefabs(editor.getAllocator()) , m_deferred_instances(editor.getAllocator()) { - editor.universeCreated().bind(this); - editor.universeDestroyed().bind(this); + editor.universeCreated().bind<&PrefabSystemImpl::onUniverseCreated>(this); + editor.universeDestroyed().bind<&PrefabSystemImpl::onUniverseDestroyed>(this); setUniverse(editor.getUniverse()); } ~PrefabSystemImpl() { - m_editor.universeCreated() - .unbind(this); - m_editor.universeDestroyed() - .unbind(this); + m_editor.universeCreated().unbind<&PrefabSystemImpl::onUniverseCreated>(this); + m_editor.universeDestroyed().unbind<&PrefabSystemImpl::onUniverseDestroyed>(this); setUniverse(nullptr); } @@ -195,15 +193,12 @@ public: { if (m_universe) { - m_universe->entityDestroyed() - .unbind( - this); + m_universe->entityDestroyed().unbind<&PrefabSystemImpl::onEntityDestroyed>(this); } m_universe = universe; if (m_universe) { - m_universe->entityDestroyed() - .bind(this); + m_universe->entityDestroyed().bind<&PrefabSystemImpl::onEntityDestroyed>(this); } } @@ -580,7 +575,7 @@ public: m_editor.destroyEntities(&entities[0], entities.size()); auto* res = m_editor.getEngine().getResourceManager().load(path); FileSystem& fs = m_editor.getEngine().getFileSystem(); - while (fs.hasWork()) fs.updateAsyncTransactions(); + while (fs.hasWork()) fs.processCallbacks(); instantiatePrefab(*res, tr.pos, tr.rot, tr.scale); m_editor.endCommandGroup(); diff --git a/src/editor/profiler_ui.cpp b/src/editor/profiler_ui.cpp index 7b805a9c2..a80b1dd9c 100644 --- a/src/editor/profiler_ui.cpp +++ b/src/editor/profiler_ui.cpp @@ -111,7 +111,7 @@ struct ProfilerUIImpl final : public ProfilerUI { while (m_engine.getFileSystem().hasWork()) { - m_engine.getFileSystem().updateAsyncTransactions(); + m_engine.getFileSystem().processCallbacks(); } m_allocation_root->clear(m_allocator); diff --git a/src/editor/studio_app.cpp b/src/editor/studio_app.cpp index 0b2ee8df8..ac2328c2d 100644 --- a/src/editor/studio_app.cpp +++ b/src/editor/studio_app.cpp @@ -106,7 +106,7 @@ struct LuaPlugin : public StudioApp::GUIPlugin lua_pop(L, 2); // [] Action* action = LUMIX_NEW(editor.getAllocator(), Action)(name, name, name); - action->func.bind(this); + action->func.bind<&LuaPlugin::onAction>(this); app.addWindowAction(action); m_is_open = false; @@ -292,14 +292,14 @@ public: update(); if (m_sleep_when_inactive && !isFocused()) { - const float frame_time = m_fps_timer.tick(); + const float frame_time = m_inactive_fps_timer.tick(); const float wanted_fps = 5.0f; if (frame_time < 1 / wanted_fps) { PROFILE_BLOCK("sleep"); MT::sleep(u32(1000 / wanted_fps - frame_time * 1000)); } - m_fps_timer.tick(); + m_inactive_fps_timer.tick(); } Profiler::frame(); @@ -445,7 +445,7 @@ public: while (m_editor->getEngine().getFileSystem().hasWork()) { - m_editor->getEngine().getFileSystem().updateAsyncTransactions(); + m_editor->getEngine().getFileSystem().processCallbacks(); } m_editor->newUniverse(); @@ -848,6 +848,13 @@ public: m_editor->update(); m_engine->update(*m_editor->getUniverse()); + ++m_fps_frame; + if (m_fps_timer.getTimeSinceTick() > 1.0f) + { + m_fps = m_fps_frame / m_fps_timer.tick(); + m_fps_frame = 0; + } + if (m_deferred_game_mode_exit) { m_deferred_game_mode_exit = false; @@ -1296,7 +1303,7 @@ public: Action& addAction(const char* label_short, const char* label_long, const char* name) { auto* a = LUMIX_NEW(m_editor->getAllocator(), Action)(label_short, label_long, name); - a->func.bind(this); + a->func.bind(this); addAction(a); return *a; } @@ -1312,7 +1319,7 @@ public: { auto* a = LUMIX_NEW(m_editor->getAllocator(), Action)(label_short, label_long, name, shortcut0, shortcut1, shortcut2); - a->func.bind(this); + a->func.bind(this); addAction(a); } @@ -1560,7 +1567,7 @@ public: StaticString<200> stats(""); if (m_engine->getFileSystem().hasWork()) stats << "Loading... | "; stats << "FPS: "; - stats << (u32)(m_engine->getFPS() + 0.5f); + stats << (u32)(m_fps + 0.5f); if (!isFocused()) stats << " - inactive window"; auto stats_size = ImGui::CalcTextSize(stats); ImGui::SameLine(ImGui::GetContentRegionMax().x - stats_size.x); @@ -2013,24 +2020,24 @@ public: addAction<&StudioAppImpl::duplicate>( ICON_FA_FILES_O "Duplicate", "Duplicate entity", "duplicate", OS::Keycode::LCTRL, OS::Keycode::D, OS::Keycode::INVALID); addAction<&StudioAppImpl::toggleOrbitCamera>(NO_ICON "Orbit camera", "Orbit camera", "orbitCamera") - .is_selected.bind(this); + .is_selected.bind<&StudioAppImpl::isOrbitCamera>(this); addAction<&StudioAppImpl::setTranslateGizmoMode>(ICON_FA_ARROWS "Translate", "Set translate mode", "setTranslateGizmoMode") - .is_selected.bind(&m_editor->getGizmo()); + .is_selected.bind<&Gizmo::isTranslateMode>(&m_editor->getGizmo()); addAction<&StudioAppImpl::setRotateGizmoMode>(ICON_FA_REPEAT "Rotate", "Set rotate mode", "setRotateGizmoMode") - .is_selected.bind(&m_editor->getGizmo()); + .is_selected.bind<&Gizmo::isRotateMode>(&m_editor->getGizmo()); addAction<&StudioAppImpl::setScaleGizmoMode>(NO_ICON "Scale", "Set scale mode", "setScaleGizmoMode") - .is_selected.bind(&m_editor->getGizmo()); + .is_selected.bind<&Gizmo::isScaleMode>(&m_editor->getGizmo()); addAction<&StudioAppImpl::setTopView>(NO_ICON "Top", "Set top camera view", "viewTop"); addAction<&StudioAppImpl::setFrontView>(NO_ICON "Front", "Set front camera view", "viewFront"); addAction<&StudioAppImpl::setSideView>(NO_ICON "Side", "Set side camera view", "viewSide"); addAction<&StudioAppImpl::setLocalCoordSystem>(NO_ICON "Local", "Set local transform system", "setLocalCoordSystem") - .is_selected.bind(&m_editor->getGizmo()); + .is_selected.bind<&Gizmo::isLocalCoordSystem>(&m_editor->getGizmo()); addAction<&StudioAppImpl::setGlobalCoordSystem>(ICON_FA_GLOBE "Global", "Set global transform system", "setGlobalCoordSystem") - .is_selected.bind(&m_editor->getGizmo()); + .is_selected.bind<&Gizmo::isGlobalCoordSystem>(&m_editor->getGizmo()); addAction<&StudioAppImpl::setPivotCenter>(ICON_FA_ALIGN_CENTER "Center", "Set center transform system", "setPivotCenter") - .is_selected.bind(&m_editor->getGizmo()); + .is_selected.bind<&Gizmo::isPivotCenter>(&m_editor->getGizmo()); addAction<&StudioAppImpl::setPivotOrigin>(NO_ICON "Pivot", "Set pivot transform system", "setPivotOrigin") - .is_selected.bind(&m_editor->getGizmo()); + .is_selected.bind<&Gizmo::isPivotOrigin>(&m_editor->getGizmo()); addAction<&StudioAppImpl::addEntity>(ICON_FA_PLUS_SQUARE_O "Create empty", "Create empty entity", "createEntity"); addAction<&StudioAppImpl::destroySelectedEntity>(ICON_FA_MINUS_SQUARE_O "Destroy", @@ -2044,21 +2051,21 @@ public: addAction<&StudioAppImpl::unparent>(ICON_FA_OBJECT_UNGROUP "Unparent", "Unparent entity", "unparent"); addAction<&StudioAppImpl::toggleGameMode>(ICON_FA_PLAY "Game Mode", "Toggle game mode", "toggleGameMode") - .is_selected.bind(m_editor); + .is_selected.bind<&WorldEditor::isGameMode>(m_editor); addAction<&StudioAppImpl::toggleMeasure>(NO_ICON "Toggle measure", "Toggle measure mode", "toggleMeasure") - .is_selected.bind(m_editor); + .is_selected.bind<&WorldEditor::isMeasureToolActive>(m_editor); addAction<&StudioAppImpl::autosnapDown>(NO_ICON "Autosnap down", "Toggle autosnap down", "autosnapDown") - .is_selected.bind(&m_editor->getGizmo()); + .is_selected.bind<&Gizmo::isAutosnapDown>(&m_editor->getGizmo()); addAction<&StudioAppImpl::snapDown>(NO_ICON "Snap down", "Snap entities down", "snapDown"); addAction<&StudioAppImpl::setEditCamTransform>(NO_ICON "Camera transform", "Set camera transformation", "setEditCamTransform"); addAction<&StudioAppImpl::copyViewTransform>(NO_ICON "Copy view transform", "Copy view transform", "copyViewTransform"); addAction<&StudioAppImpl::lookAtSelected>(NO_ICON "Look at selected", "Look at selected entity", "lookAtSelected"); addAction<&StudioAppImpl::toggleAssetBrowser>(ICON_FA_CUBES "Asset Browser", "Toggle asset browser", "assetBrowser") - .is_selected.bind(this); + .is_selected.bind<&StudioAppImpl::isAssetBrowserOpen>(this); addAction<&StudioAppImpl::toggleEntityList>(ICON_FA_LIST "Entity List", "Toggle entity list", "entityList") - .is_selected.bind(this); + .is_selected.bind<&StudioAppImpl::isEntityListOpen>(this); addAction<&StudioAppImpl::toggleSettings>(ICON_FA_COGS "Settings", "Toggle settings UI", "settings") - .is_selected.bind(this); + .is_selected.bind<&StudioAppImpl::areSettingsOpen>(this); addAction<&StudioAppImpl::showPackDataDialog>(ICON_FA_FILE_ARCHIVE_O "Pack data", "Pack data", "pack_data"); } @@ -2138,7 +2145,7 @@ public: m_watched_plugin.basename = basename; PathUtils::getDir(Span(dir), src); m_watched_plugin.watcher = FileSystemWatcher::create(dir, m_allocator); - m_watched_plugin.watcher->getCallback().bind(this); + m_watched_plugin.watcher->getCallback().bind<&StudioAppImpl::onPluginChanged>(this); m_watched_plugin.dir = dir; m_watched_plugin.plugin = loaded_plugin; } @@ -3134,10 +3141,13 @@ public: Settings m_settings; Array m_events; Vec2 m_mouse_move; - OS::Timer m_fps_timer; char m_template_name[100]; char m_open_filter[64]; char m_component_filter[32]; + float m_fps = 0; + OS::Timer m_fps_timer; + OS::Timer m_inactive_fps_timer; + u32 m_fps_frame = 0; struct PackConfig { diff --git a/src/editor/world_editor.cpp b/src/editor/world_editor.cpp index 04c0bb556..5b13ac2dd 100644 --- a/src/editor/world_editor.cpp +++ b/src/editor/world_editor.cpp @@ -2074,7 +2074,7 @@ public: void save(IOutputStream& file) { - while (m_engine.getFileSystem().hasWork()) m_engine.getFileSystem().updateAsyncTransactions(); + while (m_engine.getFileSystem().hasWork()) m_engine.getFileSystem().processCallbacks(); ASSERT(m_universe); @@ -2563,7 +2563,7 @@ public: m_universe = &m_engine.createUniverse(true); m_universe_created.invoke(); m_universe->setName(name); - m_universe->entityDestroyed().bind(this); + m_universe->entityDestroyed().bind<&WorldEditorImpl::onEntityDestroyed>(this); m_selected_entities.clear(); InputMemoryStream file(m_game_mode_file); load(file); @@ -3097,7 +3097,7 @@ public: m_universe = &m_engine.createUniverse(true); Universe* universe = m_universe; - universe->entityDestroyed().bind(this); + universe->entityDestroyed().bind<&WorldEditorImpl::onEntityDestroyed>(this); m_is_orbit = false; m_selected_entities.clear(); diff --git a/src/engine/delegate.h b/src/engine/delegate.h index 135d6b08f..f738117b5 100644 --- a/src/engine/delegate.h +++ b/src/engine/delegate.h @@ -22,19 +22,19 @@ private: InternalFunction second; }; - template static LUMIX_FORCE_INLINE R FunctionStub(InstancePtr, Args... args) + template static R FunctionStub(InstancePtr, Args... args) { return (Function)(args...); } template - static LUMIX_FORCE_INLINE R ClassMethodStub(InstancePtr instance, Args... args) + static R ClassMethodStub(InstancePtr instance, Args... args) { return (static_cast(instance)->*Function)(args...); } template - static LUMIX_FORCE_INLINE R ClassMethodStub(InstancePtr instance, Args... args) + static R ClassMethodStub(InstancePtr instance, Args... args) { return (static_cast(instance)->*Function)(args...); } @@ -54,16 +54,10 @@ public: m_stub.second = &FunctionStub; } - template void bind(C* instance) + template void bind(C* instance) { m_stub.first = instance; - m_stub.second = &ClassMethodStub; - } - - template void bind(C* instance) - { - m_stub.first = instance; - m_stub.second = &ClassMethodStub; + m_stub.second = &ClassMethodStub; } R invoke(Args... args) const diff --git a/src/engine/delegate_list.h b/src/engine/delegate_list.h index 55b343028..e5802f497 100644 --- a/src/engine/delegate_list.h +++ b/src/engine/delegate_list.h @@ -17,10 +17,10 @@ public: { } - template void bind(C* instance) + template void bind(C* instance) { Delegate cb; - cb.template bind(instance); + cb.template bind(instance); m_delegates.push(cb); } @@ -31,10 +31,24 @@ public: m_delegates.push(cb); } - template void unbind(C* instance) + template void unbind() { Delegate cb; - cb.template bind(instance); + cb.template bind(); + for (int i = 0; i < m_delegates.size(); ++i) + { + if (m_delegates[i] == cb) + { + m_delegates.swapAndPop(i); + break; + } + } + } + + template void unbind(C* instance) + { + Delegate cb; + cb.template bind(instance); for (int i = 0; i < m_delegates.size(); ++i) { if (m_delegates[i] == cb) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 732b52e74..5f4d39f62 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -24,377 +24,7 @@ namespace Lumix { -namespace LuaImGui -{ - - -int InputTextMultiline(lua_State* L) -{ - char buf[4096]; - auto* name = LuaWrapper::checkArg(L, 1); - auto* value = LuaWrapper::checkArg(L, 2); - copyString(buf, value); - bool changed = ImGui::InputTextMultiline(name, buf, sizeof(buf), ImVec2(-1, -1)); - lua_pushboolean(L, changed); - if (changed) - { - lua_pushstring(L, buf); - } - else - { - lua_pushvalue(L, 2); - } - return 2; -} - - -int DragFloat(lua_State* L) -{ - auto* name = LuaWrapper::checkArg(L, 1); - float value = LuaWrapper::checkArg(L, 2); - bool changed = ImGui::DragFloat(name, &value); - lua_pushboolean(L, changed); - lua_pushnumber(L, value); - return 2; -} - - -int DragInt(lua_State* L) -{ - auto* name = LuaWrapper::checkArg(L, 1); - int value = LuaWrapper::checkArg(L, 2); - bool changed = ImGui::DragInt(name, &value); - lua_pushboolean(L, changed); - lua_pushinteger(L, value); - return 2; -} - - -int PushStyleColor(lua_State* L) -{ - int var = LuaWrapper::checkArg(L, 1); - ImVec4 v; - v.x = LuaWrapper::checkArg(L, 2); - v.y = LuaWrapper::checkArg(L, 3); - v.z = LuaWrapper::checkArg(L, 4); - v.w = LuaWrapper::checkArg(L, 5); - ImGui::PushStyleColor(var, v); - return 0; -} - - -int PushStyleVar(lua_State* L) -{ - int var = LuaWrapper::checkArg(L, 1); - if (lua_gettop(L) > 2) - { - ImVec2 v; - v.x = LuaWrapper::checkArg(L, 2); - v.y = LuaWrapper::checkArg(L, 3); - ImGui::PushStyleVar(var, v); - } - else - { - float v = LuaWrapper::checkArg(L, 2); - ImGui::PushStyleVar(var, v); - } - return 0; -} - - -int PushID(lua_State* L) -{ - int id = LuaWrapper::checkArg(L, 1); - ImGui::PushID(id); - return 0; -} - - -int SetStyleColor(lua_State* L) -{ - auto& style = ImGui::GetStyle(); - int index = LuaWrapper::checkArg(L, 1); - ImVec4 color; - color.x = LuaWrapper::checkArg(L, 2); - color.y = LuaWrapper::checkArg(L, 3); - color.z = LuaWrapper::checkArg(L, 4); - color.w = LuaWrapper::checkArg(L, 5); - style.Colors[index] = color; - return 0; -} - - -int ShowTestWindow(lua_State* L) -{ - ImGui::ShowDemoWindow(); - return 0; -} - - -int SliderFloat(lua_State* L) -{ - auto* name = LuaWrapper::checkArg(L, 1); - float value = LuaWrapper::checkArg(L, 2); - float min = LuaWrapper::checkArg(L, 3); - float max = LuaWrapper::checkArg(L, 4); - bool changed = ImGui::SliderFloat(name, &value, min, max, ""); - lua_pushboolean(L, changed); - lua_pushnumber(L, value); - return 2; -} - - -int Text(lua_State* L) -{ - auto* text = LuaWrapper::checkArg(L, 1); - ImGui::Text("%s", text); - return 0; -} - - -int LabelText(lua_State* L) -{ - auto* label = LuaWrapper::checkArg(L, 1); - auto* text = LuaWrapper::checkArg(L, 2); - ImGui::LabelText(label, "%s", text); - return 0; -} - - -int Button(lua_State* L) -{ - auto* label = LuaWrapper::checkArg(L, 1); - ImVec2 size(0, 0); - if (lua_gettop(L) > 2) - { - size.x = LuaWrapper::checkArg(L, 2); - size.y = LuaWrapper::checkArg(L, 3); - } - bool clicked = ImGui::Button(label, size); - lua_pushboolean(L, clicked); - return 1; -} - - -int CollapsingHeader(lua_State* L) -{ - auto* label = LuaWrapper::checkArg(L, 1); - lua_pushboolean(L, ImGui::CollapsingHeader(label)); - return 1; -} - - -int CalcTextSize(lua_State* L) -{ - auto* text = LuaWrapper::checkArg(L, 1); - ImVec2 size = ImGui::CalcTextSize(text); - - LuaWrapper::push(L, size.x); - LuaWrapper::push(L, size.y); - return 2; -} - - -int Checkbox(lua_State* L) -{ - auto* label = LuaWrapper::checkArg(L, 1); - bool b = LuaWrapper::checkArg(L, 2); - bool clicked = ImGui::Checkbox(label, &b); - lua_pushboolean(L, clicked); - lua_pushboolean(L, b); - return 2; -} - - -int GetWindowPos(lua_State* L) -{ - ImVec2 pos = ImGui::GetWindowPos(); - LuaWrapper::push(L, Vec2(pos.x, pos.y)); - return 1; -} - - -int SetNextWindowPos(lua_State* L) -{ - ImVec2 pos; - pos.x = LuaWrapper::checkArg(L, 1); - pos.y = LuaWrapper::checkArg(L, 2); - ImGui::SetNextWindowPos(pos); - return 0; -} - - -int AlignTextToFramePadding(lua_State* L) -{ - ImGui::AlignTextToFramePadding(); - return 0; -} - - -int Selectable(lua_State* L) -{ - auto* label = LuaWrapper::checkArg(L, 1); - bool selected = false; - if (lua_gettop(L) > 1) - { - selected = LuaWrapper::checkArg(L, 2); - } - bool clicked = ImGui::Selectable(label, selected); - lua_pushboolean(L, clicked); - return 1; -} - - -int SetCursorScreenPos(lua_State* L) -{ - ImVec2 pos; - pos.x = LuaWrapper::checkArg(L, 1); - pos.y = LuaWrapper::checkArg(L, 2); - ImGui::SetCursorScreenPos(pos); - return 0; -} - - -int Separator(lua_State* L) -{ - ImGui::Separator(); - return 0; -} - - -void Rect(float w, float h, u32 color) -{ - ImGui::Rect(w, h, color); -} - - -void Dummy(float w, float h) -{ - ImGui::Dummy({w, h}); -} - - -bool IsItemHovered() -{ - return ImGui::IsItemHovered(); -} - - -bool IsMouseDown(int button) -{ - return ImGui::IsMouseDown(button); -} - - -bool IsMouseClicked(int button) -{ - return ImGui::IsMouseClicked(button); -} - - -int SetNextWindowPosCenter(lua_State* L) -{ - ImVec2 size = ImGui::GetIO().DisplaySize; - ImGui::SetNextWindowPos(ImVec2(size.x * 0.5f, size.y * 0.5f), 0, ImVec2(0.5f, 0.5f)); - return 0; -} - - -int SetNextWindowSize(float w, float h) -{ - ImGui::SetNextWindowSize(ImVec2(w, h)); - return 0; -} - - -int Begin(lua_State* L) -{ - auto* label = LuaWrapper::checkArg(L, 1); - ImGuiWindowFlags flags = 0; - if (lua_gettop(L) > 1) - { - flags = LuaWrapper::checkArg(L, 2); - } - bool res = ImGui::Begin(label, nullptr, flags); - lua_pushboolean(L, res); - return 1; -} - - -int BeginChildFrame(lua_State* L) -{ - auto* label = LuaWrapper::checkArg(L, 1); - ImVec2 size(0, 0); - if (lua_gettop(L) > 1) - { - size.x = LuaWrapper::checkArg(L, 2); - size.y = LuaWrapper::checkArg(L, 3); - } - bool res = ImGui::BeginChildFrame(ImGui::GetID(label), size); - lua_pushboolean(L, res); - return 1; -} - - -int BeginPopup(lua_State* L) -{ - auto* label = LuaWrapper::checkArg(L, 1); - bool res = ImGui::BeginPopup(label); - lua_pushboolean(L, res); - return 1; -} - - -int GetDisplayWidth(lua_State* L) -{ - float w = ImGui::GetIO().DisplaySize.x; - LuaWrapper::push(L, w); - return 1; -} - - -int GetDisplayHeight(lua_State* L) -{ - float w = ImGui::GetIO().DisplaySize.y; - LuaWrapper::push(L, w); - return 1; -} - - -int GetWindowWidth(lua_State* L) -{ - float w = ImGui::GetWindowWidth(); - LuaWrapper::push(L, w); - return 1; -} - - -int GetWindowHeight(lua_State* L) -{ - float w = ImGui::GetWindowHeight(); - LuaWrapper::push(L, w); - return 1; -} - - -int SameLine(lua_State* L) -{ - float pos_x = 0; - if (lua_gettop(L) > 0) - { - pos_x = LuaWrapper::checkArg(L, 1); - } - ImGui::SameLine(pos_x); - return 0; -} - - -void registerCFunction(lua_State* L, const char* name, lua_CFunction f) -{ - lua_pushcfunction(L, f); - lua_setfield(L, -2, name); -} -} +void registerEngineAPI(lua_State* L, Engine* engine); static const u32 SERIALIZED_ENGINE_MAGIC = 0x5f4c454e; // == '_LEN' @@ -413,13 +43,13 @@ public: #pragma pack() -static void showLogInVS(LogLevel level, const char* system, const char* message) +static void showLogDebugOutput(LogLevel level, const char* system, const char* message) { if(level == LogLevel::ERROR) { Debug::debugOutput("Error: "); } Debug::debugOutput(system); - Debug::debugOutput(" : "); + Debug::debugOutput(":: "); Debug::debugOutput(message); Debug::debugOutput("\n"); } @@ -470,10 +100,8 @@ public: , m_resource_manager(m_allocator) , m_lua_resources(m_allocator) , m_last_lua_resource_idx(-1) - , m_fps(0) , m_is_game_running(false) , m_last_time_delta(0) - , m_time(0) , m_path_manager(PathManager::create(m_allocator)) , m_time_multiplier(1.0f) , m_paused(false) @@ -486,19 +114,19 @@ public: installUnhandledExceptionHandler(); getLogCallback().bind(); - getLogCallback().bind(); + getLogCallback().bind(); m_platform_data = {}; m_state = luaL_newstate(); luaL_openlibs(m_state); - registerLuaAPI(); + + registerEngineAPI(m_state, this); m_file_system = FileSystem::create(working_dir, m_allocator); m_resource_manager.init(*m_file_system); m_prefab_resource_manager.create(PrefabResource::TYPE, m_resource_manager); - m_fps_frame = 0; Reflection::init(m_allocator); m_plugin_manager = PluginManager::create(*this); @@ -508,716 +136,6 @@ public: } - static bool LUA_hasFilesystemWork(Engine* engine) - { - return engine->getFileSystem().hasWork(); - } - - - static void LUA_processFilesystemWork(Engine* engine) - { - engine->getFileSystem().updateAsyncTransactions(); - } - - - static void LUA_startGame(Engine* engine, Universe* universe) - { - if(engine && universe) engine->startGame(*universe); - } - - - static bool LUA_createComponent(Universe* universe, EntityRef entity, const char* type) - { - if (!universe) return false; - ComponentType cmp_type = Reflection::getComponentType(type); - IScene* scene = universe->getScene(cmp_type); - if (!scene) return false; - if (universe->hasComponent(entity, cmp_type)) - { - logError("Lua Script") << "Component " << type << " already exists in entity " << entity.index; - return false; - } - - universe->createComponent(cmp_type, entity); - return true; - } - - - static EntityRef LUA_createEntity(Universe* univ) - { - return univ->createEntity(DVec3(0, 0, 0), Quat(0, 0, 0, 1)); - } - - - struct SetPropertyVisitor : public Reflection::IPropertyVisitor - { - void visit(const Reflection::Property& prop) override - { - if (!equalStrings(property_name, prop.name)) return; - if (lua_isnumber(L, -1)) - { - float f = (float)lua_tonumber(L, -1); - InputMemoryStream input_blob(&f, sizeof(f)); - prop.setValue(cmp, -1, input_blob); - } - } - - - void visit(const Reflection::Property& prop) override - { - if (!equalStrings(property_name, prop.name)) return; - if (lua_isnumber(L, -1)) - { - int i = (int)lua_tointeger(L, -1); - InputMemoryStream input_blob(&i, sizeof(i)); - prop.setValue(cmp, -1, input_blob); - } - - } - - - void visit(const Reflection::Property& prop) override - { - if (!equalStrings(property_name, prop.name)) return; - if (lua_isnumber(L, -1)) - { - const u32 i = (u32)lua_tointeger(L, -1); - InputMemoryStream input_blob(&i, sizeof(i)); - prop.setValue(cmp, -1, input_blob); - } - - } - - - void visit(const Reflection::Property& prop) override - { - if (!equalStrings(property_name, prop.name)) return; - if (lua_isnumber(L, -1)) - { - int i = (int)lua_tointeger(L, -1); - InputMemoryStream input_blob(&i, sizeof(i)); - prop.setValue(cmp, -1, input_blob); - } - - } - - - void visit(const Reflection::Property& prop) override - { - if (!equalStrings(property_name, prop.name)) return; - if (lua_istable(L, -1)) - { - auto v = LuaWrapper::toType(L, -1); - InputMemoryStream input_blob(&v, sizeof(v)); - prop.setValue(cmp, -1, input_blob); - } - } - - - void visit(const Reflection::Property& prop) override - { - if (!equalStrings(property_name, prop.name)) return; - if (lua_istable(L, -1)) - { - auto v = LuaWrapper::toType(L, -1); - InputMemoryStream input_blob(&v, sizeof(v)); - prop.setValue(cmp, -1, input_blob); - } - } - - - void visit(const Reflection::Property& prop) override - { - if (!equalStrings(property_name, prop.name)) return; - if (lua_istable(L, -1)) - { - auto v = LuaWrapper::toType(L, -1); - InputMemoryStream input_blob(&v, sizeof(v)); - prop.setValue(cmp, -1, input_blob); - } - } - - - void visit(const Reflection::Property& prop) override - { - if (!equalStrings(property_name, prop.name)) return; - if (lua_istable(L, -1)) - { - auto v = LuaWrapper::toType(L, -1); - InputMemoryStream input_blob(&v, sizeof(v)); - prop.setValue(cmp, -1, input_blob); - } - } - - - void visit(const Reflection::Property& prop) override - { - if (!equalStrings(property_name, prop.name)) return; - if (lua_isstring(L, -1)) - { - const char* str = lua_tostring(L, -1); - InputMemoryStream input_blob(str, stringLength(str) + 1); - prop.setValue(cmp, -1, input_blob); - } - } - - - void visit(const Reflection::Property& prop) override - { - if (!equalStrings(property_name, prop.name)) return; - if (lua_isboolean(L, -1)) - { - bool b = lua_toboolean(L, -1) != 0; - InputMemoryStream input_blob(&b, sizeof(b)); - prop.setValue(cmp, -1, input_blob); - } - } - - - void visit(const Reflection::Property& prop) override - { - if (!equalStrings(property_name, prop.name)) return; - if (lua_isstring(L, -1)) - { - const char* str = lua_tostring(L, -1); - InputMemoryStream input_blob(str, stringLength(str) + 1); - prop.setValue(cmp, -1, input_blob); - } - } - - - void visit(const Reflection::IArrayProperty& prop) override - { - if (!equalStrings(property_name, prop.name)) return; - - if (lua_istable(L, -1)) { - const int count = (int)lua_objlen(L, -1); - for (int i = 0; i < count; ++i) { - prop.addItem(cmp, prop.getCount(cmp)); - } - } - } - - - void visit(const Reflection::IEnumProperty& prop) override { - if (!equalStrings(property_name, prop.name)) return; - if (lua_isstring(L, -1)) { - const char* str = lua_tostring(L, -1); - for (int i = 0, c = prop.getEnumCount(cmp); i < c; ++i) { - if (equalStrings(prop.getEnumName(cmp, i), str)) { - const int value = prop.getEnumValue(cmp, i); - InputMemoryStream input_blob(&value, sizeof(value)); - prop.setValue(cmp, -1, input_blob); - } - } - } - } - - - void visit(const Reflection::IBlobProperty& prop) override { notSupported(prop); } - void visit(const Reflection::ISampledFuncProperty& prop) override { notSupported(prop); } - - - void notSupported(const Reflection::PropertyBase& prop) - { - if (!equalStrings(property_name, prop.name)) return; - logError("Lua Script") << "Property " << prop.name << " has unsupported type"; - } - - - lua_State* L; - ComponentUID cmp; - const char* property_name; - }; - - - static int LUA_getComponentType(const char* component_type) - { - return Reflection::getComponentType(component_type).index; - } - - - static int LUA_getComponentTypesCount() - { - return Reflection::getComponentTypesCount(); - } - - - static int LUA_getComponentTypeByIndex(int index) - { - const char* id = Reflection::getComponentTypeID(index); - return Reflection::getComponentType(id).index; - } - - - static int LUA_createEntityEx(lua_State* L) - { - auto* ctx = LuaWrapper::checkArg(L, 2); - LuaWrapper::checkTableArg(L, 3); - - EntityRef e = ctx->createEntity(DVec3(0, 0, 0), Quat(0, 0, 0, 1)); - - lua_pushvalue(L, 3); - lua_getfield(L, -1, "parent"); - if (lua_type(L, -1) != LUA_TNIL) - { - EntityRef parent = LuaWrapper::toType(L, -1); - ctx->setParent(parent, e); - } - lua_pop(L, 1); - - lua_pushnil(L); - while (lua_next(L, -2) != 0) - { - const char* parameter_name = luaL_checkstring(L, -2); - if (equalStrings(parameter_name, "position")) - { - auto pos = LuaWrapper::toType(L, -1); - ctx->setPosition(e, pos); - } - else if (equalStrings(parameter_name, "pitch")) - { - const float angle = LuaWrapper::toType(L, -1); - const Quat rot(Vec3(1, 0, 0), degreesToRadians(angle)); - ctx->setRotation(e, rot); - } - else if (equalStrings(parameter_name, "rotation")) - { - auto rot = LuaWrapper::toType(L, -1); - ctx->setRotation(e, rot); - } - else - { - ComponentType cmp_type = Reflection::getComponentType(parameter_name); - IScene* scene = ctx->getScene(cmp_type); - if (scene) - { - ComponentUID cmp(e, cmp_type, scene); - const Reflection::ComponentBase* cmp_des = Reflection::getComponent(cmp_type); - ctx->createComponent(cmp_type, e); - lua_pushvalue(L, -1); - lua_pushnil(L); - while (lua_next(L, -2) != 0) - { - const char* property_name = luaL_checkstring(L, -2); - SetPropertyVisitor v; - v.property_name = property_name; - v.cmp = cmp; - v.L = L; - cmp_des->visit(v); - - lua_pop(L, 1); - } - lua_pop(L, 1); - } - } - lua_pop(L, 1); - } - lua_pop(L, 1); - - LuaWrapper::push(L, e); - return 1; - } - - - static int LUA_setEntityRotation(lua_State* L) - { - Universe* univ = LuaWrapper::checkArg(L, 1); - int entity_index = LuaWrapper::checkArg(L, 2); - if (entity_index < 0) return 0; - - if (lua_gettop(L) > 3) - { - Vec3 axis = LuaWrapper::checkArg(L, 3); - float angle = LuaWrapper::checkArg(L, 4); - univ->setRotation({ entity_index }, Quat(axis, angle)); - } - else - { - Quat rot = LuaWrapper::checkArg(L, 3); - univ->setRotation({ entity_index }, rot); - } - return 0; - } - - - static IScene* LUA_getScene(Universe* universe, const char* name) - { - u32 hash = crc32(name); - return universe->getScene(hash); - } - - - static int LUA_loadResource(EngineImpl* engine, const char* path, const char* type) - { - Resource* res = engine->getResourceManager().load(ResourceType(type), Path(path)); - if(!res) return -1; - ++engine->m_last_lua_resource_idx; - engine->m_lua_resources.insert(engine->m_last_lua_resource_idx, res); - return engine->m_last_lua_resource_idx; - } - - - static void LUA_setEntityLocalRotation(Universe* universe, EntityRef entity, const Quat& rotation) - { - if (!universe->getParent(entity).isValid()) return; - - universe->setLocalRotation(entity, rotation); - } - - - static void LUA_setEntityLocalPosition(Universe* universe, EntityRef entity, const DVec3& position) - { - if (!universe->getParent(entity).isValid()) return; - - universe->setLocalPosition(entity, position); - } - - - static void LUA_setEntityPosition(Universe* univ, EntityRef entity, const DVec3& pos) { univ->setPosition(entity, pos); } - static float LUA_getLastTimeDelta(EngineImpl* engine) { return engine->getLastTimeDelta(); } - static void LUA_unloadResource(EngineImpl* engine, int resource_idx) { engine->unloadLuaResource(resource_idx); } - static Universe* LUA_createUniverse(EngineImpl* engine) { return &engine->createUniverse(false); } - static void LUA_destroyUniverse(EngineImpl* engine, Universe* universe) { engine->destroyUniverse(*universe); } - static Universe* LUA_getSceneUniverse(IScene* scene) { return &scene->getUniverse(); } - static void LUA_logError(const char* text) { logError("Lua Script") << text; } - static void LUA_logInfo(const char* text) { logInfo("Lua Script") << text; } - static void LUA_pause(Engine* engine, bool pause) { engine->pause(pause); } - static void LUA_nextFrame(Engine* engine) { engine->nextFrame(); } - static void LUA_setTimeMultiplier(Engine* engine, float multiplier) { engine->setTimeMultiplier(multiplier); } - static Vec4 LUA_multMatrixVec(const Matrix& m, const Vec4& v) { return m * v; } - static Quat LUA_multQuat(const Quat& a, const Quat& b) { return a * b; } - - - static int LUA_loadUniverse(lua_State* L) - { - auto* engine = LuaWrapper::checkArg(L, 1); - auto* universe = LuaWrapper::checkArg(L, 2); - auto* path = LuaWrapper::checkArg(L, 3); - if (!lua_isfunction(L, 4)) LuaWrapper::argError(L, 4, "function"); - FileSystem& fs = engine->getFileSystem(); - FileSystem::ContentCallback cb; - struct Callback - { - ~Callback() - { - luaL_unref(L, LUA_REGISTRYINDEX, lua_func); - } - - void invoke(u64 size, const u8* mem, bool success) - { - if (!success) - { - logError("Engine") << "Failed to open universe " << path; - } - else - { - InputMemoryStream blob(mem, size); - #pragma pack(1) - struct Header - { - u32 magic; - int version; - u32 hash; - u32 engine_hash; - }; - #pragma pack() - Header header; - blob.read(&header, sizeof(header)); - - if (!engine->deserialize(*universe, blob)) - { - logError("Engine") << "Failed to deserialize universe " << path; - } - else - { - lua_rawgeti(L, LUA_REGISTRYINDEX, lua_func); - if (lua_type(L, -1) != LUA_TFUNCTION) - { - ASSERT(false); - } - - if (lua_pcall(L, 0, 0, 0) != 0) - { - logError("Engine") << lua_tostring(L, -1); - lua_pop(L, 1); - } - } - } - LUMIX_DELETE(engine->getAllocator(), this); - } - - Engine* engine; - Universe* universe; - Path path; - lua_State* L; - int lua_func; - }; - Callback* inst = LUMIX_NEW(engine->getAllocator(), Callback); - inst->engine = engine; - inst->universe = universe; - inst->path = path; - inst->L = L; - inst->lua_func = luaL_ref(L, LUA_REGISTRYINDEX); - cb.bind(inst); - fs.getContent(inst->path, cb); - return 0; - } - - - static int LUA_multVecQuat(lua_State* L) - { - Vec3 v = LuaWrapper::checkArg(L, 1); - Quat q; - if (LuaWrapper::isType(L, 2)) - { - q = LuaWrapper::checkArg(L, 2); - } - else - { - Vec3 axis = LuaWrapper::checkArg(L, 2); - float angle = LuaWrapper::checkArg(L, 3); - - q = Quat(axis, angle); - } - - Vec3 res = q.rotate(v); - - LuaWrapper::push(L, res); - return 1; - } - - - static DVec3 LUA_getEntityPosition(Universe* universe, EntityRef entity) - { - return universe->getPosition(entity); - } - - - static Quat LUA_getEntityRotation(Universe* universe, EntityRef entity) - { - return universe->getRotation(entity); - } - - - static Vec3 LUA_getEntityDirection(Universe* universe, EntityRef entity) - { - Quat rot = universe->getRotation(entity); - return rot.rotate(Vec3(0, 0, 1)); - } - - - void registerLuaAPI() - { - lua_pushlightuserdata(m_state, this); - lua_setglobal(m_state, "g_engine"); - - #define REGISTER_FUNCTION(name) \ - LuaWrapper::createSystemFunction(m_state, "Engine", #name, \ - &LuaWrapper::wrap); \ - - REGISTER_FUNCTION(createComponent); - REGISTER_FUNCTION(createEntity); - REGISTER_FUNCTION(createUniverse); - REGISTER_FUNCTION(destroyUniverse); - REGISTER_FUNCTION(getComponentType); - REGISTER_FUNCTION(getComponentTypeByIndex); - REGISTER_FUNCTION(getComponentTypesCount); - REGISTER_FUNCTION(getEntityDirection); - REGISTER_FUNCTION(getEntityPosition); - REGISTER_FUNCTION(getEntityRotation); - REGISTER_FUNCTION(getLastTimeDelta); - REGISTER_FUNCTION(getScene); - REGISTER_FUNCTION(getSceneUniverse); - REGISTER_FUNCTION(hasFilesystemWork); - REGISTER_FUNCTION(loadResource); - REGISTER_FUNCTION(logError); - REGISTER_FUNCTION(logInfo); - REGISTER_FUNCTION(multMatrixVec); - REGISTER_FUNCTION(multQuat); - REGISTER_FUNCTION(nextFrame); - REGISTER_FUNCTION(pause); - REGISTER_FUNCTION(processFilesystemWork); - REGISTER_FUNCTION(setEntityLocalPosition); - REGISTER_FUNCTION(setEntityLocalRotation); - REGISTER_FUNCTION(setEntityPosition); - REGISTER_FUNCTION(setEntityRotation); - REGISTER_FUNCTION(setTimeMultiplier); - REGISTER_FUNCTION(startGame); - REGISTER_FUNCTION(unloadResource); - - LuaWrapper::createSystemFunction(m_state, "Engine", "loadUniverse", LUA_loadUniverse); - - #undef REGISTER_FUNCTION - - #define REGISTER_FUNCTION(F) \ - do { \ - auto f = &LuaWrapper::wrapMethod<&Universe::F>; \ - LuaWrapper::createSystemFunction(m_state, "Engine", #F, f); \ - } while(false) - - REGISTER_FUNCTION(cloneEntity); - REGISTER_FUNCTION(destroyEntity); - REGISTER_FUNCTION(findByName); - REGISTER_FUNCTION(getFirstChild); - REGISTER_FUNCTION(getFirstEntity); - REGISTER_FUNCTION(getNextEntity); - REGISTER_FUNCTION(getNextSibling); - REGISTER_FUNCTION(getParent); - REGISTER_FUNCTION(hasComponent); - REGISTER_FUNCTION(setParent); - - #undef REGISTER_FUNCTION - - - LuaWrapper::createSystemFunction(m_state, "Engine", "instantiatePrefab", &LUA_instantiatePrefab); - LuaWrapper::createSystemFunction(m_state, "Engine", "createEntityEx", &LUA_createEntityEx); - LuaWrapper::createSystemFunction(m_state, "Engine", "multVecQuat", &LUA_multVecQuat); - - lua_newtable(m_state); - lua_pushvalue(m_state, -1); - lua_setglobal(m_state, "ImGui"); - - LuaWrapper::createSystemVariable(m_state, "ImGui", "WindowFlags_NoMove", ImGuiWindowFlags_NoMove); - LuaWrapper::createSystemVariable(m_state, "ImGui", "WindowFlags_NoCollapse", ImGuiWindowFlags_NoCollapse); - LuaWrapper::createSystemVariable(m_state, "ImGui", "WindowFlags_NoInputs", ImGuiWindowFlags_NoInputs); - LuaWrapper::createSystemVariable(m_state, "ImGui", "WindowFlags_NoResize", ImGuiWindowFlags_NoResize); - LuaWrapper::createSystemVariable(m_state, "ImGui", "WindowFlags_NoTitleBar", ImGuiWindowFlags_NoTitleBar); - LuaWrapper::createSystemVariable(m_state, "ImGui", "WindowFlags_NoScrollbar", ImGuiWindowFlags_NoScrollbar); - LuaWrapper::createSystemVariable(m_state, "ImGui", "WindowFlags_AlwaysAutoResize", ImGuiWindowFlags_AlwaysAutoResize); - LuaWrapper::createSystemVariable(m_state, "ImGui", "Col_FrameBg", ImGuiCol_FrameBg); - LuaWrapper::createSystemVariable(m_state, "ImGui", "Col_WindowBg", ImGuiCol_WindowBg); - LuaWrapper::createSystemVariable(m_state, "ImGui", "Col_Button", ImGuiCol_Button); - LuaWrapper::createSystemVariable(m_state, "ImGui", "Col_ButtonActive", ImGuiCol_ButtonActive); - LuaWrapper::createSystemVariable(m_state, "ImGui", "Col_ButtonHovered", ImGuiCol_ButtonHovered); - LuaWrapper::createSystemVariable(m_state, "ImGui", "StyleVar_FramePadding", ImGuiStyleVar_FramePadding); - LuaWrapper::createSystemVariable(m_state, "ImGui", "StyleVar_IndentSpacing", ImGuiStyleVar_IndentSpacing); - LuaWrapper::createSystemVariable(m_state, "ImGui", "StyleVar_ItemSpacing", ImGuiStyleVar_ItemSpacing); - LuaWrapper::createSystemVariable(m_state, "ImGui", "StyleVar_ItemInnerSpacing", ImGuiStyleVar_ItemInnerSpacing); - LuaWrapper::createSystemVariable(m_state, "ImGui", "StyleVar_WindowPadding", ImGuiStyleVar_WindowPadding); - LuaImGui::registerCFunction(m_state, "AlignTextToFramePadding", &LuaImGui::AlignTextToFramePadding); - LuaImGui::registerCFunction(m_state, "Begin", &LuaImGui::Begin); - LuaImGui::registerCFunction(m_state, "BeginChildFrame", &LuaImGui::BeginChildFrame); - LuaImGui::registerCFunction(m_state, "BeginPopup", LuaImGui::BeginPopup); - LuaImGui::registerCFunction(m_state, "Button", &LuaImGui::Button); - LuaImGui::registerCFunction(m_state, "CalcTextSize", &LuaImGui::CalcTextSize); - LuaImGui::registerCFunction(m_state, "Checkbox", &LuaImGui::Checkbox); - LuaImGui::registerCFunction(m_state, "CollapsingHeader", &LuaImGui::CollapsingHeader); - LuaImGui::registerCFunction(m_state, "Columns", &LuaWrapper::wrap<&ImGui::Columns>); - LuaImGui::registerCFunction(m_state, "DragFloat", &LuaImGui::DragFloat); - LuaImGui::registerCFunction(m_state, "DragInt", &LuaImGui::DragInt); - LuaImGui::registerCFunction(m_state, "Dummy", &LuaWrapper::wrap<&LuaImGui::Dummy>); - LuaImGui::registerCFunction(m_state, "End", &LuaWrapper::wrap<&ImGui::End>); - LuaImGui::registerCFunction(m_state, "EndChildFrame", &LuaWrapper::wrap<&ImGui::EndChildFrame>); - LuaImGui::registerCFunction(m_state, "EndPopup", &LuaWrapper::wrap<&ImGui::EndPopup>); - LuaImGui::registerCFunction(m_state, "GetColumnWidth", &LuaWrapper::wrap<&ImGui::GetColumnWidth>); - LuaImGui::registerCFunction(m_state, "GetDisplayWidth", &LuaImGui::GetDisplayWidth); - LuaImGui::registerCFunction(m_state, "GetDisplayHeight", &LuaImGui::GetDisplayHeight); - LuaImGui::registerCFunction(m_state, "GetWindowWidth", &LuaImGui::GetWindowWidth); - LuaImGui::registerCFunction(m_state, "GetWindowHeight", &LuaImGui::GetWindowHeight); - LuaImGui::registerCFunction(m_state, "GetWindowPos", &LuaImGui::GetWindowPos); - LuaImGui::registerCFunction(m_state, "Indent", &LuaWrapper::wrap<&ImGui::Indent>); - LuaImGui::registerCFunction(m_state, "InputTextMultiline", &LuaImGui::InputTextMultiline); - LuaImGui::registerCFunction(m_state, "IsItemHovered", &LuaWrapper::wrap<&LuaImGui::IsItemHovered>); - LuaImGui::registerCFunction(m_state, "IsMouseClicked", &LuaWrapper::wrap<&LuaImGui::IsMouseClicked>); - LuaImGui::registerCFunction(m_state, "IsMouseDown", &LuaWrapper::wrap<&LuaImGui::IsMouseDown>); - LuaImGui::registerCFunction(m_state, "NewLine", &LuaWrapper::wrap<&ImGui::NewLine>); - LuaImGui::registerCFunction(m_state, "NextColumn", &LuaWrapper::wrap<&ImGui::NextColumn>); - LuaImGui::registerCFunction(m_state, "OpenPopup", &LuaWrapper::wrap<&ImGui::OpenPopup>); - LuaImGui::registerCFunction(m_state, "PopItemWidth", &LuaWrapper::wrap<&ImGui::PopItemWidth>); - LuaImGui::registerCFunction(m_state, "PopID", &LuaWrapper::wrap<&ImGui::PopID>); - LuaImGui::registerCFunction(m_state, "PopStyleColor", &LuaWrapper::wrap<&ImGui::PopStyleColor>); - LuaImGui::registerCFunction(m_state, "PopStyleVar", &LuaWrapper::wrap<&ImGui::PopStyleVar>); - LuaImGui::registerCFunction(m_state, "PushItemWidth", &LuaWrapper::wrap<&ImGui::PushItemWidth>); - LuaImGui::registerCFunction(m_state, "PushID", &LuaImGui::PushID); - LuaImGui::registerCFunction(m_state, "PushStyleColor", &LuaImGui::PushStyleColor); - LuaImGui::registerCFunction(m_state, "PushStyleVar", &LuaImGui::PushStyleVar); - LuaImGui::registerCFunction(m_state, "Rect", &LuaWrapper::wrap<&LuaImGui::Rect>); - LuaImGui::registerCFunction(m_state, "SameLine", &LuaImGui::SameLine); - LuaImGui::registerCFunction(m_state, "Selectable", &LuaImGui::Selectable); - LuaImGui::registerCFunction(m_state, "Separator", &LuaImGui::Separator); - LuaImGui::registerCFunction(m_state, "SetCursorScreenPos", &LuaImGui::SetCursorScreenPos); - LuaImGui::registerCFunction(m_state, "SetNextWindowPos", &LuaImGui::SetNextWindowPos); - LuaImGui::registerCFunction(m_state, "SetNextWindowPosCenter", &LuaImGui::SetNextWindowPosCenter); - LuaImGui::registerCFunction(m_state, "SetNextWindowSize", &LuaWrapper::wrap<&LuaImGui::SetNextWindowSize>); - LuaImGui::registerCFunction(m_state, "SetStyleColor", &LuaImGui::SetStyleColor); - LuaImGui::registerCFunction(m_state, "ShowTestWindow", &LuaImGui::ShowTestWindow); - LuaImGui::registerCFunction(m_state, "SliderFloat", &LuaImGui::SliderFloat); - LuaImGui::registerCFunction(m_state, "Text", &LuaImGui::Text); - LuaImGui::registerCFunction(m_state, "Unindent", &LuaWrapper::wrap<&ImGui::Unindent>); - LuaImGui::registerCFunction(m_state, "LabelText", &LuaImGui::LabelText); - - LuaWrapper::createSystemVariable(m_state, "Engine", "INPUT_DEVICE_KEYBOARD", InputSystem::Device::KEYBOARD); - LuaWrapper::createSystemVariable(m_state, "Engine", "INPUT_DEVICE_MOUSE", InputSystem::Device::MOUSE); - LuaWrapper::createSystemVariable(m_state, "Engine", "INPUT_DEVICE_CONTROLLER", InputSystem::Device::CONTROLLER); - - LuaWrapper::createSystemVariable(m_state, "Engine", "INPUT_BUTTON_STATE_UP", InputSystem::ButtonEvent::UP); - LuaWrapper::createSystemVariable(m_state, "Engine", "INPUT_BUTTON_STATE_DOWN", InputSystem::ButtonEvent::DOWN); - LuaWrapper::createSystemVariable(m_state, "Engine", "INPUT_EVENT_BUTTON", InputSystem::Event::BUTTON); - LuaWrapper::createSystemVariable(m_state, "Engine", "INPUT_EVENT_AXIS", InputSystem::Event::AXIS); - LuaWrapper::createSystemVariable(m_state, "Engine", "INPUT_EVENT_TEXT_INPUT", InputSystem::Event::TEXT_INPUT); - LuaWrapper::createSystemVariable(m_state, "Engine", "INPUT_EVENT_DEVICE_ADDED", InputSystem::Event::DEVICE_ADDED); - LuaWrapper::createSystemVariable(m_state, "Engine", "INPUT_EVENT_DEVICE_REMOVED", InputSystem::Event::DEVICE_REMOVED); - - lua_pop(m_state, 1); - - installLuaPackageLoader(); - } - - - void installLuaPackageLoader() const - { - lua_getglobal(m_state, "package"); - if (lua_type(m_state, -1) != LUA_TTABLE) { - logError("Engine") << "Lua \"package\" is not a table"; - return; - } - lua_getfield(m_state, -1, "searchers"); - if (lua_type(m_state, -1) != LUA_TTABLE) { - lua_pop(m_state, 1); - lua_getfield(m_state, -1, "loaders"); - if (lua_type(m_state, -1) != LUA_TTABLE) { - logError("Engine") << "Lua \"package.searchers\"/\"package.loaders\" is not a table"; - return; - } - } - int numLoaders = 0; - lua_pushnil(m_state); - while (lua_next(m_state, -2) != 0) { - lua_pop(m_state, 1); - numLoaders++; - } - - lua_pushinteger(m_state, numLoaders + 1); - lua_pushcfunction(m_state, LUA_packageLoader); - lua_rawset(m_state, -3); - lua_pop(m_state, 2); - } - - - static int LUA_packageLoader(lua_State* L) - { - const char* module = LuaWrapper::toType(L, 1); - StaticString tmp(module); - tmp << ".lua"; - lua_getglobal(L, "g_engine"); - auto* engine = (Engine*)lua_touserdata(L, -1); - lua_pop(L, 1); - auto& fs = engine->getFileSystem(); - Array buf(engine->getAllocator()); - if (!fs.getContentSync(Path(tmp), Ref(buf))) { - logError("Engine") << "Failed to open file " << tmp; - StaticString msg("Failed to open file "); - msg << tmp; - lua_pushstring(L, msg); - } - else if (luaL_loadbuffer(L, (const char*)buf.begin(), buf.byte_size(), tmp) != 0) { - logError("Engine") << "Failed to load package " << tmp << ": " << lua_tostring(L, -1); - } - return 1; - } - - ~EngineImpl() { for (Resource* res : m_lua_resources) @@ -1233,6 +151,7 @@ public: m_prefab_resource_manager.destroy(); lua_close(m_state); + getLogCallback().unbind(); g_log_file.close(); PathManager::destroy(*m_path_manager); } @@ -1299,14 +218,6 @@ public: } - PluginManager& getPluginManager() override - { - return *m_plugin_manager; - } - - - FileSystem& getFileSystem() override { return *m_file_system; } - void startGame(Universe& context) override { ASSERT(!m_is_game_running); @@ -1358,19 +269,12 @@ public: void update(Universe& context) override { PROFILE_FUNCTION(); - ++m_fps_frame; - if (m_fps_timer.getTimeSinceTick() > 1.0f) - { - m_fps = m_fps_frame / m_fps_timer.tick(); - m_fps_frame = 0; - } float dt = m_timer.tick() * m_time_multiplier; if (m_next_frame) { m_paused = false; dt = 1 / 30.0f; } - m_time += dt; m_last_time_delta = dt; { PROFILE_BLOCK("update scenes"); @@ -1388,7 +292,7 @@ public: } m_plugin_manager->update(dt, m_paused); m_input_system->update(dt); - getFileSystem().updateAsyncTransactions(); + m_file_system->processCallbacks(); if (m_next_frame) { @@ -1398,18 +302,6 @@ public: } - InputSystem& getInputSystem() override { return *m_input_system; } - - - ResourceManagerHub& getResourceManager() override - { - return m_resource_manager; - } - - - float getFPS() const override { return m_fps; } - - void serializerSceneVersions(OutputMemoryStream& serializer, Universe& ctx) { serializer.write(ctx.getScenes().size()); @@ -1522,88 +414,41 @@ public: } - ComponentUID createComponent(Universe& universe, EntityRef entity, ComponentType type) override + void unloadLuaResource(LuaResourceHandle resource) override { - IScene* scene = universe.getScene(type); - if (!scene) return ComponentUID::INVALID; - - universe.createComponent(type, entity); - return ComponentUID(entity, type, scene); - } - - - static int LUA_instantiatePrefab(lua_State* L) - { - auto* engine = LuaWrapper::checkArg(L, 1); - auto* universe = LuaWrapper::checkArg(L, 2); - DVec3 position = LuaWrapper::checkArg(L, 3); - int prefab_id = LuaWrapper::checkArg(L, 4); - PrefabResource* prefab = static_cast(engine->getLuaResource(prefab_id)); - if (!prefab) - { - logError("Editor") << "Cannot instantiate null prefab."; - return 0; - } - if (!prefab->isReady()) - { - logError("Editor") << "Prefab " << prefab->getPath().c_str() << " is not ready, preload it."; - return 0; - } - EntityPtr entity = universe->instantiatePrefab(*prefab, position, {0, 0, 0, 1}, 1); - - LuaWrapper::push(L, entity); - return 1; - } - - - void unloadLuaResource(int resource_idx) override - { - if (resource_idx < 0) return; - Resource* res = m_lua_resources[resource_idx]; - m_lua_resources.erase(resource_idx); + auto iter = m_lua_resources.find(resource); + if (!iter.isValid()) return; + Resource* res = iter.value(); + m_lua_resources.erase(iter); res->getResourceManager().unload(*res); } - int addLuaResource(const Path& path, ResourceType type) override + LuaResourceHandle addLuaResource(const Path& path, ResourceType type) override { Resource* res = m_resource_manager.load(type, path); - if (!res) return -1; + if (!res) return 0xffFFffFF; ++m_last_lua_resource_idx; + ASSERT(m_last_lua_resource_idx != 0xffFFffFF); m_lua_resources.insert(m_last_lua_resource_idx, res); - return m_last_lua_resource_idx; + return {m_last_lua_resource_idx}; } - Resource* getLuaResource(int idx) const override + Resource* getLuaResource(LuaResourceHandle resource) const override { - auto iter = m_lua_resources.find(idx); + auto iter = m_lua_resources.find(resource); if (iter.isValid()) return iter.value(); return nullptr; } - - void runScript(const char* src, int src_length, const char* path) override - { - if (luaL_loadbuffer(m_state, src, src_length, path) != 0) - { - logError("Engine") << path << ": " << lua_tostring(m_state, -1); - lua_pop(m_state, 1); - return; - } - - if (lua_pcall(m_state, 0, 0, 0) != 0) - { - logError("Engine") << path << ": " << lua_tostring(m_state, -1); - lua_pop(m_state, 1); - } - } - - - lua_State* getState() override { return m_state; } + PluginManager& getPluginManager() override { return *m_plugin_manager; } + FileSystem& getFileSystem() override { return *m_file_system; } + InputSystem& getInputSystem() override { return *m_input_system; } + ResourceManagerHub& getResourceManager() override { return m_resource_manager; } PathManager& getPathManager() override{ return *m_path_manager; } + lua_State* getState() override { return m_state; } float getLastTimeDelta() const override { return m_last_time_delta / m_time_multiplier; } - double getTime() const override { return m_time; } private: IAllocator& m_allocator; @@ -1617,12 +462,8 @@ private: PrefabResourceManager m_prefab_resource_manager; InputSystem* m_input_system; OS::Timer m_timer; - OS::Timer m_fps_timer; - int m_fps_frame; float m_time_multiplier; - float m_fps; float m_last_time_delta; - double m_time; bool m_is_game_running; bool m_paused; bool m_next_frame; @@ -1630,7 +471,7 @@ private: PathManager* m_path_manager; lua_State* m_state; HashMap m_lua_resources; - int m_last_lua_resource_idx; + u32 m_last_lua_resource_idx; }; diff --git a/src/engine/engine.h b/src/engine/engine.h index ff079e148..5a33b679e 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -1,38 +1,27 @@ #pragma once - #include "engine/lumix.h" - struct lua_State; - namespace Lumix { -struct ComponentUID; -class FileSystem; struct IAllocator; class InputMemoryStream; -class InputSystem; class OutputMemoryStream; -class PageAllocator; class Path; -struct PathManager; -class PluginManager; -class ResourceManagerHub; class Universe; -template class Array; - class LUMIX_ENGINE_API Engine { public: - struct PlatformData - { + struct PlatformData { void* window_handle = nullptr; }; + using LuaResourceHandle = u32; + public: virtual ~Engine() {} @@ -44,12 +33,13 @@ public: virtual void setPlatformData(const PlatformData& data) = 0; virtual const PlatformData& getPlatformData() = 0; - virtual FileSystem& getFileSystem() = 0; - virtual InputSystem& getInputSystem() = 0; - virtual PluginManager& getPluginManager() = 0; - virtual ResourceManagerHub& getResourceManager() = 0; + virtual struct PathManager& getPathManager() = 0; + virtual class FileSystem& getFileSystem() = 0; + virtual class InputSystem& getInputSystem() = 0; + virtual class PluginManager& getPluginManager() = 0; + virtual class ResourceManagerHub& getResourceManager() = 0; + virtual class PageAllocator& getPageAllocator() = 0; virtual IAllocator& getAllocator() = 0; - virtual PageAllocator& getPageAllocator() = 0; virtual void startGame(Universe& context) = 0; virtual void stopGame(Universe& context) = 0; @@ -57,19 +47,15 @@ public: virtual void update(Universe& context) = 0; virtual u32 serialize(Universe& ctx, OutputMemoryStream& serializer) = 0; virtual bool deserialize(Universe& ctx, InputMemoryStream& serializer) = 0; - virtual float getFPS() const = 0; - virtual double getTime() const = 0; virtual float getLastTimeDelta() const = 0; virtual void setTimeMultiplier(float multiplier) = 0; virtual void pause(bool pause) = 0; virtual void nextFrame() = 0; - virtual PathManager& getPathManager() = 0; virtual lua_State* getState() = 0; - virtual void runScript(const char* src, int src_length, const char* path) = 0; - virtual ComponentUID createComponent(Universe& universe, EntityRef entity, ComponentType type) = 0; - virtual class Resource* getLuaResource(int idx) const = 0; - virtual int addLuaResource(const Path& path, struct ResourceType type) = 0; - virtual void unloadLuaResource(int resource_idx) = 0; + + virtual class Resource* getLuaResource(LuaResourceHandle idx) const = 0; + virtual LuaResourceHandle addLuaResource(const Path& path, struct ResourceType type) = 0; + virtual void unloadLuaResource(LuaResourceHandle resource_idx) = 0; protected: Engine() {} diff --git a/src/engine/file_system.cpp b/src/engine/file_system.cpp index ef1722fa0..21c420506 100644 --- a/src/engine/file_system.cpp +++ b/src/engine/file_system.cpp @@ -216,7 +216,7 @@ struct FileSystemImpl final : public FileSystem } - void updateAsyncTransactions() override + void processCallbacks() override { PROFILE_FUNCTION(); diff --git a/src/engine/file_system.h b/src/engine/file_system.h index 4b874caa0..c747eef36 100644 --- a/src/engine/file_system.h +++ b/src/engine/file_system.h @@ -44,7 +44,7 @@ public: virtual void setBasePath(const char* path) = 0; virtual const char* getBasePath() const = 0; - virtual void updateAsyncTransactions() = 0; + virtual void processCallbacks() = 0; virtual bool hasWork() = 0; virtual bool getContentSync(const Path& file, Ref> content) = 0; diff --git a/src/engine/lua_api.cpp b/src/engine/lua_api.cpp new file mode 100644 index 000000000..234da6eb6 --- /dev/null +++ b/src/engine/lua_api.cpp @@ -0,0 +1,1114 @@ +#include +#include "crc32.h" +#include "engine.h" +#include "file_system.h" +#include "input_system.h" +#include "lua_wrapper.h" +#include "prefab.h" +#include "reflection.h" +#include "universe/universe.h" + + +namespace Lumix { + +namespace LuaImGui { + + +int InputTextMultiline(lua_State* L) +{ + char buf[4096]; + auto* name = LuaWrapper::checkArg(L, 1); + auto* value = LuaWrapper::checkArg(L, 2); + copyString(buf, value); + bool changed = ImGui::InputTextMultiline(name, buf, sizeof(buf), ImVec2(-1, -1)); + lua_pushboolean(L, changed); + if (changed) + { + lua_pushstring(L, buf); + } + else + { + lua_pushvalue(L, 2); + } + return 2; +} + + +int DragFloat(lua_State* L) +{ + auto* name = LuaWrapper::checkArg(L, 1); + float value = LuaWrapper::checkArg(L, 2); + bool changed = ImGui::DragFloat(name, &value); + lua_pushboolean(L, changed); + lua_pushnumber(L, value); + return 2; +} + + +int DragInt(lua_State* L) +{ + auto* name = LuaWrapper::checkArg(L, 1); + int value = LuaWrapper::checkArg(L, 2); + bool changed = ImGui::DragInt(name, &value); + lua_pushboolean(L, changed); + lua_pushinteger(L, value); + return 2; +} + + +int PushStyleColor(lua_State* L) +{ + int var = LuaWrapper::checkArg(L, 1); + ImVec4 v; + v.x = LuaWrapper::checkArg(L, 2); + v.y = LuaWrapper::checkArg(L, 3); + v.z = LuaWrapper::checkArg(L, 4); + v.w = LuaWrapper::checkArg(L, 5); + ImGui::PushStyleColor(var, v); + return 0; +} + + +int PushStyleVar(lua_State* L) +{ + int var = LuaWrapper::checkArg(L, 1); + if (lua_gettop(L) > 2) + { + ImVec2 v; + v.x = LuaWrapper::checkArg(L, 2); + v.y = LuaWrapper::checkArg(L, 3); + ImGui::PushStyleVar(var, v); + } + else + { + float v = LuaWrapper::checkArg(L, 2); + ImGui::PushStyleVar(var, v); + } + return 0; +} + + +int PushID(lua_State* L) +{ + int id = LuaWrapper::checkArg(L, 1); + ImGui::PushID(id); + return 0; +} + + +int SetStyleColor(lua_State* L) +{ + auto& style = ImGui::GetStyle(); + int index = LuaWrapper::checkArg(L, 1); + ImVec4 color; + color.x = LuaWrapper::checkArg(L, 2); + color.y = LuaWrapper::checkArg(L, 3); + color.z = LuaWrapper::checkArg(L, 4); + color.w = LuaWrapper::checkArg(L, 5); + style.Colors[index] = color; + return 0; +} + + +int ShowTestWindow(lua_State* L) +{ + ImGui::ShowDemoWindow(); + return 0; +} + + +int SliderFloat(lua_State* L) +{ + auto* name = LuaWrapper::checkArg(L, 1); + float value = LuaWrapper::checkArg(L, 2); + float min = LuaWrapper::checkArg(L, 3); + float max = LuaWrapper::checkArg(L, 4); + bool changed = ImGui::SliderFloat(name, &value, min, max, ""); + lua_pushboolean(L, changed); + lua_pushnumber(L, value); + return 2; +} + + +int Text(lua_State* L) +{ + auto* text = LuaWrapper::checkArg(L, 1); + ImGui::Text("%s", text); + return 0; +} + + +int LabelText(lua_State* L) +{ + auto* label = LuaWrapper::checkArg(L, 1); + auto* text = LuaWrapper::checkArg(L, 2); + ImGui::LabelText(label, "%s", text); + return 0; +} + + +int Button(lua_State* L) +{ + auto* label = LuaWrapper::checkArg(L, 1); + ImVec2 size(0, 0); + if (lua_gettop(L) > 2) + { + size.x = LuaWrapper::checkArg(L, 2); + size.y = LuaWrapper::checkArg(L, 3); + } + bool clicked = ImGui::Button(label, size); + lua_pushboolean(L, clicked); + return 1; +} + + +int CollapsingHeader(lua_State* L) +{ + auto* label = LuaWrapper::checkArg(L, 1); + lua_pushboolean(L, ImGui::CollapsingHeader(label)); + return 1; +} + + +int CalcTextSize(lua_State* L) +{ + auto* text = LuaWrapper::checkArg(L, 1); + ImVec2 size = ImGui::CalcTextSize(text); + + LuaWrapper::push(L, size.x); + LuaWrapper::push(L, size.y); + return 2; +} + + +int Checkbox(lua_State* L) +{ + auto* label = LuaWrapper::checkArg(L, 1); + bool b = LuaWrapper::checkArg(L, 2); + bool clicked = ImGui::Checkbox(label, &b); + lua_pushboolean(L, clicked); + lua_pushboolean(L, b); + return 2; +} + + +int GetWindowPos(lua_State* L) +{ + ImVec2 pos = ImGui::GetWindowPos(); + LuaWrapper::push(L, Vec2(pos.x, pos.y)); + return 1; +} + + +int SetNextWindowPos(lua_State* L) +{ + ImVec2 pos; + pos.x = LuaWrapper::checkArg(L, 1); + pos.y = LuaWrapper::checkArg(L, 2); + ImGui::SetNextWindowPos(pos); + return 0; +} + + +int AlignTextToFramePadding(lua_State* L) +{ + ImGui::AlignTextToFramePadding(); + return 0; +} + + +int Selectable(lua_State* L) +{ + auto* label = LuaWrapper::checkArg(L, 1); + bool selected = false; + if (lua_gettop(L) > 1) + { + selected = LuaWrapper::checkArg(L, 2); + } + bool clicked = ImGui::Selectable(label, selected); + lua_pushboolean(L, clicked); + return 1; +} + + +int SetCursorScreenPos(lua_State* L) +{ + ImVec2 pos; + pos.x = LuaWrapper::checkArg(L, 1); + pos.y = LuaWrapper::checkArg(L, 2); + ImGui::SetCursorScreenPos(pos); + return 0; +} + + +int Separator(lua_State* L) +{ + ImGui::Separator(); + return 0; +} + + +void Rect(float w, float h, u32 color) +{ + ImGui::Rect(w, h, color); +} + + +void Dummy(float w, float h) +{ + ImGui::Dummy({w, h}); +} + + +bool IsItemHovered() +{ + return ImGui::IsItemHovered(); +} + + +bool IsMouseDown(int button) +{ + return ImGui::IsMouseDown(button); +} + + +bool IsMouseClicked(int button) +{ + return ImGui::IsMouseClicked(button); +} + + +int SetNextWindowPosCenter(lua_State* L) +{ + ImVec2 size = ImGui::GetIO().DisplaySize; + ImGui::SetNextWindowPos(ImVec2(size.x * 0.5f, size.y * 0.5f), 0, ImVec2(0.5f, 0.5f)); + return 0; +} + + +int SetNextWindowSize(float w, float h) +{ + ImGui::SetNextWindowSize(ImVec2(w, h)); + return 0; +} + + +int Begin(lua_State* L) +{ + auto* label = LuaWrapper::checkArg(L, 1); + ImGuiWindowFlags flags = 0; + if (lua_gettop(L) > 1) + { + flags = LuaWrapper::checkArg(L, 2); + } + bool res = ImGui::Begin(label, nullptr, flags); + lua_pushboolean(L, res); + return 1; +} + + +int BeginChildFrame(lua_State* L) +{ + auto* label = LuaWrapper::checkArg(L, 1); + ImVec2 size(0, 0); + if (lua_gettop(L) > 1) + { + size.x = LuaWrapper::checkArg(L, 2); + size.y = LuaWrapper::checkArg(L, 3); + } + bool res = ImGui::BeginChildFrame(ImGui::GetID(label), size); + lua_pushboolean(L, res); + return 1; +} + + +int BeginPopup(lua_State* L) +{ + auto* label = LuaWrapper::checkArg(L, 1); + bool res = ImGui::BeginPopup(label); + lua_pushboolean(L, res); + return 1; +} + + +int GetDisplayWidth(lua_State* L) +{ + float w = ImGui::GetIO().DisplaySize.x; + LuaWrapper::push(L, w); + return 1; +} + + +int GetDisplayHeight(lua_State* L) +{ + float w = ImGui::GetIO().DisplaySize.y; + LuaWrapper::push(L, w); + return 1; +} + + +int GetWindowWidth(lua_State* L) +{ + float w = ImGui::GetWindowWidth(); + LuaWrapper::push(L, w); + return 1; +} + + +int GetWindowHeight(lua_State* L) +{ + float w = ImGui::GetWindowHeight(); + LuaWrapper::push(L, w); + return 1; +} + + +int SameLine(lua_State* L) +{ + float pos_x = 0; + if (lua_gettop(L) > 0) + { + pos_x = LuaWrapper::checkArg(L, 1); + } + ImGui::SameLine(pos_x); + return 0; +} + + +void registerCFunction(lua_State* L, const char* name, lua_CFunction f) +{ + lua_pushcfunction(L, f); + lua_setfield(L, -2, name); +} + +} // namespace LuaImGui + + +struct SetPropertyLuaVisitor : public Reflection::IPropertyVisitor +{ + void visit(const Reflection::Property& prop) override + { + if (!equalStrings(property_name, prop.name)) return; + if (lua_isnumber(L, -1)) + { + float f = (float)lua_tonumber(L, -1); + InputMemoryStream input_blob(&f, sizeof(f)); + prop.setValue(cmp, -1, input_blob); + } + } + + + void visit(const Reflection::Property& prop) override + { + if (!equalStrings(property_name, prop.name)) return; + if (lua_isnumber(L, -1)) + { + int i = (int)lua_tointeger(L, -1); + InputMemoryStream input_blob(&i, sizeof(i)); + prop.setValue(cmp, -1, input_blob); + } + + } + + + void visit(const Reflection::Property& prop) override + { + if (!equalStrings(property_name, prop.name)) return; + if (lua_isnumber(L, -1)) + { + const u32 i = (u32)lua_tointeger(L, -1); + InputMemoryStream input_blob(&i, sizeof(i)); + prop.setValue(cmp, -1, input_blob); + } + + } + + + void visit(const Reflection::Property& prop) override + { + if (!equalStrings(property_name, prop.name)) return; + if (lua_isnumber(L, -1)) + { + int i = (int)lua_tointeger(L, -1); + InputMemoryStream input_blob(&i, sizeof(i)); + prop.setValue(cmp, -1, input_blob); + } + + } + + + void visit(const Reflection::Property& prop) override + { + if (!equalStrings(property_name, prop.name)) return; + if (lua_istable(L, -1)) + { + auto v = LuaWrapper::toType(L, -1); + InputMemoryStream input_blob(&v, sizeof(v)); + prop.setValue(cmp, -1, input_blob); + } + } + + + void visit(const Reflection::Property& prop) override + { + if (!equalStrings(property_name, prop.name)) return; + if (lua_istable(L, -1)) + { + auto v = LuaWrapper::toType(L, -1); + InputMemoryStream input_blob(&v, sizeof(v)); + prop.setValue(cmp, -1, input_blob); + } + } + + + void visit(const Reflection::Property& prop) override + { + if (!equalStrings(property_name, prop.name)) return; + if (lua_istable(L, -1)) + { + auto v = LuaWrapper::toType(L, -1); + InputMemoryStream input_blob(&v, sizeof(v)); + prop.setValue(cmp, -1, input_blob); + } + } + + + void visit(const Reflection::Property& prop) override + { + if (!equalStrings(property_name, prop.name)) return; + if (lua_istable(L, -1)) + { + auto v = LuaWrapper::toType(L, -1); + InputMemoryStream input_blob(&v, sizeof(v)); + prop.setValue(cmp, -1, input_blob); + } + } + + + void visit(const Reflection::Property& prop) override + { + if (!equalStrings(property_name, prop.name)) return; + if (lua_isstring(L, -1)) + { + const char* str = lua_tostring(L, -1); + InputMemoryStream input_blob(str, stringLength(str) + 1); + prop.setValue(cmp, -1, input_blob); + } + } + + + void visit(const Reflection::Property& prop) override + { + if (!equalStrings(property_name, prop.name)) return; + if (lua_isboolean(L, -1)) + { + bool b = lua_toboolean(L, -1) != 0; + InputMemoryStream input_blob(&b, sizeof(b)); + prop.setValue(cmp, -1, input_blob); + } + } + + + void visit(const Reflection::Property& prop) override + { + if (!equalStrings(property_name, prop.name)) return; + if (lua_isstring(L, -1)) + { + const char* str = lua_tostring(L, -1); + InputMemoryStream input_blob(str, stringLength(str) + 1); + prop.setValue(cmp, -1, input_blob); + } + } + + + void visit(const Reflection::IArrayProperty& prop) override + { + if (!equalStrings(property_name, prop.name)) return; + + if (lua_istable(L, -1)) { + const int count = (int)lua_objlen(L, -1); + for (int i = 0; i < count; ++i) { + prop.addItem(cmp, prop.getCount(cmp)); + } + } + } + + + void visit(const Reflection::IEnumProperty& prop) override { + if (!equalStrings(property_name, prop.name)) return; + if (lua_isstring(L, -1)) { + const char* str = lua_tostring(L, -1); + for (int i = 0, c = prop.getEnumCount(cmp); i < c; ++i) { + if (equalStrings(prop.getEnumName(cmp, i), str)) { + const int value = prop.getEnumValue(cmp, i); + InputMemoryStream input_blob(&value, sizeof(value)); + prop.setValue(cmp, -1, input_blob); + } + } + } + } + + + void visit(const Reflection::IBlobProperty& prop) override { notSupported(prop); } + void visit(const Reflection::ISampledFuncProperty& prop) override { notSupported(prop); } + + + void notSupported(const Reflection::PropertyBase& prop) + { + if (!equalStrings(property_name, prop.name)) return; + logError("Lua Script") << "Property " << prop.name << " has unsupported type"; + } + + + lua_State* L; + ComponentUID cmp; + const char* property_name; +}; + + + +static int LUA_packageLoader(lua_State* L) +{ + const char* module = LuaWrapper::toType(L, 1); + StaticString tmp(module); + tmp << ".lua"; + lua_getglobal(L, "g_engine"); + auto* engine = (Engine*)lua_touserdata(L, -1); + lua_pop(L, 1); + auto& fs = engine->getFileSystem(); + Array buf(engine->getAllocator()); + if (!fs.getContentSync(Path(tmp), Ref(buf))) { + logError("Engine") << "Failed to open file " << tmp; + StaticString msg("Failed to open file "); + msg << tmp; + lua_pushstring(L, msg); + } + else if (luaL_loadbuffer(L, (const char*)buf.begin(), buf.byte_size(), tmp) != 0) { + logError("Engine") << "Failed to load package " << tmp << ": " << lua_tostring(L, -1); + } + return 1; +} + + +static void installLuaPackageLoader(lua_State* L) +{ + lua_getglobal(L, "package"); + if (lua_type(L, -1) != LUA_TTABLE) { + logError("Engine") << "Lua \"package\" is not a table"; + return; + } + lua_getfield(L, -1, "searchers"); + if (lua_type(L, -1) != LUA_TTABLE) { + lua_pop(L, 1); + lua_getfield(L, -1, "loaders"); + if (lua_type(L, -1) != LUA_TTABLE) { + logError("Engine") << "Lua \"package.searchers\"/\"package.loaders\" is not a table"; + return; + } + } + int numLoaders = 0; + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + lua_pop(L, 1); + numLoaders++; + } + + lua_pushinteger(L, numLoaders + 1); + lua_pushcfunction(L, LUA_packageLoader); + lua_rawset(L, -3); + lua_pop(L, 2); +} + + +static bool LUA_hasFilesystemWork(Engine* engine) +{ + return engine->getFileSystem().hasWork(); +} + + +static void LUA_processFilesystemWork(Engine* engine) +{ + engine->getFileSystem().processCallbacks(); +} + + +static void LUA_startGame(Engine* engine, Universe* universe) +{ + if(engine && universe) engine->startGame(*universe); +} + + +static bool LUA_createComponent(Universe* universe, EntityRef entity, const char* type) +{ + if (!universe) return false; + ComponentType cmp_type = Reflection::getComponentType(type); + IScene* scene = universe->getScene(cmp_type); + if (!scene) return false; + if (universe->hasComponent(entity, cmp_type)) + { + logError("Lua Script") << "Component " << type << " already exists in entity " << entity.index; + return false; + } + + universe->createComponent(cmp_type, entity); + return true; +} + + +static EntityRef LUA_createEntity(Universe* univ) +{ + return univ->createEntity(DVec3(0, 0, 0), Quat(0, 0, 0, 1)); +} + + +static int LUA_getComponentType(const char* component_type) +{ + return Reflection::getComponentType(component_type).index; +} + + +static int LUA_getComponentTypesCount() +{ + return Reflection::getComponentTypesCount(); +} + + +static int LUA_getComponentTypeByIndex(int index) +{ + const char* id = Reflection::getComponentTypeID(index); + return Reflection::getComponentType(id).index; +} + + +static int LUA_createEntityEx(lua_State* L) +{ + auto* ctx = LuaWrapper::checkArg(L, 2); + LuaWrapper::checkTableArg(L, 3); + + EntityRef e = ctx->createEntity(DVec3(0, 0, 0), Quat(0, 0, 0, 1)); + + lua_pushvalue(L, 3); + lua_getfield(L, -1, "parent"); + if (lua_type(L, -1) != LUA_TNIL) + { + EntityRef parent = LuaWrapper::toType(L, -1); + ctx->setParent(parent, e); + } + lua_pop(L, 1); + + lua_pushnil(L); + while (lua_next(L, -2) != 0) + { + const char* parameter_name = luaL_checkstring(L, -2); + if (equalStrings(parameter_name, "position")) + { + auto pos = LuaWrapper::toType(L, -1); + ctx->setPosition(e, pos); + } + else if (equalStrings(parameter_name, "pitch")) + { + const float angle = LuaWrapper::toType(L, -1); + const Quat rot(Vec3(1, 0, 0), degreesToRadians(angle)); + ctx->setRotation(e, rot); + } + else if (equalStrings(parameter_name, "rotation")) + { + auto rot = LuaWrapper::toType(L, -1); + ctx->setRotation(e, rot); + } + else + { + ComponentType cmp_type = Reflection::getComponentType(parameter_name); + IScene* scene = ctx->getScene(cmp_type); + if (scene) + { + ComponentUID cmp(e, cmp_type, scene); + const Reflection::ComponentBase* cmp_des = Reflection::getComponent(cmp_type); + ctx->createComponent(cmp_type, e); + lua_pushvalue(L, -1); + lua_pushnil(L); + while (lua_next(L, -2) != 0) + { + const char* property_name = luaL_checkstring(L, -2); + SetPropertyLuaVisitor v; + v.property_name = property_name; + v.cmp = cmp; + v.L = L; + cmp_des->visit(v); + + lua_pop(L, 1); + } + lua_pop(L, 1); + } + } + lua_pop(L, 1); + } + lua_pop(L, 1); + + LuaWrapper::push(L, e); + return 1; +} + + +static int LUA_setEntityRotation(lua_State* L) +{ + Universe* univ = LuaWrapper::checkArg(L, 1); + int entity_index = LuaWrapper::checkArg(L, 2); + if (entity_index < 0) return 0; + + if (lua_gettop(L) > 3) + { + Vec3 axis = LuaWrapper::checkArg(L, 3); + float angle = LuaWrapper::checkArg(L, 4); + univ->setRotation({ entity_index }, Quat(axis, angle)); + } + else + { + Quat rot = LuaWrapper::checkArg(L, 3); + univ->setRotation({ entity_index }, rot); + } + return 0; +} + + +static IScene* LUA_getScene(Universe* universe, const char* name) +{ + u32 hash = crc32(name); + return universe->getScene(hash); +} + + +static int LUA_loadResource(Engine* engine, const char* path, const char* type) +{ + return engine->addLuaResource(Path(path), ResourceType(type)); +} + + +static void LUA_setEntityLocalRotation(Universe* universe, EntityRef entity, const Quat& rotation) +{ + if (!universe->getParent(entity).isValid()) return; + + universe->setLocalRotation(entity, rotation); +} + + +static void LUA_setEntityLocalPosition(Universe* universe, EntityRef entity, const DVec3& position) +{ + if (!universe->getParent(entity).isValid()) return; + + universe->setLocalPosition(entity, position); +} + +static int LUA_multVecQuat(lua_State* L) +{ + Vec3 v = LuaWrapper::checkArg(L, 1); + Quat q; + if (LuaWrapper::isType(L, 2)) + { + q = LuaWrapper::checkArg(L, 2); + } + else + { + Vec3 axis = LuaWrapper::checkArg(L, 2); + float angle = LuaWrapper::checkArg(L, 3); + + q = Quat(axis, angle); + } + + Vec3 res = q.rotate(v); + + LuaWrapper::push(L, res); + return 1; +} + + +static DVec3 LUA_getEntityPosition(Universe* universe, EntityRef entity) +{ + return universe->getPosition(entity); +} + + +static Quat LUA_getEntityRotation(Universe* universe, EntityRef entity) +{ + return universe->getRotation(entity); +} + + +static Vec3 LUA_getEntityDirection(Universe* universe, EntityRef entity) +{ + Quat rot = universe->getRotation(entity); + return rot.rotate(Vec3(0, 0, 1)); +} + +static void LUA_setEntityPosition(Universe* univ, EntityRef entity, const DVec3& pos) { univ->setPosition(entity, pos); } +static float LUA_getLastTimeDelta(Engine* engine) { return engine->getLastTimeDelta(); } +static void LUA_unloadResource(Engine* engine, int resource_idx) { engine->unloadLuaResource(resource_idx); } +static Universe* LUA_createUniverse(Engine* engine) { return &engine->createUniverse(false); } +static void LUA_destroyUniverse(Engine* engine, Universe* universe) { engine->destroyUniverse(*universe); } +static Universe* LUA_getSceneUniverse(IScene* scene) { return &scene->getUniverse(); } +static void LUA_logError(const char* text) { logError("Lua Script") << text; } +static void LUA_logInfo(const char* text) { logInfo("Lua Script") << text; } +static void LUA_pause(Engine* engine, bool pause) { engine->pause(pause); } +static void LUA_nextFrame(Engine* engine) { engine->nextFrame(); } +static void LUA_setTimeMultiplier(Engine* engine, float multiplier) { engine->setTimeMultiplier(multiplier); } +static Vec4 LUA_multMatrixVec(const Matrix& m, const Vec4& v) { return m * v; } +static Quat LUA_multQuat(const Quat& a, const Quat& b) { return a * b; } + +static int LUA_loadUniverse(lua_State* L) +{ + auto* engine = LuaWrapper::checkArg(L, 1); + auto* universe = LuaWrapper::checkArg(L, 2); + auto* path = LuaWrapper::checkArg(L, 3); + if (!lua_isfunction(L, 4)) LuaWrapper::argError(L, 4, "function"); + FileSystem& fs = engine->getFileSystem(); + FileSystem::ContentCallback cb; + struct Callback + { + ~Callback() + { + luaL_unref(L, LUA_REGISTRYINDEX, lua_func); + } + + void invoke(u64 size, const u8* mem, bool success) + { + if (!success) + { + logError("Engine") << "Failed to open universe " << path; + } + else + { + InputMemoryStream blob(mem, size); + #pragma pack(1) + struct Header + { + u32 magic; + int version; + u32 hash; + u32 engine_hash; + }; + #pragma pack() + Header header; + blob.read(&header, sizeof(header)); + + if (!engine->deserialize(*universe, blob)) + { + logError("Engine") << "Failed to deserialize universe " << path; + } + else + { + lua_rawgeti(L, LUA_REGISTRYINDEX, lua_func); + if (lua_type(L, -1) != LUA_TFUNCTION) + { + ASSERT(false); + } + + if (lua_pcall(L, 0, 0, 0) != 0) + { + logError("Engine") << lua_tostring(L, -1); + lua_pop(L, 1); + } + } + } + LUMIX_DELETE(engine->getAllocator(), this); + } + + Engine* engine; + Universe* universe; + Path path; + lua_State* L; + int lua_func; + }; + Callback* inst = LUMIX_NEW(engine->getAllocator(), Callback); + inst->engine = engine; + inst->universe = universe; + inst->path = path; + inst->L = L; + inst->lua_func = luaL_ref(L, LUA_REGISTRYINDEX); + cb.bind<&Callback::invoke>(inst); + fs.getContent(inst->path, cb); + return 0; +} + + +static int LUA_instantiatePrefab(lua_State* L) +{ + auto* engine = LuaWrapper::checkArg(L, 1); + auto* universe = LuaWrapper::checkArg(L, 2); + DVec3 position = LuaWrapper::checkArg(L, 3); + int prefab_id = LuaWrapper::checkArg(L, 4); + PrefabResource* prefab = static_cast(engine->getLuaResource(prefab_id)); + if (!prefab) + { + logError("Editor") << "Cannot instantiate null prefab."; + return 0; + } + if (!prefab->isReady()) + { + logError("Editor") << "Prefab " << prefab->getPath().c_str() << " is not ready, preload it."; + return 0; + } + EntityPtr entity = universe->instantiatePrefab(*prefab, position, {0, 0, 0, 1}, 1); + + LuaWrapper::push(L, entity); + return 1; +} + + +void registerEngineAPI(lua_State* L, Engine* engine) +{ + lua_pushlightuserdata(L, engine); + lua_setglobal(L, "g_engine"); + + #define REGISTER_FUNCTION(name) \ + LuaWrapper::createSystemFunction(L, "Engine", #name, \ + &LuaWrapper::wrap); \ + + REGISTER_FUNCTION(createComponent); + REGISTER_FUNCTION(createEntity); + REGISTER_FUNCTION(createUniverse); + REGISTER_FUNCTION(destroyUniverse); + REGISTER_FUNCTION(getComponentType); + REGISTER_FUNCTION(getComponentTypeByIndex); + REGISTER_FUNCTION(getComponentTypesCount); + REGISTER_FUNCTION(getEntityDirection); + REGISTER_FUNCTION(getEntityPosition); + REGISTER_FUNCTION(getEntityRotation); + REGISTER_FUNCTION(getLastTimeDelta); + REGISTER_FUNCTION(getScene); + REGISTER_FUNCTION(getSceneUniverse); + REGISTER_FUNCTION(hasFilesystemWork); + REGISTER_FUNCTION(loadResource); + REGISTER_FUNCTION(logError); + REGISTER_FUNCTION(logInfo); + REGISTER_FUNCTION(multMatrixVec); + REGISTER_FUNCTION(multQuat); + REGISTER_FUNCTION(nextFrame); + REGISTER_FUNCTION(pause); + REGISTER_FUNCTION(processFilesystemWork); + REGISTER_FUNCTION(setEntityLocalPosition); + REGISTER_FUNCTION(setEntityLocalRotation); + REGISTER_FUNCTION(setEntityPosition); + REGISTER_FUNCTION(setEntityRotation); + REGISTER_FUNCTION(setTimeMultiplier); + REGISTER_FUNCTION(startGame); + REGISTER_FUNCTION(unloadResource); + + LuaWrapper::createSystemFunction(L, "Engine", "loadUniverse", LUA_loadUniverse); + + #undef REGISTER_FUNCTION + + #define REGISTER_FUNCTION(F) \ + do { \ + auto f = &LuaWrapper::wrapMethod<&Universe::F>; \ + LuaWrapper::createSystemFunction(L, "Engine", #F, f); \ + } while(false) + + REGISTER_FUNCTION(cloneEntity); + REGISTER_FUNCTION(destroyEntity); + REGISTER_FUNCTION(findByName); + REGISTER_FUNCTION(getFirstChild); + REGISTER_FUNCTION(getFirstEntity); + REGISTER_FUNCTION(getNextEntity); + REGISTER_FUNCTION(getNextSibling); + REGISTER_FUNCTION(getParent); + REGISTER_FUNCTION(hasComponent); + REGISTER_FUNCTION(setParent); + + #undef REGISTER_FUNCTION + + LuaWrapper::createSystemFunction(L, "Engine", "instantiatePrefab", &LUA_instantiatePrefab); + LuaWrapper::createSystemFunction(L, "Engine", "createEntityEx", &LUA_createEntityEx); + LuaWrapper::createSystemFunction(L, "Engine", "multVecQuat", &LUA_multVecQuat); + + lua_newtable(L); + lua_pushvalue(L, -1); + lua_setglobal(L, "ImGui"); + + LuaWrapper::createSystemVariable(L, "ImGui", "WindowFlags_NoMove", ImGuiWindowFlags_NoMove); + LuaWrapper::createSystemVariable(L, "ImGui", "WindowFlags_NoCollapse", ImGuiWindowFlags_NoCollapse); + LuaWrapper::createSystemVariable(L, "ImGui", "WindowFlags_NoInputs", ImGuiWindowFlags_NoInputs); + LuaWrapper::createSystemVariable(L, "ImGui", "WindowFlags_NoResize", ImGuiWindowFlags_NoResize); + LuaWrapper::createSystemVariable(L, "ImGui", "WindowFlags_NoTitleBar", ImGuiWindowFlags_NoTitleBar); + LuaWrapper::createSystemVariable(L, "ImGui", "WindowFlags_NoScrollbar", ImGuiWindowFlags_NoScrollbar); + LuaWrapper::createSystemVariable(L, "ImGui", "WindowFlags_AlwaysAutoResize", ImGuiWindowFlags_AlwaysAutoResize); + LuaWrapper::createSystemVariable(L, "ImGui", "Col_FrameBg", ImGuiCol_FrameBg); + LuaWrapper::createSystemVariable(L, "ImGui", "Col_WindowBg", ImGuiCol_WindowBg); + LuaWrapper::createSystemVariable(L, "ImGui", "Col_Button", ImGuiCol_Button); + LuaWrapper::createSystemVariable(L, "ImGui", "Col_ButtonActive", ImGuiCol_ButtonActive); + LuaWrapper::createSystemVariable(L, "ImGui", "Col_ButtonHovered", ImGuiCol_ButtonHovered); + LuaWrapper::createSystemVariable(L, "ImGui", "StyleVar_FramePadding", ImGuiStyleVar_FramePadding); + LuaWrapper::createSystemVariable(L, "ImGui", "StyleVar_IndentSpacing", ImGuiStyleVar_IndentSpacing); + LuaWrapper::createSystemVariable(L, "ImGui", "StyleVar_ItemSpacing", ImGuiStyleVar_ItemSpacing); + LuaWrapper::createSystemVariable(L, "ImGui", "StyleVar_ItemInnerSpacing", ImGuiStyleVar_ItemInnerSpacing); + LuaWrapper::createSystemVariable(L, "ImGui", "StyleVar_WindowPadding", ImGuiStyleVar_WindowPadding); + LuaImGui::registerCFunction(L, "AlignTextToFramePadding", &LuaImGui::AlignTextToFramePadding); + LuaImGui::registerCFunction(L, "Begin", &LuaImGui::Begin); + LuaImGui::registerCFunction(L, "BeginChildFrame", &LuaImGui::BeginChildFrame); + LuaImGui::registerCFunction(L, "BeginPopup", LuaImGui::BeginPopup); + LuaImGui::registerCFunction(L, "Button", &LuaImGui::Button); + LuaImGui::registerCFunction(L, "CalcTextSize", &LuaImGui::CalcTextSize); + LuaImGui::registerCFunction(L, "Checkbox", &LuaImGui::Checkbox); + LuaImGui::registerCFunction(L, "CollapsingHeader", &LuaImGui::CollapsingHeader); + LuaImGui::registerCFunction(L, "Columns", &LuaWrapper::wrap<&ImGui::Columns>); + LuaImGui::registerCFunction(L, "DragFloat", &LuaImGui::DragFloat); + LuaImGui::registerCFunction(L, "DragInt", &LuaImGui::DragInt); + LuaImGui::registerCFunction(L, "Dummy", &LuaWrapper::wrap<&LuaImGui::Dummy>); + LuaImGui::registerCFunction(L, "End", &LuaWrapper::wrap<&ImGui::End>); + LuaImGui::registerCFunction(L, "EndChildFrame", &LuaWrapper::wrap<&ImGui::EndChildFrame>); + LuaImGui::registerCFunction(L, "EndPopup", &LuaWrapper::wrap<&ImGui::EndPopup>); + LuaImGui::registerCFunction(L, "GetColumnWidth", &LuaWrapper::wrap<&ImGui::GetColumnWidth>); + LuaImGui::registerCFunction(L, "GetDisplayWidth", &LuaImGui::GetDisplayWidth); + LuaImGui::registerCFunction(L, "GetDisplayHeight", &LuaImGui::GetDisplayHeight); + LuaImGui::registerCFunction(L, "GetWindowWidth", &LuaImGui::GetWindowWidth); + LuaImGui::registerCFunction(L, "GetWindowHeight", &LuaImGui::GetWindowHeight); + LuaImGui::registerCFunction(L, "GetWindowPos", &LuaImGui::GetWindowPos); + LuaImGui::registerCFunction(L, "Indent", &LuaWrapper::wrap<&ImGui::Indent>); + LuaImGui::registerCFunction(L, "InputTextMultiline", &LuaImGui::InputTextMultiline); + LuaImGui::registerCFunction(L, "IsItemHovered", &LuaWrapper::wrap<&LuaImGui::IsItemHovered>); + LuaImGui::registerCFunction(L, "IsMouseClicked", &LuaWrapper::wrap<&LuaImGui::IsMouseClicked>); + LuaImGui::registerCFunction(L, "IsMouseDown", &LuaWrapper::wrap<&LuaImGui::IsMouseDown>); + LuaImGui::registerCFunction(L, "NewLine", &LuaWrapper::wrap<&ImGui::NewLine>); + LuaImGui::registerCFunction(L, "NextColumn", &LuaWrapper::wrap<&ImGui::NextColumn>); + LuaImGui::registerCFunction(L, "OpenPopup", &LuaWrapper::wrap<&ImGui::OpenPopup>); + LuaImGui::registerCFunction(L, "PopItemWidth", &LuaWrapper::wrap<&ImGui::PopItemWidth>); + LuaImGui::registerCFunction(L, "PopID", &LuaWrapper::wrap<&ImGui::PopID>); + LuaImGui::registerCFunction(L, "PopStyleColor", &LuaWrapper::wrap<&ImGui::PopStyleColor>); + LuaImGui::registerCFunction(L, "PopStyleVar", &LuaWrapper::wrap<&ImGui::PopStyleVar>); + LuaImGui::registerCFunction(L, "PushItemWidth", &LuaWrapper::wrap<&ImGui::PushItemWidth>); + LuaImGui::registerCFunction(L, "PushID", &LuaImGui::PushID); + LuaImGui::registerCFunction(L, "PushStyleColor", &LuaImGui::PushStyleColor); + LuaImGui::registerCFunction(L, "PushStyleVar", &LuaImGui::PushStyleVar); + LuaImGui::registerCFunction(L, "Rect", &LuaWrapper::wrap<&LuaImGui::Rect>); + LuaImGui::registerCFunction(L, "SameLine", &LuaImGui::SameLine); + LuaImGui::registerCFunction(L, "Selectable", &LuaImGui::Selectable); + LuaImGui::registerCFunction(L, "Separator", &LuaImGui::Separator); + LuaImGui::registerCFunction(L, "SetCursorScreenPos", &LuaImGui::SetCursorScreenPos); + LuaImGui::registerCFunction(L, "SetNextWindowPos", &LuaImGui::SetNextWindowPos); + LuaImGui::registerCFunction(L, "SetNextWindowPosCenter", &LuaImGui::SetNextWindowPosCenter); + LuaImGui::registerCFunction(L, "SetNextWindowSize", &LuaWrapper::wrap<&LuaImGui::SetNextWindowSize>); + LuaImGui::registerCFunction(L, "SetStyleColor", &LuaImGui::SetStyleColor); + LuaImGui::registerCFunction(L, "ShowTestWindow", &LuaImGui::ShowTestWindow); + LuaImGui::registerCFunction(L, "SliderFloat", &LuaImGui::SliderFloat); + LuaImGui::registerCFunction(L, "Text", &LuaImGui::Text); + LuaImGui::registerCFunction(L, "Unindent", &LuaWrapper::wrap<&ImGui::Unindent>); + LuaImGui::registerCFunction(L, "LabelText", &LuaImGui::LabelText); + + LuaWrapper::createSystemVariable(L, "Engine", "INPUT_DEVICE_KEYBOARD", InputSystem::Device::KEYBOARD); + LuaWrapper::createSystemVariable(L, "Engine", "INPUT_DEVICE_MOUSE", InputSystem::Device::MOUSE); + LuaWrapper::createSystemVariable(L, "Engine", "INPUT_DEVICE_CONTROLLER", InputSystem::Device::CONTROLLER); + + LuaWrapper::createSystemVariable(L, "Engine", "INPUT_BUTTON_STATE_UP", InputSystem::ButtonEvent::UP); + LuaWrapper::createSystemVariable(L, "Engine", "INPUT_BUTTON_STATE_DOWN", InputSystem::ButtonEvent::DOWN); + LuaWrapper::createSystemVariable(L, "Engine", "INPUT_EVENT_BUTTON", InputSystem::Event::BUTTON); + LuaWrapper::createSystemVariable(L, "Engine", "INPUT_EVENT_AXIS", InputSystem::Event::AXIS); + LuaWrapper::createSystemVariable(L, "Engine", "INPUT_EVENT_TEXT_INPUT", InputSystem::Event::TEXT_INPUT); + LuaWrapper::createSystemVariable(L, "Engine", "INPUT_EVENT_DEVICE_ADDED", InputSystem::Event::DEVICE_ADDED); + LuaWrapper::createSystemVariable(L, "Engine", "INPUT_EVENT_DEVICE_REMOVED", InputSystem::Event::DEVICE_REMOVED); + + lua_pop(L, 1); + + installLuaPackageLoader(L); +} + + +} // namespace Lumix diff --git a/src/engine/resource.cpp b/src/engine/resource.cpp index f12692c0a..5f324be78 100644 --- a/src/engine/resource.cpp +++ b/src/engine/resource.cpp @@ -143,7 +143,7 @@ void Resource::doLoad() FileSystem& fs = m_resource_manager.getOwner().getFileSystem(); FileSystem::ContentCallback cb; - cb.bind(this); + cb.bind<&Resource::fileLoaded>(this); const u32 hash = m_path.getHash(); const StaticString res_path(".lumix/assets/", hash, ".res"); @@ -156,7 +156,7 @@ void Resource::addDependency(Resource& dependent_resource) { ASSERT(m_desired_state != State::EMPTY); - dependent_resource.m_cb.bind(this); + dependent_resource.m_cb.bind<&Resource::onStateChanged>(this); if (dependent_resource.isEmpty()) ++m_empty_dep_count; if (dependent_resource.isFailure()) { ++m_failed_dep_count; @@ -168,7 +168,7 @@ void Resource::addDependency(Resource& dependent_resource) void Resource::removeDependency(Resource& dependent_resource) { - dependent_resource.m_cb.unbind(this); + dependent_resource.m_cb.unbind<&Resource::onStateChanged>(this); if (dependent_resource.isEmpty()) { ASSERT(m_empty_dep_count > 0); diff --git a/src/engine/resource.h b/src/engine/resource.h index 4632ace39..cecd922ee 100644 --- a/src/engine/resource.h +++ b/src/engine/resource.h @@ -56,9 +56,9 @@ public: const Path& getPath() const { return m_path; } ResourceManager& getResourceManager() { return m_resource_manager; } - template void onLoaded(C* instance) + template void onLoaded(C* instance) { - m_cb.bind(instance); + m_cb.bind(instance); if (isReady()) { (instance->*Function)(State::READY, State::READY, *this); diff --git a/src/gui/editor/plugins.cpp b/src/gui/editor/plugins.cpp index dd985ed6a..5c77ade9c 100644 --- a/src/gui/editor/plugins.cpp +++ b/src/gui/editor/plugins.cpp @@ -228,8 +228,8 @@ public: IAllocator& allocator = app.getWorldEditor().getAllocator(); Action* action = LUMIX_NEW(allocator, Action)("GUI Editor", "Toggle gui editor", "gui_editor"); - action->func.bind(this); - action->is_selected.bind(this); + action->func.bind<&GUIEditor::onAction>(this); + action->is_selected.bind<&GUIEditor::isOpen>(this); app.addWindowAction(action); m_editor = &app.getWorldEditor(); @@ -237,15 +237,15 @@ public: PipelineResource* pres = m_editor->getEngine().getResourceManager().load(Path("pipelines/gui_editor.pln")); m_pipeline = Pipeline::create(renderer, pres, "", allocator); - m_editor->universeCreated().bind(this); - m_editor->universeDestroyed().bind(this); + m_editor->universeCreated().bind<&GUIEditor::onUniverseChanged>(this); + m_editor->universeDestroyed().bind<&GUIEditor::onUniverseChanged>(this); } ~GUIEditor() { - m_editor->universeCreated().unbind(this); - m_editor->universeDestroyed().unbind(this); + m_editor->universeCreated().unbind<&GUIEditor::onUniverseChanged>(this); + m_editor->universeDestroyed().unbind<&GUIEditor::onUniverseChanged>(this); Pipeline::destroy(m_pipeline); } diff --git a/src/gui/gui_scene.cpp b/src/gui/gui_scene.cpp index 088397106..ab570019b 100644 --- a/src/gui/gui_scene.cpp +++ b/src/gui/gui_scene.cpp @@ -47,11 +47,11 @@ struct GUIText m_font_resource->removeRef(*m_font); m_font = nullptr; } - m_font_resource->getObserverCb().unbind(this); + m_font_resource->getObserverCb().unbind<&GUIText::onFontLoaded>(this); m_font_resource->getResourceManager().unload(*m_font_resource); } m_font_resource = res; - if (res) res->onLoaded(this); + if (res) res->onLoaded<&GUIText::onFontLoaded>(this); } diff --git a/src/gui/gui_system.cpp b/src/gui/gui_system.cpp index 33a5bb08a..b26b1de1b 100644 --- a/src/gui/gui_system.cpp +++ b/src/gui/gui_system.cpp @@ -196,7 +196,7 @@ struct GUISystemImpl final : public GUISystem auto* pipeline = m_interface->getPipeline(); pipeline->addCustomCommandHandler("renderIngameGUI") - .callback.bind(this); + .callback.bind<&GUISystemImpl::pipelineCallback>(this); } diff --git a/src/lua_script/editor/plugins.cpp b/src/lua_script/editor/plugins.cpp index 4e1da1688..eeb25bb71 100644 --- a/src/lua_script/editor/plugins.cpp +++ b/src/lua_script/editor/plugins.cpp @@ -528,8 +528,8 @@ struct ConsolePlugin final : public StudioApp::GUIPlugin , autocomplete(_app.getWorldEditor().getAllocator()) { Action* action = LUMIX_NEW(app.getWorldEditor().getAllocator(), Action)("Script Console", "Toggle script console", "script_console"); - action->func.bind(this); - action->is_selected.bind(this); + action->func.bind<&ConsolePlugin::toggleOpen>(this); + action->is_selected.bind<&ConsolePlugin::isOpen>(this); app.addWindowAction(action); buf[0] = '\0'; } diff --git a/src/lua_script/lua_script_system.cpp b/src/lua_script/lua_script_system.cpp index 3ed991cac..b5ca02221 100644 --- a/src/lua_script/lua_script_system.cpp +++ b/src/lua_script/lua_script_system.cpp @@ -1095,14 +1095,14 @@ namespace Lumix if (inst.m_state) destroyInstance(cmp, inst); inst.m_properties.clear(); auto& cb = inst.m_script->getObserverCb(); - cb.unbind(&cmp); + cb.unbind<&ScriptComponent::onScriptLoaded>(&cmp); inst.m_script->getResourceManager().unload(*inst.m_script); } ResourceManagerHub& rm = m_system.m_engine.getResourceManager(); inst.m_script = path.isValid() ? rm.load(path) : nullptr; if (inst.m_script) { - inst.m_script->onLoaded(&cmp); + inst.m_script->onLoaded<&ScriptComponent::onScriptLoaded>(&cmp); } } @@ -1183,9 +1183,9 @@ namespace Lumix m_gui_scene = (GUIScene*)m_universe.getScene(crc32("gui")); if (m_gui_scene) { - m_gui_scene->buttonClicked().bind(this); - m_gui_scene->rectHovered().bind(this); - m_gui_scene->rectHoveredOut().bind(this); + m_gui_scene->buttonClicked().bind<&LuaScriptSceneImpl::onButtonClicked>(this); + m_gui_scene->rectHovered().bind<&LuaScriptSceneImpl::onRectHovered>(this); + m_gui_scene->rectHoveredOut().bind<&LuaScriptSceneImpl::onRectHoveredOut>(this); } } @@ -1194,9 +1194,9 @@ namespace Lumix { if (m_gui_scene) { - m_gui_scene->buttonClicked().unbind(this); - m_gui_scene->rectHovered().unbind(this); - m_gui_scene->rectHoveredOut().unbind(this); + m_gui_scene->buttonClicked().unbind<&LuaScriptSceneImpl::onButtonClicked>(this); + m_gui_scene->rectHovered().unbind<&LuaScriptSceneImpl::onRectHovered>(this); + m_gui_scene->rectHoveredOut().unbind<&LuaScriptSceneImpl::onRectHoveredOut>(this); } m_gui_scene = nullptr; m_scripts_start_called = false; @@ -1226,7 +1226,7 @@ namespace Lumix if (scr.m_script) { auto& cb = scr.m_script->getObserverCb(); - cb.unbind(script); + cb.unbind<&ScriptComponent::onScriptLoaded>(script); m_system.getScriptManager().unload(*scr.m_script); } } diff --git a/src/navigation/navigation_scene.cpp b/src/navigation/navigation_scene.cpp index da81e2cc1..b51719df5 100644 --- a/src/navigation/navigation_scene.cpp +++ b/src/navigation/navigation_scene.cpp @@ -97,7 +97,7 @@ struct NavigationSceneImpl final : public NavigationScene , m_on_update(m_allocator) { setGeneratorParams(0.3f, 0.1f, 0.3f, 2.0f, 60.0f, 0.3f); - m_universe.entityTransformed().bind(this); + m_universe.entityTransformed().bind<&NavigationSceneImpl::onEntityMoved>(this); universe.registerComponentType(NAVMESH_AGENT_TYPE , this , &NavigationSceneImpl::createAgent @@ -115,7 +115,7 @@ struct NavigationSceneImpl final : public NavigationScene ~NavigationSceneImpl() { - m_universe.entityTransformed().unbind(this); + m_universe.entityTransformed().unbind<&NavigationSceneImpl::onEntityMoved>(this); for(RecastZone& zone : m_zones) { clearNavmesh(zone); } @@ -699,7 +699,7 @@ struct NavigationSceneImpl final : public NavigationScene LoadCallback* lcb = LUMIX_NEW(m_allocator, LoadCallback)(*this, zone_entity); FileSystem::ContentCallback cb; - cb.bind(lcb); + cb.bind<&LoadCallback::fileLoaded>(lcb); FileSystem& fs = m_engine.getFileSystem(); return fs.getContent(Path(path), cb).isValid(); } diff --git a/src/physics/editor/plugins.cpp b/src/physics/editor/plugins.cpp index ac24a96d8..27c0e4cc8 100644 --- a/src/physics/editor/plugins.cpp +++ b/src/physics/editor/plugins.cpp @@ -357,8 +357,8 @@ struct PhysicsUIPlugin final : public StudioApp::GUIPlugin , m_is_window_open(false) { Action* action = LUMIX_NEW(m_editor.getAllocator(), Action)("Physics", "Toggle physics UI", "physics"); - action->func.bind(this); - action->is_selected.bind(this); + action->func.bind<&PhysicsUIPlugin::onAction>(this); + action->is_selected.bind<&PhysicsUIPlugin::isOpen>(this); app.addWindowAction(action); } diff --git a/src/physics/physics_scene.cpp b/src/physics/physics_scene.cpp index 0831cf040..93567bde2 100644 --- a/src/physics/physics_scene.cpp +++ b/src/physics/physics_scene.cpp @@ -1451,14 +1451,14 @@ struct PhysicsSceneImpl final : public PhysicsScene { old_hm->getResourceManager().unload(*old_hm); auto& cb = old_hm->getObserverCb(); - cb.unbind(&terrain); + cb.unbind<&Heightfield::heightmapLoaded>(&terrain); } if (str.isValid()) { auto* new_hm = resource_manager.load(str); terrain.m_heightmap = new_hm; - new_hm->onLoaded(&terrain); + new_hm->onLoaded<&Heightfield::heightmapLoaded>(&terrain); new_hm->addDataReference(); } else @@ -5055,8 +5055,8 @@ struct PhysicsSceneImpl final : public PhysicsScene PhysicsScene* PhysicsScene::create(PhysicsSystem& system, Universe& context, Engine& engine, IAllocator& allocator) { PhysicsSceneImpl* impl = LUMIX_NEW(allocator, PhysicsSceneImpl)(context, allocator); - impl->m_universe.entityTransformed().bind(impl); - impl->m_universe.entityDestroyed().bind(impl); + impl->m_universe.entityTransformed().bind<&PhysicsSceneImpl::onEntityMoved>(impl); + impl->m_universe.entityDestroyed().bind<&PhysicsSceneImpl::onEntityDestroyed>(impl); impl->m_engine = &engine; PxSceneDesc sceneDesc(system.getPhysics()->getTolerancesScale()); sceneDesc.gravity = PxVec3(0.0f, -9.8f, 0.0f); @@ -5151,13 +5151,13 @@ void PhysicsSceneImpl::RigidActor::setResource(PhysicsGeometry* _resource) { if (resource) { - resource->getObserverCb().unbind(this); + resource->getObserverCb().unbind<&RigidActor::onStateChanged>(this); resource->getResourceManager().unload(*resource); } resource = _resource; if (resource) { - resource->onLoaded(this); + resource->onLoaded<&RigidActor::onStateChanged>(this); } } @@ -5178,7 +5178,7 @@ Heightfield::~Heightfield() if (m_heightmap) { m_heightmap->getResourceManager().unload(*m_heightmap); - m_heightmap->getObserverCb().unbind(this); + m_heightmap->getObserverCb().unbind<&Heightfield::heightmapLoaded>(this); } } diff --git a/src/renderer/editor/game_view.cpp b/src/renderer/editor/game_view.cpp index 573dec048..c60e4f514 100644 --- a/src/renderer/editor/game_view.cpp +++ b/src/renderer/editor/game_view.cpp @@ -68,20 +68,20 @@ GameView::GameView(StudioApp& app) WorldEditor& editor = app.getWorldEditor(); Action* action = LUMIX_NEW(editor.getAllocator(), Action)("Game View", "Toggle game view", "game_view"); - action->func.bind(this); - action->is_selected.bind(this); + action->func.bind<&GameView::onAction>(this); + action->is_selected.bind<&GameView::isOpen>(this); app.addWindowAction(action); Action* fullscreen_action = LUMIX_NEW(editor.getAllocator(), Action)("Game View fullscreen", "Game View fullscreen", "game_view_fullscreen"); - fullscreen_action->func.bind(this); + fullscreen_action->func.bind<&GameView::toggleFullscreen>(this); app.addAction(fullscreen_action); auto* renderer = (Renderer*)engine.getPluginManager().getPlugin("renderer"); PipelineResource* pres = engine.getResourceManager().load(Path("pipelines/main.pln")); m_pipeline = Pipeline::create(*renderer, pres, "GAME_VIEW", engine.getAllocator()); - editor.universeCreated().bind(this); - editor.universeDestroyed().bind(this); + editor.universeCreated().bind<&GameView::onUniverseCreated>(this); + editor.universeDestroyed().bind<&GameView::onUniverseDestroyed>(this); if (editor.getUniverse()) onUniverseCreated(); auto* gui = static_cast(engine.getPluginManager().getPlugin("gui")); @@ -95,8 +95,8 @@ GameView::GameView(StudioApp& app) GameView::~GameView() { - m_editor.universeCreated().unbind(this); - m_editor.universeDestroyed().unbind(this); + m_editor.universeCreated().unbind<&GameView::onUniverseCreated>(this); + m_editor.universeDestroyed().unbind<&GameView::onUniverseDestroyed>(this); auto* gui = static_cast(m_editor.getEngine().getPluginManager().getPlugin("gui")); if (gui) { diff --git a/src/renderer/editor/plugins.cpp b/src/renderer/editor/plugins.cpp index 9e7943ba4..3886729ac 100644 --- a/src/renderer/editor/plugins.cpp +++ b/src/renderer/editor/plugins.cpp @@ -1279,7 +1279,7 @@ struct ModelPlugin final : AssetBrowser::IPlugin, AssetCompiler::IPlugin m_tile.path_hash = prefab->getPath().getHash(); prefab->getResourceManager().unload(*prefab); m_tile.entity = mesh_entity; - model->onLoaded(this); + model->onLoaded<&ModelPlugin::renderPrefabSecondStage>(this); } @@ -3045,8 +3045,8 @@ struct RenderInterfaceImpl final : public RenderInterfaceBase m_font_res = rm.load(font_path); m_font = m_font_res->addRef(16); - editor.universeCreated().bind(this); - editor.universeDestroyed().bind(this); + editor.universeCreated().bind<&RenderInterfaceImpl::onUniverseCreated>(this); + editor.universeDestroyed().bind<&RenderInterfaceImpl::onUniverseDestroyed>(this); } @@ -3055,8 +3055,8 @@ struct RenderInterfaceImpl final : public RenderInterfaceBase m_shader->getResourceManager().unload(*m_shader); m_font_res->getResourceManager().unload(*m_font_res); - m_editor.universeCreated().unbind(this); - m_editor.universeDestroyed().unbind(this); + m_editor.universeCreated().unbind<&RenderInterfaceImpl::onUniverseCreated>(this); + m_editor.universeDestroyed().unbind<&RenderInterfaceImpl::onUniverseDestroyed>(this); } diff --git a/src/renderer/editor/scene_view.cpp b/src/renderer/editor/scene_view.cpp index 734a60ca8..f589f793a 100644 --- a/src/renderer/editor/scene_view.cpp +++ b/src/renderer/editor/scene_view.cpp @@ -55,15 +55,15 @@ SceneView::SceneView(StudioApp& app) auto* renderer = static_cast(engine.getPluginManager().getPlugin("renderer")); PipelineResource* pres = engine.getResourceManager().load(Path("pipelines/main.pln")); m_pipeline = Pipeline::create(*renderer, pres, "SCENE_VIEW", engine.getAllocator()); - m_pipeline->addCustomCommandHandler("renderSelection").callback.bind(this); - m_pipeline->addCustomCommandHandler("renderGizmos").callback.bind(this); - m_pipeline->addCustomCommandHandler("renderIcons").callback.bind(this); + m_pipeline->addCustomCommandHandler("renderSelection").callback.bind<&SceneView::renderSelection>(this); + m_pipeline->addCustomCommandHandler("renderGizmos").callback.bind<&SceneView::renderGizmos>(this); + m_pipeline->addCustomCommandHandler("renderIcons").callback.bind<&SceneView::renderIcons>(this); ResourceManagerHub& rm = engine.getResourceManager(); m_debug_shape_shader = rm.load(Path("pipelines/debug_shape.shd")); - m_editor.universeCreated().bind(this); - m_editor.universeDestroyed().bind(this); + m_editor.universeCreated().bind<&SceneView::onUniverseCreated>(this); + m_editor.universeDestroyed().bind<&SceneView::onUniverseDestroyed>(this); m_toggle_gizmo_step_action = LUMIX_NEW(allocator, Action)("Enable/disable gizmo step", "Enable/disable gizmo step", "toggleGizmoStep"); @@ -96,7 +96,7 @@ SceneView::SceneView(StudioApp& app) m_camera_speed_action = LUMIX_NEW(allocator, Action)("Camera speed", "Reset camera speed", "cameraSpeed"); m_camera_speed_action->is_global = false; - m_camera_speed_action->func.bind(this); + m_camera_speed_action->func.bind<&SceneView::resetCameraSpeed>(this); m_app.addAction(m_camera_speed_action); const ResourceType pipeline_type("pipeline"); @@ -112,8 +112,8 @@ void SceneView::resetCameraSpeed() SceneView::~SceneView() { - m_editor.universeCreated().unbind(this); - m_editor.universeDestroyed().unbind(this); + m_editor.universeCreated().unbind<&SceneView::onUniverseCreated>(this); + m_editor.universeDestroyed().unbind<&SceneView::onUniverseDestroyed>(this); Pipeline::destroy(m_pipeline); m_debug_shape_shader->getResourceManager().unload(*m_debug_shape_shader); m_pipeline = nullptr; diff --git a/src/renderer/editor/terrain_editor.cpp b/src/renderer/editor/terrain_editor.cpp index 43be0424f..a3bb5bc82 100644 --- a/src/renderer/editor/terrain_editor.cpp +++ b/src/renderer/editor/terrain_editor.cpp @@ -609,7 +609,7 @@ private: TerrainEditor::~TerrainEditor() { - m_world_editor.universeDestroyed().unbind(this); + m_world_editor.universeDestroyed().unbind<&TerrainEditor::onUniverseDestroyed>(this); if (m_brush_texture) { m_brush_texture->destroy(); @@ -642,9 +642,9 @@ TerrainEditor::TerrainEditor(WorldEditor& editor, StudioApp& app) { m_increase_brush_size = LUMIX_NEW(editor.getAllocator(), Action)("Increase brush size", "Terrain editor - Increase brush size", "increaseBrushSize"); m_increase_brush_size->is_global = false; - m_increase_brush_size->func.bind(this); + m_increase_brush_size->func.bind<&TerrainEditor::increaseBrushSize>(this); m_decrease_brush_size = LUMIX_NEW(editor.getAllocator(), Action)("Decrease brush size", "Terrain editor - decrease brush size", "decreaseBrushSize"); - m_decrease_brush_size->func.bind(this); + m_decrease_brush_size->func.bind<&TerrainEditor::decreaseBrushSize>(this); m_decrease_brush_size->is_global = false; app.addAction(m_increase_brush_size); app.addAction(m_decrease_brush_size); @@ -679,7 +679,7 @@ TerrainEditor::TerrainEditor(WorldEditor& editor, StudioApp& app) m_is_rotate_z = false; m_rotate_x_spread = m_rotate_y_spread = m_rotate_z_spread = Vec2(0, PI * 2); - editor.universeDestroyed().bind(this); + editor.universeDestroyed().bind<&TerrainEditor::onUniverseDestroyed>(this); } @@ -1199,13 +1199,21 @@ void TerrainEditor::onGUI() switch (m_current_brush) { case HEIGHT: - if (ImGui::Button("Save heightmap")) + if (getMaterial() + && getMaterial()->getTextureByName(HEIGHTMAP_SLOT_NAME) + &&ImGui::Button("Save heightmap")) + { getMaterial()->getTextureByName(HEIGHTMAP_SLOT_NAME)->save(); + } break; case GRASS: case LAYER: - if (ImGui::Button("Save layermap and grassmap")) + if (getMaterial() + && getMaterial()->getTextureByName(SPLATMAP_SLOT_NAME) + && ImGui::Button("Save layermap and grassmap")) + { getMaterial()->getTextureByName(SPLATMAP_SLOT_NAME)->save(); + } break; case ENTITY: break; } diff --git a/src/renderer/pipeline.cpp b/src/renderer/pipeline.cpp index ba371c383..37fb683da 100644 --- a/src/renderer/pipeline.cpp +++ b/src/renderer/pipeline.cpp @@ -298,7 +298,7 @@ struct PipelineImpl final : Pipeline const Renderer::MemRef ib_mem = m_renderer.copy(cube_indices, sizeof(cube_indices)); m_cube_ib = m_renderer.createBuffer(ib_mem, (u32)gpu::BufferFlags::IMMUTABLE); - m_resource->onLoaded(this); + m_resource->onLoaded<&PipelineImpl::onStateChanged>(this); GlobalState global_state; const Renderer::MemRef global_state_mem = m_renderer.copy(&global_state, sizeof(global_state)); diff --git a/src/renderer/render_scene.cpp b/src/renderer/render_scene.cpp index 14bffdd8a..c0881bf25 100644 --- a/src/renderer/render_scene.cpp +++ b/src/renderer/render_scene.cpp @@ -96,11 +96,11 @@ struct TextMesh m_font_resource->removeRef(*m_font); m_font = nullptr; } - m_font_resource->getObserverCb().unbind(this); + m_font_resource->getObserverCb().unbind<&TextMesh::onFontLoaded>(this); m_font_resource->getResourceManager().unload(*m_font_resource); } m_font_resource = res; - if (res) res->onLoaded(this); + if (res) res->onLoaded<&TextMesh::onFontLoaded>(this); } void onFontLoaded(Resource::State, Resource::State new_state, Resource&) @@ -160,8 +160,8 @@ public: ~RenderSceneImpl() { - m_universe.entityTransformed().unbind(this); - m_universe.entityDestroyed().unbind(this); + m_universe.entityTransformed().unbind<&RenderSceneImpl::onEntityMoved>(this); + m_universe.entityDestroyed().unbind<&RenderSceneImpl::onEntityDestroyed>(this); CullingSystem::destroy(*m_culling_system); } @@ -251,13 +251,13 @@ public: m_model_instances.clear(); for(auto iter = m_model_entity_map.begin(), end = m_model_entity_map.end(); iter != end; ++iter) { Model* model = iter.key(); - model->getObserverCb().unbind(this); + model->getObserverCb().unbind<&RenderSceneImpl::modelStateChanged>(this); } m_model_entity_map.clear(); for(auto iter = m_material_decal_map.begin(), end = m_material_decal_map.end(); iter != end; ++iter) { Material* mat = iter.key(); - mat->getObserverCb().unbind(this); + mat->getObserverCb().unbind<&RenderSceneImpl::decalMaterialStateChanged>(this); } m_material_decal_map.clear(); @@ -3135,7 +3135,7 @@ public: else { d.next_decal = INVALID_ENTITY; m_material_decal_map.insert(material, entity); - material->getObserverCb().bind(this); + material->getObserverCb().bind<&RenderSceneImpl::decalMaterialStateChanged>(this); } } @@ -3152,7 +3152,7 @@ public: else { r.next_model = INVALID_ENTITY; m_model_entity_map.insert(model, entity); - model->getObserverCb().bind(this); + model->getObserverCb().bind<&RenderSceneImpl::modelStateChanged>(this); } } @@ -3173,7 +3173,7 @@ public: } else { m_model_entity_map.erase(model); - model->getObserverCb().unbind(this); + model->getObserverCb().unbind<&RenderSceneImpl::modelStateChanged>(this); } } } @@ -3195,7 +3195,7 @@ public: } else { m_material_decal_map.erase(material); - material->getObserverCb().unbind(this); + material->getObserverCb().unbind<&RenderSceneImpl::decalMaterialStateChanged>(this); } } } @@ -3489,8 +3489,8 @@ RenderSceneImpl::RenderSceneImpl(Renderer& renderer, , m_light_probe_grids(m_allocator) { - m_universe.entityTransformed().bind(this); - m_universe.entityDestroyed().bind(this); + m_universe.entityTransformed().bind<&RenderSceneImpl::onEntityMoved>(this); + m_universe.entityDestroyed().bind<&RenderSceneImpl::onEntityDestroyed>(this); m_culling_system = CullingSystem::create(m_allocator, engine.getPageAllocator()); m_model_instances.reserve(5000); m_mesh_sort_data.reserve(5000); diff --git a/src/renderer/terrain.cpp b/src/renderer/terrain.cpp index b4970e060..5ccdbe386 100644 --- a/src/renderer/terrain.cpp +++ b/src/renderer/terrain.cpp @@ -56,7 +56,7 @@ Terrain::GrassType::~GrassType() { if (m_grass_model) { - m_grass_model->getObserverCb().unbind(&m_terrain); + m_grass_model->getObserverCb().unbind<&Terrain::grassLoaded>(&m_terrain); m_grass_model->getResourceManager().unload(*m_grass_model); } } @@ -184,13 +184,13 @@ void Terrain::setGrassTypePath(int index, const Path& path) if (type.m_grass_model) { type.m_grass_model->getResourceManager().unload(*type.m_grass_model); - type.m_grass_model->getObserverCb().unbind(this); + type.m_grass_model->getObserverCb().unbind<&Terrain::grassLoaded>(this); type.m_grass_model = nullptr; } if (path.isValid()) { type.m_grass_model = m_scene.getEngine().getResourceManager().load(path); - type.m_grass_model->onLoaded(this); + type.m_grass_model->onLoaded<&Terrain::grassLoaded>(this); } } @@ -392,11 +392,11 @@ void Terrain::setMaterial(Material* material) if (material != m_material) { if (m_material) { m_material->getResourceManager().unload(*m_material); - m_material->getObserverCb().unbind(this); + m_material->getObserverCb().unbind<&Terrain::onMaterialLoaded>(this); } m_material = material; if (m_material) { - m_material->onLoaded(this); + m_material->onLoaded<&Terrain::onMaterialLoaded>(this); } } else if(material) {