// #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include // #include "material/FileMaterialProvider.hpp" // #include "material/UnlitMaterialProvider.hpp" // #include "material/unlit.h" // #include "material/gizmo.h" // #include "StreamBufferAdapter.hpp" // #include "Log.hpp" // #include "scene/SceneManager.hpp" // #include "scene/CustomGeometry.hpp" // #include "scene/GeometrySceneAsset.hpp" // #include "scene/GltfSceneAsset.hpp" // #include "scene/Gizmo.hpp" // #include "scene/SceneAsset.hpp" // #include "scene/GeometrySceneAssetBuilder.hpp" // #include "TextureProjection.hpp" // #include "resources/translation_gizmo_glb.h" // #include "resources/rotation_gizmo_glb.h" // extern "C" // { // #include "material/image.h" // #include "material/unlit_fixed_size.h" // } // namespace thermion // { // using namespace std::chrono; // using namespace image; // using namespace utils; // using namespace filament; // using namespace filament::gltfio; // using std::unique_ptr; // SceneManager::SceneManager(const ResourceLoaderWrapperImpl *const resourceLoaderWrapper, // Engine *engine, // Scene *scene, // const char *uberArchivePath, // Camera *mainCamera) // : _resourceLoaderWrapper(resourceLoaderWrapper), // _engine(engine), // _scene(scene), // _mainCamera(mainCamera) // { // _stbDecoder = createStbProvider(_engine); // _ktxDecoder = createKtx2Provider(_engine); // _gltfResourceLoader = new ResourceLoader({.engine = _engine, // .normalizeSkinningWeights = true}); // if (uberArchivePath) // { // auto uberdata = resourceLoaderWrapper->load(uberArchivePath); // if (!uberdata.data) // { // Log("Failed to load ubershader material. This is fatal."); // } // _ubershaderProvider = gltfio::createUbershaderProvider(_engine, uberdata.data, uberdata.size); // resourceLoaderWrapper->free(uberdata); // } // else // { // _ubershaderProvider = gltfio::createUbershaderProvider( // _engine, UBERARCHIVE_DEFAULT_DATA, UBERARCHIVE_DEFAULT_SIZE); // } // _unlitMaterialProvider = new UnlitMaterialProvider(_engine, UNLIT_PACKAGE, UNLIT_UNLIT_SIZE); // utils::EntityManager &em = utils::EntityManager::get(); // _ncm = new NameComponentManager(em); // _assetLoader = AssetLoader::create({_engine, _ubershaderProvider, _ncm, &em}); // _gltfResourceLoader->addTextureProvider("image/ktx2", _ktxDecoder); // _gltfResourceLoader->addTextureProvider("image/png", _stbDecoder); // _gltfResourceLoader->addTextureProvider("image/jpeg", _stbDecoder); // auto &tm = _engine->getTransformManager(); // _collisionComponentManager = std::make_unique(tm); // _animationManager = std::make_unique(_engine, _scene); // _unlitFixedSizeMaterial = // Material::Builder() // .package(UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_DATA, UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_SIZE) // .build(*_engine); // _gizmoMaterial = // Material::Builder() // .package(GIZMO_GIZMO_DATA, GIZMO_GIZMO_SIZE) // .build(*_engine); // } // SceneManager::~SceneManager() // { // TRACE("Destroying cameras"); // for (auto camera : _cameras) // { // auto entity = camera->getEntity(); // _engine->destroyCameraComponent(entity); // _engine->getEntityManager().destroy(entity); // } // TRACE("Cameras destroyed"); // destroyAll(); // TRACE("Destroyed all assets"); // _engine->destroy(_unlitFixedSizeMaterial); // _engine->destroy(_gizmoMaterial); // TRACE("Destroyed materials"); // _cameras.clear(); // _grid = nullptr; // _gltfResourceLoader->asyncCancelLoad(); // _ubershaderProvider->destroyMaterials(); // _animationManager = std::nullptr_t(); // _collisionComponentManager = std::nullptr_t(); // delete _ncm; // delete _gltfResourceLoader; // delete _stbDecoder; // delete _ktxDecoder; // delete _ubershaderProvider; // TRACE("Destroying asset loader"); // AssetLoader::destroy(&_assetLoader); // TRACE("Destroyed asset loader"); // } // SceneAsset *SceneManager::createGrid(Material *material) // { // if (!_grid) // { // if (!material) // { // material = Material::Builder() // .package(GRID_PACKAGE, GRID_GRID_SIZE) // .build(*_engine); // } // _grid = std::make_unique(*_engine, material); // } // return _grid.get(); // } // bool SceneManager::isGridEntity(utils::Entity entity) // { // if (!_grid) // { // TRACE("No grid"); // return false; // } // if (entity == _grid->getEntity()) // { // TRACE("%d is a grid entity.", entity); // return true; // } // for (int i = 0; i < _grid->getChildEntityCount(); i++) // { // if (entity == _grid->getChildEntities()[i]) // { // TRACE("%d is a child entity of grid.", entity); // return true; // } // } // return false; // } // Gizmo *SceneManager::createGizmo(View *view, Scene *scene, GizmoType type) // { // TRACE("Creating gizmo type %d", type); // Gizmo *raw; // switch (type) // { // case GizmoType::TRANSLATION: // if (!_translationGizmoGlb) // { // TRACE("Translation gizmo source not found, loading"); // _translationGizmoGlb = loadGlbFromBuffer(TRANSLATION_GIZMO_GLB_TRANSLATION_GIZMO_DATA, TRANSLATION_GIZMO_GLB_TRANSLATION_GIZMO_SIZE, 100, true, 4, 0, false, false); // } // raw = new Gizmo(_translationGizmoGlb, _engine, view, scene, _unlitFixedSizeMaterial); // TRACE("Built translation gizmo"); // break; // case GizmoType::ROTATION: // if (!_rotationGizmoGlb) // { // TRACE("Rotation gizmo source not found, loading"); // _rotationGizmoGlb = loadGlbFromBuffer(ROTATION_GIZMO_GLB_ROTATION_GIZMO_DATA, ROTATION_GIZMO_GLB_ROTATION_GIZMO_SIZE, 100, true, 4, 0, false, false); // } // raw = new Gizmo(_rotationGizmoGlb, _engine, view, scene, _unlitFixedSizeMaterial); // TRACE("Built rotation gizmo"); // break; // } // _sceneAssets.push_back(std::unique_ptr(raw)); // return raw; // } // int SceneManager::getInstanceCount(EntityId entityId) // { // auto entity = utils::Entity::import(entityId); // for (auto &asset : _sceneAssets) // { // if (asset->getEntity() == entity) // { // return asset->getInstanceCount(); // } // } // return -1; // } // void SceneManager::getInstances(EntityId entityId, EntityId *out) // { // auto entity = utils::Entity::import(entityId); // for (auto &asset : _sceneAssets) // { // if (asset->getEntity() == entity) // { // for (int i = 0; i < asset->getInstanceCount(); i++) // { // out[i] = Entity::smuggle(asset->getInstanceAt(i)->getEntity()); // } // return; // } // } // } // SceneAsset *SceneManager::loadGltf(const char *uri, // const char *relativeResourcePath, // int numInstances, // bool keepData) // { // if (numInstances < 1) // { // return std::nullptr_t(); // } // ResourceBuffer rbuf = _resourceLoaderWrapper->load(uri); // std::vector instances(numInstances); // FilamentAsset *asset = _assetLoader->createInstancedAsset((uint8_t *)rbuf.data, rbuf.size, instances.data(), numInstances); // if (!asset) // { // Log("Unable to load glTF asset at %d", uri); // return std::nullptr_t(); // } // const char *const *const resourceUris = asset->getResourceUris(); // const size_t resourceUriCount = asset->getResourceUriCount(); // std::vector resourceBuffers; // for (size_t i = 0; i < resourceUriCount; i++) // { // std::string uri = std::string(relativeResourcePath) + std::string("/") + std::string(resourceUris[i]); // ResourceBuffer buf = _resourceLoaderWrapper->load(uri.c_str()); // resourceBuffers.push_back(buf); // ResourceLoader::BufferDescriptor b(buf.data, buf.size); // _gltfResourceLoader->addResourceData(resourceUris[i], std::move(b)); // } // #ifdef __EMSCRIPTEN__ // if (!_gltfResourceLoader->asyncBeginLoad(asset)) // { // Log("Unknown error loading glTF asset"); // _resourceLoaderWrapper->free(rbuf); // for (auto &rb : resourceBuffers) // { // _resourceLoaderWrapper->free(rb); // } // return 0; // } // while (_gltfResourceLoader->asyncGetLoadProgress() < 1.0f) // { // _gltfResourceLoader->asyncUpdateLoad(); // } // #else // // load resources synchronously // if (!_gltfResourceLoader->loadResources(asset)) // { // Log("Unknown error loading glTF asset"); // _resourceLoaderWrapper->free(rbuf); // for (auto &rb : resourceBuffers) // { // _resourceLoaderWrapper->free(rb); // } // return std::nullptr_t(); // } // #endif // auto sceneAsset = std::make_unique( // asset, // _assetLoader, // _engine, // _ncm); // auto filamentInstance = asset->getInstance(); // size_t entityCount = filamentInstance->getEntityCount(); // _scene->addEntities(filamentInstance->getEntities(), entityCount); // for (auto &rb : resourceBuffers) // { // _resourceLoaderWrapper->free(rb); // } // _resourceLoaderWrapper->free(rbuf); // auto lights = asset->getLightEntities(); // _scene->addEntities(lights, asset->getLightEntityCount()); // sceneAsset->createInstance(); // auto entityId = Entity::smuggle(sceneAsset->getEntity()); // auto *raw = sceneAsset.get(); // _sceneAssets.push_back(std::move(sceneAsset)); // Log("Loaded glTF asset from uri: %s", uri); // return raw; // } // void SceneManager::setVisibilityLayer(EntityId entityId, int layer) // { // utils::Entity entity = utils::Entity::import(entityId); // for (auto &asset : _sceneAssets) // { // if (asset->getEntity() == entity) // { // asset->setLayer(_engine->getRenderableManager(), layer); // } // } // } // SceneAsset *SceneManager::loadGlbFromBuffer(const uint8_t *data, size_t length, int numInstances, bool keepData, int priority, int layer, bool loadResourcesAsync, bool addToScene) // { // auto &rm = _engine->getRenderableManager(); // std::vector instances(numInstances); // FilamentAsset *asset = _assetLoader->createInstancedAsset((const uint8_t *)data, length, instances.data(), numInstances); // Log("Created glTF asset with %d instances.", numInstances); // if (!asset) // { // Log("Unknown error loading GLB asset."); // return std::nullptr_t(); // } // #ifdef __EMSCRIPTEN__ // if (!_gltfResourceLoader->asyncBeginLoad(asset)) // { // Log("Unknown error loading glb asset"); // return 0; // } // while (_gltfResourceLoader->asyncGetLoadProgress() < 1.0f) // { // _gltfResourceLoader->asyncUpdateLoad(); // } // #else // if (loadResourcesAsync) // { // if (!_gltfResourceLoader->asyncBeginLoad(asset)) // { // Log("Unknown error loading glb asset"); // return 0; // } // } // else // { // if (!_gltfResourceLoader->loadResources(asset)) // { // Log("Unknown error loading glb asset"); // return 0; // } // } // #endif // auto sceneAsset = std::make_unique( // asset, // _assetLoader, // _engine, // _ncm); // auto sceneAssetInstance = sceneAsset->createInstance(); // if (addToScene) // { // sceneAssetInstance->addAllEntities(_scene); // } // sceneAssetInstance->setPriority(_engine->getRenderableManager(), priority); // sceneAssetInstance->setLayer(_engine->getRenderableManager(), layer); // auto *raw = sceneAsset.get(); // _sceneAssets.push_back(std::move(sceneAsset)); // return raw; // } // SceneAsset *SceneManager::createInstance(SceneAsset *asset, MaterialInstance **materialInstances, size_t materialInstanceCount) // { // std::lock_guard lock(_mutex); // auto instance = asset->createInstance(materialInstances, materialInstanceCount); // if (instance) // { // instance->addAllEntities(_scene); // } // else // { // Log("Failed to create instance"); // } // return instance; // } // SceneAsset *SceneManager::loadGlb(const char *uri, int numInstances, bool keepData) // { // ResourceBuffer rbuf = _resourceLoaderWrapper->load(uri); // auto entity = loadGlbFromBuffer((const uint8_t *)rbuf.data, rbuf.size, numInstances, keepData); // _resourceLoaderWrapper->free(rbuf); // return entity; // } // bool SceneManager::removeFromScene(EntityId entityId) // { // _scene->remove(Entity::import(entityId)); // return true; // } // bool SceneManager::addToScene(EntityId entityId) // { // _scene->addEntity(Entity::import(entityId)); // return true; // } // void SceneManager::destroyAll() // { // destroyLights(); // destroyAssets(); // std::lock_guard lock(_mutex); // for (auto *materialInstance : _materialInstances) // { // _engine->destroy(materialInstance); // } // _materialInstances.clear(); // } // void SceneManager::destroy(SceneAsset *asset) // { // std::lock_guard lock(_mutex); // auto entity = asset->getEntity(); // _collisionComponentManager->removeComponent(entity); // _animationManager->removeAnimationComponent(utils::Entity::smuggle(entity)); // for (int i = 0; i < asset->getChildEntityCount(); i++) // { // auto childEntity = asset->getChildEntities()[i]; // _collisionComponentManager->removeComponent(childEntity); // _animationManager->removeAnimationComponent(utils::Entity::smuggle(childEntity)); // } // asset->removeAllEntities(_scene); // if (asset->isInstance()) // { // asset->destroyInstance(asset); // } // else // { // auto it = std::remove_if(_sceneAssets.begin(), _sceneAssets.end(), [=](auto &sceneAsset) // { return sceneAsset.get() == asset; }); // _sceneAssets.erase(it, _sceneAssets.end()); // } // } // utils::Entity SceneManager::addLight( // LightManager::Type t, // float colour, // float intensity, // float posX, // float posY, // float posZ, // float dirX, // float dirY, // float dirZ, // float falloffRadius, // float spotLightConeInner, // float spotLightConeOuter, // float sunAngularRadius, // float sunHaloSize, // float sunHaloFallof, // bool shadows) // { // auto light = EntityManager::get().create(); // // LightManager::ShadowOptions shadowOptions; // // shadowOptions.stable = true; // auto result = LightManager::Builder(t) // .color(Color::cct(colour)) // .intensity(intensity) // .falloff(falloffRadius) // .spotLightCone(spotLightConeInner, spotLightConeOuter) // .sunAngularRadius(sunAngularRadius) // .sunHaloSize(sunHaloSize) // .sunHaloFalloff(sunHaloFallof) // .position(filament::math::float3(posX, posY, posZ)) // .direction(filament::math::float3(dirX, dirY, dirZ)) // // .shadowOptions(shadowOptions) // .castShadows(shadows) // .build(*_engine, light); // if (result != LightManager::Builder::Result::Success) // { // Log("ERROR : failed to create light"); // } // else // { // _scene->addEntity(light); // _lights.push_back(light); // TRACE("Created light"); // } // return light; // } // void SceneManager::removeLight(utils::Entity entity) // { // auto removed = remove(_lights.begin(), _lights.end(), entity); // _scene->remove(entity); // EntityManager::get().destroy(1, &entity); // } // void SceneManager::destroyLights() // { // std::lock_guard lock(_mutex); // _scene->removeEntities(_lights.data(), _lights.size()); // EntityManager::get().destroy(_lights.size(), _lights.data()); // _lights.clear(); // } // void SceneManager::destroyAssets() // { // std::lock_guard lock(_mutex); // for (auto &asset : _sceneAssets) // { // asset->removeAllEntities(_scene); // for(int i = 0; i < asset->getInstanceCount(); i++) { // asset->getInstanceAt(i)->removeAllEntities(_scene); // } // } // _sceneAssets.clear(); // } // void SceneManager::addCollisionComponent(EntityId entityId, void (*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsTransform) // { // std::lock_guard lock(_mutex); // utils::Entity entity = utils::Entity::import(entityId); // for (auto &asset : _sceneAssets) // { // auto *instance = reinterpret_cast(asset->getInstanceByEntity(entity)); // if (instance) // { // auto collisionInstance = _collisionComponentManager->addComponent(instance->getInstance()->getRoot()); // _collisionComponentManager->elementAt<0>(collisionInstance) = instance->getInstance()->getBoundingBox(); // _collisionComponentManager->elementAt<1>(collisionInstance) = onCollisionCallback; // _collisionComponentManager->elementAt<2>(collisionInstance) = affectsTransform; // return; // } // } // } // void SceneManager::removeCollisionComponent(EntityId entityId) // { // std::lock_guard lock(_mutex); // utils::Entity entity = utils::Entity::import(entityId); // _collisionComponentManager->removeComponent(entity); // } // void SceneManager::testCollisions(EntityId entityId) // { // utils::Entity entity = utils::Entity::import(entityId); // for (auto &asset : _sceneAssets) // { // auto *instance = reinterpret_cast(asset->getInstanceByEntity(entity)); // if (instance) // { // const auto &tm = _engine->getTransformManager(); // auto transformInstance = tm.getInstance(entity); // auto worldTransform = tm.getWorldTransform(transformInstance); // auto aabb = instance->getInstance()->getBoundingBox(); // aabb = aabb.transform(worldTransform); // _collisionComponentManager->collides(entity, aabb); // } // } // } // void SceneManager::update() // { // _animationManager->update(); // _updateTransforms(); // } // void SceneManager::_updateTransforms() // { // std::lock_guard lock(_mutex); // // auto &tm = _engine->getTransformManager(); // // tm.openLocalTransformTransaction(); // // for (const auto &[entityId, transformUpdate] : _transformUpdates) // // { // // const auto &pos = _instances.find(entityId); // // bool isCollidable = true; // // Entity entity; // // filament::TransformManager::Instance transformInstance; // // filament::math::mat4f transform; // // Aabb boundingBox; // // if (pos == _instances.end()) // // { // // isCollidable = false; // // entity = Entity::import(entityId); // // } // // else // // { // // const auto *instance = pos->second; // // entity = instance->getRoot(); // // boundingBox = instance->getBoundingBox(); // // } // // transformInstance = tm.getInstance(entity); // // transform = tm.getTransform(transformInstance); // // if (isCollidable) // // { // // auto transformedBB = boundingBox.transform(transform); // // auto collisionAxes = _collisionComponentManager->collides(entity, transformedBB); // // if (collisionAxes.size() == 1) // // { // // // auto globalAxis = collisionAxes[0]; // // // globalAxis *= norm(relativeTranslation); // // // auto newRelativeTranslation = relativeTranslation + globalAxis; // // // translation -= relativeTranslation; // // // translation += newRelativeTranslation; // // // transform = composeMatrix(translation, rotation, scale); // // } // // else if (collisionAxes.size() > 1) // // { // // // translation -= relativeTranslation; // // // transform = composeMatrix(translation, rotation, scale); // // } // // } // // tm.setTransform(transformInstance, transformUpdate); // // } // // tm.commitLocalTransformTransaction(); // // _transformUpdates.clear(); // } // void SceneManager::queueRelativePositionUpdateFromViewportVector(View *view, EntityId entityId, float viewportCoordX, float viewportCoordY) // { // // Get the camera and viewport // const auto &camera = view->getCamera(); // const auto &vp = view->getViewport(); // // Convert viewport coordinates to NDC space // float ndcX = (2.0f * viewportCoordX) / vp.width - 1.0f; // float ndcY = 1.0f - (2.0f * viewportCoordY) / vp.height; // // Get the current position of the entity // auto &tm = _engine->getTransformManager(); // auto entity = Entity::import(entityId); // auto transformInstance = tm.getInstance(entity); // auto currentTransform = tm.getTransform(transformInstance); // // get entity model origin in camera space // auto entityPositionInCameraSpace = camera.getViewMatrix() * currentTransform * filament::math::float4{0.0f, 0.0f, 0.0f, 1.0f}; // // get entity model origin in clip space // auto entityPositionInClipSpace = camera.getProjectionMatrix() * entityPositionInCameraSpace; // auto entityPositionInNdcSpace = entityPositionInClipSpace / entityPositionInClipSpace.w; // // Viewport coords in NDC space (use entity position in camera space Z to project onto near plane) // math::float4 ndcNearPlanePos = {ndcX, ndcY, -1.0f, 1.0f}; // math::float4 ndcFarPlanePos = {ndcX, ndcY, 0.99f, 1.0f}; // math::float4 ndcEntityPlanePos = {ndcX, ndcY, entityPositionInNdcSpace.z, 1.0f}; // // Get viewport coords in clip space // math::float4 nearPlaneInClipSpace = Camera::inverseProjection(camera.getProjectionMatrix()) * ndcNearPlanePos; // auto nearPlaneInCameraSpace = nearPlaneInClipSpace / nearPlaneInClipSpace.w; // math::float4 farPlaneInClipSpace = Camera::inverseProjection(camera.getProjectionMatrix()) * ndcFarPlanePos; // auto farPlaneInCameraSpace = farPlaneInClipSpace / farPlaneInClipSpace.w; // math::float4 entityPlaneInClipSpace = Camera::inverseProjection(camera.getProjectionMatrix()) * ndcEntityPlanePos; // auto entityPlaneInCameraSpace = entityPlaneInClipSpace / entityPlaneInClipSpace.w; // auto entityPlaneInWorldSpace = camera.getModelMatrix() * entityPlaneInCameraSpace; // } // void SceneManager::queueTransformUpdates(EntityId *entities, math::mat4 *transforms, int numEntities) // { // std::lock_guard lock(_mutex); // for (int i = 0; i < numEntities; i++) // { // auto entity = entities[i]; // const auto &pos = _transformUpdates.find(entity); // if (pos == _transformUpdates.end()) // { // _transformUpdates.emplace(entity, transforms[i]); // } // auto curr = _transformUpdates[entity]; // _transformUpdates[entity] = curr; // } // } // Aabb3 SceneManager::getRenderableBoundingBox(EntityId entityId) // { // auto &rm = _engine->getRenderableManager(); // auto instance = rm.getInstance(Entity::import(entityId)); // if (!instance.isValid()) // { // return Aabb3{}; // } // auto box = rm.getAxisAlignedBoundingBox(instance); // return Aabb3{box.center.x, box.center.y, box.center.z, box.halfExtent.x, box.halfExtent.y, box.halfExtent.z}; // } // Aabb2 SceneManager::getScreenSpaceBoundingBox(View *view, EntityId entityId) // { // const auto &camera = view->getCamera(); // const auto &viewport = view->getViewport(); // auto &tcm = _engine->getTransformManager(); // auto &rcm = _engine->getRenderableManager(); // // Get the projection and view matrices // math::mat4 projMatrix = camera.getProjectionMatrix(); // math::mat4 viewMatrix = camera.getViewMatrix(); // math::mat4 vpMatrix = projMatrix * viewMatrix; // auto entity = Entity::import(entityId); // auto renderable = rcm.getInstance(entity); // auto worldTransform = tcm.getWorldTransform(tcm.getInstance(entity)); // // Get the axis-aligned bounding box in model space // Box aabb = rcm.getAxisAlignedBoundingBox(renderable); // auto min = aabb.getMin(); // auto max = aabb.getMax(); // // Transform the 8 corners of the AABB to clip space // std::array corners = { // worldTransform * math::float4(min.x, min.y, min.z, 1.0f), // worldTransform * math::float4(max.x, min.y, min.z, 1.0f), // worldTransform * math::float4(min.x, max.y, min.z, 1.0f), // worldTransform * math::float4(max.x, max.y, min.z, 1.0f), // worldTransform * math::float4(min.x, min.y, max.z, 1.0f), // worldTransform * math::float4(max.x, min.y, max.z, 1.0f), // worldTransform * math::float4(min.x, max.y, max.z, 1.0f), // worldTransform * math::float4(max.x, max.y, max.z, 1.0f)}; // // Project corners to clip space and convert to viewport space // float minX = std::numeric_limits::max(); // float minY = std::numeric_limits::max(); // float maxX = std::numeric_limits::lowest(); // float maxY = std::numeric_limits::lowest(); // for (const auto &corner : corners) // { // math::float4 clipSpace = vpMatrix * corner; // // Check if the point is behind the camera // if (clipSpace.w <= 0) // { // continue; // Skip this point // } // // Perform perspective division // math::float3 ndcSpace = clipSpace.xyz / clipSpace.w; // // Clamp NDC coordinates to [-1, 1] range // ndcSpace.x = std::max(-1.0f, std::min(1.0f, ndcSpace.x)); // ndcSpace.y = std::max(-1.0f, std::min(1.0f, ndcSpace.y)); // // Convert NDC to viewport space // float viewportX = (ndcSpace.x * 0.5f + 0.5f) * viewport.width; // float viewportY = (1.0f - (ndcSpace.y * 0.5f + 0.5f)) * viewport.height; // Flip Y-axis // minX = std::min(minX, viewportX); // minY = std::min(minY, viewportY); // maxX = std::max(maxX, viewportX); // maxY = std::max(maxY, viewportY); // } // return Aabb2{minX, minY, maxX, maxY}; // } // static filament::gltfio::MaterialKey getDefaultUnlitMaterialConfig(int numUvs) // { // filament::gltfio::MaterialKey config; // memset(&config, 0, sizeof(config)); // config.unlit = false; // config.doubleSided = false; // config.useSpecularGlossiness = false; // config.alphaMode = filament::gltfio::AlphaMode::OPAQUE; // config.hasBaseColorTexture = numUvs > 0; // config.baseColorUV = 0; // config.hasVertexColors = false; // return config; // } // SceneAsset *SceneManager::createGeometry( // float *vertices, // uint32_t numVertices, // float *normals, // uint32_t numNormals, // float *uvs, // uint32_t numUvs, // uint16_t *indices, // uint32_t numIndices, // filament::RenderableManager::PrimitiveType primitiveType, // filament::MaterialInstance **materialInstances, // size_t materialInstanceCount, // bool keepData) // { // utils::Entity entity; // auto builder = GeometrySceneAssetBuilder(_engine) // .vertices(vertices, numVertices) // .indices(indices, numIndices) // .primitiveType(primitiveType); // if (normals) // { // builder.normals(normals, numNormals); // } // if (uvs) // { // builder.uvs(uvs, numUvs); // } // builder.materials(materialInstances, materialInstanceCount); // auto sceneAsset = builder.build(); // if (!sceneAsset) // { // Log("Failed to create geometry"); // return std::nullptr_t(); // } // sceneAsset->addAllEntities(_scene); // auto *raw = sceneAsset.get(); // _sceneAssets.push_back(std::move(sceneAsset)); // return raw; // } // void SceneManager::destroy(filament::MaterialInstance *instance) // { // auto it = std::find(_materialInstances.begin(), _materialInstances.end(), instance); // if (it != _materialInstances.end()) // { // _materialInstances.erase(it); // } // _engine->destroy(instance); // } // MaterialInstance *SceneManager::createUnlitFixedSizeMaterialInstance() // { // auto instance = _unlitFixedSizeMaterial->createInstance(); // instance->setParameter("scale", 1.0f); // return instance; // } // MaterialInstance *SceneManager::createUnlitMaterialInstance() // { // UvMap uvmap; // auto instance = _unlitMaterialProvider->createMaterialInstance(nullptr, &uvmap); // instance->setParameter("baseColorFactor", filament::math::float4{1.0f, 1.0f, 1.0f, 1.0f}); // instance->setParameter("baseColorIndex", -1); // instance->setParameter("uvScale", filament::math::float2{1.0f, 1.0f}); // _materialInstances.push_back(instance); // return instance; // } // Camera *SceneManager::createCamera() // { // auto entity = EntityManager::get().create(); // auto camera = _engine->createCamera(entity); // _cameras.push_back(camera); // return camera; // } // void SceneManager::destroyCamera(Camera *camera) // { // auto entity = camera->getEntity(); // _engine->destroyCameraComponent(entity); // _engine->getEntityManager().destroy(entity); // auto it = std::find(_cameras.begin(), _cameras.end(), camera); // if (it != _cameras.end()) // { // _cameras.erase(it); // } // } // size_t SceneManager::getCameraCount() // { // return _cameras.size() + 1; // } // Camera *SceneManager::getCameraAt(size_t index) // { // if (index == 0) // { // return _mainCamera; // } // if (index - 1 > _cameras.size() - 1) // { // return nullptr; // } // return _cameras[index - 1]; // } // } // namespace thermion