Files
cup_edit/thermion_dart/native/include/scene/Gizmo.hpp
Nick Fisher 0cbbc058e0 refactoring
2025-03-22 10:49:24 +08:00

221 lines
6.9 KiB
C++

#pragma once
#include <vector>
#include <utils/Entity.h>
#include <filament/Box.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 <filament/RenderableManager.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 "scene/SceneAsset.hpp"
namespace thermion
{
using namespace filament;
using namespace utils;
class Gizmo : public SceneAsset
{
public:
Gizmo(
SceneAsset *sceneAsset,
Engine *engine,
View *view,
Material *material) noexcept;
Gizmo(Gizmo &&other) noexcept;
~Gizmo() override;
enum Axis
{
X,
Y,
Z
};
enum GizmoPickResultType
{
AxisX,
AxisY,
AxisZ,
Parent,
None
};
typedef void (*GizmoPickCallback)(Gizmo::GizmoPickResultType result, float x, float y, float z);
void pick(uint32_t x, uint32_t y, GizmoPickCallback callback);
bool isGizmoEntity(Entity entity);
SceneAssetType getType() override { return SceneAssetType::Gizmo; }
utils::Entity getEntity() override { return _parent; }
bool isInstance() override { return false; }
SceneAsset *getInstanceOwner() override { return std::nullptr_t(); }
SceneAsset *createInstance(MaterialInstance **materialInstances, size_t materialInstanceCount) override { return nullptr; }
void destroyInstance(SceneAsset *instance) override { return; }
MaterialInstance **getMaterialInstances() override { return _materialInstances.data(); }
size_t getMaterialInstanceCount() override { return _materialInstances.size(); }
void addAllEntities(Scene *scene) override
{
TRACE("addAllEntities called with %d entities", _entities.size());
for (const auto &entity : _entities)
{
if (entity.isNull())
{
continue;
}
scene->addEntity(entity);
}
}
void removeAllEntities(Scene *scene) override
{
for (const auto &entity : _entities)
{
scene->remove(entity);
}
}
size_t getInstanceCount() override { return 0; }
SceneAsset *getInstanceByEntity(utils::Entity entity) override { return nullptr; }
SceneAsset *getInstanceAt(size_t index) override { return nullptr; }
size_t getChildEntityCount() override { return _entities.size() - 1; }
const Entity *getChildEntities() override { return _entities.data() + 1; }
Entity findEntityByName(const char *name) override
{
return utils::Entity::import(0);
}
void highlight(Gizmo::Axis axis);
void unhighlight(Gizmo::Axis axis);
private:
class PickCallbackHandler
{
public:
PickCallbackHandler(Gizmo *gizmo, GizmoPickCallback callback)
: _gizmo(gizmo), _callback(callback) {}
void handle(filament::View::PickingQueryResult const &result)
{
_gizmo->unhighlight(Gizmo::Axis::X);
_gizmo->unhighlight(Gizmo::Axis::Y);
_gizmo->unhighlight(Gizmo::Axis::Z);
Gizmo::GizmoPickResultType resultType = _gizmo->getPickResult(result.renderable);
_callback(resultType, result.fragCoords.x, result.fragCoords.y, result.fragCoords.z);
}
private:
Gizmo *_gizmo;
GizmoPickCallback _callback;
};
Entity createParentEntity();
void createAxisInstance(Gizmo::Axis axis);
math::mat4f getRotationForAxis(Gizmo::Axis axis);
const filament::Aabb getBoundingBox() const override {
return _boundingBox;
}
private:
SceneAsset *_source;
Engine *_engine;
Scene *_scene;
View *_view;
Material *_material;
float _scale = 10.0f;
utils::Entity _parent;
std::vector<SceneAsset *> _axes;
std::vector<utils::Entity> _hitTest;
std::vector<utils::Entity> _entities;
std::vector<MaterialInstance *> _materialInstances;
filament::Aabb _boundingBox;
GizmoPickResultType getPickResult(utils::Entity entity)
{
if (entity.isNull())
{
return Gizmo::GizmoPickResultType::None;
}
TRACE("Checking picked entity %d against gizmo axes with (%d axis hit test entities : %d %d %d)", entity, _hitTest.size(), _hitTest[0], _hitTest[1], _hitTest[2]);
if (entity == _parent)
{
return GizmoPickResultType::Parent;
}
for (int axisIndex = 0; axisIndex < _axes.size(); axisIndex++)
{
auto axis = _axes[axisIndex];
TRACE("Checking for axisindex %d with %d child entities", axisIndex, axis->getChildEntityCount());
GizmoPickResultType result = GizmoPickResultType::None;
if (entity == _hitTest[axisIndex])
{
TRACE("MATCHED AXIS HIT TEST ENTITY for axisIndex %d", axisIndex);
result = GizmoPickResultType(axisIndex);
}
else
{
if (entity == axis->getEntity())
{
TRACE("MATCHED AXIS HEAD ENTITY");
result = GizmoPickResultType(axisIndex);
}
else
{
for (int entityIndex = 0; entityIndex < axis->getChildEntityCount(); entityIndex++)
{
auto childEntity = axis->getChildEntities()[entityIndex];
if (entity == childEntity)
{
TRACE("MATCHED AXIS CHILD ENTITY %d (index %d)", childEntity, entityIndex);
result = GizmoPickResultType(axisIndex);
break;
}
TRACE("Failed to match entity %d against axis child entity %d", entity, childEntity);
}
}
}
if (result != GizmoPickResultType::None)
{
highlight(Gizmo::Axis(axisIndex));
return result;
}
}
return Gizmo::GizmoPickResultType::None;
}
};
}