diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index 72ca9685..25e2d553 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -245,7 +245,7 @@ SET(CUSTOM_CONFIGURATION ON CACHE BOOL "" FORCE) SET(ENABLE_ALL_WARNINGS OFF CACHE BOOL "" FORCE) SET(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) ADD_SUBDIRECTORY(JoltPhysics/Build EXCLUDE_FROM_ALL) -target_compile_options(Jolt PRIVATE "-fPIC") +set_property(TARGET Jolt PROPERTY POSITION_INDEPENDENT_CODE ON) SET( GODOT_CPP_SYSTEM_HEADERS ON CACHE BOOL "" FORCE ) diff --git a/CMakeLists.txt b/CMakeLists.txt index 293a62f3..4399a211 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,27 +51,6 @@ endif() # Set project name PROJECT(OSP-MAGNUM CXX) -# From: https://crascit.com/2016/04/09/using-ccache-with-cmake/ -find_program( CCACHE_PROGRAM ccache ) - -if ( CCACHE_PROGRAM ) - # get version information - execute_process( - COMMAND "${CCACHE_PROGRAM}" --version - OUTPUT_VARIABLE CCACHE_VERSION - ) - - string( REGEX MATCH "[^\r\n]*" CCACHE_VERSION ${CCACHE_VERSION} ) - - message( STATUS "Using ccache: ${CCACHE_PROGRAM} (${CCACHE_VERSION})" ) - - # Turn on ccache for all targets - set( CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}" ) - set( CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}" ) - - unset( CCACHE_VERSION ) -endif() - # Setup things for the test subdir below # Has to be in toplevel CMakeLists.txt or ctest gets mad. enable_testing() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0e632ebe..60453402 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,7 +32,7 @@ if(NOT Threads_FOUND) endif() #compile as position-independant to avoid link errors on static link -add_compile_options("-fPIC") +set(CMAKE_POSITION_INDEPENDENT_CODE ON) add_subdirectory(adera) add_subdirectory(adera_app) diff --git a/src/adera_app/features/vehicles_machines.cpp b/src/adera_app/features/vehicles_machines.cpp index 82ad58ec..17fbcabd 100644 --- a/src/adera_app/features/vehicles_machines.cpp +++ b/src/adera_app/features/vehicles_machines.cpp @@ -160,6 +160,7 @@ FeatureDef const ftrMagicRocketThrustIndicator = feature_def("MagicRocketThrustI if (thrustMag == 0.0f) { rScnRender.m_visible.erase(drawEnt); + rMat.m_dirty.push_back(drawEnt); continue; } diff --git a/src/gdextension/feature_interfaces.h b/src/gdextension/feature_interfaces.h index ea26d52e..e179c0d2 100644 --- a/src/gdextension/feature_interfaces.h +++ b/src/gdextension/feature_interfaces.h @@ -47,7 +47,7 @@ struct FIGodot { struct FIGodotScene { struct DataIds { - DataId scnRenderGl; + DataId scnRenderGd; DataId camera; }; diff --git a/src/gdextension/flying_scene.cpp b/src/gdextension/flying_scene.cpp index ece5c105..a1bca459 100644 --- a/src/gdextension/flying_scene.cpp +++ b/src/gdextension/flying_scene.cpp @@ -1,7 +1,7 @@ #include "flying_scene.h" -#include "scenarios.h" #include "feature_interfaces.h" +#include "scenarios.h" #include "sessions/godot.h" #include "spdlog/pattern_formatter.h" #include "spdlog/sinks/callback_sink.h" @@ -24,8 +24,8 @@ #include #include -#include #include +#include #include #include #include @@ -67,574 +67,522 @@ using namespace osp::draw; using namespace osp::fw; using namespace ospgdext; -void FlyingScene::_bind_methods() -{ - ClassDB::bind_method(D_METHOD("get_scene"), &FlyingScene::get_scene); - ClassDB::bind_method(D_METHOD("set_scene", "scene"), &FlyingScene::set_scene); - ClassDB::add_property( - "FlyingScene", PropertyInfo(Variant::STRING, "scene"), "set_scene", "get_scene"); +void FlyingScene::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_scene"), &FlyingScene::get_scene); + ClassDB::bind_method(D_METHOD("set_scene", "scene"), &FlyingScene::set_scene); + ClassDB::add_property("FlyingScene", PropertyInfo(Variant::STRING, "scene"), + "set_scene", "get_scene"); } -FlyingScene::FlyingScene() -{ - // setup the Debug thingies - new Corrade::Utility::Debug{ &m_dbgStream }; - new Corrade::Utility::Warning{ &m_warnStream }; - new Corrade::Utility::Error{ &m_errStream }; +FlyingScene::FlyingScene() { + // setup the Debug thingies + new Corrade::Utility::Debug{&m_dbgStream}; + new Corrade::Utility::Warning{&m_warnStream}; + new Corrade::Utility::Error{&m_errStream}; } -FlyingScene::~FlyingScene() -{ - //delete (ExecutorType *)m_pExecutor; +FlyingScene::~FlyingScene() { + // delete (ExecutorType *)m_pExecutor; } osp::Logger_t g_mainThreadLogger; - -class GodotLogSink final : public spdlog::sinks::base_sink -{ +class GodotLogSink final + : public spdlog::sinks::base_sink { protected: - void sink_it_(spdlog::details::log_msg const &msg) override - { - spdlog::memory_buf_t formatBuf; - this->formatter_->format(msg, formatBuf); - formatBuf.push_back('\x00'); - - // kinda stupid that print functions only support godot::String, which is utf-32, and - // godot just converts it back to utf-8 to print to the terminal. - godot::String gdStr{formatBuf.begin()}; - switch (msg.level) - { - case spdlog::level::err: - godot::UtilityFunctions::printerr(std::move(gdStr)); - break; - default: - godot::UtilityFunctions::print(std::move(gdStr)); - break; - } + void sink_it_(spdlog::details::log_msg const &msg) override { + spdlog::memory_buf_t formatBuf; + this->formatter_->format(msg, formatBuf); + formatBuf.push_back('\x00'); + + // kinda stupid that print functions only support godot::String, which is + // utf-32, and godot just converts it back to utf-8 to print to the + // terminal. + godot::String gdStr{formatBuf.begin()}; + switch (msg.level) { + case spdlog::level::err: + godot::UtilityFunctions::printerr(std::move(gdStr)); + break; + default: + godot::UtilityFunctions::print(std::move(gdStr)); + break; } - void flush_() override { } + } + void flush_() override {} }; void FlyingScene::_enter_tree() // practically main()? { - auto pSink = std::make_shared(); - pSink->set_pattern("[%T.%e] [%n] [%^%l%$] [%s:%#] %v"); - g_mainThreadLogger = std::make_shared("main-thread", pSink); - osp::set_thread_logger(g_mainThreadLogger); - + auto pSink = std::make_shared(); + pSink->set_pattern("[%T.%e] [%n] [%^%l%$] [%s:%#] %v"); + g_mainThreadLogger = std::make_shared("main-thread", pSink); + osp::set_thread_logger(g_mainThreadLogger); - OSP_LOG_INFO("Enter tree"); - register_stage_enums(); + OSP_LOG_INFO("Enter tree"); + register_stage_enums(); - m_mainContext = m_framework.m_contextIds.create(); + m_mainContext = m_framework.m_contextIds.create(); - ContextBuilder mainCB { m_mainContext, {}, m_framework }; - mainCB.add_feature(ftrMain); - ContextBuilder::finalize(std::move(mainCB)); + ContextBuilder mainCB{m_mainContext, {}, m_framework}; + mainCB.add_feature(ftrMain); + ContextBuilder::finalize(std::move(mainCB)); - auto const fiMain = m_framework.get_interface(m_mainContext); - auto &rResources = m_framework.data_get(fiMain.di.resources); - rResources.resize_types(osp::ResTypeIdReg_t::size()); - m_defaultPkg = rResources.pkg_create(); + auto const fiMain = m_framework.get_interface(m_mainContext); + auto &rResources = + m_framework.data_get(fiMain.di.resources); + rResources.resize_types(osp::ResTypeIdReg_t::size()); + m_defaultPkg = rResources.pkg_create(); + load_a_bunch_of_stuff(); + OSP_LOG_INFO("Resources loaded"); - load_a_bunch_of_stuff(); - OSP_LOG_INFO("Resources loaded"); + RenderingServer *renderingServer = RenderingServer::get_singleton(); + m_scenario = get_world_3d()->get_scenario(); + m_viewport = get_viewport()->get_viewport_rid(); - RenderingServer *renderingServer = RenderingServer::get_singleton(); - m_scenario = get_world_3d()->get_scenario(); - m_viewport = get_viewport()->get_viewport_rid(); + m_lightInstance = renderingServer->instance_create(); + renderingServer->instance_set_scenario(m_lightInstance, m_scenario); - m_lightInstance = renderingServer->instance_create(); - renderingServer->instance_set_scenario(m_lightInstance, m_scenario); + m_light = renderingServer->directional_light_create(); + renderingServer->light_set_distance_fade(m_light, false, 0., 0., 0.); + renderingServer->light_set_shadow(m_light, false); + renderingServer->instance_set_base(m_lightInstance, m_light); - RID light = renderingServer->directional_light_create(); - renderingServer->light_set_distance_fade(light, false, 0., 0., 0.); - renderingServer->light_set_shadow(light, false); - renderingServer->instance_set_base(m_lightInstance, light); + Transform3D lform = + Transform3D(Basis().rotated(Vector3(1, 1, 1), -1.), Vector3(0., 0., 0.)); + renderingServer->instance_set_transform(m_lightInstance, lform); - Transform3D lform = Transform3D(Basis().rotated(Vector3(1, 1, 1), -1.), Vector3(0., 0., 0.)); - renderingServer->instance_set_transform(m_lightInstance, lform); - - OSP_LOG_INFO("Created viewport, scenario, and light"); - - CharString const utf8 = m_scene.utf8(); - OSP_LOG_INFO("Scene is {}", utf8.ptr()); - auto const it = scenarios().find("vehicles" /*m_scene.utf8().get_data()*/); - if ( it == std::end(scenarios()) ) - { - OSP_LOG_INFO("Unknown scene"); - clear_resource_owners(); - return; - } - ScenarioOption const &rSelectedScenario = it->second; - - // Loads data into the framework; contains nothing godot-related - rSelectedScenario.loadFunc(m_framework, m_mainContext, m_defaultPkg); + OSP_LOG_INFO("Created viewport, scenario, and light"); + CharString const utf8 = m_scene.utf8(); + OSP_LOG_INFO("Scene is {}", utf8.ptr()); + auto const it = scenarios().find("vehicles" /*m_scene.utf8().get_data()*/); + if (it == std::end(scenarios())) { + OSP_LOG_INFO("Unknown scene"); + clear_resource_owners(); + return; + } + ScenarioOption const &rSelectedScenario = it->second; + // Loads data into the framework; contains nothing godot-related + rSelectedScenario.loadFunc(m_framework, m_mainContext, m_defaultPkg); } -void FlyingScene::_ready() -{ - // Setup godot-related stuff based on whatever features the scenario loaded into the framework - +void FlyingScene::_ready() { + // Setup godot-related stuff based on whatever features the scenario loaded + // into the framework - setup_app(); + setup_app(); } -void FlyingScene::_physics_process(double delta) -{ - // ospjolt::SysJolt::update_world() update the world +void FlyingScene::_physics_process(double delta) { + // ospjolt::SysJolt::update_world() update the world } -void FlyingScene::_process(double delta) -{ - auto const mainApp = m_framework.get_interface(m_mainContext); - auto const& appCtxs = m_framework.data_get(mainApp.di.appContexts); - auto const windowApp = m_framework.get_interface(appCtxs.window); - auto &rUserInput = m_framework.data_get(windowApp.di.userInput); - - rUserInput.update_controls(); - draw_event(); - rUserInput.clear_events(); - // print the corrade messages - if ( m_dbgStream.tellp() != std::streampos(0) ) - { - godot::UtilityFunctions::print(m_dbgStream.str().data()); - m_dbgStream.str(""); - } - if ( m_warnStream.tellp() != std::streampos(0) ) - { - godot::UtilityFunctions::print(m_warnStream.str().data()); - m_warnStream.str(""); - } - if ( m_errStream.tellp() != std::streampos(0) ) - { - godot::UtilityFunctions::print(m_errStream.str().data()); - m_errStream.str(""); - } +void FlyingScene::_process(double delta) { + auto const mainApp = m_framework.get_interface(m_mainContext); + auto const &appCtxs = + m_framework.data_get(mainApp.di.appContexts); + auto const windowApp = m_framework.get_interface(appCtxs.window); + auto &rUserInput = + m_framework.data_get(windowApp.di.userInput); + + rUserInput.update_controls(); + draw_event(); + rUserInput.clear_events(); + // print the corrade messages + if (m_dbgStream.tellp() != std::streampos(0)) { + godot::UtilityFunctions::print(m_dbgStream.str().data()); + m_dbgStream.str(""); + } + if (m_warnStream.tellp() != std::streampos(0)) { + godot::UtilityFunctions::print(m_warnStream.str().data()); + m_warnStream.str(""); + } + if (m_errStream.tellp() != std::streampos(0)) { + godot::UtilityFunctions::print(m_errStream.str().data()); + m_errStream.str(""); + } } -void FlyingScene::_exit_tree() -{ - destroy_app(); +void FlyingScene::_exit_tree() { destroy_app(); } + +void FlyingScene::drive_scene_cycle(UpdateParams p) { + Framework &rFW = m_framework; + + auto const mainApp = rFW.get_interface(m_mainContext); + auto const &rAppCtxs = rFW.data_get(mainApp.di.appContexts); + auto &rMainLoopCtrl = rFW.data_get(mainApp.di.mainLoopCtrl); + rMainLoopCtrl.doUpdate = p.update; + + auto const scene = rFW.get_interface(rAppCtxs.scene); + if (scene.id.has_value()) { + auto &rSceneLoopCtrl = rFW.data_get(scene.di.loopControl); + auto &rDeltaTimeIn = rFW.data_get(scene.di.deltaTimeIn); + rSceneLoopCtrl.doSceneUpdate = p.sceneUpdate; + rDeltaTimeIn = p.deltaTimeIn; + } + + auto const windowApp = rFW.get_interface(rAppCtxs.window); + auto &rWindowLoopCtrl = + rFW.data_get(windowApp.di.windowAppLoopCtrl); + rWindowLoopCtrl.doRender = p.render; + rWindowLoopCtrl.doSync = p.sync; + rWindowLoopCtrl.doResync = p.resync; + + m_executor.signal(m_framework, mainApp.pl.mainLoop); + m_executor.signal(m_framework, windowApp.pl.inputs); + m_executor.signal(m_framework, windowApp.pl.sync); + m_executor.signal(m_framework, windowApp.pl.resync); + + m_executor.wait(m_framework); } -void FlyingScene::drive_scene_cycle(UpdateParams p) -{ - Framework &rFW = m_framework; - - auto const mainApp = rFW.get_interface (m_mainContext); - auto const &rAppCtxs = rFW.data_get (mainApp.di.appContexts); - auto &rMainLoopCtrl = rFW.data_get (mainApp.di.mainLoopCtrl); - rMainLoopCtrl.doUpdate = p.update; - - auto const scene = rFW.get_interface (rAppCtxs.scene); - if (scene.id.has_value()) - { - auto &rSceneLoopCtrl = rFW.data_get(scene.di.loopControl); - auto &rDeltaTimeIn = rFW.data_get (scene.di.deltaTimeIn); - rSceneLoopCtrl.doSceneUpdate = p.sceneUpdate; - rDeltaTimeIn = p.deltaTimeIn; +void FlyingScene::run_context_cleanup(ContextId ctx) { + auto const cleanup = m_framework.get_interface(ctx); + if (cleanup.id.has_value()) { + // Run cleanup pipeline for the window context + m_executor.run(m_framework, cleanup.pl.cleanup); + m_executor.wait(m_framework); + + if (m_executor.is_running(m_framework)) { + OSP_LOG_CRITICAL("Deadlock in cleanup pipeline"); + std::abort(); } + } +} - auto const windowApp = rFW.get_interface (rAppCtxs.window); - auto &rWindowLoopCtrl = rFW.data_get (windowApp.di.windowAppLoopCtrl); - rWindowLoopCtrl.doRender = p.render; - rWindowLoopCtrl.doSync = p.sync; - rWindowLoopCtrl.doResync = p.resync; +void FlyingScene::clear_resource_owners() { + using namespace osp::restypes; - m_executor.signal(m_framework, mainApp.pl.mainLoop); - m_executor.signal(m_framework, windowApp.pl.inputs); - m_executor.signal(m_framework, windowApp.pl.sync); - m_executor.signal(m_framework, windowApp.pl.resync); + auto const mainApp = m_framework.get_interface(m_mainContext); - m_executor.wait(m_framework); -} + auto &rResources = m_framework.data_get(mainApp.di.resources); -void FlyingScene::run_context_cleanup(ContextId ctx) -{ - auto const cleanup = m_framework.get_interface (ctx); - if ( cleanup.id.has_value() ) - { - // Run cleanup pipeline for the window context - m_executor.run(m_framework, cleanup.pl.cleanup); - m_executor.wait(m_framework); - - if (m_executor.is_running(m_framework)) - { - OSP_LOG_CRITICAL("Deadlock in cleanup pipeline"); - std::abort(); - } + // Texture resources contain osp::TextureImgSource, which refererence counts + // their associated image data + for (osp::ResId const id : rResources.ids(gc_texture)) { + auto *const pData = + rResources.data_try_get(gc_texture, id); + if (pData != nullptr) { + rResources.owner_destroy(gc_image, std::move(*pData)); } + }; + + // Importer data own a lot of other resources + for (osp::ResId const id : rResources.ids(gc_importer)) { + auto *const pData = + rResources.data_try_get(gc_importer, id); + if (pData != nullptr) { + for (osp::ResIdOwner_t &rOwner : std::move(pData->m_images)) { + rResources.owner_destroy(gc_image, std::move(rOwner)); + } + + for (osp::ResIdOwner_t &rOwner : std::move(pData->m_textures)) { + rResources.owner_destroy(gc_texture, std::move(rOwner)); + } + + for (osp::ResIdOwner_t &rOwner : std::move(pData->m_meshes)) { + rResources.owner_destroy(gc_mesh, std::move(rOwner)); + } + } + }; + + godot::RenderingServer *rs = godot::RenderingServer::get_singleton(); + rs->free_rid(m_lightInstance); + rs->free_rid(m_light); + m_light = {}; + m_lightInstance = {}; + m_scenario = {}; + m_viewport = {}; } -void FlyingScene::clear_resource_owners() -{ - using namespace osp::restypes; - - auto const mainApp = m_framework.get_interface(m_mainContext); - - auto &rResources = m_framework.data_get(mainApp.di.resources); - - // Texture resources contain osp::TextureImgSource, which refererence counts - // their associated image data - for (osp::ResId const id : rResources.ids(gc_texture)) - { - auto * const pData = rResources.data_try_get(gc_texture, id); - if (pData != nullptr) - { - rResources.owner_destroy(gc_image, std::move(*pData)); - } - }; - - // Importer data own a lot of other resources - for (osp::ResId const id : rResources.ids(gc_importer)) - { - auto * const pData = rResources.data_try_get(gc_importer, id); - if (pData != nullptr) - { - for (osp::ResIdOwner_t &rOwner : std::move(pData->m_images)) - { - rResources.owner_destroy(gc_image, std::move(rOwner)); - } - - for (osp::ResIdOwner_t &rOwner : std::move(pData->m_textures)) - { - rResources.owner_destroy(gc_texture, std::move(rOwner)); - } - - for (osp::ResIdOwner_t &rOwner : std::move(pData->m_meshes)) - { - rResources.owner_destroy(gc_mesh, std::move(rOwner)); - } - } - }; -} - -void FlyingScene::load_a_bunch_of_stuff() -{ - using namespace osp::restypes; - using namespace Magnum; - using Primitives::ConeFlag; - using Primitives::CylinderFlag; - - auto const fiMain = m_framework.get_interface(m_mainContext); - auto &rResources = m_framework.data_get(fiMain.di.resources); - rResources.data_register(gc_image); - rResources.data_register(gc_texture); - rResources.data_register(gc_texture); - rResources.data_register(gc_mesh); - rResources.data_register(gc_importer); - rResources.data_register(gc_importer); - osp::register_tinygltf_resources(rResources); - // Load sturdy glTF files - // FIXME this works in editor, but probably not for exported game. - const std::string_view datapath = { "OSPData/adera/" }; - const std::vector meshes = { - "spamcan.sturdy.gltf", - "stomper.sturdy.gltf", - "ph_capsule.sturdy.gltf", - "ph_fuselage.sturdy.gltf", - "ph_engine.sturdy.gltf", - //"ph_plume.sturdy.gltf", - "ph_rcs.sturdy.gltf" - //"ph_rcs_plume.sturdy.gltf" - }; - // TODO: Make new gltf loader. This will read gltf files and dump meshes, - // images, textures, and other relevant data into osp::Resources - for ( auto const &meshName : meshes ) - { - auto str = osp::string_concat(datapath, meshName); - osp::ResId res = osp::load_tinygltf_file(str, rResources, m_defaultPkg); - if (res != lgrn::id_null()) - { - osp::assigns_prefabs_tinygltf(rResources, res); - } +void FlyingScene::load_a_bunch_of_stuff() { + using namespace osp::restypes; + using namespace Magnum; + using Primitives::ConeFlag; + using Primitives::CylinderFlag; + + auto const fiMain = m_framework.get_interface(m_mainContext); + auto &rResources = + m_framework.data_get(fiMain.di.resources); + rResources.data_register(gc_image); + rResources.data_register(gc_texture); + rResources.data_register(gc_texture); + rResources.data_register(gc_mesh); + rResources.data_register(gc_importer); + rResources.data_register(gc_importer); + osp::register_tinygltf_resources(rResources); + // Load sturdy glTF files + // FIXME this works in editor, but probably not for exported game. + const std::string_view datapath = {"OSPData/adera/"}; + const std::vector meshes = { + "spamcan.sturdy.gltf", "stomper.sturdy.gltf", "ph_capsule.sturdy.gltf", + "ph_fuselage.sturdy.gltf", "ph_engine.sturdy.gltf", + //"ph_plume.sturdy.gltf", + "ph_rcs.sturdy.gltf" + //"ph_rcs_plume.sturdy.gltf" + }; + // TODO: Make new gltf loader. This will read gltf files and dump meshes, + // images, textures, and other relevant data into osp::Resources + for (auto const &meshName : meshes) { + auto str = osp::string_concat(datapath, meshName); + osp::ResId res = osp::load_tinygltf_file(str, rResources, m_defaultPkg); + if (res != lgrn::id_null()) { + osp::assigns_prefabs_tinygltf(rResources, res); } - - // Add a default primitives - auto const add_mesh_quick = [&rResources = rResources, this] (std::string_view const name, Trade::MeshData&& data) - { - osp::ResId const meshId = rResources.create(gc_mesh, m_defaultPkg, osp::SharedString::create(name)); - rResources.data_add(gc_mesh, meshId, std::move(data)); - }; - - Trade::MeshData &&cylinder = Magnum::MeshTools::transform3D( - Primitives::cylinderSolid(3, 16, 1.0f, CylinderFlag::CapEnds), - Matrix4::rotationX(Deg(90)), - 0); - Trade::MeshData &&cone = Magnum::MeshTools::transform3D( - Primitives::coneSolid(3, 16, 1.0f, ConeFlag::CapEnd), Matrix4::rotationX(Deg(90)), 0); - - add_mesh_quick("cube", Primitives::cubeSolid()); - add_mesh_quick("cubewire", Primitives::cubeWireframe()); - add_mesh_quick("sphere", Primitives::icosphereSolid(2)); - add_mesh_quick("cylinder", std::move(cylinder)); - add_mesh_quick("cone", std::move(cone)); - add_mesh_quick("grid64solid", Primitives::grid3DSolid({ 63, 63 })); - - OSP_LOG_INFO("Resource loading complete"); + } + + // Add a default primitives + auto const add_mesh_quick = [&rResources = rResources, + this](std::string_view const name, + Trade::MeshData &&data) { + osp::ResId const meshId = rResources.create( + gc_mesh, m_defaultPkg, osp::SharedString::create(name)); + rResources.data_add(gc_mesh, meshId, std::move(data)); + }; + + Trade::MeshData &&cylinder = Magnum::MeshTools::transform3D( + Primitives::cylinderSolid(3, 16, 1.0f, CylinderFlag::CapEnds), + Matrix4::rotationX(Deg(90)), 0); + Trade::MeshData &&cone = Magnum::MeshTools::transform3D( + Primitives::coneSolid(3, 16, 1.0f, ConeFlag::CapEnd), + Matrix4::rotationX(Deg(90)), 0); + + add_mesh_quick("cube", Primitives::cubeSolid()); + add_mesh_quick("cubewire", Primitives::cubeWireframe()); + add_mesh_quick("sphere", Primitives::icosphereSolid(2)); + add_mesh_quick("cylinder", std::move(cylinder)); + add_mesh_quick("cone", std::move(cone)); + add_mesh_quick("grid64solid", Primitives::grid3DSolid({63, 63})); + + OSP_LOG_INFO("Resource loading complete"); } -ContextId make_scene_renderer(Framework &rFW, ContextId mainCtx, ContextId sceneCtx, ContextId windowCtx, PkgId defaultPkg) -{ - auto const godot = rFW.get_interface (windowCtx); - - ContextId const scnRdrCtx = rFW.m_contextIds.create(); +ContextId make_scene_renderer(Framework &rFW, ContextId mainCtx, + ContextId sceneCtx, ContextId windowCtx, + PkgId defaultPkg) { + auto const godot = rFW.get_interface(windowCtx); - // TODO: comment below is lying, and just adds features without guidance. + ContextId const scnRdrCtx = rFW.m_contextIds.create(); - // Choose which renderer features to use based on information on which features the scene - // context contains. + // TODO: comment below is lying, and just adds features without guidance. - ContextBuilder scnRdrCB { scnRdrCtx, { mainCtx, windowCtx, sceneCtx }, rFW }; + // Choose which renderer features to use based on information on which + // features the scene context contains. - if (rFW.get_interface(sceneCtx).id.has_value()) - { - scnRdrCB.add_feature(ftrSceneRenderer); - scnRdrCB.add_feature(ftrGodotScene); + ContextBuilder scnRdrCB{scnRdrCtx, {mainCtx, windowCtx, sceneCtx}, rFW}; - auto scnRender = rFW.get_interface (scnRdrCtx); - auto &rScnRender = rFW.data_get (scnRender.di.scnRender); + if (rFW.get_interface(sceneCtx).id.has_value()) { + scnRdrCB.add_feature(ftrSceneRenderer); + scnRdrCB.add_feature(ftrGodotScene); - MaterialId const matFlat = rScnRender.m_materialIds.create(); - rScnRender.m_materials.resize(rScnRender.m_materialIds.size()); + auto scnRender = rFW.get_interface(scnRdrCtx); + auto &rScnRender = + rFW.data_get(scnRender.di.scnRender); - scnRdrCB.add_feature(ftrCameraControlGD); - - scnRdrCB.add_feature(ftrThrower); - scnRdrCB.add_feature(ftrPhysicsShapesDraw, matFlat); - scnRdrCB.add_feature(ftrCursor, TplPkgIdMaterialId{defaultPkg, matFlat}); - - - if (rFW.get_interface_id(sceneCtx).has_value()) - { - scnRdrCB.add_feature(ftrPrefabDraw, matFlat); - } - - if (rFW.get_interface_id(sceneCtx).has_value()) - { - scnRdrCB.add_feature(ftrVehicleControl); - scnRdrCB.add_feature(ftrVehicleCamera); - scnRdrCB.add_feature(ftrVehicleSpawnDraw); - } - else - { - scnRdrCB.add_feature(ftrCameraFree); - } - - if (rFW.get_interface_id(sceneCtx).has_value()) - { - scnRdrCB.add_feature(ftrMagicRocketThrustIndicator, TplPkgIdMaterialId{ defaultPkg, matFlat }); - } + MaterialId const matFlat = rScnRender.m_materialIds.create(); + rScnRender.m_materials.resize(rScnRender.m_materialIds.size()); + scnRdrCB.add_feature(ftrCameraControlGD); + scnRdrCB.add_feature(ftrThrower); + scnRdrCB.add_feature(ftrPhysicsShapesDraw, matFlat); + scnRdrCB.add_feature(ftrCursor, TplPkgIdMaterialId{defaultPkg, matFlat}); + if (rFW.get_interface_id(sceneCtx).has_value()) { + scnRdrCB.add_feature(ftrPrefabDraw, matFlat); } + if (rFW.get_interface_id(sceneCtx).has_value()) { + scnRdrCB.add_feature(ftrVehicleControl); + scnRdrCB.add_feature(ftrVehicleCamera); + scnRdrCB.add_feature(ftrVehicleSpawnDraw); + } else { + scnRdrCB.add_feature(ftrCameraFree); + } + if (rFW.get_interface_id(sceneCtx).has_value()) { + scnRdrCB.add_feature(ftrMagicRocketThrustIndicator, + TplPkgIdMaterialId{defaultPkg, matFlat}); + } + } - ContextBuilder::finalize(std::move(scnRdrCB)); - return scnRdrCtx; + ContextBuilder::finalize(std::move(scnRdrCB)); + return scnRdrCtx; } // make_scene_renderer -void FlyingScene::setup_app() -{ - // Setup Godot 'window application' renderer context - // This is intended to stay alive as long as godot is open (forever), unlike the scene renderer - // which is intended to be swapped out when the scene changes. - - auto const mainApp = m_framework.get_interface(m_mainContext); - ContextId const sceneCtx = m_framework.data_get(mainApp.di.appContexts).scene; - ContextId const windowCtx = m_framework.m_contextIds.create(); - ContextBuilder windowCB { windowCtx, { m_mainContext, sceneCtx }, m_framework }; - windowCB.add_feature(adera::ftrWindowApp); - windowCB.add_feature(ftrGodot, entt::make_any(this)); - ContextBuilder::finalize(std::move(windowCB)); - - OSP_LOG_INFO("Setup godot"); - - // Setup scene renderer sessions - - ContextId const sceneRenderCtx = make_scene_renderer(m_framework, m_mainContext, sceneCtx, windowCtx, m_defaultPkg); - - // All contexts and features are now created, keep track of them - - auto &rAppCtxs = m_framework.data_get(mainApp.di.appContexts); - rAppCtxs.window = windowCtx; - rAppCtxs.sceneRender = sceneRenderCtx; - - // Start the main loop - - m_executor.load(m_framework); - m_executor.run(m_framework, mainApp.pl.mainLoop); - - // Resynchronize renderer; Resync+Sync without stepping through time. - // This makes sure meshes, textures, shaders, and other GPU-related resources specified by - // the scene are properly loaded and assigned to entities within the renderer. - drive_scene_cycle({.deltaTimeIn = 0.0f, - .update = true, - .sceneUpdate = false, - .resync = true, - .sync = true, - .render = false }); +void FlyingScene::setup_app() { + // Setup Godot 'window application' renderer context + // This is intended to stay alive as long as godot is open (forever), unlike + // the scene renderer which is intended to be swapped out when the scene + // changes. + + auto const mainApp = m_framework.get_interface(m_mainContext); + ContextId const sceneCtx = + m_framework.data_get(mainApp.di.appContexts).scene; + ContextId const windowCtx = m_framework.m_contextIds.create(); + ContextBuilder windowCB{windowCtx, {m_mainContext, sceneCtx}, m_framework}; + windowCB.add_feature(adera::ftrWindowApp); + windowCB.add_feature(ftrGodot, entt::make_any(this)); + ContextBuilder::finalize(std::move(windowCB)); + + OSP_LOG_INFO("Setup godot"); + + // Setup scene renderer sessions + + ContextId const sceneRenderCtx = make_scene_renderer( + m_framework, m_mainContext, sceneCtx, windowCtx, m_defaultPkg); + + // All contexts and features are now created, keep track of them + + auto &rAppCtxs = m_framework.data_get(mainApp.di.appContexts); + rAppCtxs.window = windowCtx; + rAppCtxs.sceneRender = sceneRenderCtx; + + // Start the main loop + + m_executor.load(m_framework); + m_executor.run(m_framework, mainApp.pl.mainLoop); + + // Resynchronize renderer; Resync+Sync without stepping through time. + // This makes sure meshes, textures, shaders, and other GPU-related resources + // specified by the scene are properly loaded and assigned to entities within + // the renderer. + drive_scene_cycle({.deltaTimeIn = 0.0f, + .update = true, + .sceneUpdate = false, + .resync = true, + .sync = true, + .render = false}); } -void FlyingScene::draw_event() -{ - drive_scene_cycle({.deltaTimeIn = 1.0f/60.0f, - .update = true, - .sceneUpdate = true, - .resync = false, - .sync = true, - .render = true }); +void FlyingScene::draw_event() { + drive_scene_cycle({.deltaTimeIn = 1.0f / 60.0f, + .update = true, + .sceneUpdate = true, + .resync = false, + .sync = true, + .render = true}); } -void FlyingScene::_input(const Ref &input) -{ - auto const mainApp = m_framework.get_interface(m_mainContext); - auto const& appCtxs = m_framework.data_get(mainApp.di.appContexts); - auto const windowApp = m_framework.get_interface(appCtxs.window); - auto &rUserInput = m_framework.data_get(windowApp.di.userInput); - - - // FIXME using dynamic_cast is a bit ugly, but afaik it's the best way if we bypass Godot's - // InputMap (which we probably shouldn't in the long term) - - // keyboard - auto inputKey = dynamic_cast(input.ptr()); - if ( inputKey != nullptr ) - { - if ( inputKey->is_echo() ) - { - return; - } - EButtonEvent dir; - if ( inputKey->is_pressed() ) - { - dir = EButtonEvent::Pressed; - } - else if ( inputKey->is_released() ) - { - dir = EButtonEvent::Released; - } - else - { - return; - } - rUserInput.event_raw( - osp::input::sc_keyboard, (int)inputKey->get_physical_keycode(), dir); - return; +void FlyingScene::_input(const Ref &input) { + auto const mainApp = m_framework.get_interface(m_mainContext); + auto const &appCtxs = + m_framework.data_get(mainApp.di.appContexts); + auto const windowApp = m_framework.get_interface(appCtxs.window); + auto &rUserInput = + m_framework.data_get(windowApp.di.userInput); + + // FIXME using dynamic_cast is a bit ugly, but afaik it's the best way if we + // bypass Godot's InputMap (which we probably shouldn't in the long term) + + // keyboard + auto inputKey = dynamic_cast(input.ptr()); + if (inputKey != nullptr) { + if (inputKey->is_echo()) { + return; } - - // mouse button - auto inputMouseButton = dynamic_cast(input.ptr()); - if ( inputMouseButton != nullptr ) - { - if ( inputMouseButton->get_button_index() <= MOUSE_BUTTON_MIDDLE ) - { - EButtonEvent dir; - if ( inputMouseButton->is_pressed() ) - { - dir = EButtonEvent::Pressed; - } - else if ( inputMouseButton->is_released() ) - { - dir = EButtonEvent::Released; - } - else - { - return; - } - rUserInput.event_raw( - osp::input::sc_mouse, (int)inputMouseButton->get_button_index(), dir); - return; - } - osp::Vector2i scroll_delta; - if ( inputMouseButton->get_button_index() == MOUSE_BUTTON_WHEEL_UP ) - { - scroll_delta.y() += static_cast(inputMouseButton->get_factor()); - } - else if ( inputMouseButton->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN ) - { - scroll_delta.y() -= static_cast(inputMouseButton->get_factor()); - } - else if ( inputMouseButton->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT ) - { - scroll_delta.x() += static_cast(inputMouseButton->get_factor()); - } - else if ( inputMouseButton->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT ) - { - scroll_delta.x() -= static_cast(inputMouseButton->get_factor()); - } - rUserInput.scroll_delta(scroll_delta); - return; + EButtonEvent dir; + if (inputKey->is_pressed()) { + dir = EButtonEvent::Pressed; + } else if (inputKey->is_released()) { + dir = EButtonEvent::Released; + } else { + return; } - - // mouse motion - auto inputMouseMotion = dynamic_cast(input.ptr()); - if ( inputMouseMotion != nullptr ) - { - godot::Vector2 mdelta = inputMouseMotion->get_relative(); - // Godot mouse position is in floats apparently. Error is probably minimal. - rUserInput.mouse_delta({ static_cast(mdelta.x), static_cast(mdelta.y) }); + rUserInput.event_raw(osp::input::sc_keyboard, + (int)inputKey->get_physical_keycode(), dir); + return; + } + + // mouse button + auto inputMouseButton = dynamic_cast(input.ptr()); + if (inputMouseButton != nullptr) { + if (inputMouseButton->get_button_index() <= MOUSE_BUTTON_MIDDLE) { + EButtonEvent dir; + if (inputMouseButton->is_pressed()) { + dir = EButtonEvent::Pressed; + } else if (inputMouseButton->is_released()) { + dir = EButtonEvent::Released; + } else { return; + } + rUserInput.event_raw(osp::input::sc_mouse, + (int)inputMouseButton->get_button_index(), dir); + return; } -}; - -void FlyingScene::destroy_app() -{ - OSP_LOG_INFO("Destroy App"); - - // Stops the pipeline loop - drive_scene_cycle({.deltaTimeIn = 0.0f, - .update = false, - .sceneUpdate = false, - .resync = false, - .sync = false, - .render = false }); - if (m_executor.is_running(m_framework)) - { - OSP_LOG_CRITICAL("Expected main loop to stop, but something is blocking it and cannot exit"); - std::abort(); - } - - auto const mainApp = m_framework.get_interface(m_mainContext); - auto const appCtxs = m_framework.data_get(mainApp.di.appContexts); - - run_context_cleanup(appCtxs.sceneRender); - run_context_cleanup(appCtxs.window); - run_context_cleanup(appCtxs.scene); - run_context_cleanup(appCtxs.main); - - if (m_executor.is_running(m_framework)) - { - OSP_LOG_CRITICAL("Expected main loop to stop, but something is blocking it and cannot exit"); - std::abort(); + osp::Vector2i scroll_delta; + if (inputMouseButton->get_button_index() == MOUSE_BUTTON_WHEEL_UP) { + scroll_delta.y() += static_cast(inputMouseButton->get_factor()); + } else if (inputMouseButton->get_button_index() == + MOUSE_BUTTON_WHEEL_DOWN) { + scroll_delta.y() -= static_cast(inputMouseButton->get_factor()); + } else if (inputMouseButton->get_button_index() == + MOUSE_BUTTON_WHEEL_RIGHT) { + scroll_delta.x() += static_cast(inputMouseButton->get_factor()); + } else if (inputMouseButton->get_button_index() == + MOUSE_BUTTON_WHEEL_LEFT) { + scroll_delta.x() -= static_cast(inputMouseButton->get_factor()); } + rUserInput.scroll_delta(scroll_delta); + return; + } + + // mouse motion + auto inputMouseMotion = dynamic_cast(input.ptr()); + if (inputMouseMotion != nullptr) { + godot::Vector2 mdelta = inputMouseMotion->get_relative(); + // Godot mouse position is in floats apparently. Error is probably minimal. + rUserInput.mouse_delta( + {static_cast(mdelta.x), static_cast(mdelta.y)}); + return; + } +}; - m_framework.close_context(appCtxs.sceneRender); - m_framework.close_context(appCtxs.window); - m_framework.close_context(appCtxs.scene); - - clear_resource_owners(); - m_framework.close_context(appCtxs.main); - - // leak test app cause there is a free bug. FIXME of course. -// auto leak_tp = new TestApp; -// std::swap(*leak_tp, m_testApp);*/ -} - -void FlyingScene::set_scene(String const &scene) -{ - m_scene = scene; +void FlyingScene::destroy_app() { + OSP_LOG_INFO("Destroy App"); + + // Stops the pipeline loop + drive_scene_cycle({.deltaTimeIn = 0.0f, + .update = false, + .sceneUpdate = false, + .resync = false, + .sync = false, + .render = false}); + if (m_executor.is_running(m_framework)) { + OSP_LOG_CRITICAL("Expected main loop to stop, but something is blocking it " + "and cannot exit"); + std::abort(); + } + + auto const mainApp = m_framework.get_interface(m_mainContext); + auto const appCtxs = + m_framework.data_get(mainApp.di.appContexts); + + run_context_cleanup(appCtxs.sceneRender); + run_context_cleanup(appCtxs.window); + run_context_cleanup(appCtxs.scene); + run_context_cleanup(appCtxs.main); + + if (m_executor.is_running(m_framework)) { + OSP_LOG_CRITICAL("Expected main loop to stop, but something is blocking it " + "and cannot exit"); + std::abort(); + } + + m_framework.close_context(appCtxs.sceneRender); + m_framework.close_context(appCtxs.window); + m_framework.close_context(appCtxs.scene); + + clear_resource_owners(); + m_framework.close_context(appCtxs.main); + + // leak test app cause there is a free bug. FIXME of course. + // auto leak_tp = new TestApp; + // std::swap(*leak_tp, m_testApp);*/ } -String const &FlyingScene::get_scene() const -{ - return m_scene; -} +void FlyingScene::set_scene(String const &scene) { m_scene = scene; } +String const &FlyingScene::get_scene() const { return m_scene; } diff --git a/src/gdextension/flying_scene.h b/src/gdextension/flying_scene.h index eedffb63..d1a70d83 100644 --- a/src/gdextension/flying_scene.h +++ b/src/gdextension/flying_scene.h @@ -34,6 +34,7 @@ class FlyingScene : public Node3D RID m_scenario; RID m_viewport; RID m_lightInstance; + RID m_light; //TestApp m_testApp; //adera::MainLoopControl *m_mainLoopCtrl; diff --git a/src/gdextension/render.cpp b/src/gdextension/render.cpp index ad420ae7..987180bf 100644 --- a/src/gdextension/render.cpp +++ b/src/gdextension/render.cpp @@ -52,6 +52,7 @@ #include #include #include +#include using Magnum::Trade::ImageData2D; using Magnum::Trade::MeshData; @@ -159,12 +160,16 @@ void SysRenderGd::compile_resource_textures( continue; } godot::RenderingServer *rs = godot::RenderingServer::get_singleton(); + godot::PackedByteArray pba; + pba.resize( static_cast(( imgData.data().size()))); + std::memcpy(pba.ptrw(), imgData.data(), imgData.data().size()); + godot::Ref img = godot::Image::create_from_data(imgData.size().x(), imgData.size().y(), - true, + false, formatMToGd(imgData.format()), - godot::Variant(imgData.data())); + pba); godot::RID rid = rs->texture_2d_create(img); rRenderGd.m_texGd.emplace(newId, rid); } @@ -340,6 +345,17 @@ void SysRenderGd::sync_drawent_texture(DrawEnt const en } } +void osp::draw::ACtxSceneRenderGd::clear_resource_owners() +{ + godot::RenderingServer* rs = godot::RenderingServer::get_singleton(); + for ([[maybe_unused]] godot::RID &rOwner : std::exchange(m_instanceId, {})) + { + rs->free_rid(rOwner); + rOwner = {}; + } + m_scenario = {}; +} + void SysRenderGd::clear_resource_owners(RenderGd &rRenderGd, Resources &rResources) { for ( [[maybe_unused]] auto &&[_, rOwner] : std::exchange(rRenderGd.m_texToRes, {}) ) @@ -353,28 +369,21 @@ void SysRenderGd::clear_resource_owners(RenderGd &rRenderGd, Resources &rResourc rResources.owner_destroy(restypes::gc_mesh, std::move(rOwner)); } rRenderGd.m_resToMesh.clear(); -} -// FIXME -void SysRenderGd::render_opaque( - RenderGroup const &group, DrawEntSet_t const &visible, ViewProjMatrix const &viewProj) -{ - draw_group(group, visible, viewProj); -} -// FIXME -void SysRenderGd::render_transparent( - RenderGroup const &group, DrawEntSet_t const &visible, ViewProjMatrix const &viewProj) -{ - draw_group(group, visible, viewProj); -} -void SysRenderGd::draw_group( - RenderGroup const &group, DrawEntSet_t const &visible, ViewProjMatrix const &viewProj) -{ - for ( auto const &[ent, toDraw] : entt::basic_view{ group.entities }.each() ) + godot::RenderingServer* rs = godot::RenderingServer::get_singleton(); + for ([[maybe_unused]] godot::RID rOwner : std::exchange(rRenderGd.m_meshGd, {})) { - if ( visible.contains(ent) ) - { - toDraw.draw(ent, viewProj, toDraw.data); - } + godot::RID material = rs->mesh_surface_get_material(rOwner, 0); + rs->free_rid(rOwner); + rs->free_rid(material); + rOwner = {}; } -} + for ([[maybe_unused]] godot::RID rOwner : std::exchange(rRenderGd.m_texGd, {})) + { + rs->free_rid(rOwner); + rOwner = {}; + } + + rRenderGd.scenario = {}; + rRenderGd.viewport = {}; +} \ No newline at end of file diff --git a/src/gdextension/render.h b/src/gdextension/render.h index 1df36416..871e180d 100644 --- a/src/gdextension/render.h +++ b/src/gdextension/render.h @@ -108,6 +108,8 @@ struct ACtxSceneRenderGd InstanceGdEntStorage_t m_instanceId; DrawEntSet_t m_render; godot::RID m_scenario; + + void clear_resource_owners(); }; /** diff --git a/src/gdextension/sessions/godot.cpp b/src/gdextension/sessions/godot.cpp index e59f5cef..e30ae23c 100644 --- a/src/gdextension/sessions/godot.cpp +++ b/src/gdextension/sessions/godot.cpp @@ -118,6 +118,7 @@ osp::fw::FeatureDef const ftrGodotScene = feature_def("GodotScene", [] ( Implement gdScn, DependOn godot, DependOn mainApp, + DependOn cleanup, DependOn windowApp, DependOn scnRender, DependOn scn, @@ -129,7 +130,7 @@ osp::fw::FeatureDef const ftrGodotScene = feature_def("GodotScene", [] ( rFB.pipeline(gdScn.pl.fbo).parent(scnRender.pl.render); rFB.pipeline(gdScn.pl.camera).parent(scnRender.pl.render); - rFB.data_emplace(gdScn.di.scnRenderGl); + rFB.data_emplace(gdScn.di.scnRenderGd); godot::RID &rCamera = rFB.data_emplace(gdScn.di.camera); rCamera = rs->camera_create(); @@ -140,7 +141,7 @@ osp::fw::FeatureDef const ftrGodotScene = feature_def("GodotScene", [] ( .name("Resize ACtxSceneRenderGd to fit all DrawEnts") .run_on({ scnRender.pl.drawEntResized(Run) }) .sync_with({}) - .args({ scnRender.di.scnRender, gdScn.di.scnRenderGl }) + .args({ scnRender.di.scnRender, gdScn.di.scnRenderGd }) .func([](osp::draw::ACtxSceneRender const &rScnRender, draw::ACtxSceneRenderGd &rScnRenderGd) noexcept { std::size_t const capacity = rScnRender.m_drawIds.capacity(); @@ -182,7 +183,7 @@ osp::fw::FeatureDef const ftrGodotScene = feature_def("GodotScene", [] ( godot.pl.texture(Ready), godot.pl.entTexture(Modify), scnRender.pl.drawEntResized(Done) }) - .args({ comScn.di.drawing, comScn.di.drawingRes, scnRender.di.scnRender, gdScn.di.scnRenderGl, godot.di.render }) + .args({ comScn.di.drawing, comScn.di.drawingRes, scnRender.di.scnRender, gdScn.di.scnRenderGd, godot.di.render }) .func([](draw::ACtxDrawing &rDrawing, draw::ACtxDrawingRes &rDrawingRes, draw::ACtxSceneRender &rScnRender, @@ -203,7 +204,7 @@ osp::fw::FeatureDef const ftrGodotScene = feature_def("GodotScene", [] ( godot.pl.texture(Ready), godot.pl.entTexture(Modify), scnRender.pl.drawEntResized(Done) }) - .args({ comScn.di.drawingRes, scnRender.di.scnRender, gdScn.di.scnRenderGl, godot.di.render }) + .args({ comScn.di.drawingRes, scnRender.di.scnRender, gdScn.di.scnRenderGd, godot.di.render }) .func([](draw::ACtxDrawingRes &rDrawingRes, draw::ACtxSceneRender &rScnRender, draw::ACtxSceneRenderGd &rScnRenderGl, @@ -226,7 +227,7 @@ osp::fw::FeatureDef const ftrGodotScene = feature_def("GodotScene", [] ( godot.pl.mesh(Ready), godot.pl.entMesh(Modify), scnRender.pl.drawEntResized(Done) }) - .args({ comScn.di.drawingRes, scnRender.di.scnRender, gdScn.di.scnRenderGl, godot.di.render }) + .args({ comScn.di.drawingRes, scnRender.di.scnRender, gdScn.di.scnRenderGd, godot.di.render }) .func([](draw::ACtxDrawingRes &rDrawingRes, draw::ACtxSceneRender &rScnRender, draw::ACtxSceneRenderGd &rScnRenderGl, @@ -247,7 +248,7 @@ osp::fw::FeatureDef const ftrGodotScene = feature_def("GodotScene", [] ( godot.pl.mesh(Ready), godot.pl.entMesh(Modify), scnRender.pl.drawEntResized(Done) }) - .args({ comScn.di.drawingRes, scnRender.di.scnRender, gdScn.di.scnRenderGl, godot.di.render }) + .args({ comScn.di.drawingRes, scnRender.di.scnRender, gdScn.di.scnRenderGd, godot.di.render }) .func([](draw::ACtxDrawingRes &rDrawingRes, draw::ACtxSceneRender &rScnRender, draw::ACtxSceneRenderGd &rScnRenderGl, @@ -275,16 +276,13 @@ osp::fw::FeatureDef const ftrGodotScene = feature_def("GodotScene", [] ( godot.pl.entMesh(Ready), godot.pl.entTexture(Ready), scnRender.pl.drawEnt(Ready) }) - .args({ scnRender.di.scnRender, godot.di.render, gdScn.di.scnRenderGl }) + .args({ scnRender.di.scnRender, godot.di.render, gdScn.di.scnRenderGd }) .func([](draw::ACtxSceneRender &rScnRender, draw::RenderGd &rRenderGd, draw::ACtxSceneRenderGd &rScnRenderGd) noexcept { for (DrawEnt const& ent : rScnRenderGd.m_render) { - if ( rScnRender.m_visible.contains(ent) ) - { - sync_godot_ent(ent, rScnRender, rScnRenderGd, rRenderGd); - } + sync_godot_ent(ent, rScnRender, rScnRenderGd, rRenderGd); } }); @@ -292,7 +290,7 @@ osp::fw::FeatureDef const ftrGodotScene = feature_def("GodotScene", [] ( .name("Delete entities from render groups") .run_on({ scnRender.pl.drawEntDelete(UseOrRun) }) .sync_with({ scnRender.pl.groupEnts(Delete) }) - .args({ comScn.di.drawEntDel, gdScn.di.scnRenderGl}) + .args({ comScn.di.drawEntDel, gdScn.di.scnRenderGd}) .func([](draw::DrawEntVec_t const &rDrawEntDel, draw::ACtxSceneRenderGd &rScnRenderGl) noexcept { rScnRenderGl.m_render.erase(rDrawEntDel.begin(), rDrawEntDel.end()); @@ -301,7 +299,7 @@ osp::fw::FeatureDef const ftrGodotScene = feature_def("GodotScene", [] ( rFB.task() .name("Delete entities instance from scene") .run_on({ scnRender.pl.drawEntDelete(UseOrRun) }) - .args({ comScn.di.drawing, comScn.di.drawEntDel, gdScn.di.scnRenderGl }) + .args({ comScn.di.drawing, comScn.di.drawEntDel, gdScn.di.scnRenderGd }) .func([](draw::ACtxDrawing const &rDrawing, draw::DrawEntVec_t const &rDrawEntDel, draw::ACtxSceneRenderGd &rScnRenderGl) noexcept { @@ -320,7 +318,7 @@ osp::fw::FeatureDef const ftrGodotScene = feature_def("GodotScene", [] ( .sync_with({ scnRender.pl.groupEnts(Modify), scnRender.pl.group(Modify), scnRender.pl.materialDirty(UseOrRun) }) - .args({ scnRender.di.scnRender, gdScn.di.scnRenderGl, godot.di.render}) + .args({ scnRender.di.scnRender, gdScn.di.scnRenderGd, godot.di.render}) .func([](ACtxSceneRender &rScnRender, ACtxSceneRenderGd &rScnRenderGd, RenderGd &rRenderGd) noexcept { @@ -338,7 +336,7 @@ osp::fw::FeatureDef const ftrGodotScene = feature_def("GodotScene", [] ( godot.pl.texture(Ready), scnRender.pl.groupEnts(Modify), scnRender.pl.group(Modify) }) - .args({ scnRender.di.scnRender, gdScn.di.scnRenderGl, godot.di.render}) + .args({ scnRender.di.scnRender, gdScn.di.scnRenderGd, godot.di.render}) .func([](ACtxSceneRender &rScnRender, ACtxSceneRenderGd &rScnRenderGd, RenderGd &rRenderGd) noexcept { @@ -347,6 +345,16 @@ osp::fw::FeatureDef const ftrGodotScene = feature_def("GodotScene", [] ( rScnRenderGd.m_render.insert(rMat.m_ents.begin(), rMat.m_ents.end()); } }); + rFB.task() + .name("Clean up scene") + .run_on({ cleanup.pl.cleanup(Run_) }) + .args({ gdScn.di.scnRenderGd , gdScn.di.camera}) + .func([](ACtxSceneRenderGd &rScnRenderGd, godot::RID& rCamera) noexcept { + godot::RenderingServer *rs = godot::RenderingServer::get_singleton(); + rs->free_rid(rCamera); + rScnRenderGd.clear_resource_owners(); + rScnRenderGd = {}; // Needs the OpenGL thread for destruction + }); }); // ftrGodotScene void sync_godot_ent(DrawEnt ent, ACtxSceneRender &rScnRender, ACtxSceneRenderGd &rScnRenderGd, RenderGd &rRenderGd) noexcept @@ -357,6 +365,23 @@ void sync_godot_ent(DrawEnt ent, ACtxSceneRender &rScnRender, ACtxSceneRenderGd auto rs = godot::RenderingServer::get_singleton(); + // Create instance if it does not exist + if ( ! rInstance.is_valid() ) + { + rInstance = rs->instance_create(); + rs->instance_set_scenario(rInstance, rRenderGd.scenario); + } + + // set visibility + if (rScnRender.m_visible.contains(ent)) { + rs->instance_set_visible(rInstance, true); + } + else + { + rs->instance_set_visible(rInstance, false); + return; + } + MeshGdId const meshId = rScnRenderGd.m_meshId[ent].m_glId; if ( meshId == lgrn::id_null()) { @@ -368,6 +393,7 @@ void sync_godot_ent(DrawEnt ent, ACtxSceneRender &rScnRender, ACtxSceneRenderGd if ( ! material.is_valid() ) { material = rs->material_create(); + rs->mesh_surface_set_material(rMesh, 0, material); } // test if the mesh is textured or not. if ( rScnRenderGd.m_diffuseTexId[ent].m_gdId != lgrn::id_null() ) @@ -380,13 +406,10 @@ void sync_godot_ent(DrawEnt ent, ACtxSceneRender &rScnRender, ACtxSceneRenderGd // Set albdedo color auto color = rScnRender.m_color[ent]; rs->material_set_param( - material, "albedo_color", godot::Color(color.r(), color.g(), color.b(), color.a())); + material, "albedo_color", godot::Color(1., 0., 0., 0.5)); - // Create instance if it does not exist - if ( ! rInstance.is_valid() ) - { - rInstance = rs->instance_create2(rMesh, rRenderGd.scenario); - } + rs->mesh_surface_set_material(rMesh, 0, material); + rs->instance_set_base(rInstance, rMesh); auto rot = Magnum::Quaternion::fromMatrix(drawTf.rotation()).data(); auto scale = drawTf.scaling(); @@ -397,6 +420,7 @@ void sync_godot_ent(DrawEnt ent, ACtxSceneRender &rScnRender, ACtxSceneRenderGd auto origin = godot::Vector3(pos.x(), pos.y(), pos.z()); auto tf = godot::Transform3D(basis, origin); rs->instance_set_transform(rInstance, tf); + } osp::fw::FeatureDef const ftrCameraControlGD = feature_def("CameraControlGodot", [] (