reimplement grid as SceneAsset

This commit is contained in:
Nick Fisher
2024-11-30 16:01:25 +08:00
parent e43e1c9cbd
commit 1c5b5c890b
10 changed files with 245 additions and 132 deletions

View File

@@ -2,13 +2,13 @@ import 'dart:async';
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart';
import 'package:thermion_dart/src/viewer/src/shared_types/entities.dart';
import 'thermion_dart.g.dart';
import 'package:thermion_dart/thermion_dart.dart';
import 'package:vector_math/vector_math_64.dart';
import 'ffi_view.dart';
class FFIGizmo extends FFIAsset implements GizmoAsset {
final Set<ThermionEntity> nonPickableEntities;
final Set<ThermionEntity> gizmoEntities;
late NativeCallable<GizmoPickCallbackFunction> _nativeCallback;
@@ -20,8 +20,10 @@ class FFIGizmo extends FFIAsset implements GizmoAsset {
_callback?.call(GizmoPickResultType.values[resultType], Vector3(x, y, z));
}
bool isNonPickable(ThermionEntity entity) =>
nonPickableEntities.contains(entity);
bool isNonPickable(ThermionEntity entity) {
return SceneManager_isGridEntity(sceneManager!, entity);
}
bool isGizmoEntity(ThermionEntity entity) => gizmoEntities.contains(entity);
FFIGizmo(
@@ -30,7 +32,6 @@ class FFIGizmo extends FFIAsset implements GizmoAsset {
super.sceneManager,
super.renderableManager,
super.unlitMaterialProvider,
this.nonPickableEntities,
this.gizmoEntities) {
_nativeCallback =
NativeCallable<GizmoPickCallbackFunction>.listener(_onPickResult);

View File

@@ -1905,16 +1905,17 @@ external ffi.Pointer<TNameComponentManager>
ffi.Pointer<TSceneManager> tSceneManager,
);
@ffi.Native<ffi.Size Function(ffi.Pointer<TSceneManager>)>(isLeaf: true)
external int SceneManager_getOverlayEntityCount(
@ffi.Native<ffi.Pointer<TSceneAsset> Function(ffi.Pointer<TSceneManager>)>(
isLeaf: true)
external ffi.Pointer<TSceneAsset> SceneManager_createGrid(
ffi.Pointer<TSceneManager> tSceneManager,
);
@ffi.Native<EntityId Function(ffi.Pointer<TSceneManager>, ffi.Size)>(
@ffi.Native<ffi.Bool Function(ffi.Pointer<TSceneManager>, EntityId)>(
isLeaf: true)
external int SceneManager_getOverlayEntityAt(
external bool SceneManager_isGridEntity(
ffi.Pointer<TSceneManager> tSceneManager,
int index,
int entityId,
);
@ffi.Native<

View File

@@ -1755,6 +1755,31 @@ class ThermionViewerFFI extends ThermionViewer {
SceneManager_setVisibilityLayer(_sceneManager!, entity, layer.value);
}
FFIAsset? _grid;
///
///
///
Future showGridOverlay() async {
final ptr = SceneManager_createGrid(_sceneManager!);
_grid ??= FFIAsset(ptr, _sceneManager!, _engine!, _unlitMaterialProvider!);
await _grid!.addToScene();
}
///
///
///
Future removeGridOverlay() async {
if (_grid != null) {
await _grid!.removeFromScene();
SceneManager_destroyAsset(_sceneManager!, _grid!.pointer);
_grid = null;
}
}
///
///
///
Future<Uint8List> unproject(ThermionEntity entity, Uint8List input,
int inputWidth, int inputHeight, int outWidth, int outHeight) async {
final outPtr = Uint8List(outWidth * outHeight * 4);
@@ -1933,6 +1958,9 @@ class ThermionViewerFFI extends ThermionViewer {
return instance;
}
///
///
///
@override
Future requestFrame() async {
for (final hook in _hooks) {
@@ -1963,6 +1991,9 @@ class ThermionViewerFFI extends ThermionViewer {
return camera;
}
///
///
///
Future destroyCamera(FFICamera camera) async {
SceneManager_destroyCamera(_sceneManager!, camera.camera);
}
@@ -2037,10 +2068,6 @@ class ThermionViewerFFI extends ThermionViewer {
if (gizmo == nullptr) {
throw Exception("Failed to create gizmo");
}
final overlayEntityCount =
SceneManager_getOverlayEntityCount(_sceneManager!);
final overlayEntities = List<ThermionEntity>.generate(overlayEntityCount,
(i) => SceneManager_getOverlayEntityAt(_sceneManager!, i)).toSet();
final gizmoEntityCount =
SceneAsset_getChildEntityCount(gizmo.cast<TSceneAsset>());
@@ -2054,7 +2081,6 @@ class ThermionViewerFFI extends ThermionViewer {
_sceneManager!,
_engine!,
nullptr,
overlayEntities,
gizmoEntities.toSet()
..add(SceneAsset_getEntity(gizmo.cast<TSceneAsset>())));
}

View File

@@ -724,8 +724,7 @@ abstract class ThermionViewer {
///
/// The gizmo for translating/rotating objects. Only one gizmo can be active for a given view.
///
Future<GizmoAsset> createGizmo(covariant View view,
GizmoType type);
Future<GizmoAsset> createGizmo(covariant View view, GizmoType type);
///
/// Register a callback to be invoked when this viewer is disposed.
@@ -763,6 +762,16 @@ abstract class ThermionViewer {
///
Future setVisibilityLayer(ThermionEntity entity, VisibilityLayers layer);
///
///
///
Future showGridOverlay();
///
///
///
Future removeGridOverlay();
///
/// Decodes the specified image data and creates a texture.
///
@@ -875,7 +884,7 @@ abstract class ThermionViewer {
///
/// Returns the camera specified by the given index. Note that the camera at
/// index 0 is always the main camera; this cannot be destroyed.
///
///
/// Throws an exception if the index is out-of-bounds.
///
Camera getCameraAt(int index);

View File

@@ -57,8 +57,9 @@ extern "C"
EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAll(TSceneManager *tSceneManager);
EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAsset(TSceneManager *tSceneManager, TSceneAsset *sceneAsset);
EMSCRIPTEN_KEEPALIVE TNameComponentManager *SceneManager_getNameComponentManager(TSceneManager *tSceneManager);
EMSCRIPTEN_KEEPALIVE size_t SceneManager_getOverlayEntityCount(TSceneManager *tSceneManager);
EMSCRIPTEN_KEEPALIVE EntityId SceneManager_getOverlayEntityAt(TSceneManager *tSceneManager, size_t index);
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneManager_createGrid(TSceneManager *tSceneManager);
EMSCRIPTEN_KEEPALIVE bool SceneManager_isGridEntity(TSceneManager *tSceneManager, EntityId entityId);
#ifdef __cplusplus

View File

@@ -1,49 +1,56 @@
#pragma once
#include <vector>
#include <memory>
#include <vector>
#include <utils/Entity.h>
#include <filament/Engine.h>
#include <filament/Material.h>
#include <filament/MaterialInstance.h>
#include <filament/Scene.h>
#include <filament/Camera.h>
#include <filament/View.h>
#include <filament/Viewport.h>
#include <gltfio/AssetLoader.h>
#include <gltfio/FilamentAsset.h>
#include <gltfio/FilamentInstance.h>
#include <gltfio/ResourceLoader.h>
#include <filament/IndexBuffer.h>
#include <filament/InstanceBuffer.h>
#include <utils/Entity.h>
#include "scene/SceneAsset.hpp"
namespace thermion {
using namespace filament;
using namespace utils;
class GridOverlay {
public:
GridOverlay(Engine& engine);
void destroy();
class GridOverlay : public SceneAsset {
public:
GridOverlay(Engine& engine);
~GridOverlay();
utils::Entity sphere() {
return _sphereEntity;
}
SceneAssetType getType() override { return SceneAsset::SceneAssetType::Gizmo; }
bool isInstance() override { return false; }
SceneAsset* createInstance(MaterialInstance** materialInstances = nullptr,
size_t materialInstanceCount = 0) override;
MaterialInstance** getMaterialInstances() override { return &_materialInstance; }
size_t getMaterialInstanceCount() override { return 1; }
void addAllEntities(Scene* scene) override;
void removeAllEntities(Scene* scene) override;
void setPriority(RenderableManager& rm, int priority) override;
void setLayer(RenderableManager& rm, int layer) override;
utils::Entity grid() {
return _gridEntity;
}
private:
Engine &_engine;
utils::Entity _gridEntity;
utils::Entity _sphereEntity;
Material* _material;
MaterialInstance* _materialInstance;
MaterialInstance* _sphereMaterialInstance;
size_t getInstanceCount() override { return _instances.size(); }
SceneAsset* getInstanceByEntity(utils::Entity entity) override;
SceneAsset* getInstanceAt(size_t index) override;
size_t getChildEntityCount() override { return 2; }
const Entity* getChildEntities() override;
Entity findEntityByName(const char* name) override;
private:
Engine& _engine;
utils::Entity _gridEntity;
utils::Entity _sphereEntity;
Entity _childEntities[2];
Material* _material;
MaterialInstance* _materialInstance;
std::vector<std::unique_ptr<GridOverlay>> _instances;
void createGrid();
void createSphere();
};
}
} // namespace thermion

View File

@@ -299,21 +299,9 @@ namespace thermion
return _ncm;
}
Entity getOverlayEntity(size_t index) {
if(index == 0) {
return _gridOverlay->grid();
} else if(index == 1) {
return _gridOverlay->sphere();
} else {
return Entity();
}
}
size_t getOverlayEntityCount() {
return 2;
}
SceneAsset *createGrid();
bool isGridEntity(utils::Entity entity);
private:
gltfio::AssetLoader *_assetLoader = nullptr;
@@ -345,7 +333,7 @@ namespace thermion
std::unique_ptr<AnimationManager> _animationManager = std::nullptr_t();
std::unique_ptr<CollisionComponentManager> _collisionComponentManager = std::nullptr_t();
GridOverlay *_gridOverlay = std::nullptr_t();
std::unique_ptr<GridOverlay> _grid = std::nullptr_t();
void _updateTransforms();
};

View File

@@ -1,31 +1,36 @@
#ifdef _WIN32
#define _USE_MATH_DEFINES
#include <cmath>
#endif
#include "scene/GridOverlay.hpp"
#include <filament/Engine.h>
#include <utils/Entity.h>
#include <utils/EntityManager.h>
#include <filament/RenderableManager.h>
#include <filament/TransformManager.h>
#include <gltfio/math.h>
#include "material/grid.h"
#include "scene/SceneManager.hpp"
#include "material/grid.h"
#include "Log.hpp"
namespace thermion
{
using namespace filament::gltfio;
GridOverlay::GridOverlay(Engine &engine) : _engine(engine)
{
auto &entityManager = EntityManager::get();
auto &transformManager = engine.getTransformManager();
createGrid();
createSphere();
_childEntities[0] = _gridEntity;
_childEntities[1] = _sphereEntity;
}
GridOverlay::~GridOverlay()
{
auto &rm = _engine.getRenderableManager();
auto &tm = _engine.getTransformManager();
rm.destroy(_sphereEntity);
rm.destroy(_gridEntity);
tm.destroy(_sphereEntity);
tm.destroy(_gridEntity);
_engine.destroy(_sphereEntity);
_engine.destroy(_gridEntity);
_engine.destroy(_materialInstance);
_engine.destroy(_material);
}
void GridOverlay::createGrid()
{
const int gridSize = 100;
const float gridSpacing = 1.0f;
int vertexCount = (gridSize + 1) * 4; // 2 axes, 2 vertices per line
@@ -61,10 +66,10 @@ namespace thermion
.vertexCount(vertexCount)
.bufferCount(1)
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
.build(engine);
.build(_engine);
vb->setBufferAt(engine, 0, VertexBuffer::BufferDescriptor(gridVertices, vertexCount * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
{ delete[] static_cast<float *>(buffer); }));
vb->setBufferAt(_engine, 0, VertexBuffer::BufferDescriptor(gridVertices, vertexCount * sizeof(math::float3), [](void *buffer, size_t size, void *)
{ delete[] static_cast<float *>(buffer); }));
uint32_t *gridIndices = new uint32_t[vertexCount];
for (uint32_t i = 0; i < vertexCount; ++i)
@@ -75,22 +80,22 @@ namespace thermion
auto ib = IndexBuffer::Builder()
.indexCount(vertexCount)
.bufferType(IndexBuffer::IndexType::UINT)
.build(engine);
.build(_engine);
ib->setBuffer(engine, IndexBuffer::BufferDescriptor(
gridIndices, vertexCount * sizeof(uint32_t),
[](void *buffer, size_t size, void *)
{ delete[] static_cast<uint32_t *>(buffer); }));
ib->setBuffer(_engine, IndexBuffer::BufferDescriptor(
gridIndices,
vertexCount * sizeof(uint32_t),
[](void *buffer, size_t size, void *)
{ delete[] static_cast<uint32_t *>(buffer); }));
_gridEntity = entityManager.create();
_gridEntity = utils::EntityManager::get().create();
_material = Material::Builder()
.package(GRID_PACKAGE, GRID_GRID_SIZE)
.build(engine);
.build(_engine);
_materialInstance = _material->createInstance();
_materialInstance->setParameter("maxDistance", 50.0f); // Adjust as needed
_materialInstance->setParameter("color", math::float3{0.05f, 0.05f, 0.05f}); // Gray color for the grid
_materialInstance->setParameter("maxDistance", 50.0f);
_materialInstance->setParameter("color", math::float3{0.05f, 0.05f, 0.05f});
RenderableManager::Builder(1)
.boundingBox({{-gridSize * gridSpacing / 2, 0, -gridSize * gridSpacing / 2},
@@ -102,12 +107,16 @@ namespace thermion
.culling(true)
.receiveShadows(false)
.castShadows(false)
.build(engine, _gridEntity);
.build(_engine, _gridEntity);
}
void GridOverlay::createSphere()
{
const float sphereRadius = 0.05f;
const int sphereSegments = 16;
const int sphereRings = 16;
vertexCount = (sphereRings + 1) * (sphereSegments + 1);
int vertexCount = (sphereRings + 1) * (sphereSegments + 1);
int indexCount = sphereRings * sphereSegments * 6;
math::float3 *vertices = new math::float3[vertexCount];
@@ -158,22 +167,23 @@ namespace thermion
.vertexCount(vertexCount)
.bufferCount(1)
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
.build(engine);
.build(_engine);
sphereVb->setBufferAt(engine, 0, VertexBuffer::BufferDescriptor(vertices, vertexCount * sizeof(math::float3), [](void *buffer, size_t size, void *)
{ delete[] static_cast<math::float3 *>(buffer); }));
sphereVb->setBufferAt(_engine, 0, VertexBuffer::BufferDescriptor(vertices, vertexCount * sizeof(math::float3), [](void *buffer, size_t size, void *)
{ delete[] static_cast<math::float3 *>(buffer); }));
auto sphereIb = IndexBuffer::Builder()
.indexCount(indexCount)
.bufferType(IndexBuffer::IndexType::UINT)
.build(engine);
.build(_engine);
sphereIb->setBuffer(engine, IndexBuffer::BufferDescriptor(
indices, indexCount * sizeof(uint32_t),
[](void *buffer, size_t size, void *)
{ delete[] static_cast<uint32_t *>(buffer); }));
sphereIb->setBuffer(_engine, IndexBuffer::BufferDescriptor(
indices,
indexCount * sizeof(uint32_t),
[](void *buffer, size_t size, void *)
{ delete[] static_cast<uint32_t *>(buffer); }));
_sphereEntity = entityManager.create();
_sphereEntity = utils::EntityManager::get().create();
RenderableManager::Builder(1)
.boundingBox({{-sphereRadius, -sphereRadius, -sphereRadius},
@@ -184,19 +194,70 @@ namespace thermion
.culling(true)
.receiveShadows(false)
.castShadows(false)
.build(engine, _sphereEntity);
.build(_engine, _sphereEntity);
}
void GridOverlay::destroy()
SceneAsset *GridOverlay::createInstance(MaterialInstance **materialInstances, size_t materialInstanceCount)
{
auto &rm = _engine.getRenderableManager();
auto &tm = _engine.getTransformManager();
rm.destroy(_sphereEntity);
rm.destroy(_gridEntity);
tm.destroy(_sphereEntity);
tm.destroy(_gridEntity);
_engine.destroy(_sphereEntity);
_engine.destroy(_gridEntity);
auto instance = std::make_unique<GridOverlay>(_engine);
auto *raw = instance.get();
_instances.push_back(std::move(instance));
return reinterpret_cast<SceneAsset*>(raw);
}
void GridOverlay::addAllEntities(Scene *scene)
{
scene->addEntity(_gridEntity);
scene->addEntity(_sphereEntity);
}
void GridOverlay::removeAllEntities(Scene *scene)
{
scene->remove(_gridEntity);
scene->remove(_sphereEntity);
}
void GridOverlay::setPriority(RenderableManager &rm, int priority)
{
auto gridInstance = rm.getInstance(_gridEntity);
rm.setPriority(gridInstance, priority);
auto sphereInstance = rm.getInstance(_sphereEntity);
rm.setPriority(sphereInstance, priority);
}
void GridOverlay::setLayer(RenderableManager &rm, int layer)
{
auto gridInstance = rm.getInstance(_gridEntity);
rm.setLayerMask(gridInstance, 0xFF, 1u << (uint8_t)layer);
auto sphereInstance = rm.getInstance(_sphereEntity);
rm.setLayerMask(sphereInstance, 0xFF, 1u << (uint8_t)layer);
}
SceneAsset *GridOverlay::getInstanceByEntity(utils::Entity entity)
{
for (auto &instance : _instances)
{
if (instance->_gridEntity == entity || instance->_sphereEntity == entity)
{
return instance.get();
}
}
return nullptr;
}
SceneAsset *GridOverlay::getInstanceAt(size_t index)
{
return _instances[index].get();
}
const Entity *GridOverlay::getChildEntities()
{
return _childEntities;
}
Entity GridOverlay::findEntityByName(const char *name)
{
return Entity(); // Not implemented
}
} // namespace thermion

View File

@@ -207,13 +207,15 @@ extern "C"
return reinterpret_cast<TNameComponentManager*>(sceneManager->getNameComponentManager());
}
EMSCRIPTEN_KEEPALIVE size_t SceneManager_getOverlayEntityCount(TSceneManager *tSceneManager) {
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneManager_createGrid(TSceneManager *tSceneManager) {
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
return sceneManager->getOverlayEntityCount();
auto *grid = sceneManager->createGrid();
return reinterpret_cast<TSceneAsset*>(grid);
}
EMSCRIPTEN_KEEPALIVE EntityId SceneManager_getOverlayEntityAt(TSceneManager *tSceneManager, size_t index) {
EMSCRIPTEN_KEEPALIVE bool SceneManager_isGridEntity(TSceneManager *tSceneManager, EntityId entityId) {
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
auto entity = sceneManager->getOverlayEntity(index);
return utils::Entity::smuggle(entity);
return sceneManager->isGridEntity(utils::Entity::import(entityId));
}
}

View File

@@ -107,11 +107,6 @@ namespace thermion
_animationManager = std::make_unique<AnimationManager>(_engine, _scene);
_gridOverlay = new GridOverlay(*_engine);
_scene->addEntity(_gridOverlay->sphere());
_scene->addEntity(_gridOverlay->grid());
_unlitFixedSizeMaterial =
Material::Builder()
.package(UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_DATA, UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_SIZE)
@@ -131,8 +126,8 @@ namespace thermion
_engine->destroy(_unlitFixedSizeMaterial);
_cameras.clear();
_gridOverlay->destroy();
_grid = nullptr;
_gltfResourceLoader->asyncCancelLoad();
_ubershaderProvider->destroyMaterials();
@@ -148,6 +143,28 @@ namespace thermion
AssetLoader::destroy(&_assetLoader);
}
SceneAsset *SceneManager::createGrid() {
if(!_grid) {
_grid = std::make_unique<GridOverlay>(*_engine);
}
return _grid.get();
}
bool SceneManager::isGridEntity(utils::Entity entity) {
if(!_grid) {
return false;
}
if(entity == _grid->getEntity()) {
return true;
}
for(int i =0; i < _grid->getChildEntityCount(); i++) {
if(entity == _grid->getChildEntities()[i]) {
return true;
}
}
return false;
}
Gizmo *SceneManager::createGizmo(View *view, Scene *scene)
{
auto gizmo = std::make_unique<Gizmo>(_engine, view, scene, _unlitFixedSizeMaterial);