feature!:
This is a breaking change needed to fully implement instancing and stencil highlighting.
Previously, users would work directly with entities (on the Dart side, ThermionEntity), e.g.
final entity = await viewer.loadGlb("some.glb");
However, Filament "entities" are a lower-level abstraction.
Loading a glTF file, for example, inserts multiple entities into the scene.
For example, each mesh, light, and camera within a glTF asset will be assigned an entity. A top-level (non-renderable) entity will also be created for the glTF asset, which can be used to transform the entire hierarchy.
"Asset" is a better representation for loading/inserting objects into the scene; think of this as a bundle of entities.
Unless you need to work directly with transforms, instancing, materials and renderables, you can work directly with ThermionAsset.
This commit is contained in:
@@ -120,7 +120,8 @@ namespace thermion
|
||||
static constexpr filament::math::float4 sFullScreenTriangleVertices[3] = {
|
||||
{-1.0f, -1.0f, 1.0f, 1.0f},
|
||||
{3.0f, -1.0f, 1.0f, 1.0f},
|
||||
{-1.0f, 3.0f, 1.0f, 1.0f}};
|
||||
{-1.0f, 3.0f, 1.0f, 1.0f}
|
||||
};
|
||||
|
||||
static const uint16_t sFullScreenTriangleIndices[3] = {0, 1, 2};
|
||||
|
||||
@@ -705,8 +706,8 @@ namespace thermion
|
||||
.width(width)
|
||||
.height(height)
|
||||
.levels(1)
|
||||
.usage(filament::Texture::Usage::DEPTH_ATTACHMENT | filament::Texture::Usage::SAMPLEABLE)
|
||||
.format(filament::Texture::InternalFormat::DEPTH32F)
|
||||
.usage(filament::Texture::Usage::DEPTH_ATTACHMENT | filament::Texture::Usage::STENCIL_ATTACHMENT | filament::Texture::Usage::SAMPLEABLE)
|
||||
.format(filament::Texture::InternalFormat::DEPTH24_STENCIL8)
|
||||
.build(*_engine);
|
||||
auto rt = filament::RenderTarget::Builder()
|
||||
.texture(RenderTarget::AttachmentPoint::COLOR, rtColor)
|
||||
@@ -767,6 +768,9 @@ namespace thermion
|
||||
view->setStencilBufferEnabled(true);
|
||||
view->setAmbientOcclusionOptions({.enabled = false});
|
||||
view->setDynamicResolutionOptions({.enabled = false});
|
||||
ACESToneMapper tm;
|
||||
auto colorGrading = ColorGrading::Builder().toneMapper(&tm).build(*_engine);
|
||||
view->setColorGrading(colorGrading);
|
||||
#if defined(_WIN32)
|
||||
view->setStereoscopicOptions({.enabled = false});
|
||||
#endif
|
||||
@@ -797,25 +801,6 @@ namespace thermion
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// @brief
|
||||
///
|
||||
///
|
||||
void FilamentViewer::clearEntities()
|
||||
{
|
||||
_sceneManager->destroyAll();
|
||||
}
|
||||
|
||||
/// @brief
|
||||
/// @param asset
|
||||
///
|
||||
void FilamentViewer::removeEntity(EntityId asset)
|
||||
{
|
||||
_renderMutex.lock();
|
||||
// todo - what if we are using a camera from this asset?
|
||||
_sceneManager->remove(asset);
|
||||
_renderMutex.unlock();
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@@ -1046,8 +1031,7 @@ namespace thermion
|
||||
uint64_t frameTimeInNanos)
|
||||
{
|
||||
|
||||
_sceneManager->updateTransforms();
|
||||
_sceneManager->updateAnimations();
|
||||
_sceneManager->update();
|
||||
|
||||
for(auto swapChain : _swapChains) {
|
||||
auto views = _renderable[swapChain];
|
||||
@@ -1091,7 +1075,6 @@ namespace thermion
|
||||
}
|
||||
};
|
||||
|
||||
// Create a fence
|
||||
Fence *fence = nullptr;
|
||||
if (useFence)
|
||||
{
|
||||
@@ -1127,7 +1110,7 @@ namespace thermion
|
||||
{
|
||||
|
||||
if(swapChain && !_engine->isValid(swapChain)) {
|
||||
Log("SWAPCHAIN PROVIDED BUT NOT VALID");
|
||||
Log("SwapChain exists, but is not valid");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1191,21 +1174,9 @@ namespace thermion
|
||||
return _engine->getCameraComponent(Entity::import(entity));
|
||||
}
|
||||
|
||||
bool FilamentViewer::isNonPickableEntity(EntityId entityId) {
|
||||
auto renderable = Entity::import(entityId);
|
||||
return _sceneManager->isGizmoEntity(renderable) || renderable == _imageEntity || renderable == _sceneManager->_gridOverlay->sphere() || _sceneManager->_gridOverlay->grid();
|
||||
}
|
||||
|
||||
void FilamentViewer::pick(View *view, uint32_t x, uint32_t y, PickCallback callback)
|
||||
{
|
||||
view->pick(x, y, [=](filament::View::PickingQueryResult const &result) {
|
||||
callback(Entity::smuggle(result.renderable), x, y, view, result.depth, result.fragCoords.x, result.fragCoords.y, result.fragCoords.z);
|
||||
});
|
||||
}
|
||||
|
||||
void FilamentViewer::unprojectTexture(EntityId entityId, uint8_t *input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight)
|
||||
{
|
||||
const auto *geometry = _sceneManager->getGeometry(entityId);
|
||||
// const auto *geometry = _sceneManager->getGeometry(entityId);
|
||||
// if (!geometry->uvs)
|
||||
// {
|
||||
// Log("No UVS");
|
||||
|
||||
@@ -1,345 +0,0 @@
|
||||
#include "Gizmo.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 "SceneManager.hpp"
|
||||
#include "material/unlit_fixed_size.h"
|
||||
#include "Log.hpp"
|
||||
|
||||
namespace thermion {
|
||||
|
||||
using namespace filament::gltfio;
|
||||
|
||||
Gizmo::Gizmo(Engine *engine, View *view, Scene* scene, Material* material) : _engine(engine), _view(view), _scene(scene), _material(material)
|
||||
{
|
||||
|
||||
auto &entityManager = EntityManager::get();
|
||||
|
||||
auto &transformManager = _engine->getTransformManager();
|
||||
|
||||
// First, create the black cube at the center
|
||||
// The axes widgets will be parented to this entity
|
||||
_entities[3] = entityManager.create();
|
||||
|
||||
_materialInstances[3] = _material->createInstance();
|
||||
_materialInstances[3]->setParameter("baseColorFactor", math::float4{0.0f, 0.0f, 0.0f, 1.0f}); // Black color
|
||||
|
||||
// Create center cube vertices
|
||||
float centerCubeSize = 0.01f;
|
||||
float *centerCubeVertices = new float[8 * 3]{
|
||||
-centerCubeSize, -centerCubeSize, -centerCubeSize,
|
||||
centerCubeSize, -centerCubeSize, -centerCubeSize,
|
||||
centerCubeSize, centerCubeSize, -centerCubeSize,
|
||||
-centerCubeSize, centerCubeSize, -centerCubeSize,
|
||||
-centerCubeSize, -centerCubeSize, centerCubeSize,
|
||||
centerCubeSize, -centerCubeSize, centerCubeSize,
|
||||
centerCubeSize, centerCubeSize, centerCubeSize,
|
||||
-centerCubeSize, centerCubeSize, centerCubeSize};
|
||||
|
||||
// Create center cube indices
|
||||
uint16_t *centerCubeIndices = new uint16_t[36]{
|
||||
0, 1, 2, 2, 3, 0,
|
||||
1, 5, 6, 6, 2, 1,
|
||||
5, 4, 7, 7, 6, 5,
|
||||
4, 0, 3, 3, 7, 4,
|
||||
3, 2, 6, 6, 7, 3,
|
||||
4, 5, 1, 1, 0, 4};
|
||||
|
||||
auto centerCubeVb = VertexBuffer::Builder()
|
||||
.vertexCount(8)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.build(*engine);
|
||||
|
||||
centerCubeVb->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor(centerCubeVertices, 8 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<float *>(buffer); }));
|
||||
|
||||
auto centerCubeIb = IndexBuffer::Builder().indexCount(36).bufferType(IndexBuffer::IndexType::USHORT).build(*engine);
|
||||
centerCubeIb->setBuffer(*engine, IndexBuffer::BufferDescriptor(
|
||||
centerCubeIndices, 36 * sizeof(uint16_t),
|
||||
[](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<uint16_t *>(buffer); }));
|
||||
|
||||
RenderableManager::Builder(1)
|
||||
.boundingBox({{-centerCubeSize, -centerCubeSize, -centerCubeSize},
|
||||
{centerCubeSize, centerCubeSize, centerCubeSize}})
|
||||
.material(0, _materialInstances[3])
|
||||
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
.priority(7)
|
||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, centerCubeVb, centerCubeIb, 0, 36)
|
||||
.culling(false)
|
||||
.build(*engine, _entities[3]);
|
||||
|
||||
auto cubeTransformInstance = transformManager.getInstance(_entities[3]);
|
||||
math::mat4f cubeTransform;
|
||||
transformManager.setTransform(cubeTransformInstance, cubeTransform);
|
||||
|
||||
// Line and arrow vertices
|
||||
float lineLength = 0.6f;
|
||||
float lineWidth = 0.004f;
|
||||
float arrowLength = 0.06f;
|
||||
float arrowWidth = 0.02f;
|
||||
float *vertices = new float[13 * 3]{
|
||||
// Line vertices (8 vertices)
|
||||
-lineWidth, -lineWidth, 0.0f,
|
||||
lineWidth, -lineWidth, 0.0f,
|
||||
lineWidth, lineWidth, 0.0f,
|
||||
-lineWidth, lineWidth, 0.0f,
|
||||
-lineWidth, -lineWidth, lineLength,
|
||||
lineWidth, -lineWidth, lineLength,
|
||||
lineWidth, lineWidth, lineLength,
|
||||
-lineWidth, lineWidth, lineLength,
|
||||
// Arrow vertices (5 vertices)
|
||||
0.0f, 0.0f, lineLength + arrowLength, // Tip of the arrow
|
||||
-arrowWidth, -arrowWidth, lineLength, // Base of the arrow
|
||||
arrowWidth, -arrowWidth, lineLength,
|
||||
arrowWidth, arrowWidth, lineLength,
|
||||
-arrowWidth, arrowWidth, lineLength};
|
||||
|
||||
// Line and arrow indices
|
||||
uint16_t *indices = new uint16_t[54]{
|
||||
// Line indices (24 indices)
|
||||
0, 1, 5, 5, 4, 0,
|
||||
1, 2, 6, 6, 5, 1,
|
||||
2, 3, 7, 7, 6, 2,
|
||||
3, 0, 4, 4, 7, 3,
|
||||
// Arrow indices (30 indices)
|
||||
8, 9, 10, // Front face
|
||||
8, 10, 11, // Right face
|
||||
8, 11, 12, // Back face
|
||||
8, 12, 9, // Left face
|
||||
9, 12, 11, 11, 10, 9 // Base of the arrow
|
||||
};
|
||||
|
||||
auto vb = VertexBuffer::Builder()
|
||||
.vertexCount(13)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.build(*engine);
|
||||
|
||||
vb->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor(vertices, 13 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<float *>(buffer); }));
|
||||
|
||||
auto ib = IndexBuffer::Builder().indexCount(54).bufferType(IndexBuffer::IndexType::USHORT).build(*engine);
|
||||
ib->setBuffer(*engine, IndexBuffer::BufferDescriptor(
|
||||
indices, 54 * sizeof(uint16_t),
|
||||
[](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<uint16_t *>(buffer); }));
|
||||
|
||||
// Create the three axes
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
_entities[i] = entityManager.create();
|
||||
_materialInstances[i] = _material->createInstance();
|
||||
|
||||
auto baseColor = inactiveColors[i];
|
||||
|
||||
math::mat4f transform;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case Axis::X:
|
||||
// _materialInstances[i]->setParameter("axisDirection", math::float3 { 1.0f, 0.0f, 0.0f});
|
||||
transform = math::mat4f::rotation(math::F_PI_2, math::float3{0, 1, 0});
|
||||
break;
|
||||
case 1:
|
||||
// _materialInstances[i]->setParameter("axisDirection", math::float3 { 0.0f, 1.0f, 0.0f});
|
||||
transform = math::mat4f::rotation(-math::F_PI_2, math::float3{1, 0, 0});
|
||||
break;
|
||||
case 2:
|
||||
// _materialInstances[i]->setParameter("axisDirection", math::float3 { 0.0f, 0.0f, 1.0f});
|
||||
break;
|
||||
}
|
||||
|
||||
_materialInstances[i]->setParameter("baseColorFactor", baseColor);
|
||||
|
||||
RenderableManager::Builder(1)
|
||||
.boundingBox({{-arrowWidth, -arrowWidth, 0},
|
||||
{arrowWidth, arrowWidth, lineLength + arrowLength}})
|
||||
.material(0, _materialInstances[i])
|
||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vb, ib, 0, 54)
|
||||
.priority(6)
|
||||
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
.culling(false)
|
||||
.receiveShadows(false)
|
||||
.castShadows(false)
|
||||
.build(*engine, _entities[i]);
|
||||
|
||||
|
||||
auto instance = transformManager.getInstance(_entities[i]);
|
||||
transformManager.setTransform(instance, transform);
|
||||
|
||||
// parent the axis to the center cube
|
||||
transformManager.setParent(instance, cubeTransformInstance);
|
||||
|
||||
}
|
||||
|
||||
createTransparentRectangles();
|
||||
}
|
||||
|
||||
Gizmo::~Gizmo() {
|
||||
_scene->removeEntities(_entities, 7);
|
||||
|
||||
for(int i = 0; i < 7; i++) {
|
||||
_engine->destroy(_entities[i]);
|
||||
}
|
||||
|
||||
for(int i = 0; i < 7; i++) {
|
||||
_engine->destroy(_materialInstances[i]);
|
||||
}
|
||||
|
||||
_engine->destroy(_material);
|
||||
|
||||
}
|
||||
|
||||
void Gizmo::createTransparentRectangles()
|
||||
{
|
||||
auto &entityManager = EntityManager::get();
|
||||
auto &transformManager = _engine->getTransformManager();
|
||||
|
||||
float volumeWidth = 0.2f;
|
||||
float volumeLength = 1.2f;
|
||||
float volumeDepth = 0.2f;
|
||||
|
||||
float *volumeVertices = new float[8 * 3]{
|
||||
-volumeWidth / 2, -volumeDepth / 2, 0,
|
||||
volumeWidth / 2, -volumeDepth / 2, 0,
|
||||
volumeWidth / 2, -volumeDepth / 2, volumeLength,
|
||||
-volumeWidth / 2, -volumeDepth / 2, volumeLength,
|
||||
-volumeWidth / 2, volumeDepth / 2, 0,
|
||||
volumeWidth / 2, volumeDepth / 2, 0,
|
||||
volumeWidth / 2, volumeDepth / 2, volumeLength,
|
||||
-volumeWidth / 2, volumeDepth / 2, volumeLength
|
||||
};
|
||||
|
||||
uint16_t *volumeIndices = new uint16_t[36]{
|
||||
0, 1, 2, 2, 3, 0, // Bottom face
|
||||
4, 5, 6, 6, 7, 4, // Top face
|
||||
0, 4, 7, 7, 3, 0, // Left face
|
||||
1, 5, 6, 6, 2, 1, // Right face
|
||||
0, 1, 5, 5, 4, 0, // Front face
|
||||
3, 2, 6, 6, 7, 3 // Back face
|
||||
};
|
||||
|
||||
auto volumeVb = VertexBuffer::Builder()
|
||||
.vertexCount(8)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.build(*_engine);
|
||||
|
||||
volumeVb->setBufferAt(*_engine, 0, VertexBuffer::BufferDescriptor(
|
||||
volumeVertices, 8 * sizeof(filament::math::float3),
|
||||
[](void *buffer, size_t size, void *) { delete[] static_cast<float *>(buffer); }
|
||||
));
|
||||
|
||||
auto volumeIb = IndexBuffer::Builder()
|
||||
.indexCount(36)
|
||||
.bufferType(IndexBuffer::IndexType::USHORT)
|
||||
.build(*_engine);
|
||||
|
||||
volumeIb->setBuffer(*_engine, IndexBuffer::BufferDescriptor(
|
||||
volumeIndices, 36 * sizeof(uint16_t),
|
||||
[](void *buffer, size_t size, void *) { delete[] static_cast<uint16_t *>(buffer); }
|
||||
));
|
||||
|
||||
for (int i = 4; i < 7; i++)
|
||||
{
|
||||
_entities[i] = entityManager.create();
|
||||
_materialInstances[i] = _material->createInstance();
|
||||
|
||||
_materialInstances[i]->setParameter("color", math::float4{0.0f, 0.0f, 0.0f, 0.0f});
|
||||
|
||||
math::mat4f transform;
|
||||
switch (i-4)
|
||||
{
|
||||
case Axis::X:
|
||||
transform = math::mat4f::rotation(math::F_PI_2, math::float3{0, 1, 0});
|
||||
break;
|
||||
case Axis::Y:
|
||||
transform = math::mat4f::rotation(-math::F_PI_2, math::float3{1, 0, 0});
|
||||
break;
|
||||
case Axis::Z:
|
||||
break;
|
||||
}
|
||||
|
||||
RenderableManager::Builder(1)
|
||||
.boundingBox({{-volumeWidth / 2, -volumeDepth / 2, 0}, {volumeWidth / 2, volumeDepth / 2, volumeLength}})
|
||||
.material(0, _materialInstances[i])
|
||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, volumeVb, volumeIb, 0, 36)
|
||||
.priority(7)
|
||||
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
.culling(false)
|
||||
.receiveShadows(false)
|
||||
.castShadows(false)
|
||||
.build(*_engine, _entities[i]);
|
||||
|
||||
auto instance = transformManager.getInstance(_entities[i]);
|
||||
transformManager.setTransform(instance, transform);
|
||||
|
||||
// Parent the picking volume to the center cube
|
||||
transformManager.setParent(instance, transformManager.getInstance(_entities[3]));
|
||||
}
|
||||
}
|
||||
|
||||
void Gizmo::highlight(Entity entity) {
|
||||
auto &rm = _engine->getRenderableManager();
|
||||
auto renderableInstance = rm.getInstance(entity);
|
||||
auto materialInstance = rm.getMaterialInstanceAt(renderableInstance, 0);
|
||||
|
||||
math::float4 baseColor;
|
||||
if(entity == x()) {
|
||||
baseColor = activeColors[Axis::X];
|
||||
} else if(entity == y()) {
|
||||
baseColor = activeColors[Axis::Y];
|
||||
} else if(entity == z()) {
|
||||
baseColor = activeColors[Axis::Z];
|
||||
} else {
|
||||
baseColor = math::float4 { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
}
|
||||
|
||||
materialInstance->setParameter("color", baseColor);
|
||||
|
||||
}
|
||||
|
||||
void Gizmo::unhighlight() {
|
||||
auto &rm = _engine->getRenderableManager();
|
||||
|
||||
for(int i = 0; i < 3; i++) {
|
||||
auto renderableInstance = rm.getInstance(_entities[i]);
|
||||
auto materialInstance = rm.getMaterialInstanceAt(renderableInstance, 0);
|
||||
|
||||
math::float4 baseColor = inactiveColors[i];
|
||||
materialInstance->setParameter("color", baseColor);
|
||||
}
|
||||
}
|
||||
|
||||
void Gizmo::pick(uint32_t x, uint32_t y, PickCallback callback)
|
||||
{
|
||||
auto handler = new Gizmo::PickCallbackHandler(this, callback);
|
||||
_view->pick(x, y, [=](filament::View::PickingQueryResult const &result) {
|
||||
handler->handle(result);
|
||||
});
|
||||
}
|
||||
|
||||
bool Gizmo::isGizmoEntity(Entity e) {
|
||||
for(int i = 0; i < 7; i++) {
|
||||
if(e == _entities[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Gizmo::setVisibility(bool visible) {
|
||||
if(visible) {
|
||||
_scene->addEntities(_entities, 7);
|
||||
} else {
|
||||
_scene->removeEntities(_entities, 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <cmath>
|
||||
#endif
|
||||
|
||||
#include "GridOverlay.hpp"
|
||||
#include "scene/GridOverlay.hpp"
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <utils/Entity.h>
|
||||
@@ -13,190 +13,190 @@
|
||||
#include <gltfio/math.h>
|
||||
|
||||
#include "material/grid.h"
|
||||
#include "SceneManager.hpp"
|
||||
#include "scene/SceneManager.hpp"
|
||||
#include "Log.hpp"
|
||||
|
||||
namespace thermion {
|
||||
|
||||
using namespace filament::gltfio;
|
||||
|
||||
GridOverlay::GridOverlay(Engine &engine) : _engine(engine)
|
||||
namespace thermion
|
||||
{
|
||||
auto &entityManager = EntityManager::get();
|
||||
auto &transformManager = engine.getTransformManager();
|
||||
|
||||
const int gridSize = 100;
|
||||
const float gridSpacing = 1.0f;
|
||||
int vertexCount = (gridSize + 1) * 4; // 2 axes, 2 vertices per line
|
||||
using namespace filament::gltfio;
|
||||
|
||||
float* gridVertices = new float[vertexCount * 3];
|
||||
int index = 0;
|
||||
GridOverlay::GridOverlay(Engine &engine) : _engine(engine)
|
||||
{
|
||||
auto &entityManager = EntityManager::get();
|
||||
auto &transformManager = engine.getTransformManager();
|
||||
|
||||
// Create grid lines
|
||||
for (int i = 0; i <= gridSize; ++i) {
|
||||
float pos = i * gridSpacing - (gridSize * gridSpacing / 2);
|
||||
const int gridSize = 100;
|
||||
const float gridSpacing = 1.0f;
|
||||
int vertexCount = (gridSize + 1) * 4; // 2 axes, 2 vertices per line
|
||||
|
||||
// X-axis lines
|
||||
gridVertices[index++] = pos;
|
||||
gridVertices[index++] = 0;
|
||||
gridVertices[index++] = -(gridSize * gridSpacing / 2);
|
||||
float *gridVertices = new float[vertexCount * 3];
|
||||
int index = 0;
|
||||
|
||||
gridVertices[index++] = pos;
|
||||
gridVertices[index++] = 0;
|
||||
gridVertices[index++] = (gridSize * gridSpacing / 2);
|
||||
// Create grid lines
|
||||
for (int i = 0; i <= gridSize; ++i)
|
||||
{
|
||||
float pos = i * gridSpacing - (gridSize * gridSpacing / 2);
|
||||
|
||||
// Z-axis lines
|
||||
gridVertices[index++] = -(gridSize * gridSpacing / 2);
|
||||
gridVertices[index++] = 0;
|
||||
gridVertices[index++] = pos;
|
||||
// X-axis lines
|
||||
gridVertices[index++] = pos;
|
||||
gridVertices[index++] = 0;
|
||||
gridVertices[index++] = -(gridSize * gridSpacing / 2);
|
||||
|
||||
gridVertices[index++] = (gridSize * gridSpacing / 2);
|
||||
gridVertices[index++] = 0;
|
||||
gridVertices[index++] = pos;
|
||||
gridVertices[index++] = pos;
|
||||
gridVertices[index++] = 0;
|
||||
gridVertices[index++] = (gridSize * gridSpacing / 2);
|
||||
|
||||
// Z-axis lines
|
||||
gridVertices[index++] = -(gridSize * gridSpacing / 2);
|
||||
gridVertices[index++] = 0;
|
||||
gridVertices[index++] = pos;
|
||||
|
||||
gridVertices[index++] = (gridSize * gridSpacing / 2);
|
||||
gridVertices[index++] = 0;
|
||||
gridVertices[index++] = pos;
|
||||
}
|
||||
|
||||
auto vb = VertexBuffer::Builder()
|
||||
.vertexCount(vertexCount)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.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); }));
|
||||
|
||||
uint32_t *gridIndices = new uint32_t[vertexCount];
|
||||
for (uint32_t i = 0; i < vertexCount; ++i)
|
||||
{
|
||||
gridIndices[i] = i;
|
||||
}
|
||||
|
||||
auto ib = IndexBuffer::Builder()
|
||||
.indexCount(vertexCount)
|
||||
.bufferType(IndexBuffer::IndexType::UINT)
|
||||
.build(engine);
|
||||
|
||||
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();
|
||||
_material = Material::Builder()
|
||||
.package(GRID_PACKAGE, GRID_GRID_SIZE)
|
||||
.build(engine);
|
||||
|
||||
_materialInstance = _material->createInstance();
|
||||
|
||||
_materialInstance->setParameter("maxDistance", 50.0f); // Adjust as needed
|
||||
_materialInstance->setParameter("color", math::float3{0.5f, 0.5f, 0.5f}); // Gray color for the grid
|
||||
|
||||
RenderableManager::Builder(1)
|
||||
.boundingBox({{-gridSize * gridSpacing / 2, 0, -gridSize * gridSpacing / 2},
|
||||
{gridSize * gridSpacing / 2, 0, gridSize * gridSpacing / 2}})
|
||||
.material(0, _materialInstance)
|
||||
.geometry(0, RenderableManager::PrimitiveType::LINES, vb, ib, 0, vertexCount)
|
||||
.priority(0)
|
||||
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
.culling(true)
|
||||
.receiveShadows(false)
|
||||
.castShadows(false)
|
||||
.build(engine, _gridEntity);
|
||||
const float sphereRadius = 0.05f;
|
||||
const int sphereSegments = 16;
|
||||
const int sphereRings = 16;
|
||||
|
||||
vertexCount = (sphereRings + 1) * (sphereSegments + 1);
|
||||
int indexCount = sphereRings * sphereSegments * 6;
|
||||
|
||||
math::float3 *vertices = new math::float3[vertexCount];
|
||||
uint32_t *indices = new uint32_t[indexCount];
|
||||
|
||||
int vertexIndex = 0;
|
||||
// Generate sphere vertices
|
||||
for (int ring = 0; ring <= sphereRings; ++ring)
|
||||
{
|
||||
float theta = ring * M_PI / sphereRings;
|
||||
float sinTheta = std::sin(theta);
|
||||
float cosTheta = std::cos(theta);
|
||||
|
||||
for (int segment = 0; segment <= sphereSegments; ++segment)
|
||||
{
|
||||
float phi = segment * 2 * M_PI / sphereSegments;
|
||||
float sinPhi = std::sin(phi);
|
||||
float cosPhi = std::cos(phi);
|
||||
|
||||
float x = cosPhi * sinTheta;
|
||||
float y = cosTheta;
|
||||
float z = sinPhi * sinTheta;
|
||||
|
||||
vertices[vertexIndex++] = {x * sphereRadius, y * sphereRadius, z * sphereRadius};
|
||||
}
|
||||
}
|
||||
|
||||
int indexIndex = 0;
|
||||
// Generate sphere indices
|
||||
for (int ring = 0; ring < sphereRings; ++ring)
|
||||
{
|
||||
for (int segment = 0; segment < sphereSegments; ++segment)
|
||||
{
|
||||
uint32_t current = ring * (sphereSegments + 1) + segment;
|
||||
uint32_t next = current + sphereSegments + 1;
|
||||
|
||||
indices[indexIndex++] = current;
|
||||
indices[indexIndex++] = next;
|
||||
indices[indexIndex++] = current + 1;
|
||||
|
||||
indices[indexIndex++] = current + 1;
|
||||
indices[indexIndex++] = next;
|
||||
indices[indexIndex++] = next + 1;
|
||||
}
|
||||
}
|
||||
|
||||
auto sphereVb = VertexBuffer::Builder()
|
||||
.vertexCount(vertexCount)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.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); }));
|
||||
|
||||
auto sphereIb = IndexBuffer::Builder()
|
||||
.indexCount(indexCount)
|
||||
.bufferType(IndexBuffer::IndexType::UINT)
|
||||
.build(engine);
|
||||
|
||||
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();
|
||||
|
||||
RenderableManager::Builder(1)
|
||||
.boundingBox({{-sphereRadius, -sphereRadius, -sphereRadius},
|
||||
{sphereRadius, sphereRadius, sphereRadius}})
|
||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, sphereVb, sphereIb, 0, indexCount)
|
||||
.priority(0)
|
||||
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
.culling(true)
|
||||
.receiveShadows(false)
|
||||
.castShadows(false)
|
||||
.build(engine, _sphereEntity);
|
||||
}
|
||||
|
||||
auto vb = VertexBuffer::Builder()
|
||||
.vertexCount(vertexCount)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.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); }
|
||||
));
|
||||
|
||||
uint32_t* gridIndices = new uint32_t[vertexCount];
|
||||
for (uint32_t i = 0; i < vertexCount; ++i) {
|
||||
gridIndices[i] = i;
|
||||
void GridOverlay::destroy()
|
||||
{
|
||||
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 ib = IndexBuffer::Builder()
|
||||
.indexCount(vertexCount)
|
||||
.bufferType(IndexBuffer::IndexType::UINT)
|
||||
.build(engine);
|
||||
|
||||
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();
|
||||
_material = Material::Builder()
|
||||
.package(GRID_PACKAGE, GRID_GRID_SIZE)
|
||||
.build(engine);
|
||||
|
||||
_materialInstance = _material->createInstance();
|
||||
|
||||
_materialInstance->setParameter("maxDistance", 50.0f); // Adjust as needed
|
||||
_materialInstance->setParameter("color", math::float3{0.5f, 0.5f, 0.5f}); // Gray color for the grid
|
||||
|
||||
|
||||
RenderableManager::Builder(1)
|
||||
.boundingBox({{-gridSize * gridSpacing / 2, 0, -gridSize * gridSpacing / 2},
|
||||
{gridSize * gridSpacing / 2, 0, gridSize * gridSpacing / 2}})
|
||||
.material(0, _materialInstance)
|
||||
.geometry(0, RenderableManager::PrimitiveType::LINES, vb, ib, 0, vertexCount)
|
||||
.priority(6)
|
||||
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
.culling(false)
|
||||
.receiveShadows(false)
|
||||
.castShadows(false)
|
||||
.build(engine, _gridEntity);
|
||||
const float sphereRadius = 0.05f;
|
||||
const int sphereSegments = 16;
|
||||
const int sphereRings = 16;
|
||||
|
||||
vertexCount = (sphereRings + 1) * (sphereSegments + 1);
|
||||
int indexCount = sphereRings * sphereSegments * 6;
|
||||
|
||||
math::float3* vertices = new math::float3[vertexCount];
|
||||
uint32_t* indices = new uint32_t[indexCount];
|
||||
|
||||
int vertexIndex = 0;
|
||||
// Generate sphere vertices
|
||||
for (int ring = 0; ring <= sphereRings; ++ring) {
|
||||
float theta = ring * M_PI / sphereRings;
|
||||
float sinTheta = std::sin(theta);
|
||||
float cosTheta = std::cos(theta);
|
||||
|
||||
for (int segment = 0; segment <= sphereSegments; ++segment) {
|
||||
float phi = segment * 2 * M_PI / sphereSegments;
|
||||
float sinPhi = std::sin(phi);
|
||||
float cosPhi = std::cos(phi);
|
||||
|
||||
float x = cosPhi * sinTheta;
|
||||
float y = cosTheta;
|
||||
float z = sinPhi * sinTheta;
|
||||
|
||||
vertices[vertexIndex++] = {x * sphereRadius, y * sphereRadius, z * sphereRadius};
|
||||
}
|
||||
}
|
||||
|
||||
int indexIndex = 0;
|
||||
// Generate sphere indices
|
||||
for (int ring = 0; ring < sphereRings; ++ring) {
|
||||
for (int segment = 0; segment < sphereSegments; ++segment) {
|
||||
uint32_t current = ring * (sphereSegments + 1) + segment;
|
||||
uint32_t next = current + sphereSegments + 1;
|
||||
|
||||
indices[indexIndex++] = current;
|
||||
indices[indexIndex++] = next;
|
||||
indices[indexIndex++] = current + 1;
|
||||
|
||||
indices[indexIndex++] = current + 1;
|
||||
indices[indexIndex++] = next;
|
||||
indices[indexIndex++] = next + 1;
|
||||
}
|
||||
}
|
||||
|
||||
auto sphereVb = VertexBuffer::Builder()
|
||||
.vertexCount(vertexCount)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.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); }
|
||||
));
|
||||
|
||||
auto sphereIb = IndexBuffer::Builder()
|
||||
.indexCount(indexCount)
|
||||
.bufferType(IndexBuffer::IndexType::UINT)
|
||||
.build(engine);
|
||||
|
||||
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();
|
||||
|
||||
RenderableManager::Builder(1)
|
||||
.boundingBox({{-sphereRadius, -sphereRadius, -sphereRadius},
|
||||
{sphereRadius, sphereRadius, sphereRadius}})
|
||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, sphereVb, sphereIb, 0, indexCount)
|
||||
.priority(6)
|
||||
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
.culling(false)
|
||||
.receiveShadows(false)
|
||||
.castShadows(false)
|
||||
.build(engine, _sphereEntity);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void GridOverlay::destroy()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
} // namespace thermion
|
||||
@@ -1,172 +1,178 @@
|
||||
#include <filament/Material.h>
|
||||
#include <filament/MaterialInstance.h>
|
||||
#include <utils/EntityManager.h>
|
||||
// #include <filament/Material.h>
|
||||
// #include <filament/MaterialInstance.h>
|
||||
// #include <utils/EntityManager.h>
|
||||
|
||||
#include "SceneManager.hpp"
|
||||
// #include "scene/SceneManager.hpp"
|
||||
|
||||
namespace thermion
|
||||
{
|
||||
// namespace thermion
|
||||
// {
|
||||
|
||||
SceneManager::HighlightOverlay::HighlightOverlay(
|
||||
EntityId entityId,
|
||||
SceneManager *const sceneManager,
|
||||
Engine *engine,
|
||||
float r,
|
||||
float g,
|
||||
float b) : _sceneManager(sceneManager), _engine(engine)
|
||||
{
|
||||
// SceneManager::HighlightOverlay::HighlightOverlay(
|
||||
// EntityId entityId,
|
||||
// SceneManager *const sceneManager,
|
||||
// Engine *engine,
|
||||
// float r,
|
||||
// float g,
|
||||
// float b) : _sceneManager(sceneManager), _engine(engine)
|
||||
// {
|
||||
|
||||
auto &rm = engine->getRenderableManager();
|
||||
// auto &rm = engine->getRenderableManager();
|
||||
|
||||
auto &tm = engine->getTransformManager();
|
||||
// auto &tm = engine->getTransformManager();
|
||||
|
||||
// Create the outline/highlight material instance
|
||||
filament::gltfio::MaterialKey dummyKey; // We're not using the key for this simple material
|
||||
filament::gltfio::UvMap dummyUvMap; // We're not using UV mapping for this simple material
|
||||
// // Create the outline/highlight material instance
|
||||
// filament::gltfio::MaterialKey dummyKey; // We're not using the key for this simple material
|
||||
// filament::gltfio::UvMap dummyUvMap; // We're not using UV mapping for this simple material
|
||||
|
||||
auto materialProvider = sceneManager->unlitMaterialProvider();
|
||||
// auto materialProvider = sceneManager->unlitMaterialProvider();
|
||||
|
||||
_highlightMaterialInstance = materialProvider->createMaterialInstance(&dummyKey, &dummyUvMap);
|
||||
_highlightMaterialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP);
|
||||
_highlightMaterialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::KEEP);
|
||||
_highlightMaterialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::REPLACE);
|
||||
_highlightMaterialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::NE);
|
||||
_highlightMaterialInstance->setStencilReferenceValue(1);
|
||||
// _highlightMaterialInstance = materialProvider->createMaterialInstance(&dummyKey, &dummyUvMap);
|
||||
// _highlightMaterialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP);
|
||||
// _highlightMaterialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::KEEP);
|
||||
// _highlightMaterialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::REPLACE);
|
||||
// _highlightMaterialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::NE);
|
||||
// _highlightMaterialInstance->setStencilReferenceValue(1);
|
||||
|
||||
_highlightMaterialInstance->setParameter("baseColorFactor", filament::math::float3{r, g, b});
|
||||
_highlightMaterialInstance->setParameter("vertexScale", 1.04f);
|
||||
_highlightMaterialInstance->setCullingMode(filament::backend::CullingMode::FRONT);
|
||||
// _highlightMaterialInstance->setParameter("baseColorFactor", filament::math::float3{r, g, b});
|
||||
// _highlightMaterialInstance->setParameter("vertexScale", 1.04f);
|
||||
// _highlightMaterialInstance->setCullingMode(filament::backend::CullingMode::FRONT);
|
||||
|
||||
// auto scene = sceneManager->getScene();
|
||||
|
||||
auto scene = sceneManager->getScene();
|
||||
// // _isGeometryEntity = sceneManager->isGeometryEntity(entityId);
|
||||
// // _isGltfAsset = sceneManager->isGltfAsset(entityId);
|
||||
|
||||
_isGeometryEntity = sceneManager->isGeometryEntity(entityId);
|
||||
_isGltfAsset = sceneManager->isGltfAsset(entityId);
|
||||
// if (!(_isGeometryEntity || _isGltfAsset))
|
||||
// {
|
||||
// Log("Failed to set stencil outline for entity %d: the entity is a child of another entity. "
|
||||
// "Currently, we only support outlining top-level entities."
|
||||
// "Call getAncestor() to get the ancestor of this entity, then set on that",
|
||||
// entityId);
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (!(_isGeometryEntity || _isGltfAsset))
|
||||
{
|
||||
Log("Failed to set stencil outline for entity %d: the entity is a child of another entity. "
|
||||
"Currently, we only support outlining top-level entities."
|
||||
"Call getAncestor() to get the ancestor of this entity, then set on that",
|
||||
entityId);
|
||||
return;
|
||||
}
|
||||
// if (_isGeometryEntity)
|
||||
// {
|
||||
|
||||
if (_isGeometryEntity)
|
||||
{
|
||||
// auto geometryEntity = Entity::import(entityId);
|
||||
// auto renderable = rm.getInstance(geometryEntity);
|
||||
|
||||
auto geometryEntity = Entity::import(entityId);
|
||||
auto renderable = rm.getInstance(geometryEntity);
|
||||
// auto materialInstance = rm.getMaterialInstanceAt(renderable, 0);
|
||||
|
||||
auto materialInstance = rm.getMaterialInstanceAt(renderable, 0);
|
||||
// // set stencil write on the existing material
|
||||
// materialInstance->setStencilWrite(true);
|
||||
// materialInstance->setDepthWrite(true);
|
||||
// materialInstance->setStencilReferenceValue(1);
|
||||
// materialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP);
|
||||
// materialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::KEEP);
|
||||
// materialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::KEEP);
|
||||
// materialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::A);
|
||||
// // materialInstance->setCullingMode(filament::MaterialInstance::CullingMode::BACK);
|
||||
|
||||
// set stencil write on the existing material
|
||||
materialInstance->setStencilWrite(true);
|
||||
materialInstance->setDepthWrite(true);
|
||||
materialInstance->setStencilReferenceValue(1);
|
||||
materialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP);
|
||||
materialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::KEEP);
|
||||
materialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::KEEP);
|
||||
materialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::A);
|
||||
// materialInstance->setCullingMode(filament::MaterialInstance::CullingMode::BACK);
|
||||
// // auto geometry = sceneManager->getGeometry(entityId);
|
||||
|
||||
auto geometry = sceneManager->getGeometry(entityId);
|
||||
// // _entity = geometry->createInstance(materialInstance);
|
||||
|
||||
_entity = geometry->createInstance(materialInstance);
|
||||
// scene->addEntity(_entity);
|
||||
// auto outlineTransformInstance = tm.getInstance(_entity);
|
||||
// auto entityTransformInstance = tm.getInstance(geometryEntity);
|
||||
// tm.setParent(outlineTransformInstance, entityTransformInstance);
|
||||
// }
|
||||
// else if (_isGltfAsset)
|
||||
// {
|
||||
// Log("Entity %d is gltf", entityId);
|
||||
// // auto *asset = sceneManager->getAssetByEntityId(entityId);
|
||||
|
||||
scene->addEntity(_entity);
|
||||
auto outlineTransformInstance = tm.getInstance(_entity);
|
||||
auto entityTransformInstance = tm.getInstance(geometryEntity);
|
||||
tm.setParent(outlineTransformInstance, entityTransformInstance);
|
||||
}
|
||||
else if (_isGltfAsset)
|
||||
{
|
||||
Log("Entity %d is gltf", entityId);
|
||||
auto *asset = sceneManager->getAssetByEntityId(entityId);
|
||||
// // if (asset)
|
||||
// // {
|
||||
|
||||
if (asset)
|
||||
{
|
||||
// // Log("Found glTF FilamentAsset with %d material instances", asset->getInstance()->getMaterialInstanceCount());
|
||||
|
||||
Log("Found glTF FilamentAsset with %d material instances", asset->getInstance()->getMaterialInstanceCount());
|
||||
// // auto materialInstance = asset->getInstance()->getMaterialInstances()[0];
|
||||
|
||||
auto materialInstance = asset->getInstance()->getMaterialInstances()[0];
|
||||
// // // set stencil write on the existing material
|
||||
// // materialInstance->setStencilWrite(true);
|
||||
// // materialInstance->setDepthWrite(true);
|
||||
// // materialInstance->setStencilReferenceValue(1);
|
||||
// // materialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP);
|
||||
// // materialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::REPLACE);
|
||||
// // materialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::REPLACE);
|
||||
// // materialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::A);
|
||||
|
||||
// set stencil write on the existing material
|
||||
materialInstance->setStencilWrite(true);
|
||||
materialInstance->setDepthWrite(true);
|
||||
materialInstance->setStencilReferenceValue(1);
|
||||
materialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP);
|
||||
materialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::REPLACE);
|
||||
materialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::REPLACE);
|
||||
materialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::A);
|
||||
// // _newInstance = sceneManager->createGltfAssetInstance(asset);
|
||||
|
||||
_newInstance = sceneManager->createGltfAssetInstance(asset);
|
||||
// // _entity = _newInstance->getRoot();
|
||||
|
||||
_entity = _newInstance->getRoot();
|
||||
// // auto newTransformInstance = tm.getInstance(_entity);
|
||||
|
||||
auto newTransformInstance = tm.getInstance(_entity);
|
||||
// // auto entityTransformInstance = tm.getInstance(asset->getRoot());
|
||||
// // tm.setParent(newTransformInstance, entityTransformInstance);
|
||||
// // if (!_newInstance)
|
||||
// // {
|
||||
// // Log("Couldn't create new instance");
|
||||
// // }
|
||||
// // else
|
||||
// // {
|
||||
// // for (int i = 0; i < _newInstance->getEntityCount(); i++)
|
||||
// // {
|
||||
// // auto entity = _newInstance->getEntities()[i];
|
||||
// // auto renderableInstance = rm.getInstance(entity);
|
||||
// // rm.setPriority(renderableInstance, 7);
|
||||
// // if (renderableInstance.isValid())
|
||||
// // {
|
||||
// // for (int primitiveIndex = 0; primitiveIndex < rm.getPrimitiveCount(renderableInstance); primitiveIndex++)
|
||||
// // {
|
||||
// // rm.setMaterialInstanceAt(renderableInstance, primitiveIndex, _highlightMaterialInstance);
|
||||
// // }
|
||||
// // }
|
||||
// // else
|
||||
// // {
|
||||
// // Log("Not renderable, ignoring");
|
||||
// // }
|
||||
// // }
|
||||
// // scene->addEntities(_newInstance->getEntities(), _newInstance->getEntityCount());
|
||||
// // }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Log("Not FilamentAsset");
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
auto entityTransformInstance = tm.getInstance(asset->getRoot());
|
||||
tm.setParent(newTransformInstance, entityTransformInstance);
|
||||
if (!_newInstance)
|
||||
{
|
||||
Log("Couldn't create new instance");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < _newInstance->getEntityCount(); i++)
|
||||
{
|
||||
auto entity = _newInstance->getEntities()[i];
|
||||
auto renderableInstance = rm.getInstance(entity);
|
||||
rm.setPriority(renderableInstance, 7);
|
||||
if (renderableInstance.isValid())
|
||||
{
|
||||
for (int primitiveIndex = 0; primitiveIndex < rm.getPrimitiveCount(renderableInstance); primitiveIndex++)
|
||||
{
|
||||
rm.setMaterialInstanceAt(renderableInstance, primitiveIndex, _highlightMaterialInstance);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("Not renderable, ignoring");
|
||||
}
|
||||
}
|
||||
scene->addEntities(_newInstance->getEntities(), _newInstance->getEntityCount());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("Not FilamentAsset");
|
||||
}
|
||||
}
|
||||
}
|
||||
// SceneManager::HighlightOverlay::~HighlightOverlay()
|
||||
// {
|
||||
// if (_entity.isNull())
|
||||
// {
|
||||
// Log("Null entity");
|
||||
// return;
|
||||
// }
|
||||
|
||||
SceneManager::HighlightOverlay::~HighlightOverlay()
|
||||
{
|
||||
if (_entity.isNull())
|
||||
{
|
||||
Log("Null entity");
|
||||
return;
|
||||
}
|
||||
|
||||
if (_isGltfAsset)
|
||||
{
|
||||
_sceneManager->getScene()->removeEntities(_newInstance->getEntities(), _newInstance->getEntityCount());
|
||||
_newInstance->detachMaterialInstances();
|
||||
_engine->destroy(_highlightMaterialInstance);
|
||||
}
|
||||
else if (_isGeometryEntity)
|
||||
{
|
||||
auto &tm = _engine->getTransformManager();
|
||||
auto transformInstance = tm.getInstance(_entity);
|
||||
_sceneManager->getScene()->remove(_entity);
|
||||
utils::EntityManager::get().destroy(_entity);
|
||||
_engine->destroy(_entity);
|
||||
_engine->destroy(_highlightMaterialInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("FATAL: Unknown highlight overlay entity type");
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (_isGltfAsset)
|
||||
// {
|
||||
// Log("Destroyed gltf asset highlight overlay");
|
||||
// _sceneManager->getScene()->removeEntities(_newInstance->getEntities(), _newInstance->getEntityCount());
|
||||
// // _sceneManager->destroyGltfAssetInstance(_newInstance);
|
||||
// // auto materialInstances = _newInstance->getMaterialInstances();
|
||||
// // auto numMaterialInstances = _newInstance->getMaterialInstanceCount();
|
||||
// // _newInstance->detachMaterialInstances();
|
||||
// // for(int i = 0; i < numMaterialInstances; i++) {
|
||||
// // _engine->destroy(_highlightMaterialInstance);
|
||||
// // }
|
||||
// // _engine->destroy(_newInstance);
|
||||
// }
|
||||
// else if (_isGeometryEntity)
|
||||
// {
|
||||
// auto &tm = _engine->getTransformManager();
|
||||
// auto transformInstance = tm.getInstance(_entity);
|
||||
// _sceneManager->getScene()->remove(_entity);
|
||||
// utils::EntityManager::get().destroy(_entity);
|
||||
// _engine->destroy(_entity);
|
||||
// _engine->destroy(_highlightMaterialInstance);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Log("FATAL: Unknown highlight overlay entity type");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,31 +0,0 @@
|
||||
#include <filament/View.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/Scene.h>
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
#include "TGizmo.h"
|
||||
#include "Gizmo.hpp"
|
||||
#include "Log.hpp"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace thermion {
|
||||
extern "C"
|
||||
{
|
||||
using namespace filament;
|
||||
#endif
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Gizmo_pick(TGizmo *tGizmo, uint32_t x, uint32_t y, GizmoPickCallback callback)
|
||||
{
|
||||
auto *gizmo = reinterpret_cast<Gizmo*>(tGizmo);
|
||||
gizmo->pick(x, y, reinterpret_cast<Gizmo::PickCallback>(callback));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Gizmo_setVisibility(TGizmo *tGizmo, bool visible) {
|
||||
auto *gizmo = reinterpret_cast<Gizmo*>(tGizmo);
|
||||
gizmo->setVisibility(visible);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,57 +0,0 @@
|
||||
#include <filament/MaterialInstance.h>
|
||||
#include <math/mat4.h>
|
||||
#include <math/vec4.h>
|
||||
#include <math/vec2.h>
|
||||
|
||||
#include "Log.hpp"
|
||||
#include "TMaterialInstance.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace thermion
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthWrite(TMaterialInstance *materialInstance, bool enabled)
|
||||
{
|
||||
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setDepthWrite(enabled);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthCulling(TMaterialInstance *materialInstance, bool enabled)
|
||||
{
|
||||
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setDepthCulling(enabled);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat4(TMaterialInstance *tMaterialInstance, const char *propertyName, double x, double y, double z, double w)
|
||||
{
|
||||
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
|
||||
filament::math::float4 data{static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(w)};
|
||||
materialInstance->setParameter(propertyName, data);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat2(TMaterialInstance *materialInstance, const char *propertyName, double x, double y)
|
||||
{
|
||||
filament::math::float2 data{static_cast<float>(x), static_cast<float>(y)};
|
||||
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setParameter(propertyName, data);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat(TMaterialInstance *materialInstance, const char *propertyName, double value)
|
||||
{
|
||||
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setParameter(propertyName, static_cast<float>(value));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterInt(TMaterialInstance *materialInstance, const char *propertyName, int value)
|
||||
{
|
||||
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setParameter(propertyName, value);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthFunc(TMaterialInstance *tMaterialInstance, TDepthFunc tDepthFunc) {
|
||||
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
|
||||
auto depthFunc = static_cast<filament::MaterialInstance::DepthFunc>(tDepthFunc);
|
||||
materialInstance->setDepthFunc(depthFunc);
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,140 +0,0 @@
|
||||
#include "filament/LightManager.h"
|
||||
#include "ResourceBuffer.hpp"
|
||||
#include "FilamentViewer.hpp"
|
||||
#include "Log.hpp"
|
||||
#include "APIExport.h"
|
||||
|
||||
using namespace thermion;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
#include "TSceneManager.h"
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TGizmo *SceneManager_createGizmo(TSceneManager *tSceneManager, TView *tView, TScene *tScene)
|
||||
{
|
||||
auto sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
auto *scene = reinterpret_cast<Scene *>(tScene);
|
||||
auto *view = reinterpret_cast<View *>(tView);
|
||||
auto gizmo = sceneManager->createGizmo(view, scene);
|
||||
return reinterpret_cast<TGizmo *>(gizmo);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId SceneManager_loadGlbFromBuffer(TSceneManager *sceneManager, const uint8_t *const data, size_t length, bool keepData, int priority, int layer, bool loadResourcesAsync)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->loadGlbFromBuffer((const uint8_t *)data, length, 1, keepData, priority, layer, loadResourcesAsync);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool SceneManager_setMorphAnimation(
|
||||
TSceneManager *sceneManager,
|
||||
EntityId asset,
|
||||
const float *const morphData,
|
||||
const uint32_t *const morphIndices,
|
||||
int numMorphTargets,
|
||||
int numFrames,
|
||||
float frameLengthInMs)
|
||||
{
|
||||
auto result = ((SceneManager *)sceneManager)->setMorphAnimationBuffer(asset, morphData, morphIndices, numMorphTargets, numFrames, frameLengthInMs);
|
||||
return result;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_getCameraByName(TSceneManager *tSceneManager, EntityId entityId, const char *name)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool SceneManager_setTransform(TSceneManager *sceneManager, EntityId entityId, const double *const transform)
|
||||
{
|
||||
auto matrix = math::mat4(
|
||||
transform[0], transform[1], transform[2],
|
||||
transform[3],
|
||||
transform[4],
|
||||
transform[5],
|
||||
transform[6],
|
||||
transform[7],
|
||||
transform[8],
|
||||
transform[9],
|
||||
transform[10],
|
||||
transform[11],
|
||||
transform[12],
|
||||
transform[13],
|
||||
transform[14],
|
||||
transform[15]);
|
||||
return ((SceneManager *)sceneManager)->setTransform(entityId, matrix);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE Aabb3 SceneManager_getRenderableBoundingBox(TSceneManager *tSceneManager, EntityId entity)
|
||||
{
|
||||
auto sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
return sceneManager->getRenderableBoundingBox(entity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_setVisibilityLayer(TSceneManager *tSceneManager, EntityId entity, int layer)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
sceneManager->setVisibilityLayer(entity, layer);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *SceneManager_createUnlitMaterialInstance(TSceneManager *sceneManager)
|
||||
{
|
||||
auto *instance = ((SceneManager *)sceneManager)->createUnlitMaterialInstance();
|
||||
return reinterpret_cast<TMaterialInstance *>(instance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *SceneManager_createUnlitFixedSizeMaterialInstance(TSceneManager *sceneManager)
|
||||
{
|
||||
auto *instance = ((SceneManager *)sceneManager)->createUnlitFixedSizeMaterialInstance();
|
||||
return reinterpret_cast<TMaterialInstance *>(instance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_createCamera(TSceneManager *tSceneManager)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
return reinterpret_cast<TCamera *>(sceneManager->createCamera());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_destroyCamera(TSceneManager *tSceneManager, TCamera *tCamera)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
auto *camera = reinterpret_cast<Camera *>(tCamera);
|
||||
sceneManager->destroyCamera(camera);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE size_t SceneManager_getCameraCount(TSceneManager *tSceneManager)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
return sceneManager->getCameraCount();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_getCameraAt(TSceneManager *tSceneManager, size_t index)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
auto *camera = sceneManager->getCameraAt(index);
|
||||
return reinterpret_cast<TCamera *>(camera);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId SceneManager_createGeometry(
|
||||
TSceneManager *sceneManager,
|
||||
float *vertices,
|
||||
int numVertices,
|
||||
float *normals,
|
||||
int numNormals,
|
||||
float *uvs,
|
||||
int numUvs,
|
||||
uint16_t *indices,
|
||||
int numIndices,
|
||||
int primitiveType,
|
||||
TMaterialInstance *materialInstance,
|
||||
bool keepData)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->createGeometry(vertices, static_cast<uint32_t>(numVertices), normals, static_cast<uint32_t>(numNormals), uvs, static_cast<uint32_t>(numUvs), indices, static_cast<uint32_t>(numIndices), (filament::RenderableManager::PrimitiveType)primitiveType, reinterpret_cast<MaterialInstance *>(materialInstance), keepData);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_destroyMaterialInstance(TSceneManager *sceneManager, TMaterialInstance *instance)
|
||||
{
|
||||
((SceneManager *)sceneManager)->destroy(reinterpret_cast<MaterialInstance *>(instance));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,952 +0,0 @@
|
||||
#ifdef _WIN32
|
||||
#include "ThermionWin32.h"
|
||||
#endif
|
||||
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten/emscripten.h>
|
||||
#endif
|
||||
|
||||
#include "filament/LightManager.h"
|
||||
#include "ResourceBuffer.hpp"
|
||||
#include "FilamentViewer.hpp"
|
||||
#include "Log.hpp"
|
||||
#include "ThreadPool.hpp"
|
||||
|
||||
using namespace thermion;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TViewer *Viewer_create(const void *context, const void *const loader, void *const platform, const char *uberArchivePath)
|
||||
{
|
||||
const auto *loaderImpl = new ResourceLoaderWrapperImpl((ResourceLoaderWrapper *)loader);
|
||||
auto viewer = new FilamentViewer(context, loaderImpl, platform, uberArchivePath);
|
||||
return reinterpret_cast<TViewer *>(viewer);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TEngine *Viewer_getEngine(TViewer *viewer)
|
||||
{
|
||||
auto *engine = reinterpret_cast<FilamentViewer *>(viewer)->getEngine();
|
||||
return reinterpret_cast<TEngine *>(engine);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TRenderTarget *Viewer_createRenderTarget(TViewer *tViewer, intptr_t texture, uint32_t width, uint32_t height)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto renderTarget = viewer->createRenderTarget(texture, width, height);
|
||||
return reinterpret_cast<TRenderTarget *>(renderTarget);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroyRenderTarget(TViewer *tViewer, TRenderTarget *tRenderTarget)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto renderTarget = reinterpret_cast<RenderTarget *>(tRenderTarget);
|
||||
viewer->destroyRenderTarget(renderTarget);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_pick(TViewer *tViewer, TView* tView, int x, int y, void (*callback)(EntityId entityId, int x, int y, TView *tView, float depth, float fragX, float fragY, float fragZ))
|
||||
{
|
||||
auto *viewer = reinterpret_cast<FilamentViewer*>(tViewer);
|
||||
auto *view = reinterpret_cast<View*>(tView);
|
||||
((FilamentViewer *)viewer)->pick(view, static_cast<uint32_t>(x), static_cast<uint32_t>(y), reinterpret_cast<FilamentViewer::PickCallback>(callback));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool Viewer_isNonPickableEntity(TViewer *tViewer, EntityId entityId) {
|
||||
auto *viewer = reinterpret_cast<FilamentViewer*>(tViewer);
|
||||
return viewer->isNonPickableEntity(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroy(TViewer *viewer)
|
||||
{
|
||||
delete ((FilamentViewer *)viewer);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_color(TViewer *viewer, const float r, const float g, const float b, const float a)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setBackgroundColor(r, g, b, a);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void clear_background_image(TViewer *viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->clearBackgroundImage();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image(TViewer *viewer, const char *path, bool fillHeight)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setBackgroundImage(path, fillHeight, 100, 100);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position(TViewer *viewer, float x, float y, bool clamp)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setBackgroundImagePosition(x, y, clamp, 100, 100);
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void load_skybox(TViewer *viewer, const char *skyboxPath)
|
||||
{
|
||||
((FilamentViewer *)viewer)->loadSkybox(skyboxPath);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void create_ibl(TViewer *viewer, float r, float g, float b, float intensity)
|
||||
{
|
||||
((FilamentViewer *)viewer)->createIbl(r, g, b, intensity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_loadIbl(TViewer *viewer, const char *iblPath, float intensity)
|
||||
{
|
||||
((FilamentViewer *)viewer)->loadIbl(iblPath, intensity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void rotate_ibl(TViewer *viewer, float *rotationMatrix)
|
||||
{
|
||||
math::mat3f matrix(rotationMatrix[0], rotationMatrix[1],
|
||||
rotationMatrix[2],
|
||||
rotationMatrix[3],
|
||||
rotationMatrix[4],
|
||||
rotationMatrix[5],
|
||||
rotationMatrix[6],
|
||||
rotationMatrix[7],
|
||||
rotationMatrix[8]);
|
||||
|
||||
((FilamentViewer *)viewer)->rotateIbl(matrix);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void remove_skybox(TViewer *viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->removeSkybox();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void remove_ibl(TViewer *viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->removeIbl();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId add_light(
|
||||
TViewer *viewer,
|
||||
uint8_t type,
|
||||
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)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->addLight((LightManager::Type)type, colour, intensity, posX, posY, posZ, dirX, dirY, dirZ, falloffRadius, spotLightConeInner, spotLightConeOuter, sunAngularRadius, sunHaloSize, sunHaloFallof, shadows);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_light_position(TViewer *viewer, int32_t entityId, float x, float y, float z)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setLightPosition(entityId, x, y, z);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_light_direction(TViewer *viewer, int32_t entityId, float x, float y, float z)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setLightDirection(entityId, x, y, z);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void remove_light(TViewer *viewer, int32_t entityId)
|
||||
{
|
||||
((FilamentViewer *)viewer)->removeLight(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void clear_lights(TViewer *viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->clearLights();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId load_glb(TSceneManager *sceneManager, const char *assetPath, int numInstances, bool keepData)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->loadGlb(assetPath, numInstances, keepData);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId create_instance(TSceneManager *sceneManager, EntityId entityId)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->createInstance(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE int get_instance_count(TSceneManager *sceneManager, EntityId entityId)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getInstanceCount(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void get_instances(TSceneManager *sceneManager, EntityId entityId, EntityId *out)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getInstances(entityId, out);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId load_gltf(TSceneManager *sceneManager, const char *assetPath, const char *relativePath, bool keepData)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->loadGltf(assetPath, relativePath, keepData);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_setMainCamera(TViewer *tViewer, TView *tView)
|
||||
{
|
||||
auto *viewer = reinterpret_cast<FilamentViewer*>(tViewer);
|
||||
auto *view = reinterpret_cast<View*>(tView);
|
||||
viewer->setMainCamera(view);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId get_main_camera(TViewer *viewer)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->getMainCamera();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE float get_camera_fov(TCamera *camera, bool horizontal)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
return cam->getFieldOfViewInDegrees(horizontal ? Camera::Fov::HORIZONTAL : Camera::Fov::VERTICAL);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_focal_length(TCamera *const camera)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
return cam->getFocalLength();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_projection_from_fov(TCamera *camera, double fovInDegrees, double aspect, double near, double far, bool horizontal)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
cam->setProjection(fovInDegrees, aspect, near, far, horizontal ? Camera::Fov::HORIZONTAL : Camera::Fov::VERTICAL);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *get_camera(TViewer *viewer, EntityId entity)
|
||||
{
|
||||
auto filamentCamera = ((FilamentViewer *)viewer)->getCamera(entity);
|
||||
return reinterpret_cast<TCamera *>(filamentCamera);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_model_matrix(TCamera *camera)
|
||||
{
|
||||
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getModelMatrix();
|
||||
return convert_mat4_to_double4x4(mat);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_view_matrix(TCamera *camera)
|
||||
{
|
||||
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getViewMatrix();
|
||||
return convert_mat4_to_double4x4(mat);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_projection_matrix(TCamera *camera)
|
||||
{
|
||||
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getProjectionMatrix();
|
||||
return convert_mat4_to_double4x4(mat);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_culling_projection_matrix(TCamera *camera)
|
||||
{
|
||||
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getCullingProjectionMatrix();
|
||||
return convert_mat4_to_double4x4(mat);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_projection_matrix(TCamera *camera, double4x4 matrix, double near, double far)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
const auto &mat = convert_double4x4_to_mat4(matrix);
|
||||
cam->setCustomProjection(mat, near, far);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setLensProjection(TCamera *camera, double near, double far, double aspect, double focalLength)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
cam->setLensProjection(focalLength, aspect, near, far);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setModelMatrix(TCamera *camera, double4x4 matrix)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
cam->setModelMatrix(convert_double4x4_to_mat4(matrix));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_near(TCamera *camera)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
return cam->getNear();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_culling_far(TCamera *camera)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
return cam->getCullingFar();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_frustum(TCamera *camera)
|
||||
{
|
||||
|
||||
const auto frustum = reinterpret_cast<filament::Camera *>(camera)->getFrustum();
|
||||
|
||||
const math::float4 *planes = frustum.getNormalizedPlanes();
|
||||
double *array = (double *)calloc(24, sizeof(double));
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
auto plane = planes[i];
|
||||
array[i * 4] = double(plane.x);
|
||||
array[i * 4 + 1] = double(plane.y);
|
||||
array[i * 4 + 2] = double(plane.z);
|
||||
array[i * 4 + 3] = double(plane.w);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_focus_distance(TCamera *camera, float distance)
|
||||
{
|
||||
auto *cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
cam->setFocusDistance(distance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_exposure(TCamera *camera, float aperture, float shutterSpeed, float sensitivity)
|
||||
{
|
||||
auto *cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
cam->setExposure(aperture, shutterSpeed, sensitivity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_model_matrix(TCamera *camera, double4x4 matrix)
|
||||
{
|
||||
auto *cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
const filament::math::mat4 &mat = convert_double4x4_to_mat4(matrix);
|
||||
cam->setModelMatrix(mat);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_render(
|
||||
TViewer *tViewer)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
viewer->render(0);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_setViewRenderable(TViewer *tViewer, TSwapChain *tSwapChain, TView *tView, bool renderable) {
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = reinterpret_cast<SwapChain*>(tSwapChain);
|
||||
auto *view = reinterpret_cast<View*>(tView);
|
||||
viewer->setRenderable(view, swapChain, renderable);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_capture(
|
||||
TViewer *tViewer,
|
||||
TView *tView,
|
||||
TSwapChain *tSwapChain,
|
||||
uint8_t *pixelBuffer,
|
||||
void (*callback)(void))
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
bool useFence = true;
|
||||
#else
|
||||
bool useFence = false;
|
||||
#endif
|
||||
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto *view = reinterpret_cast<View*>(tView);
|
||||
viewer->capture(view, pixelBuffer, useFence, swapChain, callback);
|
||||
};
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTarget(
|
||||
TViewer *tViewer,
|
||||
TView *tView,
|
||||
TSwapChain *tSwapChain,
|
||||
TRenderTarget *tRenderTarget,
|
||||
uint8_t *pixelBuffer,
|
||||
void (*callback)(void))
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
bool useFence = true;
|
||||
#else
|
||||
bool useFence = false;
|
||||
#endif
|
||||
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
|
||||
auto renderTarget = reinterpret_cast<RenderTarget *>(tRenderTarget);
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto *view = reinterpret_cast<View*>(tView);
|
||||
viewer->capture(view, pixelBuffer, useFence, swapChain, renderTarget, callback);
|
||||
};
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_frame_interval(
|
||||
TViewer *viewer,
|
||||
float frameInterval)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setFrameInterval(frameInterval);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChain(TViewer *tViewer, TSwapChain *tSwapChain)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
|
||||
viewer->destroySwapChain(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createHeadlessSwapChain(TViewer *tViewer, uint32_t width, uint32_t height)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = viewer->createSwapChain(width, height);
|
||||
return reinterpret_cast<TSwapChain *>(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createSwapChain(TViewer *tViewer, const void *const window)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = viewer->createSwapChain(window);
|
||||
return reinterpret_cast<TSwapChain *>(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain* Viewer_getSwapChainAt(TViewer *tViewer, int index) {
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = viewer->getSwapChainAt(index);
|
||||
return reinterpret_cast<TSwapChain *>(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TView *Viewer_createView(TViewer *tViewer)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto view = viewer->createView();
|
||||
return reinterpret_cast<TView *>(view);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TView *Viewer_getViewAt(TViewer *tViewer, int32_t index)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto view = viewer->getViewAt(index);
|
||||
return reinterpret_cast<TView *>(view);
|
||||
}
|
||||
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSceneManager *Viewer_getSceneManager(TViewer *tViewer)
|
||||
{
|
||||
auto *viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto *sceneManager = viewer->getSceneManager();
|
||||
return reinterpret_cast<TSceneManager *>(sceneManager);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void apply_weights(
|
||||
TSceneManager *sceneManager,
|
||||
EntityId asset,
|
||||
const char *const entityName,
|
||||
float *const weights,
|
||||
int count)
|
||||
{
|
||||
// ((SceneManager*)sceneManager)->setMorphTargetWeights(asset, entityName, weights, count);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool set_morph_target_weights(
|
||||
TSceneManager *sceneManager,
|
||||
EntityId asset,
|
||||
const float *const weights,
|
||||
const int numWeights)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->setMorphTargetWeights(asset, weights, numWeights);
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void clear_morph_animation(TSceneManager *sceneManager, EntityId asset)
|
||||
{
|
||||
((SceneManager *)sceneManager)->clearMorphAnimationBuffer(asset);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose(TSceneManager *sceneManager, EntityId entityId)
|
||||
{
|
||||
((SceneManager *)sceneManager)->resetBones(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void add_bone_animation(
|
||||
TSceneManager *sceneManager,
|
||||
EntityId asset,
|
||||
int skinIndex,
|
||||
int boneIndex,
|
||||
const float *const frameData,
|
||||
int numFrames,
|
||||
float frameLengthInMs,
|
||||
float fadeOutInSecs,
|
||||
float fadeInInSecs,
|
||||
float maxDelta)
|
||||
{
|
||||
((SceneManager *)sceneManager)->addBoneAnimation(asset, skinIndex, boneIndex, frameData, numFrames, frameLengthInMs, fadeOutInSecs, fadeInInSecs, maxDelta);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId get_bone(TSceneManager *sceneManager,
|
||||
EntityId entityId,
|
||||
int skinIndex,
|
||||
int boneIndex)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getBone(entityId, skinIndex, boneIndex);
|
||||
}
|
||||
EMSCRIPTEN_KEEPALIVE void get_world_transform(TSceneManager *sceneManager,
|
||||
EntityId entityId, float *const out)
|
||||
{
|
||||
auto transform = ((SceneManager *)sceneManager)->getWorldTransform(entityId);
|
||||
out[0] = transform[0][0];
|
||||
out[1] = transform[0][1];
|
||||
out[2] = transform[0][2];
|
||||
out[3] = transform[0][3];
|
||||
out[4] = transform[1][0];
|
||||
out[5] = transform[1][1];
|
||||
out[6] = transform[1][2];
|
||||
out[7] = transform[1][3];
|
||||
out[8] = transform[2][0];
|
||||
out[9] = transform[2][1];
|
||||
out[10] = transform[2][2];
|
||||
out[11] = transform[2][3];
|
||||
out[12] = transform[3][0];
|
||||
out[13] = transform[3][1];
|
||||
out[14] = transform[3][2];
|
||||
out[15] = transform[3][3];
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void get_local_transform(TSceneManager *sceneManager,
|
||||
EntityId entityId, float *const out)
|
||||
{
|
||||
auto transform = ((SceneManager *)sceneManager)->getLocalTransform(entityId);
|
||||
out[0] = transform[0][0];
|
||||
out[1] = transform[0][1];
|
||||
out[2] = transform[0][2];
|
||||
out[3] = transform[0][3];
|
||||
out[4] = transform[1][0];
|
||||
out[5] = transform[1][1];
|
||||
out[6] = transform[1][2];
|
||||
out[7] = transform[1][3];
|
||||
out[8] = transform[2][0];
|
||||
out[9] = transform[2][1];
|
||||
out[10] = transform[2][2];
|
||||
out[11] = transform[2][3];
|
||||
out[12] = transform[3][0];
|
||||
out[13] = transform[3][1];
|
||||
out[14] = transform[3][2];
|
||||
out[15] = transform[3][3];
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void get_rest_local_transforms(TSceneManager *sceneManager,
|
||||
EntityId entityId, int skinIndex, float *const out, int numBones)
|
||||
{
|
||||
const auto transforms = ((SceneManager *)sceneManager)->getBoneRestTranforms(entityId, skinIndex);
|
||||
auto numTransforms = transforms->size();
|
||||
if (numTransforms != numBones)
|
||||
{
|
||||
Log("Error - %d bone transforms available but you only specified %d.", numTransforms, numBones);
|
||||
return;
|
||||
}
|
||||
for (int boneIndex = 0; boneIndex < numTransforms; boneIndex++)
|
||||
{
|
||||
const auto transform = transforms->at(boneIndex);
|
||||
for (int colNum = 0; colNum < 4; colNum++)
|
||||
{
|
||||
for (int rowNum = 0; rowNum < 4; rowNum++)
|
||||
{
|
||||
out[(boneIndex * 16) + (colNum * 4) + rowNum] = transform[colNum][rowNum];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void get_inverse_bind_matrix(TSceneManager *sceneManager,
|
||||
EntityId entityId, int skinIndex, int boneIndex, float *const out)
|
||||
{
|
||||
auto transform = ((SceneManager *)sceneManager)->getInverseBindMatrix(entityId, skinIndex, boneIndex);
|
||||
out[0] = transform[0][0];
|
||||
out[1] = transform[0][1];
|
||||
out[2] = transform[0][2];
|
||||
out[3] = transform[0][3];
|
||||
out[4] = transform[1][0];
|
||||
out[5] = transform[1][1];
|
||||
out[6] = transform[1][2];
|
||||
out[7] = transform[1][3];
|
||||
out[8] = transform[2][0];
|
||||
out[9] = transform[2][1];
|
||||
out[10] = transform[2][2];
|
||||
out[11] = transform[2][3];
|
||||
out[12] = transform[3][0];
|
||||
out[13] = transform[3][1];
|
||||
out[14] = transform[3][2];
|
||||
out[15] = transform[3][3];
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool set_bone_transform(
|
||||
TSceneManager *sceneManager,
|
||||
EntityId entityId,
|
||||
int skinIndex,
|
||||
int boneIndex,
|
||||
const float *const transform)
|
||||
{
|
||||
auto matrix = math::mat4f(
|
||||
transform[0], transform[1], transform[2],
|
||||
transform[3],
|
||||
transform[4],
|
||||
transform[5],
|
||||
transform[6],
|
||||
transform[7],
|
||||
transform[8],
|
||||
transform[9],
|
||||
transform[10],
|
||||
transform[11],
|
||||
transform[12],
|
||||
transform[13],
|
||||
transform[14],
|
||||
transform[15]);
|
||||
return ((SceneManager *)sceneManager)->setBoneTransform(entityId, skinIndex, boneIndex, matrix);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void play_animation(
|
||||
TSceneManager *sceneManager,
|
||||
EntityId asset,
|
||||
int index,
|
||||
bool loop,
|
||||
bool reverse,
|
||||
bool replaceActive,
|
||||
float crossfade,
|
||||
float startOffset)
|
||||
{
|
||||
((SceneManager *)sceneManager)->playAnimation(asset, index, loop, reverse, replaceActive, crossfade, startOffset);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_animation_frame(
|
||||
TSceneManager *sceneManager,
|
||||
EntityId asset,
|
||||
int animationIndex,
|
||||
int animationFrame)
|
||||
{
|
||||
// ((SceneManager*)sceneManager)->setAnimationFrame(asset, animationIndex, animationFrame);
|
||||
}
|
||||
|
||||
float get_animation_duration(TSceneManager *sceneManager, EntityId asset, int animationIndex)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getAnimationDuration(asset, animationIndex);
|
||||
}
|
||||
|
||||
int get_animation_count(
|
||||
TSceneManager *sceneManager,
|
||||
EntityId asset)
|
||||
{
|
||||
auto names = ((SceneManager *)sceneManager)->getAnimationNames(asset);
|
||||
return (int)names->size();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void get_animation_name(
|
||||
TSceneManager *sceneManager,
|
||||
EntityId asset,
|
||||
char *const outPtr,
|
||||
int index)
|
||||
{
|
||||
auto names = ((SceneManager *)sceneManager)->getAnimationNames(asset);
|
||||
std::string name = names->at(index);
|
||||
strcpy(outPtr, name.c_str());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE int get_bone_count(TSceneManager *sceneManager, EntityId assetEntity, int skinIndex)
|
||||
{
|
||||
auto names = ((SceneManager *)sceneManager)->getBoneNames(assetEntity, skinIndex);
|
||||
return names->size();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void get_bone_names(TSceneManager *sceneManager, EntityId assetEntity, const char **out, int skinIndex)
|
||||
{
|
||||
auto names = ((SceneManager *)sceneManager)->getBoneNames(assetEntity, skinIndex);
|
||||
for (int i = 0; i < names->size(); i++)
|
||||
{
|
||||
auto name_c = names->at(i).c_str();
|
||||
memcpy((void *)out[i], name_c, strlen(name_c) + 1);
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool update_bone_matrices(TSceneManager *sceneManager, EntityId entityId)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->updateBoneMatrices(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE int get_morph_target_name_count(TSceneManager *sceneManager, EntityId assetEntity, EntityId childEntity)
|
||||
{
|
||||
auto names = ((SceneManager *)sceneManager)->getMorphTargetNames(assetEntity, childEntity);
|
||||
return (int)names->size();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void get_morph_target_name(TSceneManager *sceneManager, EntityId assetEntity, EntityId childEntity, char *const outPtr, int index)
|
||||
{
|
||||
auto names = ((SceneManager *)sceneManager)->getMorphTargetNames(assetEntity, childEntity);
|
||||
std::string name = names->at(index);
|
||||
strcpy(outPtr, name.c_str());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void remove_entity(TViewer *viewer, EntityId asset)
|
||||
{
|
||||
((FilamentViewer *)viewer)->removeEntity(asset);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void clear_entities(TViewer *viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->clearEntities();
|
||||
}
|
||||
|
||||
bool set_material_color(TSceneManager *sceneManager, EntityId asset, const char *meshName, int materialIndex, const float r, const float g, const float b, const float a)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->setMaterialColor(asset, meshName, materialIndex, r, g, b, a);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void transform_to_unit_cube(TSceneManager *sceneManager, EntityId asset)
|
||||
{
|
||||
((SceneManager *)sceneManager)->transformToUnitCube(asset);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_position(TSceneManager *sceneManager, EntityId asset, float x, float y, float z)
|
||||
{
|
||||
((SceneManager *)sceneManager)->setPosition(asset, x, y, z);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_rotation(TSceneManager *sceneManager, EntityId asset, float rads, float x, float y, float z, float w)
|
||||
{
|
||||
((SceneManager *)sceneManager)->setRotation(asset, rads, x, y, z, w);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_scale(TSceneManager *sceneManager, EntityId asset, float scale)
|
||||
{
|
||||
((SceneManager *)sceneManager)->setScale(asset, scale);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void queue_position_update_from_viewport_coords(TSceneManager *sceneManager, TView *tView, EntityId entity, float viewportX, float viewportY)
|
||||
{
|
||||
auto *view = reinterpret_cast<View*>(tView);
|
||||
((SceneManager *)sceneManager)->queueRelativePositionUpdateFromViewportVector(view, entity, viewportX, viewportY);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void stop_animation(TSceneManager *sceneManager, EntityId asset, int index)
|
||||
{
|
||||
((SceneManager *)sceneManager)->stopAnimation(asset, index);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE int hide_mesh(TSceneManager *sceneManager, EntityId asset, const char *meshName)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->hide(asset, meshName);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE int reveal_mesh(TSceneManager *sceneManager, EntityId asset, const char *meshName)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->reveal(asset, meshName);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE const char *get_name_for_entity(TSceneManager *sceneManager, const EntityId entityId)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getNameForEntity(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE int get_entity_count(TSceneManager *sceneManager, const EntityId target, bool renderableOnly)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getEntityCount(target, renderableOnly);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void get_entities(TSceneManager *sceneManager, const EntityId target, bool renderableOnly, EntityId *out)
|
||||
{
|
||||
((SceneManager *)sceneManager)->getEntities(target, renderableOnly, out);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE const char *get_entity_name_at(TSceneManager *sceneManager, const EntityId target, int index, bool renderableOnly)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getEntityNameAt(target, index, renderableOnly);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void ios_dummy()
|
||||
{
|
||||
Log("Dummy called");
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void thermion_filament_free(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void add_collision_component(TSceneManager *sceneManager, EntityId entityId, void (*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform)
|
||||
{
|
||||
((SceneManager *)sceneManager)->addCollisionComponent(entityId, onCollisionCallback, affectsCollidingTransform);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void remove_collision_component(TSceneManager *sceneManager, EntityId entityId)
|
||||
{
|
||||
((SceneManager *)sceneManager)->removeCollisionComponent(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool add_animation_component(TSceneManager *sceneManager, EntityId entityId)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->addAnimationComponent(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void remove_animation_component(TSceneManager *sceneManager, EntityId entityId)
|
||||
{
|
||||
((SceneManager *)sceneManager)->removeAnimationComponent(entityId);
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId find_child_entity_by_name(TSceneManager *sceneManager, const EntityId parent, const char *name)
|
||||
{
|
||||
auto entity = ((SceneManager *)sceneManager)->findChildEntityByName(parent, name);
|
||||
return utils::Entity::smuggle(entity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId get_parent(TSceneManager *sceneManager, EntityId child)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getParent(child);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId get_ancestor(TSceneManager *sceneManager, EntityId child)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getAncestor(child);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_parent(TSceneManager *sceneManager, EntityId child, EntityId parent, bool preserveScaling)
|
||||
{
|
||||
((SceneManager *)sceneManager)->setParent(child, parent, preserveScaling);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void test_collisions(TSceneManager *sceneManager, EntityId entity)
|
||||
{
|
||||
((SceneManager *)sceneManager)->testCollisions(entity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_priority(TSceneManager *sceneManager, EntityId entity, int priority)
|
||||
{
|
||||
((SceneManager *)sceneManager)->setPriority(entity, priority);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE Aabb2 get_bounding_box(TSceneManager *sceneManager, TView *tView, EntityId entity)
|
||||
{
|
||||
auto view = reinterpret_cast<View*>(tView);
|
||||
return ((SceneManager *)sceneManager)->getScreenSpaceBoundingBox(view, entity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void get_bounding_box_to_out(TSceneManager *sceneManager, TView *tView, EntityId entity, float *minX, float *minY, float *maxX, float *maxY)
|
||||
{
|
||||
auto view = reinterpret_cast<View*>(tView);
|
||||
auto box = ((SceneManager *)sceneManager)->getScreenSpaceBoundingBox(view, entity);
|
||||
*minX = box.minX;
|
||||
*minY = box.minY;
|
||||
*maxX = box.maxX;
|
||||
*maxY = box.maxY;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void thermion_flutter_free(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_stencil_highlight(TSceneManager *sceneManager, EntityId entityId, float r, float g, float b)
|
||||
{
|
||||
((SceneManager *)sceneManager)->setStencilHighlight(entityId, r, g, b);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void remove_stencil_highlight(TSceneManager *sceneManager, EntityId entityId)
|
||||
{
|
||||
((SceneManager *)sceneManager)->removeStencilHighlight(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_material_property_float(TSceneManager *sceneManager, EntityId entity, int materialIndex, const char *property, float value)
|
||||
{
|
||||
((SceneManager *)sceneManager)->setMaterialProperty(entity, materialIndex, property, value);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *get_material_instance_at(TSceneManager *sceneManager, EntityId entity, int materialIndex)
|
||||
{
|
||||
auto instance = ((SceneManager *)sceneManager)->getMaterialInstanceAt(entity, materialIndex);
|
||||
return reinterpret_cast<TMaterialInstance *>(instance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_material_property_int(TSceneManager *sceneManager, EntityId entity, int materialIndex, const char *property, int32_t value)
|
||||
{
|
||||
((SceneManager *)sceneManager)->setMaterialProperty(entity, materialIndex, property, value);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_material_property_float4(TSceneManager *sceneManager, EntityId entity, int materialIndex, const char *property, double4 value)
|
||||
{
|
||||
filament::math::float4 filamentValue;
|
||||
filamentValue.x = static_cast<float>(value.x);
|
||||
filamentValue.y = static_cast<float>(value.y);
|
||||
filamentValue.z = static_cast<float>(value.z);
|
||||
filamentValue.w = static_cast<float>(value.w);
|
||||
((SceneManager *)sceneManager)->setMaterialProperty(entity, materialIndex, property, filamentValue);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void unproject_texture(TViewer *viewer, EntityId entity, uint8_t *input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight)
|
||||
{
|
||||
((FilamentViewer *)viewer)->unprojectTexture(entity, input, inputWidth, inputHeight, out, outWidth, outHeight);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void *const create_texture(TSceneManager *sceneManager, uint8_t *data, size_t length)
|
||||
{
|
||||
return (void *const)((SceneManager *)sceneManager)->createTexture(data, length, "SOMETEXTURE");
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void apply_texture_to_material(TSceneManager *sceneManager, EntityId entity, void *const texture, const char *parameterName, int materialIndex)
|
||||
{
|
||||
((SceneManager *)sceneManager)->applyTexture(entity, reinterpret_cast<Texture *>(texture), parameterName, materialIndex);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_texture(TSceneManager *sceneManager, void *const texture)
|
||||
{
|
||||
((SceneManager *)sceneManager)->destroyTexture(reinterpret_cast<Texture *>(texture));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *create_material_instance(TSceneManager *sceneManager, TMaterialKey materialConfig)
|
||||
{
|
||||
|
||||
filament::gltfio::MaterialKey config;
|
||||
memset(&config, 0, sizeof(MaterialKey));
|
||||
|
||||
// Set and log each field
|
||||
config.unlit = materialConfig.unlit;
|
||||
config.doubleSided = materialConfig.doubleSided;
|
||||
config.useSpecularGlossiness = materialConfig.useSpecularGlossiness;
|
||||
config.alphaMode = static_cast<filament::gltfio::AlphaMode>(materialConfig.alphaMode);
|
||||
config.hasBaseColorTexture = materialConfig.hasBaseColorTexture;
|
||||
config.hasClearCoat = materialConfig.hasClearCoat;
|
||||
config.hasClearCoatNormalTexture = materialConfig.hasClearCoatNormalTexture;
|
||||
config.hasClearCoatRoughnessTexture = materialConfig.hasClearCoatRoughnessTexture;
|
||||
config.hasEmissiveTexture = materialConfig.hasEmissiveTexture;
|
||||
config.hasIOR = materialConfig.hasIOR;
|
||||
config.hasMetallicRoughnessTexture = materialConfig.hasMetallicRoughnessTexture;
|
||||
config.hasNormalTexture = materialConfig.hasNormalTexture;
|
||||
config.hasOcclusionTexture = materialConfig.hasOcclusionTexture;
|
||||
config.hasSheen = materialConfig.hasSheen;
|
||||
config.hasSheenColorTexture = materialConfig.hasSheenColorTexture;
|
||||
config.hasSheenRoughnessTexture = materialConfig.hasSheenRoughnessTexture;
|
||||
config.hasTextureTransforms = materialConfig.hasTextureTransforms;
|
||||
config.hasTransmission = materialConfig.hasTransmission;
|
||||
config.hasTransmissionTexture = materialConfig.hasTransmissionTexture;
|
||||
config.hasVolume = materialConfig.hasVolume;
|
||||
config.hasVolumeThicknessTexture = materialConfig.hasVolumeThicknessTexture;
|
||||
config.baseColorUV = materialConfig.baseColorUV;
|
||||
config.hasVertexColors = materialConfig.hasVertexColors;
|
||||
auto materialInstance = ((SceneManager *)sceneManager)->createUbershaderMaterialInstance(config);
|
||||
return reinterpret_cast<TMaterialInstance *>(materialInstance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine *tEngine, EntityId entityId)
|
||||
{
|
||||
auto *engine = reinterpret_cast<Engine *>(tEngine);
|
||||
auto *camera = engine->getCameraComponent(utils::Entity::import(entityId));
|
||||
return reinterpret_cast<TCamera *>(camera);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_setTransform(TEngine *tEngine, EntityId entity, double4x4 transform)
|
||||
{
|
||||
auto *engine = reinterpret_cast<Engine *>(tEngine);
|
||||
auto &transformManager = engine->getTransformManager();
|
||||
|
||||
auto transformInstance = transformManager.getInstance(utils::Entity::import(entity));
|
||||
if (!transformInstance.isValid())
|
||||
{
|
||||
Log("Transform instance not valid");
|
||||
}
|
||||
transformManager.setTransform(transformInstance, convert_double4x4_to_mat4(transform));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "CustomGeometry.hpp"
|
||||
#include "scene/CustomGeometry.hpp"
|
||||
#include "UnprojectTexture.hpp"
|
||||
|
||||
namespace thermion
|
||||
|
||||
300
thermion_dart/native/src/c_api/TAnimationManager.cpp
Normal file
300
thermion_dart/native/src/c_api/TAnimationManager.cpp
Normal file
@@ -0,0 +1,300 @@
|
||||
#include "Log.hpp"
|
||||
|
||||
#include "c_api/APIExport.h"
|
||||
#include "scene/AnimationManager.hpp"
|
||||
|
||||
using namespace thermion;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
#include "c_api/TAnimationManager.h"
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void AnimationManager_addAnimationComponent(TAnimationManager *tAnimationManager, EntityId entityId)
|
||||
{
|
||||
auto animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
|
||||
animationManager->addAnimationComponent(entityId);
|
||||
}
|
||||
EMSCRIPTEN_KEEPALIVE void AnimationManager_removeAnimationComponent(TAnimationManager *tAnimationManager, EntityId entityId)
|
||||
{
|
||||
auto animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
|
||||
animationManager->removeAnimationComponent(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool AnimationManager_setMorphAnimation(
|
||||
TAnimationManager *tAnimationManager,
|
||||
EntityId entityId,
|
||||
const float *const morphData,
|
||||
const uint32_t *const morphIndices,
|
||||
int numMorphTargets,
|
||||
int numFrames,
|
||||
float frameLengthInMs)
|
||||
{
|
||||
auto entity = utils::Entity::import(entityId);
|
||||
auto *animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
|
||||
auto result = animationManager->setMorphAnimationBuffer(entity, morphData, morphIndices, numMorphTargets, numFrames, frameLengthInMs);
|
||||
return result;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool AnimationManager_setMorphTargetWeights(
|
||||
TAnimationManager *tAnimationManager,
|
||||
EntityId entityId,
|
||||
const float *const morphData,
|
||||
int numWeights)
|
||||
{
|
||||
auto entity = utils::Entity::import(entityId);
|
||||
auto *animationManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
|
||||
animationManager->setMorphTargetWeights(entity, morphData, numWeights);
|
||||
return true;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool AnimationManager_clearMorphAnimation(TAnimationManager *tAnimationManager, EntityId entityId)
|
||||
{
|
||||
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
|
||||
auto entity = utils::Entity::import(entityId);
|
||||
animManager->clearMorphAnimationBuffer(entity);
|
||||
return true;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void AnimationManager_resetToRestPose(TAnimationManager *tAnimationManager, TSceneAsset *sceneAsset)
|
||||
{
|
||||
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
|
||||
auto asset = reinterpret_cast<SceneAsset *>(sceneAsset);
|
||||
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance())
|
||||
{
|
||||
auto *instance = reinterpret_cast<GltfSceneAssetInstance *>(asset);
|
||||
animManager->resetToRestPose(instance);
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void AnimationManager_addBoneAnimation(
|
||||
TAnimationManager *tAnimationManager,
|
||||
TSceneAsset *sceneAsset,
|
||||
int skinIndex,
|
||||
int boneIndex,
|
||||
const float *const frameData,
|
||||
int numFrames,
|
||||
float frameLengthInMs,
|
||||
float fadeOutInSecs,
|
||||
float fadeInInSecs,
|
||||
float maxDelta)
|
||||
{
|
||||
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
|
||||
auto asset = reinterpret_cast<SceneAsset *>(sceneAsset);
|
||||
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance())
|
||||
{
|
||||
animManager->addBoneAnimation(reinterpret_cast<GltfSceneAssetInstance *>(asset), skinIndex, boneIndex, frameData, numFrames, frameLengthInMs,
|
||||
fadeOutInSecs, fadeInInSecs, maxDelta);
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId AnimationManager_getBone(
|
||||
TAnimationManager *tAnimationManager,
|
||||
TSceneAsset *sceneAsset,
|
||||
int skinIndex,
|
||||
int boneIndex)
|
||||
{
|
||||
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
|
||||
auto asset = reinterpret_cast<SceneAsset *>(sceneAsset);
|
||||
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance())
|
||||
{
|
||||
auto entities = animManager->getBoneEntities(reinterpret_cast<GltfSceneAssetInstance *>(asset), skinIndex);
|
||||
if (boneIndex < entities.size())
|
||||
{
|
||||
return utils::Entity::smuggle(entities[boneIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void AnimationManager_getRestLocalTransforms(
|
||||
TAnimationManager *tAnimationManager,
|
||||
TSceneAsset *sceneAsset,
|
||||
int skinIndex,
|
||||
float *const out,
|
||||
int numBones)
|
||||
{
|
||||
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
|
||||
auto asset = reinterpret_cast<SceneAsset *>(sceneAsset);
|
||||
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance())
|
||||
{
|
||||
auto *instance = reinterpret_cast<GltfSceneAssetInstance *>(asset);
|
||||
const auto transforms = animManager->getBoneRestTranforms(instance, skinIndex);
|
||||
auto numTransforms = transforms.size();
|
||||
if (numTransforms != numBones)
|
||||
{
|
||||
Log("Error - %d bone transforms available but you only specified %d.", numTransforms, numBones);
|
||||
return;
|
||||
}
|
||||
for (int boneIndex = 0; boneIndex < numTransforms; boneIndex++)
|
||||
{
|
||||
const auto transform = transforms[boneIndex];
|
||||
for (int colNum = 0; colNum < 4; colNum++)
|
||||
{
|
||||
for (int rowNum = 0; rowNum < 4; rowNum++)
|
||||
{
|
||||
out[(boneIndex * 16) + (colNum * 4) + rowNum] = transform[colNum][rowNum];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void AnimationManager_getInverseBindMatrix(
|
||||
TAnimationManager *tAnimationManager,
|
||||
TSceneAsset *sceneAsset,
|
||||
int skinIndex,
|
||||
int boneIndex,
|
||||
float *const out)
|
||||
{
|
||||
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
|
||||
auto asset = reinterpret_cast<SceneAsset *>(sceneAsset);
|
||||
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance())
|
||||
{
|
||||
auto *instance = reinterpret_cast<GltfSceneAssetInstance *>(asset);
|
||||
auto transform = animManager->getInverseBindMatrix(instance, skinIndex, boneIndex);
|
||||
for (int colNum = 0; colNum < 4; colNum++)
|
||||
{
|
||||
for (int rowNum = 0; rowNum < 4; rowNum++)
|
||||
{
|
||||
out[(colNum * 4) + rowNum] = transform[colNum][rowNum];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void AnimationManager_playAnimation(
|
||||
TAnimationManager *tAnimationManager,
|
||||
TSceneAsset *sceneAsset,
|
||||
int index,
|
||||
bool loop,
|
||||
bool reverse,
|
||||
bool replaceActive,
|
||||
float crossfade,
|
||||
float startOffset)
|
||||
{
|
||||
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
|
||||
auto asset = reinterpret_cast<SceneAsset *>(sceneAsset);
|
||||
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance())
|
||||
{
|
||||
auto *instance = reinterpret_cast<GltfSceneAssetInstance *>(asset);
|
||||
|
||||
animManager->playGltfAnimation(instance, index, loop, reverse, replaceActive, crossfade, startOffset);
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void AnimationManager_stopAnimation(
|
||||
TAnimationManager *tAnimationManager,
|
||||
TSceneAsset *sceneAsset,
|
||||
int index)
|
||||
{
|
||||
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
|
||||
auto asset = reinterpret_cast<SceneAsset *>(sceneAsset);
|
||||
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance())
|
||||
{
|
||||
auto *instance = reinterpret_cast<GltfSceneAssetInstance *>(asset);
|
||||
|
||||
animManager->stopGltfAnimation(instance, index);
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void AnimationManager_setGltfAnimationFrame(
|
||||
TAnimationManager *tAnimationManager,
|
||||
TSceneAsset *tSceneAsset,
|
||||
int animationIndex,
|
||||
int frame)
|
||||
{
|
||||
auto *animManager = reinterpret_cast<AnimationManager *>(tAnimationManager);
|
||||
auto asset = reinterpret_cast<SceneAsset *>(tSceneAsset);
|
||||
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && asset->isInstance())
|
||||
{
|
||||
auto *instance = reinterpret_cast<GltfSceneAssetInstance *>(asset);
|
||||
animManager->setGltfAnimationFrame(instance, animationIndex, frame);
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE float AnimationManager_getAnimationDuration(
|
||||
TAnimationManager *tAnimationManager,
|
||||
TSceneAsset *sceneAsset,
|
||||
int animationIndex)
|
||||
{
|
||||
auto instance = ((GltfSceneAssetInstance *)sceneAsset);
|
||||
return ((AnimationManager *)tAnimationManager)->getGltfAnimationDuration(instance, animationIndex);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE int AnimationManager_getAnimationCount(
|
||||
TAnimationManager *tAnimationManager,
|
||||
TSceneAsset *sceneAsset)
|
||||
{
|
||||
auto instance = ((GltfSceneAssetInstance *)sceneAsset);
|
||||
auto names = ((AnimationManager *)tAnimationManager)->getGltfAnimationNames(instance);
|
||||
return (int)names.size();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void AnimationManager_getAnimationName(
|
||||
TAnimationManager *tAnimationManager,
|
||||
TSceneAsset *sceneAsset,
|
||||
char *const outPtr,
|
||||
int index)
|
||||
{
|
||||
auto instance = ((GltfSceneAssetInstance *)sceneAsset);
|
||||
auto names = ((AnimationManager *)tAnimationManager)->getGltfAnimationNames(instance);
|
||||
std::string name = names[index];
|
||||
strcpy(outPtr, name.c_str());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE int AnimationManager_getBoneCount(
|
||||
TAnimationManager *tAnimationManager,
|
||||
TSceneAsset *sceneAsset,
|
||||
int skinIndex)
|
||||
{
|
||||
auto instance = ((GltfSceneAssetInstance *)sceneAsset);
|
||||
auto entities = ((AnimationManager *)tAnimationManager)->getBoneEntities(instance, skinIndex);
|
||||
return (int)entities.size();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void AnimationManager_getBoneNames(
|
||||
TAnimationManager *tAnimationManager,
|
||||
TSceneAsset *sceneAsset,
|
||||
const char **out,
|
||||
int skinIndex)
|
||||
{
|
||||
auto instance = ((GltfSceneAssetInstance *)sceneAsset);
|
||||
auto entities = ((AnimationManager *)tAnimationManager)->getBoneEntities(instance, skinIndex);
|
||||
// Note: This needs implementation of a method to get bone names from entities
|
||||
// Current source doesn't show how bone names are retrieved
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool AnimationManager_updateBoneMatrices(
|
||||
TAnimationManager *tAnimationManager,
|
||||
TSceneAsset *sceneAsset)
|
||||
{
|
||||
auto instance = ((GltfSceneAssetInstance *)sceneAsset);
|
||||
((AnimationManager *)tAnimationManager)->updateBoneMatrices(instance);
|
||||
return true;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE int AnimationManager_getMorphTargetNameCount(
|
||||
TAnimationManager *tAnimationManager,
|
||||
TSceneAsset *sceneAsset,
|
||||
EntityId childEntity)
|
||||
{
|
||||
auto asset = ((GltfSceneAsset *)sceneAsset);
|
||||
auto names = ((AnimationManager *)tAnimationManager)->getMorphTargetNames(asset, childEntity);
|
||||
return (int)names.size();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void AnimationManager_getMorphTargetName(
|
||||
TAnimationManager *tAnimationManager,
|
||||
TSceneAsset *sceneAsset,
|
||||
EntityId childEntity,
|
||||
char *const outPtr,
|
||||
int index)
|
||||
{
|
||||
auto asset = ((GltfSceneAsset *)sceneAsset);
|
||||
auto names = ((AnimationManager *)tAnimationManager)->getMorphTargetNames(asset, childEntity);
|
||||
std::string name = names[index];
|
||||
strcpy(outPtr, name.c_str());
|
||||
}
|
||||
}
|
||||
@@ -6,11 +6,11 @@
|
||||
#include <filament/Camera.h>
|
||||
#include <utils/Entity.h>
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
#include "TCamera.h"
|
||||
#include "ThermionDartAPIUtils.h"
|
||||
|
||||
#include "c_api/ThermionDartApi.h"
|
||||
#include "c_api/TCamera.h"
|
||||
#include "Log.hpp"
|
||||
#include "MathUtils.hpp"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace thermion
|
||||
41
thermion_dart/native/src/c_api/TGizmo.cpp
Normal file
41
thermion_dart/native/src/c_api/TGizmo.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include <filament/View.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/Scene.h>
|
||||
|
||||
#include "c_api/TGizmo.h"
|
||||
#include "scene/Gizmo.hpp"
|
||||
#include "Log.hpp"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace thermion
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
using namespace filament;
|
||||
#endif
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Gizmo_pick(TGizmo *tGizmo, uint32_t x, uint32_t y, GizmoPickCallback callback)
|
||||
{
|
||||
auto *gizmo = reinterpret_cast<Gizmo *>(tGizmo);
|
||||
gizmo->pick(x, y, reinterpret_cast<Gizmo::GizmoPickCallback>(callback));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Gizmo_highlight(TGizmo *tGizmo, TGizmoAxis tAxis)
|
||||
{
|
||||
auto *gizmo = reinterpret_cast<Gizmo *>(tGizmo);
|
||||
auto axis = static_cast<Gizmo::Axis>(tAxis);
|
||||
gizmo->highlight(axis);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Gizmo_unhighlight(TGizmo *tGizmo)
|
||||
{
|
||||
auto *gizmo = reinterpret_cast<Gizmo *>(tGizmo);
|
||||
gizmo->unhighlight(Gizmo::Axis::X);
|
||||
gizmo->unhighlight(Gizmo::Axis::Y);
|
||||
gizmo->unhighlight(Gizmo::Axis::Z);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
#endif
|
||||
136
thermion_dart/native/src/c_api/TMaterialInstance.cpp
Normal file
136
thermion_dart/native/src/c_api/TMaterialInstance.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
#include <filament/MaterialInstance.h>
|
||||
#include <math/mat4.h>
|
||||
#include <math/vec4.h>
|
||||
#include <math/vec2.h>
|
||||
|
||||
#include "Log.hpp"
|
||||
#include "c_api/TMaterialInstance.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace thermion
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool MaterialInstance_isStencilWriteEnabled(TMaterialInstance *tMaterialInstance)
|
||||
{
|
||||
return reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance)->isStencilWriteEnabled();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthWrite(TMaterialInstance *materialInstance, bool enabled)
|
||||
{
|
||||
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setDepthWrite(enabled);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthCulling(TMaterialInstance *materialInstance, bool enabled)
|
||||
{
|
||||
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setDepthCulling(enabled);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat4(TMaterialInstance *tMaterialInstance, const char *propertyName, double x, double y, double z, double w)
|
||||
{
|
||||
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
|
||||
filament::math::float4 data{static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(w)};
|
||||
materialInstance->setParameter(propertyName, data);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat2(TMaterialInstance *materialInstance, const char *propertyName, double x, double y)
|
||||
{
|
||||
filament::math::float2 data{static_cast<float>(x), static_cast<float>(y)};
|
||||
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setParameter(propertyName, data);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat(TMaterialInstance *materialInstance, const char *propertyName, double value)
|
||||
{
|
||||
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setParameter(propertyName, static_cast<float>(value));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterInt(TMaterialInstance *materialInstance, const char *propertyName, int value)
|
||||
{
|
||||
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setParameter(propertyName, value);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthFunc(TMaterialInstance *tMaterialInstance, TSamplerCompareFunc tDepthFunc)
|
||||
{
|
||||
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
|
||||
auto depthFunc = static_cast<filament::MaterialInstance::DepthFunc>(tDepthFunc);
|
||||
materialInstance->setDepthFunc(depthFunc);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilOpStencilFail(TMaterialInstance *tMaterialInstance,
|
||||
TStencilOperation tOp, TStencilFace tFace)
|
||||
{
|
||||
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
|
||||
auto op = static_cast<filament::MaterialInstance::StencilOperation>(tOp);
|
||||
auto face = static_cast<filament::MaterialInstance::StencilFace>(tFace);
|
||||
materialInstance->setStencilOpStencilFail(op, face);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilOpDepthFail(TMaterialInstance *tMaterialInstance,
|
||||
TStencilOperation tOp, TStencilFace tFace)
|
||||
{
|
||||
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
|
||||
auto op = static_cast<filament::MaterialInstance::StencilOperation>(tOp);
|
||||
auto face = static_cast<filament::MaterialInstance::StencilFace>(tFace);
|
||||
materialInstance->setStencilOpDepthFail(op, face);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilOpDepthStencilPass(TMaterialInstance *tMaterialInstance,
|
||||
TStencilOperation tOp, TStencilFace tFace)
|
||||
{
|
||||
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
|
||||
auto op = static_cast<filament::MaterialInstance::StencilOperation>(tOp);
|
||||
auto face = static_cast<filament::MaterialInstance::StencilFace>(tFace);
|
||||
materialInstance->setStencilOpDepthStencilPass(op, face);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilCompareFunction(TMaterialInstance *tMaterialInstance,
|
||||
TSamplerCompareFunc tFunc, TStencilFace tFace)
|
||||
{
|
||||
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
|
||||
auto func = static_cast<filament::MaterialInstance::StencilCompareFunc>(tFunc);
|
||||
auto face = static_cast<filament::MaterialInstance::StencilFace>(tFace);
|
||||
materialInstance->setStencilCompareFunction(func, face);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilReferenceValue(TMaterialInstance *tMaterialInstance,
|
||||
uint8_t value, TStencilFace tFace)
|
||||
{
|
||||
auto *materialInstance = reinterpret_cast<::filament::MaterialInstance *>(tMaterialInstance);
|
||||
auto face = static_cast<filament::MaterialInstance::StencilFace>(tFace);
|
||||
materialInstance->setStencilReferenceValue(value, face);
|
||||
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilWrite(TMaterialInstance *materialInstance, bool enabled)
|
||||
{
|
||||
reinterpret_cast<::filament::MaterialInstance *>(materialInstance)->setStencilWrite(enabled);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setCullingMode(TMaterialInstance *materialInstance, TCullingMode culling)
|
||||
{
|
||||
auto *instance = reinterpret_cast<::filament::MaterialInstance *>(materialInstance);
|
||||
auto cullingMode = static_cast<filament::MaterialInstance::CullingMode>(culling);
|
||||
instance->setCullingMode(cullingMode);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilReadMask(
|
||||
TMaterialInstance *materialInstance,
|
||||
uint8_t mask)
|
||||
{
|
||||
auto *instance = reinterpret_cast<::filament::MaterialInstance *>(materialInstance);
|
||||
instance->setStencilReadMask(mask);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setStencilWriteMask(
|
||||
TMaterialInstance *materialInstance,
|
||||
uint8_t mask)
|
||||
{
|
||||
auto *instance = reinterpret_cast<::filament::MaterialInstance *>(materialInstance);
|
||||
instance->setStencilWriteMask(mask);
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
#endif
|
||||
57
thermion_dart/native/src/c_api/TMaterialProvider.cpp
Normal file
57
thermion_dart/native/src/c_api/TMaterialProvider.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#include <filament/MaterialInstance.h>
|
||||
#include <gltfio/MaterialProvider.h>
|
||||
#include <math/mat4.h>
|
||||
#include <math/vec4.h>
|
||||
#include <math/vec2.h>
|
||||
|
||||
#include "Log.hpp"
|
||||
#include "c_api/TMaterialProvider.h"
|
||||
#include "c_api/TMaterialInstance.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace thermion
|
||||
{
|
||||
using namespace filament;
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *MaterialProvider_createMaterialInstance(TMaterialProvider *tMaterialProvider, TMaterialKey *materialConfig)
|
||||
{
|
||||
gltfio::MaterialKey config;
|
||||
gltfio::UvMap uvMap;
|
||||
memset(&config, 0, sizeof(gltfio::MaterialKey));
|
||||
|
||||
// Set and log each field
|
||||
config.unlit = materialConfig->unlit;
|
||||
config.doubleSided = materialConfig->doubleSided;
|
||||
config.useSpecularGlossiness = materialConfig->useSpecularGlossiness;
|
||||
config.alphaMode = static_cast<filament::gltfio::AlphaMode>(materialConfig->alphaMode);
|
||||
config.hasBaseColorTexture = materialConfig->hasBaseColorTexture;
|
||||
config.hasClearCoat = materialConfig->hasClearCoat;
|
||||
config.hasClearCoatNormalTexture = materialConfig->hasClearCoatNormalTexture;
|
||||
config.hasClearCoatRoughnessTexture = materialConfig->hasClearCoatRoughnessTexture;
|
||||
config.hasEmissiveTexture = materialConfig->hasEmissiveTexture;
|
||||
config.hasIOR = materialConfig->hasIOR;
|
||||
config.hasMetallicRoughnessTexture = materialConfig->hasMetallicRoughnessTexture;
|
||||
config.hasNormalTexture = materialConfig->hasNormalTexture;
|
||||
config.hasOcclusionTexture = materialConfig->hasOcclusionTexture;
|
||||
config.hasSheen = materialConfig->hasSheen;
|
||||
config.hasSheenColorTexture = materialConfig->hasSheenColorTexture;
|
||||
config.hasSheenRoughnessTexture = materialConfig->hasSheenRoughnessTexture;
|
||||
config.hasTextureTransforms = materialConfig->hasTextureTransforms;
|
||||
config.hasTransmission = materialConfig->hasTransmission;
|
||||
config.hasTransmissionTexture = materialConfig->hasTransmissionTexture;
|
||||
config.hasVolume = materialConfig->hasVolume;
|
||||
config.hasVolumeThicknessTexture = materialConfig->hasVolumeThicknessTexture;
|
||||
config.baseColorUV = materialConfig->baseColorUV;
|
||||
config.hasVertexColors = materialConfig->hasVertexColors;
|
||||
|
||||
auto *materialProvider = reinterpret_cast<gltfio::MaterialProvider *>(tMaterialProvider);
|
||||
auto materialInstance = materialProvider->createMaterialInstance(&config, &uvMap);
|
||||
return reinterpret_cast<TMaterialInstance *>(materialInstance);
|
||||
}
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
#endif
|
||||
20
thermion_dart/native/src/c_api/TNameComponentManager.cpp
Normal file
20
thermion_dart/native/src/c_api/TNameComponentManager.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include <utils/NameComponentManager.h>
|
||||
|
||||
#include "c_api/APIExport.h"
|
||||
#include "c_api/APIBoundaryTypes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE const char *NameComponentManager_getName(TNameComponentManager *tNameComponentManager, EntityId entity)
|
||||
{
|
||||
auto ncm = reinterpret_cast<utils::NameComponentManager *>(tNameComponentManager);
|
||||
auto instance = ncm->getInstance(utils::Entity::import(entity));
|
||||
return ncm->getName(instance);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
44
thermion_dart/native/src/c_api/TRenderableManager.cpp
Normal file
44
thermion_dart/native/src/c_api/TRenderableManager.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
|
||||
#include <filament/MaterialInstance.h>
|
||||
#include <filament/RenderableManager.h>
|
||||
#include <utils/Entity.h>
|
||||
|
||||
#include "Log.hpp"
|
||||
#include "c_api/TRenderableManager.h"
|
||||
|
||||
namespace thermion
|
||||
{
|
||||
|
||||
extern "C"
|
||||
{
|
||||
using namespace filament;
|
||||
using namespace utils;
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void RenderableManager_setMaterialInstanceAt(TRenderableManager *tRenderableManager, EntityId entityId, int primitiveIndex, TMaterialInstance *tMaterialInstance)
|
||||
{
|
||||
auto *renderableManager = reinterpret_cast<filament::RenderableManager *>(tRenderableManager);
|
||||
const auto &entity = utils::Entity::import(entityId);
|
||||
auto renderableInstance = renderableManager->getInstance(entity);
|
||||
auto materialInstance = reinterpret_cast<MaterialInstance *>(tMaterialInstance);
|
||||
renderableManager->setMaterialInstanceAt(renderableInstance, primitiveIndex, materialInstance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *RenderableManager_getMaterialInstanceAt(TRenderableManager *tRenderableManager, EntityId entityId, int primitiveIndex) {
|
||||
auto *renderableManager = reinterpret_cast<filament::RenderableManager *>(tRenderableManager);
|
||||
const auto &entity = utils::Entity::import(entityId);
|
||||
auto renderableInstance = renderableManager->getInstance(entity);
|
||||
if(!renderableInstance.isValid()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto materialInstance = renderableManager->getMaterialInstanceAt(renderableInstance, primitiveIndex);
|
||||
return reinterpret_cast<TMaterialInstance*>(materialInstance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void RenderableManager_setPriority(TRenderableManager *tRenderableManager, EntityId entityId, int priority) {
|
||||
auto *renderableManager = reinterpret_cast<filament::RenderableManager *>(tRenderableManager);
|
||||
const auto &entity = utils::Entity::import(entityId);
|
||||
auto renderableInstance = renderableManager->getInstance(entity);
|
||||
renderableManager->setPriority(renderableInstance, priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
108
thermion_dart/native/src/c_api/TSceneAsset.cpp
Normal file
108
thermion_dart/native/src/c_api/TSceneAsset.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
#include "c_api/TSceneAsset.h"
|
||||
#include "scene/SceneAsset.hpp"
|
||||
#include "scene/GltfSceneAsset.hpp"
|
||||
|
||||
using namespace thermion;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneAsset_addToScene(TSceneAsset *tSceneAsset, TScene *tScene) {
|
||||
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
|
||||
auto *scene = reinterpret_cast<Scene*>(tScene);
|
||||
asset->addAllEntities(scene);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId SceneAsset_getEntity(TSceneAsset *tSceneAsset) {
|
||||
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
|
||||
return utils::Entity::smuggle(asset->getEntity());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE int SceneAsset_getChildEntityCount(TSceneAsset* tSceneAsset) {
|
||||
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
|
||||
return asset->getChildEntityCount();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneAsset_getChildEntities(TSceneAsset* tSceneAsset, EntityId *out)
|
||||
{
|
||||
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
|
||||
auto entities = asset->getChildEntities();
|
||||
for(int i = 0; i < asset->getChildEntityCount(); i++) {
|
||||
out[i] = utils::Entity::smuggle(entities[i]);
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE const utils::Entity *SceneAsset_getCameraEntities(TSceneAsset* tSceneAsset)
|
||||
{
|
||||
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
|
||||
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && !asset->isInstance())
|
||||
{
|
||||
auto gltfSceneAsset = reinterpret_cast<GltfSceneAsset *>(asset);
|
||||
return gltfSceneAsset->getAsset()->getCameraEntities();
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::nullptr_t();
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE size_t SceneAsset_getCameraEntityCount(TSceneAsset* tSceneAsset)
|
||||
{
|
||||
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
|
||||
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && !asset->isInstance())
|
||||
{
|
||||
auto gltfSceneAsset = reinterpret_cast<GltfSceneAsset *>(asset);
|
||||
return gltfSceneAsset->getAsset()->getCameraEntityCount();
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE const utils::Entity *SceneAsset_getLightEntities(TSceneAsset* tSceneAsset)
|
||||
{
|
||||
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
|
||||
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && !asset->isInstance())
|
||||
{
|
||||
auto gltfSceneAsset = reinterpret_cast<GltfSceneAsset *>(asset);
|
||||
return gltfSceneAsset->getAsset()->getLightEntities();
|
||||
}
|
||||
|
||||
return std::nullptr_t();
|
||||
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE size_t SceneAsset_getLightEntityCount(TSceneAsset* tSceneAsset)
|
||||
{
|
||||
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
|
||||
if (asset->getType() == SceneAsset::SceneAssetType::Gltf && !asset->isInstance())
|
||||
{
|
||||
auto gltfSceneAsset = reinterpret_cast<GltfSceneAsset *>(asset);
|
||||
return gltfSceneAsset->getAsset()->getLightEntityCount();
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneAsset_getInstance(TSceneAsset *tSceneAsset, int index) {
|
||||
auto *asset = reinterpret_cast<SceneAsset*>(tSceneAsset);
|
||||
auto *instance = asset->getInstanceAt(index);
|
||||
return reinterpret_cast<TSceneAsset*>(instance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneAsset_createInstance(TSceneAsset *tSceneAsset, TMaterialInstance **tMaterialInstances, int materialInstanceCount)
|
||||
{
|
||||
auto *materialInstances = reinterpret_cast<MaterialInstance **>(tMaterialInstances);
|
||||
auto *sceneAsset = reinterpret_cast<SceneAsset*>(tSceneAsset);
|
||||
auto *instance = sceneAsset->createInstance(materialInstances, materialInstanceCount);
|
||||
return reinterpret_cast<TSceneAsset *>(instance);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
219
thermion_dart/native/src/c_api/TSceneManager.cpp
Normal file
219
thermion_dart/native/src/c_api/TSceneManager.cpp
Normal file
@@ -0,0 +1,219 @@
|
||||
#include <filament/LightManager.h>
|
||||
|
||||
#include "c_api/APIExport.h"
|
||||
#include "ResourceBuffer.hpp"
|
||||
#include "FilamentViewer.hpp"
|
||||
#include "Log.hpp"
|
||||
|
||||
using namespace thermion;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
#include "c_api/TSceneManager.h"
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TScene *SceneManager_getScene(TSceneManager *tSceneManager) {
|
||||
auto sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
return reinterpret_cast<TScene*>(sceneManager->getScene());
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialProvider *SceneManager_getUnlitMaterialProvider(TSceneManager *tSceneManager) {
|
||||
auto sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
auto provider = sceneManager->getUnlitMaterialProvider();
|
||||
return reinterpret_cast<TMaterialProvider*>(provider);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialProvider *SceneManager_getUbershaderMaterialProvider(TSceneManager *tSceneManager) {
|
||||
auto sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
auto provider = sceneManager->getUbershaderMaterialProvider();
|
||||
return reinterpret_cast<TMaterialProvider*>(provider);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TGizmo *SceneManager_createGizmo(TSceneManager *tSceneManager, TView *tView, TScene *tScene)
|
||||
{
|
||||
auto sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
auto *scene = reinterpret_cast<Scene *>(tScene);
|
||||
auto *view = reinterpret_cast<View *>(tView);
|
||||
auto gizmo = sceneManager->createGizmo(view, scene);
|
||||
return reinterpret_cast<TGizmo *>(gizmo);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneManager_loadGlb(TSceneManager *tSceneManager, const char *assetPath, int numInstances, bool keepData)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
auto *asset = sceneManager->loadGlb(assetPath, numInstances, keepData);
|
||||
return reinterpret_cast<TSceneAsset *>(asset);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneManager_loadGltf(TSceneManager *tSceneManager,
|
||||
const char *assetPath,
|
||||
const char *relativeResourcePath,
|
||||
bool keepData)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
auto *asset = sceneManager->loadGltf(assetPath, relativeResourcePath, 1, keepData);
|
||||
return reinterpret_cast<TSceneAsset *>(asset);
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneManager_loadGlbFromBuffer(TSceneManager *tSceneManager, const uint8_t *const data, size_t length, bool keepData, int priority, int layer, bool loadResourcesAsync)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
auto *asset = sceneManager->loadGlbFromBuffer((const uint8_t *)data, length, 1, keepData, priority, layer, loadResourcesAsync);
|
||||
return reinterpret_cast<TSceneAsset *>(asset);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_getCameraByName(TSceneManager *tSceneManager, EntityId entityId, const char *name)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE Aabb3 SceneManager_getRenderableBoundingBox(TSceneManager *tSceneManager, EntityId entity)
|
||||
{
|
||||
auto sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
return sceneManager->getRenderableBoundingBox(entity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_setVisibilityLayer(TSceneManager *tSceneManager, EntityId entity, int layer)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
sceneManager->setVisibilityLayer(entity, layer);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *SceneManager_createUnlitMaterialInstance(TSceneManager *sceneManager)
|
||||
{
|
||||
auto *instance = ((SceneManager *)sceneManager)->createUnlitMaterialInstance();
|
||||
return reinterpret_cast<TMaterialInstance *>(instance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *SceneManager_createUnlitFixedSizeMaterialInstance(TSceneManager *sceneManager)
|
||||
{
|
||||
auto *instance = ((SceneManager *)sceneManager)->createUnlitFixedSizeMaterialInstance();
|
||||
return reinterpret_cast<TMaterialInstance *>(instance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_createCamera(TSceneManager *tSceneManager)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
return reinterpret_cast<TCamera *>(sceneManager->createCamera());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_destroyCamera(TSceneManager *tSceneManager, TCamera *tCamera)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
auto *camera = reinterpret_cast<Camera *>(tCamera);
|
||||
sceneManager->destroyCamera(camera);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE size_t SceneManager_getCameraCount(TSceneManager *tSceneManager)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
return sceneManager->getCameraCount();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_getCameraAt(TSceneManager *tSceneManager, size_t index)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
auto *camera = sceneManager->getCameraAt(index);
|
||||
return reinterpret_cast<TCamera *>(camera);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSceneAsset *SceneManager_createGeometry(
|
||||
TSceneManager *tSceneManager,
|
||||
float *vertices,
|
||||
int numVertices,
|
||||
float *normals,
|
||||
int numNormals,
|
||||
float *uvs,
|
||||
int numUvs,
|
||||
uint16_t *indices,
|
||||
int numIndices,
|
||||
int primitiveType,
|
||||
TMaterialInstance **tMaterialInstances,
|
||||
int materialInstanceCount,
|
||||
bool keepData)
|
||||
{
|
||||
auto sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
auto castedNumVertices = static_cast<uint32_t>(numVertices);
|
||||
auto castedNumNormals = static_cast<uint32_t>(numNormals);
|
||||
auto castedNumUvs = static_cast<uint32_t>(numUvs);
|
||||
auto castedNumIndices = static_cast<uint32_t>(numIndices);
|
||||
auto castedPrimitiveType = static_cast<filament::RenderableManager::PrimitiveType>(primitiveType);
|
||||
auto materialInstances = reinterpret_cast<MaterialInstance **>(tMaterialInstances);
|
||||
|
||||
auto *asset = sceneManager->createGeometry(
|
||||
vertices,
|
||||
castedNumVertices,
|
||||
normals,
|
||||
castedNumNormals,
|
||||
uvs,
|
||||
castedNumUvs,
|
||||
indices,
|
||||
castedNumIndices,
|
||||
castedPrimitiveType,
|
||||
materialInstances,
|
||||
materialInstanceCount,
|
||||
keepData);
|
||||
return reinterpret_cast<TSceneAsset *>(asset);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_destroyMaterialInstance(TSceneManager *sceneManager, TMaterialInstance *instance)
|
||||
{
|
||||
((SceneManager *)sceneManager)->destroy(reinterpret_cast<MaterialInstance *>(instance));
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE int SceneManager_removeFromScene(TSceneManager *sceneManager, EntityId entityId)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->removeFromScene(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE int SceneManager_addToScene(TSceneManager *sceneManager, EntityId entityId)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->addToScene(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_transformToUnitCube(TSceneManager *sceneManager, EntityId entityId)
|
||||
{
|
||||
((SceneManager *)sceneManager)->transformToUnitCube(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TAnimationManager *SceneManager_getAnimationManager(TSceneManager *tSceneManager)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
auto *animationManager = sceneManager->getAnimationManager();
|
||||
return reinterpret_cast<TAnimationManager *>(animationManager);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAll(TSceneManager *tSceneManager)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
sceneManager->destroyAll();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAsset(TSceneManager *tSceneManager, TSceneAsset *tSceneAsset)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
auto *sceneAsset = reinterpret_cast<SceneAsset *>(tSceneAsset);
|
||||
sceneManager->destroy(sceneAsset);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TNameComponentManager *SceneManager_getNameComponentManager(TSceneManager *tSceneManager) {
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
return reinterpret_cast<TNameComponentManager*>(sceneManager->getNameComponentManager());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE size_t SceneManager_getOverlayEntityCount(TSceneManager *tSceneManager) {
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
return sceneManager->getOverlayEntityCount();
|
||||
}
|
||||
EMSCRIPTEN_KEEPALIVE EntityId SceneManager_getOverlayEntityAt(TSceneManager *tSceneManager, size_t index) {
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
auto entity = sceneManager->getOverlayEntity(index);
|
||||
return utils::Entity::smuggle(entity);
|
||||
}
|
||||
}
|
||||
155
thermion_dart/native/src/c_api/TTransformManager.cpp
Normal file
155
thermion_dart/native/src/c_api/TTransformManager.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
#include <utils/Entity.h>
|
||||
#include <filament/TransformManager.h>
|
||||
#include <filament/math/mat4.h>
|
||||
#include <gltfio/math.h>
|
||||
|
||||
#include "c_api/APIExport.h"
|
||||
#include "MathUtils.hpp"
|
||||
#include "Log.hpp"
|
||||
|
||||
using namespace thermion;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
using namespace filament;
|
||||
using namespace utils;
|
||||
using namespace filament::gltfio;
|
||||
|
||||
#include "c_api/TTransformManager.h"
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 TransformManager_getLocalTransform(TTransformManager *tTransformManager, EntityId entityId)
|
||||
{
|
||||
auto *transformManager = reinterpret_cast<filament::TransformManager *>(tTransformManager);
|
||||
const auto &entity = utils::Entity::import(entityId);
|
||||
auto transformInstance = transformManager->getInstance(entity);
|
||||
if (!transformInstance)
|
||||
{
|
||||
Log("Failed to find transform instance");
|
||||
return double4x4();
|
||||
}
|
||||
auto transform = transformManager->getTransformAccurate(transformInstance);
|
||||
return convert_mat4_to_double4x4(transform);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 TransformManager_getWorldTransform(TTransformManager *tTransformManager, EntityId entityId)
|
||||
{
|
||||
auto *transformManager = reinterpret_cast<filament::TransformManager *>(tTransformManager);
|
||||
const auto &entity = utils::Entity::import(entityId);
|
||||
auto transformInstance = transformManager->getInstance(entity);
|
||||
if (!transformInstance)
|
||||
{
|
||||
Log("Failed to find transform instance");
|
||||
return double4x4();
|
||||
}
|
||||
auto transform = transformManager->getWorldTransformAccurate(transformInstance);
|
||||
return convert_mat4_to_double4x4(transform);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void TransformManager_setTransform(TTransformManager *tTransformManager, EntityId entityId, double4x4 transform)
|
||||
{
|
||||
auto *transformManager = reinterpret_cast<filament::TransformManager *>(tTransformManager);
|
||||
const auto &entity = utils::Entity::import(entityId);
|
||||
auto transformInstance = transformManager->getInstance(entity);
|
||||
if (!transformInstance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
transformManager->setTransform(transformInstance, convert_double4x4_to_mat4(transform));
|
||||
}
|
||||
|
||||
// EMSCRIPTEN_KEEPALIVE void TransformManager_transformToUnitCube(TTransformManager *tTransformManager, EntityId entityId) {
|
||||
// auto *transformManager = reinterpret_cast<filament::TransformManager*>(tTransformManager);
|
||||
// const auto &entity = utils::Entity::import(entityId);
|
||||
// auto transformInstance = transformManager->getInstance(entity);
|
||||
// if (!transformInstance)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// auto aabb = instance->getBoundingBox();
|
||||
// auto center = aabb.center();
|
||||
// auto halfExtent = aabb.extent();
|
||||
// auto maxExtent = max(halfExtent) * 2;
|
||||
// auto scaleFactor = 2.0f / maxExtent;
|
||||
// auto transform = math::mat4f::scaling(scaleFactor) * math::mat4f::translation(-center);
|
||||
// tm.setTransform(tm.getInstance(instance->getRoot()), transform);
|
||||
// }
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void TransformManager_setParent(TTransformManager *tTransformManager, EntityId childId, EntityId parentId, bool preserveScaling)
|
||||
{
|
||||
auto tm = reinterpret_cast<TransformManager *>(tTransformManager);
|
||||
const auto child = Entity::import(childId);
|
||||
const auto parent = Entity::import(parentId);
|
||||
|
||||
const auto &parentInstance = tm->getInstance(parent);
|
||||
const auto &childInstance = tm->getInstance(child);
|
||||
|
||||
if (!parentInstance.isValid())
|
||||
{
|
||||
Log("Parent instance is not valid");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!childInstance.isValid())
|
||||
{
|
||||
Log("Child instance is not valid");
|
||||
return;
|
||||
}
|
||||
|
||||
if (preserveScaling)
|
||||
{
|
||||
auto parentTransform = tm->getWorldTransform(parentInstance);
|
||||
math::float3 parentTranslation;
|
||||
math::quatf parentRotation;
|
||||
math::float3 parentScale;
|
||||
|
||||
decomposeMatrix(parentTransform, &parentTranslation, &parentRotation, &parentScale);
|
||||
|
||||
auto childTransform = tm->getTransform(childInstance);
|
||||
math::float3 childTranslation;
|
||||
math::quatf childRotation;
|
||||
math::float3 childScale;
|
||||
|
||||
decomposeMatrix(childTransform, &childTranslation, &childRotation, &childScale);
|
||||
|
||||
childScale = childScale * (1 / parentScale);
|
||||
|
||||
childTransform = composeMatrix(childTranslation, childRotation, childScale);
|
||||
|
||||
tm->setTransform(childInstance, childTransform);
|
||||
}
|
||||
|
||||
tm->setParent(childInstance, parentInstance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId TransformManager_getParent(TTransformManager *tTransformManager, EntityId childId)
|
||||
{
|
||||
auto tm = reinterpret_cast<TransformManager *>(tTransformManager);
|
||||
const auto child = Entity::import(childId);
|
||||
const auto &childInstance = tm->getInstance(child);
|
||||
|
||||
return Entity::smuggle(tm->getParent(childInstance));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId TransformManager_getAncestor(TTransformManager *tTransformManager, EntityId childEntityId)
|
||||
{
|
||||
auto tm = reinterpret_cast<TransformManager *>(tTransformManager);
|
||||
|
||||
const auto child = Entity::import(childEntityId);
|
||||
auto transformInstance = tm->getInstance(child);
|
||||
Entity parent;
|
||||
|
||||
while (true)
|
||||
{
|
||||
auto newParent = tm->getParent(transformInstance);
|
||||
if (newParent.isNull())
|
||||
{
|
||||
break;
|
||||
}
|
||||
parent = newParent;
|
||||
transformInstance = tm->getInstance(parent);
|
||||
}
|
||||
|
||||
return Entity::smuggle(parent);
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,8 @@
|
||||
#include <filament/ColorGrading.h>
|
||||
#include <filament/Camera.h>
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
#include "TView.h"
|
||||
#include "c_api/ThermionDartApi.h"
|
||||
#include "c_api/TView.h"
|
||||
#include "Log.hpp"
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -155,6 +155,25 @@ using namespace filament;
|
||||
return reinterpret_cast<TCamera*>(&(view->getCamera()));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_setStencilBufferEnabled(TView *tView, bool enabled) {
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
view->setStencilBufferEnabled(enabled);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool View_isStencilBufferEnabled(TView *tView) {
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
return view->isStencilBufferEnabled();
|
||||
}
|
||||
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_pick(TView *tView, uint32_t requestId, uint32_t x, uint32_t y, PickCallback callback)
|
||||
{
|
||||
auto *view = reinterpret_cast<View *>(tView);
|
||||
view->pick(x, y, [=](filament::View::PickingQueryResult const &result) {
|
||||
callback(requestId, utils::Entity::smuggle(result.renderable), result.depth, result.fragCoords.x, result.fragCoords.y, result.fragCoords.z);
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
511
thermion_dart/native/src/c_api/ThermionDartApi.cpp
Normal file
511
thermion_dart/native/src/c_api/ThermionDartApi.cpp
Normal file
@@ -0,0 +1,511 @@
|
||||
#ifdef _WIN32
|
||||
#include "ThermionWin32.h"
|
||||
#endif
|
||||
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten/emscripten.h>
|
||||
#endif
|
||||
|
||||
#include "filament/LightManager.h"
|
||||
#include "ResourceBuffer.hpp"
|
||||
#include "FilamentViewer.hpp"
|
||||
#include "Log.hpp"
|
||||
#include "ThreadPool.hpp"
|
||||
|
||||
using namespace thermion;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
#include "c_api/ThermionDartApi.h"
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TViewer *Viewer_create(const void *context, const void *const loader, void *const platform, const char *uberArchivePath)
|
||||
{
|
||||
const auto *loaderImpl = new ResourceLoaderWrapperImpl((ResourceLoaderWrapper *)loader);
|
||||
auto viewer = new FilamentViewer(context, loaderImpl, platform, uberArchivePath);
|
||||
return reinterpret_cast<TViewer *>(viewer);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TEngine *Viewer_getEngine(TViewer *viewer)
|
||||
{
|
||||
auto *engine = reinterpret_cast<FilamentViewer *>(viewer)->getEngine();
|
||||
return reinterpret_cast<TEngine *>(engine);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TRenderTarget *Viewer_createRenderTarget(TViewer *tViewer, intptr_t texture, uint32_t width, uint32_t height)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto renderTarget = viewer->createRenderTarget(texture, width, height);
|
||||
return reinterpret_cast<TRenderTarget *>(renderTarget);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroyRenderTarget(TViewer *tViewer, TRenderTarget *tRenderTarget)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto renderTarget = reinterpret_cast<RenderTarget *>(tRenderTarget);
|
||||
viewer->destroyRenderTarget(renderTarget);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroy(TViewer *viewer)
|
||||
{
|
||||
delete ((FilamentViewer *)viewer);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_color(TViewer *viewer, const float r, const float g, const float b, const float a)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setBackgroundColor(r, g, b, a);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void clear_background_image(TViewer *viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->clearBackgroundImage();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image(TViewer *viewer, const char *path, bool fillHeight)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setBackgroundImage(path, fillHeight, 100, 100);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position(TViewer *viewer, float x, float y, bool clamp)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setBackgroundImagePosition(x, y, clamp, 100, 100);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void load_skybox(TViewer *viewer, const char *skyboxPath)
|
||||
{
|
||||
((FilamentViewer *)viewer)->loadSkybox(skyboxPath);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void create_ibl(TViewer *viewer, float r, float g, float b, float intensity)
|
||||
{
|
||||
((FilamentViewer *)viewer)->createIbl(r, g, b, intensity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_loadIbl(TViewer *viewer, const char *iblPath, float intensity)
|
||||
{
|
||||
((FilamentViewer *)viewer)->loadIbl(iblPath, intensity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void rotate_ibl(TViewer *viewer, float *rotationMatrix)
|
||||
{
|
||||
math::mat3f matrix(rotationMatrix[0], rotationMatrix[1],
|
||||
rotationMatrix[2],
|
||||
rotationMatrix[3],
|
||||
rotationMatrix[4],
|
||||
rotationMatrix[5],
|
||||
rotationMatrix[6],
|
||||
rotationMatrix[7],
|
||||
rotationMatrix[8]);
|
||||
|
||||
((FilamentViewer *)viewer)->rotateIbl(matrix);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void remove_skybox(TViewer *viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->removeSkybox();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void remove_ibl(TViewer *viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->removeIbl();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId add_light(
|
||||
TViewer *viewer,
|
||||
uint8_t type,
|
||||
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)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->addLight((LightManager::Type)type, colour, intensity, posX, posY, posZ, dirX, dirY, dirZ, falloffRadius, spotLightConeInner, spotLightConeOuter, sunAngularRadius, sunHaloSize, sunHaloFallof, shadows);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_light_position(TViewer *viewer, int32_t entityId, float x, float y, float z)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setLightPosition(entityId, x, y, z);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_light_direction(TViewer *viewer, int32_t entityId, float x, float y, float z)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setLightDirection(entityId, x, y, z);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void remove_light(TViewer *viewer, int32_t entityId)
|
||||
{
|
||||
((FilamentViewer *)viewer)->removeLight(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void clear_lights(TViewer *viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->clearLights();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE int get_instance_count(TSceneManager *sceneManager, EntityId entityId)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getInstanceCount(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void get_instances(TSceneManager *sceneManager, EntityId entityId, EntityId *out)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getInstances(entityId, out);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_setMainCamera(TViewer *tViewer, TView *tView)
|
||||
{
|
||||
auto *viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto *view = reinterpret_cast<View *>(tView);
|
||||
viewer->setMainCamera(view);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId get_main_camera(TViewer *viewer)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->getMainCamera();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE float get_camera_fov(TCamera *camera, bool horizontal)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
return cam->getFieldOfViewInDegrees(horizontal ? Camera::Fov::HORIZONTAL : Camera::Fov::VERTICAL);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_focal_length(TCamera *const camera)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
return cam->getFocalLength();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_projection_from_fov(TCamera *camera, double fovInDegrees, double aspect, double near, double far, bool horizontal)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
cam->setProjection(fovInDegrees, aspect, near, far, horizontal ? Camera::Fov::HORIZONTAL : Camera::Fov::VERTICAL);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *get_camera(TViewer *viewer, EntityId entity)
|
||||
{
|
||||
auto filamentCamera = ((FilamentViewer *)viewer)->getCamera(entity);
|
||||
return reinterpret_cast<TCamera *>(filamentCamera);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_model_matrix(TCamera *camera)
|
||||
{
|
||||
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getModelMatrix();
|
||||
return convert_mat4_to_double4x4(mat);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_view_matrix(TCamera *camera)
|
||||
{
|
||||
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getViewMatrix();
|
||||
return convert_mat4_to_double4x4(mat);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_projection_matrix(TCamera *camera)
|
||||
{
|
||||
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getProjectionMatrix();
|
||||
return convert_mat4_to_double4x4(mat);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_culling_projection_matrix(TCamera *camera)
|
||||
{
|
||||
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getCullingProjectionMatrix();
|
||||
return convert_mat4_to_double4x4(mat);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_projection_matrix(TCamera *camera, double4x4 matrix, double near, double far)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
const auto &mat = convert_double4x4_to_mat4(matrix);
|
||||
cam->setCustomProjection(mat, near, far);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setLensProjection(TCamera *camera, double near, double far, double aspect, double focalLength)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
cam->setLensProjection(focalLength, aspect, near, far);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setModelMatrix(TCamera *camera, double4x4 matrix)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
cam->setModelMatrix(convert_double4x4_to_mat4(matrix));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_near(TCamera *camera)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
return cam->getNear();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_culling_far(TCamera *camera)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
return cam->getCullingFar();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_frustum(TCamera *camera)
|
||||
{
|
||||
|
||||
const auto frustum = reinterpret_cast<filament::Camera *>(camera)->getFrustum();
|
||||
|
||||
const math::float4 *planes = frustum.getNormalizedPlanes();
|
||||
double *array = (double *)calloc(24, sizeof(double));
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
auto plane = planes[i];
|
||||
array[i * 4] = double(plane.x);
|
||||
array[i * 4 + 1] = double(plane.y);
|
||||
array[i * 4 + 2] = double(plane.z);
|
||||
array[i * 4 + 3] = double(plane.w);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_focus_distance(TCamera *camera, float distance)
|
||||
{
|
||||
auto *cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
cam->setFocusDistance(distance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_exposure(TCamera *camera, float aperture, float shutterSpeed, float sensitivity)
|
||||
{
|
||||
auto *cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
cam->setExposure(aperture, shutterSpeed, sensitivity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_model_matrix(TCamera *camera, double4x4 matrix)
|
||||
{
|
||||
auto *cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
const filament::math::mat4 &mat = convert_double4x4_to_mat4(matrix);
|
||||
cam->setModelMatrix(mat);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_render(
|
||||
TViewer *tViewer)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
viewer->render(0);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_setViewRenderable(TViewer *tViewer, TSwapChain *tSwapChain, TView *tView, bool renderable)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
|
||||
auto *view = reinterpret_cast<View *>(tView);
|
||||
viewer->setRenderable(view, swapChain, renderable);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_capture(
|
||||
TViewer *tViewer,
|
||||
TView *tView,
|
||||
TSwapChain *tSwapChain,
|
||||
uint8_t *pixelBuffer,
|
||||
void (*callback)(void))
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
bool useFence = true;
|
||||
#else
|
||||
bool useFence = false;
|
||||
#endif
|
||||
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto *view = reinterpret_cast<View *>(tView);
|
||||
viewer->capture(view, pixelBuffer, useFence, swapChain, callback);
|
||||
};
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTarget(
|
||||
TViewer *tViewer,
|
||||
TView *tView,
|
||||
TSwapChain *tSwapChain,
|
||||
TRenderTarget *tRenderTarget,
|
||||
uint8_t *pixelBuffer,
|
||||
void (*callback)(void))
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
bool useFence = true;
|
||||
#else
|
||||
bool useFence = false;
|
||||
#endif
|
||||
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
|
||||
auto renderTarget = reinterpret_cast<RenderTarget *>(tRenderTarget);
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto *view = reinterpret_cast<View *>(tView);
|
||||
viewer->capture(view, pixelBuffer, useFence, swapChain, renderTarget, callback);
|
||||
};
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_frame_interval(
|
||||
TViewer *viewer,
|
||||
float frameInterval)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setFrameInterval(frameInterval);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChain(TViewer *tViewer, TSwapChain *tSwapChain)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
|
||||
viewer->destroySwapChain(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createHeadlessSwapChain(TViewer *tViewer, uint32_t width, uint32_t height)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = viewer->createSwapChain(width, height);
|
||||
return reinterpret_cast<TSwapChain *>(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createSwapChain(TViewer *tViewer, const void *const window)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = viewer->createSwapChain(window);
|
||||
return reinterpret_cast<TSwapChain *>(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_getSwapChainAt(TViewer *tViewer, int index)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = viewer->getSwapChainAt(index);
|
||||
return reinterpret_cast<TSwapChain *>(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TView *Viewer_createView(TViewer *tViewer)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto view = viewer->createView();
|
||||
return reinterpret_cast<TView *>(view);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TView *Viewer_getViewAt(TViewer *tViewer, int32_t index)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto view = viewer->getViewAt(index);
|
||||
return reinterpret_cast<TView *>(view);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSceneManager *Viewer_getSceneManager(TViewer *tViewer)
|
||||
{
|
||||
auto *viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto *sceneManager = viewer->getSceneManager();
|
||||
return reinterpret_cast<TSceneManager *>(sceneManager);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void queue_position_update_from_viewport_coords(TSceneManager *sceneManager, TView *tView, EntityId entity, float viewportX, float viewportY)
|
||||
{
|
||||
auto *view = reinterpret_cast<View *>(tView);
|
||||
((SceneManager *)sceneManager)->queueRelativePositionUpdateFromViewportVector(view, entity, viewportX, viewportY);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void ios_dummy()
|
||||
{
|
||||
Log("Dummy called");
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void thermion_filament_free(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void add_collision_component(TSceneManager *sceneManager, EntityId entityId, void (*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform)
|
||||
{
|
||||
((SceneManager *)sceneManager)->addCollisionComponent(entityId, onCollisionCallback, affectsCollidingTransform);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void remove_collision_component(TSceneManager *sceneManager, EntityId entityId)
|
||||
{
|
||||
((SceneManager *)sceneManager)->removeCollisionComponent(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void test_collisions(TSceneManager *sceneManager, EntityId entity)
|
||||
{
|
||||
((SceneManager *)sceneManager)->testCollisions(entity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE Aabb2 get_bounding_box(TSceneManager *sceneManager, TView *tView, EntityId entity)
|
||||
{
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
return ((SceneManager *)sceneManager)->getScreenSpaceBoundingBox(view, entity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void get_bounding_box_to_out(TSceneManager *sceneManager, TView *tView, EntityId entity, float *minX, float *minY, float *maxX, float *maxY)
|
||||
{
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
auto box = ((SceneManager *)sceneManager)->getScreenSpaceBoundingBox(view, entity);
|
||||
*minX = box.minX;
|
||||
*minY = box.minY;
|
||||
*maxX = box.maxX;
|
||||
*maxY = box.maxY;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void thermion_flutter_free(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void unproject_texture(TViewer *viewer, EntityId entity, uint8_t *input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight)
|
||||
{
|
||||
((FilamentViewer *)viewer)->unprojectTexture(entity, input, inputWidth, inputHeight, out, outWidth, outHeight);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void *const create_texture(TSceneManager *sceneManager, uint8_t *data, size_t length)
|
||||
{
|
||||
return (void *const)((SceneManager *)sceneManager)->createTexture(data, length, "SOMETEXTURE");
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void apply_texture_to_material(TSceneManager *sceneManager, EntityId entity, void *const texture, const char *parameterName, int materialIndex)
|
||||
{
|
||||
((SceneManager *)sceneManager)->applyTexture(entity, reinterpret_cast<Texture *>(texture), parameterName, materialIndex);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_texture(TSceneManager *sceneManager, void *const texture)
|
||||
{
|
||||
((SceneManager *)sceneManager)->destroyTexture(reinterpret_cast<Texture *>(texture));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TTransformManager *Engine_getTransformManager(TEngine *tEngine)
|
||||
{
|
||||
auto *engine = reinterpret_cast<Engine *>(tEngine);
|
||||
auto &transformManager = engine->getTransformManager();
|
||||
return reinterpret_cast<TTransformManager *>(&transformManager);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TRenderableManager *Engine_getRenderableManager(TEngine *tEngine)
|
||||
{
|
||||
auto *engine = reinterpret_cast<Engine *>(tEngine);
|
||||
auto &renderableManager = engine->getRenderableManager();
|
||||
return reinterpret_cast<TRenderableManager *>(&renderableManager);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine *tEngine, EntityId entityId)
|
||||
{
|
||||
auto *engine = reinterpret_cast<Engine *>(tEngine);
|
||||
auto *camera = engine->getCameraComponent(utils::Entity::import(entityId));
|
||||
return reinterpret_cast<TCamera *>(camera);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_setTransform(TEngine *tEngine, EntityId entity, double4x4 transform)
|
||||
{
|
||||
auto *engine = reinterpret_cast<Engine *>(tEngine);
|
||||
auto &transformManager = engine->getTransformManager();
|
||||
|
||||
auto transformInstance = transformManager.getInstance(utils::Entity::import(entity));
|
||||
if (!transformInstance.isValid())
|
||||
{
|
||||
Log("Transform instance not valid");
|
||||
}
|
||||
transformManager.setTransform(transformInstance, convert_double4x4_to_mat4(transform));
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,20 @@
|
||||
#include <thread>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ThermionDartRenderThreadApi.h"
|
||||
#include "FilamentViewer.hpp"
|
||||
#include "TView.h"
|
||||
#include "Log.hpp"
|
||||
#include "ThreadPool.hpp"
|
||||
#include "TSceneManager.h"
|
||||
#include <filament/LightManager.h>
|
||||
|
||||
#include "c_api/APIBoundaryTypes.h"
|
||||
#include "c_api/TView.h"
|
||||
#include "c_api/TSceneAsset.h"
|
||||
#include "c_api/TSceneManager.h"
|
||||
#include "c_api/TAnimationManager.h"
|
||||
#include "c_api/ThermionDartRenderThreadApi.h"
|
||||
|
||||
#include "FilamentViewer.hpp"
|
||||
#include "Log.hpp"
|
||||
|
||||
#include "ThreadPool.hpp"
|
||||
|
||||
#include "filament/LightManager.h"
|
||||
|
||||
using namespace thermion;
|
||||
using namespace std::chrono_literals;
|
||||
@@ -99,8 +105,7 @@ public:
|
||||
}
|
||||
|
||||
_cv.wait_for(taskLock, std::chrono::microseconds(2000), [this]
|
||||
{ return !_tasks.empty() || _stop; });
|
||||
|
||||
{ return !_tasks.empty() || _stop; });
|
||||
}
|
||||
|
||||
void createViewer(void *const context,
|
||||
@@ -109,7 +114,7 @@ public:
|
||||
const ResourceLoaderWrapper *const loader,
|
||||
void (*renderCallback)(void *),
|
||||
void *const owner,
|
||||
void (*callback)(TViewer*))
|
||||
void (*callback)(TViewer *))
|
||||
{
|
||||
_renderCallback = renderCallback;
|
||||
_renderCallbackOwner = owner;
|
||||
@@ -117,8 +122,7 @@ public:
|
||||
{
|
||||
auto viewer = (FilamentViewer *)Viewer_create(context, loader, platform, uberArchivePath);
|
||||
_viewer = reinterpret_cast<TViewer*>(viewer);
|
||||
callback(_viewer);
|
||||
});
|
||||
callback(_viewer); });
|
||||
auto fut = add_task(lambda);
|
||||
}
|
||||
|
||||
@@ -159,7 +163,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
void(*_requestFrameRenderCallback)() = nullptr;
|
||||
void (*_requestFrameRenderCallback)() = nullptr;
|
||||
bool _stop = false;
|
||||
int _frameIntervalInMicroseconds = 1000000 / 60;
|
||||
std::mutex _mutex;
|
||||
@@ -205,9 +209,9 @@ extern "C"
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createHeadlessSwapChainRenderThread(TViewer *viewer,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
void (*onComplete)(TSwapChain*))
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
void (*onComplete)(TSwapChain *))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
@@ -219,8 +223,8 @@ extern "C"
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createSwapChainRenderThread(TViewer *viewer,
|
||||
void *const surface,
|
||||
void (*onComplete)(TSwapChain*))
|
||||
void *const surface,
|
||||
void (*onComplete)(TSwapChain *))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
@@ -242,8 +246,7 @@ extern "C"
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_requestFrameRenderThread(TViewer *viewer, void(*onComplete)())
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_requestFrameRenderThread(TViewer *viewer, void (*onComplete)())
|
||||
{
|
||||
if (!_rl)
|
||||
{
|
||||
@@ -255,24 +258,26 @@ extern "C"
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_loadIblRenderThread(TViewer *viewer, const char *iblPath, float intensity, void(*onComplete)()) {
|
||||
std::packaged_task<void()> lambda(
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_loadIblRenderThread(TViewer *viewer, const char *iblPath, float intensity, void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
Viewer_loadIbl(viewer, iblPath, intensity);
|
||||
onComplete();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createRenderTargetRenderThread(TViewer *viewer, intptr_t texture, uint32_t width, uint32_t height, void(*onComplete)(TRenderTarget*)) {
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createRenderTargetRenderThread(TViewer *viewer, intptr_t texture, uint32_t width, uint32_t height, void (*onComplete)(TRenderTarget *))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
auto renderTarget = Viewer_createRenderTarget(viewer, texture, width, height);
|
||||
onComplete(renderTarget);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void
|
||||
@@ -287,9 +292,7 @@ extern "C"
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_renderRenderThread(TViewer *viewer, TView *tView, TSwapChain *tSwapChain)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{
|
||||
_rl->doRender();
|
||||
});
|
||||
{ _rl->doRender(); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
@@ -300,7 +303,7 @@ extern "C"
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTargetRenderThread(TViewer *viewer, TView *view, TSwapChain *tSwapChain, TRenderTarget* tRenderTarget, uint8_t *pixelBuffer, void (*onComplete)())
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTargetRenderThread(TViewer *viewer, TView *view, TSwapChain *tSwapChain, TRenderTarget *tRenderTarget, uint8_t *pixelBuffer, void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{ Viewer_captureRenderTarget(viewer, view, tSwapChain, tRenderTarget, pixelBuffer, onComplete); });
|
||||
@@ -317,32 +320,30 @@ extern "C"
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void load_gltf_render_thread(TSceneManager *sceneManager,
|
||||
const char *path,
|
||||
const char *relativeResourcePath,
|
||||
bool keepData,
|
||||
void (*callback)(EntityId))
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_loadGltfRenderThread(TSceneManager *sceneManager,
|
||||
const char *path,
|
||||
const char *relativeResourcePath,
|
||||
bool keepData,
|
||||
void (*callback)(TSceneAsset *))
|
||||
{
|
||||
std::packaged_task<EntityId()> lambda([=]() mutable
|
||||
{
|
||||
auto entity = load_gltf(sceneManager, path, relativeResourcePath, keepData);
|
||||
callback(entity);
|
||||
return entity; });
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{
|
||||
auto entity = SceneManager_loadGltf(sceneManager, path, relativeResourcePath, keepData);
|
||||
callback(entity); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void load_glb_render_thread(TSceneManager *sceneManager,
|
||||
const char *path,
|
||||
int numInstances,
|
||||
bool keepData,
|
||||
void (*callback)(EntityId))
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_loadGlbRenderThread(TSceneManager *sceneManager,
|
||||
const char *path,
|
||||
int numInstances,
|
||||
bool keepData,
|
||||
void (*callback)(TSceneAsset *))
|
||||
{
|
||||
std::packaged_task<EntityId()> lambda(
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
auto entity = load_glb(sceneManager, path, numInstances, keepData);
|
||||
callback(entity);
|
||||
return entity;
|
||||
auto asset = SceneManager_loadGlb(sceneManager, path, numInstances, keepData);
|
||||
callback(asset);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
@@ -358,22 +359,47 @@ extern "C"
|
||||
uint16_t *indices,
|
||||
int numIndices,
|
||||
int primitiveType,
|
||||
TMaterialInstance *materialInstance,
|
||||
TMaterialInstance **materialInstances,
|
||||
int materialInstanceCount,
|
||||
bool keepData,
|
||||
void (*callback)(EntityId))
|
||||
void (*callback)(TSceneAsset *))
|
||||
{
|
||||
std::packaged_task<EntityId()> lambda(
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{
|
||||
auto entity = SceneManager_createGeometry(sceneManager, vertices, numVertices, normals, numNormals, uvs, numUvs, indices, numIndices, primitiveType, materialInstance, keepData);
|
||||
callback(entity);
|
||||
return entity;
|
||||
auto *asset = SceneManager_createGeometry(sceneManager, vertices, numVertices, normals, numNormals, uvs, numUvs, indices, numIndices, primitiveType, materialInstances, materialInstanceCount, keepData);
|
||||
callback(asset);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneAsset_createInstanceRenderThread(
|
||||
TSceneAsset *asset, TMaterialInstance **tMaterialInstances,
|
||||
int materialInstanceCount,
|
||||
void (*callback)(TSceneAsset *))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{
|
||||
auto instanceAsset = SceneAsset_createInstance(asset, tMaterialInstances, materialInstanceCount);
|
||||
callback(instanceAsset);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_createUnlitMaterialInstanceRenderThread(TSceneManager *sceneManager, void (*callback)(TMaterialInstance*)) {
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialProvider_createMaterialInstanceRenderThread(TMaterialProvider *tMaterialProvider, TMaterialKey *tKey, void (*callback)(TMaterialInstance *))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{
|
||||
auto materialInstance = MaterialProvider_createMaterialInstance(tMaterialProvider, tKey);
|
||||
callback(materialInstance);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_createUnlitMaterialInstanceRenderThread(TSceneManager *sceneManager, void (*callback)(TMaterialInstance *))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
@@ -383,7 +409,8 @@ extern "C"
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_createUnlitFixedSizeMaterialInstanceRenderThread(TSceneManager *sceneManager, void (*callback)(TMaterialInstance*)) {
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_createUnlitFixedSizeMaterialInstanceRenderThread(TSceneManager *sceneManager, void (*callback)(TMaterialInstance *))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
@@ -394,21 +421,20 @@ extern "C"
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_loadGlbFromBufferRenderThread(TSceneManager *sceneManager,
|
||||
const uint8_t *const data,
|
||||
size_t length,
|
||||
int numInstances,
|
||||
bool keepData,
|
||||
int priority,
|
||||
int layer,
|
||||
bool loadResourcesAsync,
|
||||
void (*callback)(EntityId))
|
||||
const uint8_t *const data,
|
||||
size_t length,
|
||||
int numInstances,
|
||||
bool keepData,
|
||||
int priority,
|
||||
int layer,
|
||||
bool loadResourcesAsync,
|
||||
void (*callback)(TSceneAsset *))
|
||||
{
|
||||
std::packaged_task<EntityId()> lambda(
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
auto entity = SceneManager_loadGlbFromBuffer(sceneManager, data, length, keepData, priority, layer, loadResourcesAsync);
|
||||
callback(entity);
|
||||
return entity;
|
||||
auto *asset = SceneManager_loadGlbFromBuffer(sceneManager, data, length, keepData, priority, layer, loadResourcesAsync);
|
||||
callback(asset);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
@@ -432,7 +458,7 @@ extern "C"
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position_render_thread(TViewer *viewer,
|
||||
float x, float y,
|
||||
bool clamp)
|
||||
@@ -442,7 +468,7 @@ extern "C"
|
||||
{ set_background_image_position(viewer, x, y, clamp); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void load_skybox_render_thread(TViewer *viewer,
|
||||
const char *skyboxPath,
|
||||
void (*onComplete)())
|
||||
@@ -450,11 +476,10 @@ extern "C"
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{
|
||||
load_skybox(viewer, skyboxPath);
|
||||
onComplete();
|
||||
});
|
||||
onComplete(); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void remove_skybox_render_thread(TViewer *viewer)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
@@ -469,159 +494,8 @@ extern "C"
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void remove_entity_render_thread(TViewer *viewer,
|
||||
EntityId asset, void (*callback)())
|
||||
EMSCRIPTEN_KEEPALIVE void View_setToneMappingRenderThread(TView *tView, TEngine *tEngine, thermion::ToneMapping toneMapping)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{
|
||||
remove_entity(viewer, asset);
|
||||
callback();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void clear_entities_render_thread(TViewer *viewer, void (*callback)())
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{
|
||||
clear_entities(viewer);
|
||||
callback();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void
|
||||
get_morph_target_name_render_thread(TSceneManager *sceneManager, EntityId assetEntity,
|
||||
EntityId childEntity, char *const outPtr, int index, void (*callback)())
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{
|
||||
get_morph_target_name(sceneManager, assetEntity, childEntity, outPtr, index);
|
||||
callback();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void
|
||||
get_morph_target_name_count_render_thread(TSceneManager *sceneManager, EntityId assetEntity,
|
||||
EntityId childEntity, void (*callback)(int))
|
||||
{
|
||||
std::packaged_task<int()> lambda([=]
|
||||
{
|
||||
auto count = get_morph_target_name_count(sceneManager, assetEntity, childEntity);
|
||||
callback(count);
|
||||
return count; });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_animation_frame_render_thread(TSceneManager *sceneManager,
|
||||
EntityId asset,
|
||||
int animationIndex,
|
||||
int animationFrame)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{ set_animation_frame(sceneManager, asset, animationIndex, animationFrame); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void stop_animation_render_thread(TSceneManager *sceneManager,
|
||||
EntityId asset, int index)
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{ stop_animation(sceneManager, asset, index); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void get_animation_count_render_thread(TSceneManager *sceneManager,
|
||||
EntityId asset,
|
||||
void (*callback)(int))
|
||||
{
|
||||
std::packaged_task<int()> lambda(
|
||||
[=]
|
||||
{
|
||||
auto count = get_animation_count(sceneManager, asset);
|
||||
callback(count);
|
||||
return count;
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void get_animation_name_render_thread(TSceneManager *sceneManager,
|
||||
EntityId asset,
|
||||
char *const outPtr,
|
||||
int index,
|
||||
void (*callback)())
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{
|
||||
get_animation_name(sceneManager, asset, outPtr, index);
|
||||
callback();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void
|
||||
get_name_for_entity_render_thread(TSceneManager *sceneManager, const EntityId entityId, void (*callback)(const char *))
|
||||
{
|
||||
std::packaged_task<const char *()> lambda(
|
||||
[=]
|
||||
{
|
||||
auto name = get_name_for_entity(sceneManager, entityId);
|
||||
callback(name);
|
||||
return name;
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_morph_target_weights_render_thread(TSceneManager *sceneManager,
|
||||
EntityId asset,
|
||||
const float *const morphData,
|
||||
int numWeights,
|
||||
void (*callback)(bool))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{
|
||||
auto result = set_morph_target_weights(sceneManager, asset, morphData, numWeights);
|
||||
callback(result);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_bone_transform_render_thread(
|
||||
TSceneManager *sceneManager,
|
||||
EntityId asset,
|
||||
int skinIndex,
|
||||
int boneIndex,
|
||||
const float *const transform,
|
||||
void (*callback)(bool))
|
||||
{
|
||||
std::packaged_task<bool()> lambda(
|
||||
[=]
|
||||
{
|
||||
auto success = set_bone_transform(sceneManager, asset, skinIndex, boneIndex, transform);
|
||||
callback(success);
|
||||
return success;
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void update_bone_matrices_render_thread(TSceneManager *sceneManager,
|
||||
EntityId entity, void (*callback)(bool))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{
|
||||
auto success = update_bone_matrices(sceneManager, entity);
|
||||
callback(success);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_setToneMappingRenderThread(TView *tView, TEngine *tEngine, thermion::ToneMapping toneMapping) {
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{
|
||||
@@ -629,8 +503,9 @@ extern "C"
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_setBloomRenderThread(TView *tView, double bloom) {
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_setBloomRenderThread(TView *tView, double bloom)
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{
|
||||
@@ -639,20 +514,31 @@ extern "C"
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose_render_thread(TSceneManager *sceneManager, EntityId entityId, void (*callback)())
|
||||
EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAllRenderThread(TSceneManager *tSceneManager, void (*callback)())
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
[=]() mutable
|
||||
{
|
||||
reset_to_rest_pose(sceneManager, entityId);
|
||||
SceneManager_destroyAll(tSceneManager);
|
||||
callback();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void *SceneManager_destroyAssetRenderThread(TSceneManager *tSceneManager, TSceneAsset *tSceneAsset, void (*callback)())
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
SceneManager_destroyAsset(tSceneManager, tSceneAsset);
|
||||
callback();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void unproject_texture_render_thread(TViewer* viewer, EntityId entity, uint8_t *input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight, void (*callback)())
|
||||
EMSCRIPTEN_KEEPALIVE void unproject_texture_render_thread(TViewer *viewer, EntityId entity, uint8_t *input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight, void (*callback)())
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
@@ -662,4 +548,34 @@ extern "C"
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void AnimationManager_updateBoneMatricesRenderThread(
|
||||
TAnimationManager *tAnimationManager,
|
||||
TSceneAsset *sceneAsset,
|
||||
void (*callback)(bool))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
bool result = AnimationManager_updateBoneMatrices(tAnimationManager, sceneAsset);
|
||||
callback(result);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void AnimationManager_setMorphTargetWeightsRenderThread(
|
||||
TAnimationManager *tAnimationManager,
|
||||
EntityId entityId,
|
||||
const float *const morphData,
|
||||
int numWeights,
|
||||
void (*callback)(bool))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
bool result = AnimationManager_setMorphTargetWeights(tAnimationManager, entityId, morphData, numWeights);
|
||||
callback(result);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
}
|
||||
521
thermion_dart/native/src/scene/AnimationManager.cpp
Normal file
521
thermion_dart/native/src/scene/AnimationManager.cpp
Normal file
@@ -0,0 +1,521 @@
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/TransformManager.h>
|
||||
#include <filament/RenderableManager.h>
|
||||
|
||||
#include <gltfio/Animator.h>
|
||||
|
||||
#include "Log.hpp"
|
||||
|
||||
#include "scene/AnimationManager.hpp"
|
||||
#include "scene/SceneAsset.hpp"
|
||||
#include "scene/GltfSceneAssetInstance.hpp"
|
||||
|
||||
namespace thermion
|
||||
{
|
||||
|
||||
using namespace filament;
|
||||
using namespace utils;
|
||||
|
||||
AnimationManager::AnimationManager(Engine *engine, Scene *scene) : _engine(engine), _scene(scene)
|
||||
{
|
||||
auto &transformManager = _engine->getTransformManager();
|
||||
auto &renderableManager = _engine->getRenderableManager();
|
||||
_animationComponentManager = std::make_unique<AnimationComponentManager>(transformManager, renderableManager);
|
||||
}
|
||||
|
||||
AnimationManager::~AnimationManager()
|
||||
{
|
||||
_animationComponentManager = std::nullptr_t();
|
||||
}
|
||||
|
||||
bool AnimationManager::setMorphAnimationBuffer(
|
||||
utils::Entity entity,
|
||||
const float *const morphData,
|
||||
const uint32_t *const morphIndices,
|
||||
int numMorphTargets,
|
||||
int numFrames,
|
||||
float frameLengthInMs)
|
||||
{
|
||||
std::lock_guard lock(_mutex);
|
||||
|
||||
if (!_animationComponentManager->hasComponent(entity))
|
||||
{
|
||||
_animationComponentManager->addAnimationComponent(entity);
|
||||
}
|
||||
|
||||
MorphAnimation morphAnimation;
|
||||
|
||||
morphAnimation.meshTarget = entity;
|
||||
morphAnimation.frameData.clear();
|
||||
morphAnimation.frameData.insert(
|
||||
morphAnimation.frameData.begin(),
|
||||
morphData,
|
||||
morphData + (numFrames * numMorphTargets));
|
||||
morphAnimation.frameLengthInMs = frameLengthInMs;
|
||||
morphAnimation.morphIndices.resize(numMorphTargets);
|
||||
for (int i = 0; i < numMorphTargets; i++)
|
||||
{
|
||||
morphAnimation.morphIndices[i] = morphIndices[i];
|
||||
}
|
||||
morphAnimation.durationInSecs = (frameLengthInMs * numFrames) / 1000.0f;
|
||||
|
||||
morphAnimation.start = high_resolution_clock::now();
|
||||
morphAnimation.lengthInFrames = static_cast<int>(
|
||||
morphAnimation.durationInSecs * 1000.0f /
|
||||
frameLengthInMs);
|
||||
|
||||
auto animationComponentInstance = _animationComponentManager->getInstance(entity);
|
||||
auto &animationComponent = _animationComponentManager->elementAt<0>(animationComponentInstance);
|
||||
auto &morphAnimations = animationComponent.morphAnimations;
|
||||
|
||||
morphAnimations.emplace_back(morphAnimation);
|
||||
return true;
|
||||
}
|
||||
|
||||
void AnimationManager::clearMorphAnimationBuffer(
|
||||
utils::Entity entity)
|
||||
{
|
||||
std::lock_guard lock(_mutex);
|
||||
|
||||
auto animationComponentInstance = _animationComponentManager->getInstance(entity);
|
||||
auto &animationComponent = _animationComponentManager->elementAt<0>(animationComponentInstance);
|
||||
auto &morphAnimations = animationComponent.morphAnimations;
|
||||
morphAnimations.clear();
|
||||
}
|
||||
|
||||
void AnimationManager::resetToRestPose(GltfSceneAssetInstance *instance)
|
||||
{
|
||||
std::lock_guard lock(_mutex);
|
||||
|
||||
auto filamentInstance = instance->getInstance();
|
||||
auto skinCount = filamentInstance->getSkinCount();
|
||||
|
||||
TransformManager &transformManager = _engine->getTransformManager();
|
||||
|
||||
//
|
||||
// To reset the skeleton to its rest pose, we could just call animator->resetBoneMatrices(),
|
||||
// which sets all bone matrices to the identity matrix. However, any subsequent calls to animator->updateBoneMatrices()
|
||||
// may result in unexpected poses, because that method uses each bone's transform to calculate
|
||||
// the bone matrices (and resetBoneMatrices does not affect this transform).
|
||||
// To "fully" reset the bone, we need to set its local transform (i.e. relative to its parent)
|
||||
// to its original orientation in rest pose.
|
||||
//
|
||||
// This can be calculated as:
|
||||
//
|
||||
// auto rest = inverse(parentTransformInModelSpace) * bindMatrix
|
||||
//
|
||||
// (where bindMatrix is the inverse of the inverseBindMatrix).
|
||||
//
|
||||
// The only requirement is that parent bone transforms are reset before child bone transforms.
|
||||
// glTF/Filament does not guarantee that parent bones are listed before child bones under a FilamentInstance.
|
||||
// We ensure that parents are reset before children by:
|
||||
// - pushing all bones onto a stack
|
||||
// - iterate over the stack
|
||||
// - look at the bone at the top of the stack
|
||||
// - if the bone already been reset, pop and continue iterating over the stack
|
||||
// - otherwise
|
||||
// - if the bone has a parent that has not been reset, push the parent to the top of the stack and continue iterating
|
||||
// - otherwise
|
||||
// - pop the bone, reset its transform and mark it as completed
|
||||
for (int skinIndex = 0; skinIndex < skinCount; skinIndex++)
|
||||
{
|
||||
std::unordered_set<Entity, Entity::Hasher> joints;
|
||||
std::unordered_set<Entity, Entity::Hasher> completed;
|
||||
std::stack<Entity> stack;
|
||||
|
||||
auto transforms = getBoneRestTranforms(instance, skinIndex);
|
||||
|
||||
for (int i = 0; i < filamentInstance->getJointCountAt(skinIndex); i++)
|
||||
{
|
||||
auto restTransform = transforms[i];
|
||||
const auto &joint = filamentInstance->getJointsAt(skinIndex)[i];
|
||||
auto transformInstance = transformManager.getInstance(joint);
|
||||
transformManager.setTransform(transformInstance, restTransform);
|
||||
}
|
||||
}
|
||||
filamentInstance->getAnimator()->updateBoneMatrices();
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<math::mat4f> AnimationManager::getBoneRestTranforms(GltfSceneAssetInstance *instance, int skinIndex)
|
||||
{
|
||||
|
||||
std::vector<math::mat4f> transforms;
|
||||
|
||||
auto filamentInstance = instance->getInstance();
|
||||
auto skinCount = filamentInstance->getSkinCount();
|
||||
|
||||
TransformManager &transformManager = _engine->getTransformManager();
|
||||
|
||||
transforms.resize(filamentInstance->getJointCountAt(skinIndex));
|
||||
|
||||
//
|
||||
// To reset the skeleton to its rest pose, we could just call animator->resetBoneMatrices(),
|
||||
// which sets all bone matrices to the identity matrix. However, any subsequent calls to animator->updateBoneMatrices()
|
||||
// may result in unexpected poses, because that method uses each bone's transform to calculate
|
||||
// the bone matrices (and resetBoneMatrices does not affect this transform).
|
||||
// To "fully" reset the bone, we need to set its local transform (i.e. relative to its parent)
|
||||
// to its original orientation in rest pose.
|
||||
//
|
||||
// This can be calculated as:
|
||||
//
|
||||
// auto rest = inverse(parentTransformInModelSpace) * bindMatrix
|
||||
//
|
||||
// (where bindMatrix is the inverse of the inverseBindMatrix).
|
||||
//
|
||||
// The only requirement is that parent bone transforms are reset before child bone transforms.
|
||||
// glTF/Filament does not guarantee that parent bones are listed before child bones under a FilamentInstance.
|
||||
// We ensure that parents are reset before children by:
|
||||
// - pushing all bones onto a stack
|
||||
// - iterate over the stack
|
||||
// - look at the bone at the top of the stack
|
||||
// - if the bone already been reset, pop and continue iterating over the stack
|
||||
// - otherwise
|
||||
// - if the bone has a parent that has not been reset, push the parent to the top of the stack and continue iterating
|
||||
// - otherwise
|
||||
// - pop the bone, reset its transform and mark it as completed
|
||||
std::vector<Entity> joints;
|
||||
std::unordered_set<Entity, Entity::Hasher> completed;
|
||||
std::stack<Entity> stack;
|
||||
|
||||
for (int i = 0; i < filamentInstance->getJointCountAt(skinIndex); i++)
|
||||
{
|
||||
const auto &joint = filamentInstance->getJointsAt(skinIndex)[i];
|
||||
joints.push_back(joint);
|
||||
stack.push(joint);
|
||||
}
|
||||
|
||||
while (!stack.empty())
|
||||
{
|
||||
const auto &joint = stack.top();
|
||||
|
||||
// if we've already handled this node previously (e.g. when we encountered it as a parent), then skip
|
||||
if (completed.find(joint) != completed.end())
|
||||
{
|
||||
stack.pop();
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto transformInstance = transformManager.getInstance(joint);
|
||||
auto parent = transformManager.getParent(transformInstance);
|
||||
|
||||
// we need to handle parent joints before handling their children
|
||||
// therefore, if this joint has a parent that hasn't been handled yet,
|
||||
// push the parent to the top of the stack and start the loop again
|
||||
const auto &jointIter = std::find(joints.begin(), joints.end(), joint);
|
||||
auto parentIter = std::find(joints.begin(), joints.end(), parent);
|
||||
|
||||
if (parentIter != joints.end() && completed.find(parent) == completed.end())
|
||||
{
|
||||
stack.push(parent);
|
||||
continue;
|
||||
}
|
||||
|
||||
// otherwise let's get the inverse bind matrix for the joint
|
||||
math::mat4f inverseBindMatrix;
|
||||
bool found = false;
|
||||
for (int i = 0; i < filamentInstance->getJointCountAt(skinIndex); i++)
|
||||
{
|
||||
if (filamentInstance->getJointsAt(skinIndex)[i] == joint)
|
||||
{
|
||||
inverseBindMatrix = filamentInstance->getInverseBindMatricesAt(skinIndex)[i];
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ASSERT_PRECONDITION(found, "Failed to find inverse bind matrix for joint %d", joint);
|
||||
|
||||
// now we need to ascend back up the hierarchy to calculate the modelSpaceTransform
|
||||
math::mat4f modelSpaceTransform;
|
||||
while (parentIter != joints.end())
|
||||
{
|
||||
const auto transformInstance = transformManager.getInstance(parent);
|
||||
const auto parentIndex = distance(joints.begin(), parentIter);
|
||||
const auto transform = transforms[parentIndex];
|
||||
modelSpaceTransform = transform * modelSpaceTransform;
|
||||
parent = transformManager.getParent(transformInstance);
|
||||
parentIter = std::find(joints.begin(), joints.end(), parent);
|
||||
}
|
||||
|
||||
const auto bindMatrix = inverse(inverseBindMatrix);
|
||||
|
||||
const auto inverseModelSpaceTransform = inverse(modelSpaceTransform);
|
||||
|
||||
const auto jointIndex = distance(joints.begin(), jointIter);
|
||||
transforms[jointIndex] = inverseModelSpaceTransform * bindMatrix;
|
||||
completed.insert(joint);
|
||||
stack.pop();
|
||||
}
|
||||
return transforms;
|
||||
}
|
||||
|
||||
void AnimationManager::updateBoneMatrices(GltfSceneAssetInstance *instance)
|
||||
{
|
||||
instance->getInstance()->getAnimator()->updateBoneMatrices();
|
||||
}
|
||||
|
||||
bool AnimationManager::addBoneAnimation(GltfSceneAssetInstance *instance,
|
||||
int skinIndex,
|
||||
int boneIndex,
|
||||
const float *const frameData,
|
||||
int numFrames,
|
||||
float frameLengthInMs,
|
||||
float fadeOutInSecs,
|
||||
float fadeInInSecs,
|
||||
float maxDelta)
|
||||
{
|
||||
std::lock_guard lock(_mutex);
|
||||
|
||||
BoneAnimation animation;
|
||||
animation.boneIndex = boneIndex;
|
||||
animation.frameData.clear();
|
||||
|
||||
const auto &inverseBindMatrix = instance->getInstance()->getInverseBindMatricesAt(skinIndex)[boneIndex];
|
||||
for (int i = 0; i < numFrames; i++)
|
||||
{
|
||||
math::mat4f frame(
|
||||
frameData[i * 16],
|
||||
frameData[(i * 16) + 1],
|
||||
frameData[(i * 16) + 2],
|
||||
frameData[(i * 16) + 3],
|
||||
frameData[(i * 16) + 4],
|
||||
frameData[(i * 16) + 5],
|
||||
frameData[(i * 16) + 6],
|
||||
frameData[(i * 16) + 7],
|
||||
frameData[(i * 16) + 8],
|
||||
frameData[(i * 16) + 9],
|
||||
frameData[(i * 16) + 10],
|
||||
frameData[(i * 16) + 11],
|
||||
frameData[(i * 16) + 12],
|
||||
frameData[(i * 16) + 13],
|
||||
frameData[(i * 16) + 14],
|
||||
frameData[(i * 16) + 15]);
|
||||
|
||||
animation.frameData.push_back(frame);
|
||||
}
|
||||
|
||||
animation.frameLengthInMs = frameLengthInMs;
|
||||
animation.start = std::chrono::high_resolution_clock::now();
|
||||
animation.reverse = false;
|
||||
animation.durationInSecs = (frameLengthInMs * numFrames) / 1000.0f;
|
||||
animation.lengthInFrames = numFrames;
|
||||
animation.frameLengthInMs = frameLengthInMs;
|
||||
animation.fadeOutInSecs = fadeOutInSecs;
|
||||
animation.fadeInInSecs = fadeInInSecs;
|
||||
animation.maxDelta = maxDelta;
|
||||
animation.skinIndex = skinIndex;
|
||||
if (!_animationComponentManager->hasComponent(instance->getInstance()->getRoot()))
|
||||
{
|
||||
Log("ERROR: specified entity is not animatable (has no animation component attached).");
|
||||
return false;
|
||||
}
|
||||
auto animationComponentInstance = _animationComponentManager->getInstance(instance->getInstance()->getRoot());
|
||||
|
||||
auto &animationComponent = _animationComponentManager->elementAt<0>(animationComponentInstance);
|
||||
auto &boneAnimations = animationComponent.boneAnimations;
|
||||
|
||||
boneAnimations.emplace_back(animation);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AnimationManager::playGltfAnimation(GltfSceneAssetInstance *instance, int index, bool loop, bool reverse, bool replaceActive, float crossfade, float startOffset)
|
||||
{
|
||||
std::lock_guard lock(_mutex);
|
||||
|
||||
if (index < 0)
|
||||
{
|
||||
Log("ERROR: glTF animation index must be greater than zero.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_animationComponentManager->hasComponent(instance->getEntity()))
|
||||
{
|
||||
Log("ERROR: specified entity is not animatable (has no animation component attached).");
|
||||
return;
|
||||
}
|
||||
|
||||
auto animationComponentInstance = _animationComponentManager->getInstance(instance->getEntity());
|
||||
|
||||
auto &animationComponent = _animationComponentManager->elementAt<0>(animationComponentInstance);
|
||||
|
||||
if (replaceActive)
|
||||
{
|
||||
if (animationComponent.gltfAnimations.size() > 0)
|
||||
{
|
||||
auto &last = animationComponent.gltfAnimations.back();
|
||||
animationComponent.fadeGltfAnimationIndex = last.index;
|
||||
animationComponent.fadeDuration = crossfade;
|
||||
auto now = high_resolution_clock::now();
|
||||
auto elapsedInSecs = float(std::chrono::duration_cast<std::chrono::milliseconds>(now - last.start).count()) / 1000.0f;
|
||||
animationComponent.fadeOutAnimationStart = elapsedInSecs;
|
||||
animationComponent.gltfAnimations.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
animationComponent.fadeGltfAnimationIndex = -1;
|
||||
animationComponent.fadeDuration = 0.0f;
|
||||
}
|
||||
}
|
||||
else if (crossfade > 0)
|
||||
{
|
||||
Log("ERROR: crossfade only supported when replaceActive is true.");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
animationComponent.fadeGltfAnimationIndex = -1;
|
||||
animationComponent.fadeDuration = 0.0f;
|
||||
}
|
||||
|
||||
GltfAnimation animation;
|
||||
animation.startOffset = startOffset;
|
||||
animation.index = index;
|
||||
animation.start = std::chrono::high_resolution_clock::now();
|
||||
animation.loop = loop;
|
||||
animation.reverse = reverse;
|
||||
animation.durationInSecs = instance->getInstance()->getAnimator()->getAnimationDuration(index);
|
||||
|
||||
bool found = false;
|
||||
|
||||
// don't play the animation if it's already running
|
||||
for (int i = 0; i < animationComponent.gltfAnimations.size(); i++)
|
||||
{
|
||||
if (animationComponent.gltfAnimations[i].index == index)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
animationComponent.gltfAnimations.push_back(animation);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationManager::stopGltfAnimation(GltfSceneAssetInstance *instance, int index)
|
||||
{
|
||||
|
||||
auto animationComponentInstance = _animationComponentManager->getInstance(instance->getEntity());
|
||||
auto &animationComponent = _animationComponentManager->elementAt<0>(animationComponentInstance);
|
||||
|
||||
auto erased = std::remove_if(animationComponent.gltfAnimations.begin(),
|
||||
animationComponent.gltfAnimations.end(),
|
||||
[=](GltfAnimation &anim)
|
||||
{ return anim.index == index; });
|
||||
animationComponent.gltfAnimations.erase(erased,
|
||||
animationComponent.gltfAnimations.end());
|
||||
return;
|
||||
}
|
||||
|
||||
void AnimationManager::setMorphTargetWeights(utils::Entity entity, const float *const weights, const int count)
|
||||
{
|
||||
RenderableManager &rm = _engine->getRenderableManager();
|
||||
auto renderableInstance = rm.getInstance(entity);
|
||||
rm.setMorphWeights(
|
||||
renderableInstance,
|
||||
weights,
|
||||
count);
|
||||
}
|
||||
|
||||
void AnimationManager::setGltfAnimationFrame(GltfSceneAssetInstance *instance, int animationIndex, int animationFrame)
|
||||
{
|
||||
auto offset = 60 * animationFrame * 1000; // TODO - don't hardcore 60fps framerate
|
||||
instance->getInstance()->getAnimator()->applyAnimation(animationIndex, offset);
|
||||
instance->getInstance()->getAnimator()->updateBoneMatrices();
|
||||
return;
|
||||
}
|
||||
|
||||
float AnimationManager::getGltfAnimationDuration(GltfSceneAssetInstance *instance, int animationIndex)
|
||||
{
|
||||
return instance->getInstance()->getAnimator()->getAnimationDuration(animationIndex);
|
||||
}
|
||||
|
||||
std::vector<std::string> AnimationManager::getGltfAnimationNames(GltfSceneAssetInstance *instance)
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
|
||||
size_t count = instance->getInstance()->getAnimator()->getAnimationCount();
|
||||
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
names.push_back(instance->getInstance()->getAnimator()->getAnimationName(i));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
std::vector<std::string> AnimationManager::getMorphTargetNames(GltfSceneAsset *asset, EntityId childEntity)
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
|
||||
auto filamentAsset = asset->getAsset();
|
||||
|
||||
const utils::Entity targetEntity = utils::Entity::import(childEntity);
|
||||
|
||||
size_t count = filamentAsset->getMorphTargetCountAt(targetEntity);
|
||||
for (int j = 0; j < count; j++)
|
||||
{
|
||||
const char *morphName = filamentAsset->getMorphTargetNameAt(targetEntity, j);
|
||||
names.push_back(morphName);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
vector<Entity> AnimationManager::getBoneEntities(GltfSceneAssetInstance *instance, int skinIndex)
|
||||
{
|
||||
auto *joints = instance->getInstance()->getJointsAt(skinIndex);
|
||||
auto jointCount = instance->getInstance()->getJointCountAt(skinIndex);
|
||||
std::vector<Entity> boneEntities(joints, joints + jointCount);
|
||||
return boneEntities;
|
||||
}
|
||||
|
||||
void AnimationManager::update()
|
||||
{
|
||||
std::lock_guard lock(_mutex);
|
||||
_animationComponentManager->update();
|
||||
}
|
||||
|
||||
math::mat4f AnimationManager::getInverseBindMatrix(GltfSceneAssetInstance *instance, int skinIndex, int boneIndex)
|
||||
{
|
||||
return instance->getInstance()->getInverseBindMatricesAt(skinIndex)[boneIndex];
|
||||
}
|
||||
|
||||
bool AnimationManager::setBoneTransform(GltfSceneAssetInstance *instance, int32_t skinIndex, int boneIndex, math::mat4f transform)
|
||||
{
|
||||
std::lock_guard lock(_mutex);
|
||||
|
||||
RenderableManager &rm = _engine->getRenderableManager();
|
||||
|
||||
const auto &renderableInstance = rm.getInstance(instance->getEntity());
|
||||
|
||||
if (!renderableInstance.isValid())
|
||||
{
|
||||
Log("Specified entity is not a renderable. You probably provided the ultimate parent entity of a glTF asset, which is non-renderable. ");
|
||||
return false;
|
||||
}
|
||||
|
||||
rm.setBones(
|
||||
renderableInstance,
|
||||
&transform,
|
||||
1,
|
||||
boneIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AnimationManager::addAnimationComponent(EntityId entity)
|
||||
{
|
||||
_animationComponentManager->addAnimationComponent(utils::Entity::import(entity));
|
||||
return true;
|
||||
}
|
||||
|
||||
void AnimationManager::removeAnimationComponent(EntityId entity)
|
||||
{
|
||||
_animationComponentManager->removeComponent(utils::Entity::import(entity));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <filament/Viewport.h>
|
||||
#include <filament/geometry/SurfaceOrientation.h>
|
||||
|
||||
#include "CustomGeometry.hpp"
|
||||
#include "scene/CustomGeometry.hpp"
|
||||
#include "Log.hpp"
|
||||
|
||||
namespace thermion
|
||||
@@ -22,9 +22,10 @@ namespace thermion
|
||||
float *normals, uint32_t numNormals, float *uvs,
|
||||
uint32_t numUvs, uint16_t *indices,
|
||||
uint32_t numIndices,
|
||||
MaterialInstance* materialInstance,
|
||||
RenderableManager::PrimitiveType primitiveType,
|
||||
Engine *engine)
|
||||
: numVertices(numVertices), numIndices(numIndices), _engine(engine)
|
||||
: numVertices(numVertices), numIndices(numIndices), _materialInstance(materialInstance), _engine(engine)
|
||||
{
|
||||
|
||||
this->primitiveType = primitiveType;
|
||||
@@ -214,7 +215,6 @@ namespace thermion
|
||||
|
||||
CustomGeometry::~CustomGeometry()
|
||||
{
|
||||
Log("GEOMETRY DESTRUCTOR");
|
||||
_engine->destroy(vertexBuffer);
|
||||
_engine->destroy(indexBuffer);
|
||||
}
|
||||
125
thermion_dart/native/src/scene/GeometrySceneAsset.cpp
Normal file
125
thermion_dart/native/src/scene/GeometrySceneAsset.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
#include <vector>
|
||||
|
||||
#include <gltfio/MaterialProvider.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/Frustum.h>
|
||||
#include <filament/RenderableManager.h>
|
||||
#include <filament/Texture.h>
|
||||
#include <filament/TransformManager.h>
|
||||
#include <filament/Viewport.h>
|
||||
#include <filament/geometry/SurfaceOrientation.h>
|
||||
|
||||
#include "Log.hpp"
|
||||
#include "scene/GeometrySceneAsset.hpp"
|
||||
#include "scene/GeometrySceneAssetBuilder.hpp"
|
||||
|
||||
namespace thermion
|
||||
{
|
||||
|
||||
using namespace filament;
|
||||
|
||||
GeometrySceneAsset::GeometrySceneAsset(
|
||||
bool isInstance,
|
||||
Engine *engine,
|
||||
VertexBuffer *vertexBuffer,
|
||||
IndexBuffer *indexBuffer,
|
||||
MaterialInstance **materialInstances,
|
||||
size_t materialInstanceCount,
|
||||
RenderableManager::PrimitiveType primitiveType,
|
||||
Box boundingBox)
|
||||
: _isInstance(isInstance),
|
||||
_engine(engine), _vertexBuffer(vertexBuffer), _indexBuffer(indexBuffer), _materialInstances(materialInstances), _materialInstanceCount(materialInstanceCount), _primitiveType(primitiveType), _boundingBox(boundingBox)
|
||||
{
|
||||
_entity = utils::EntityManager::get().create();
|
||||
|
||||
RenderableManager::Builder builder(1);
|
||||
builder.boundingBox(_boundingBox)
|
||||
.geometry(0, _primitiveType, _vertexBuffer, _indexBuffer)
|
||||
.culling(true)
|
||||
.receiveShadows(true)
|
||||
.castShadows(true);
|
||||
for (int i = 0; i < materialInstanceCount; i++)
|
||||
{
|
||||
builder.material(i, materialInstances[i]);
|
||||
}
|
||||
builder.build(*_engine, _entity);
|
||||
}
|
||||
|
||||
|
||||
|
||||
GeometrySceneAsset::~GeometrySceneAsset()
|
||||
{
|
||||
if (_engine)
|
||||
{
|
||||
if (_vertexBuffer && !_isInstance)
|
||||
_engine->destroy(_vertexBuffer);
|
||||
if (_indexBuffer && !_isInstance)
|
||||
_engine->destroy(_indexBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
SceneAsset *GeometrySceneAsset::createInstance(MaterialInstance **materialInstances, size_t materialInstanceCount)
|
||||
{
|
||||
if (_isInstance)
|
||||
{
|
||||
Log("Cannot create an instance from another instance. Ensure you are calling createInstance with the original asset.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<GeometrySceneAsset> instance = std::make_unique<GeometrySceneAsset>(
|
||||
true,
|
||||
_engine,
|
||||
_vertexBuffer,
|
||||
_indexBuffer,
|
||||
materialInstances,
|
||||
materialInstanceCount,
|
||||
_primitiveType,
|
||||
_boundingBox);
|
||||
auto *raw = instance.get();
|
||||
_instances.push_back(std::move(instance));
|
||||
return raw;
|
||||
}
|
||||
|
||||
// std::unique_ptr<GeometrySceneAsset> GeometrySceneAsset::create(
|
||||
// float *vertices, uint32_t numVertices,
|
||||
// float *normals, uint32_t numNormals,
|
||||
// float *uvs, uint32_t numUvs,
|
||||
// uint16_t *indices, uint32_t numIndices,
|
||||
// MaterialInstance **materialInstances,
|
||||
// size_t materialInstanceCount,
|
||||
// RenderableManager::PrimitiveType primitiveType,
|
||||
// Engine *engine)
|
||||
// {
|
||||
|
||||
// // Setup texture if needed
|
||||
// if (asset && uvs && numUvs > 0 &&
|
||||
// asset->getMaterialInstance() &&
|
||||
// asset->getMaterialInstance()->getMaterial()->hasParameter("baseColorMap"))
|
||||
// {
|
||||
// static constexpr uint32_t textureSize = 1;
|
||||
// static constexpr uint32_t white = 0x00ffffff;
|
||||
|
||||
// auto texture = Texture::Builder()
|
||||
// .width(textureSize)
|
||||
// .height(textureSize)
|
||||
// .levels(1)
|
||||
// .format(Texture::InternalFormat::RGBA8)
|
||||
// .build(*engine);
|
||||
|
||||
// filament::backend::PixelBufferDescriptor pbd(
|
||||
// &white, 4, Texture::Format::RGBA, Texture::Type::UBYTE);
|
||||
// texture->setImage(*engine, 0, std::move(pbd));
|
||||
|
||||
// TextureSampler sampler(
|
||||
// TextureSampler::MinFilter::NEAREST,
|
||||
// TextureSampler::MagFilter::NEAREST);
|
||||
// sampler.setWrapModeS(TextureSampler::WrapMode::REPEAT);
|
||||
// sampler.setWrapModeT(TextureSampler::WrapMode::REPEAT);
|
||||
|
||||
// asset->getMaterialInstance()->setParameter("baseColorMap", texture, sampler);
|
||||
// }
|
||||
|
||||
// return asset;
|
||||
// }
|
||||
|
||||
} // namespace thermion
|
||||
367
thermion_dart/native/src/scene/Gizmo.cpp
Normal file
367
thermion_dart/native/src/scene/Gizmo.cpp
Normal file
@@ -0,0 +1,367 @@
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/RenderableManager.h>
|
||||
#include <filament/TransformManager.h>
|
||||
|
||||
#include <utils/Entity.h>
|
||||
#include <utils/EntityManager.h>
|
||||
|
||||
#include <gltfio/math.h>
|
||||
|
||||
#include "scene/Gizmo.hpp"
|
||||
#include "scene/SceneManager.hpp"
|
||||
|
||||
#include "material/unlit_fixed_size.h"
|
||||
|
||||
#include "Log.hpp"
|
||||
|
||||
namespace thermion
|
||||
{
|
||||
|
||||
using namespace filament::gltfio;
|
||||
|
||||
// First, create the black cube at the center
|
||||
// The axes widgets will be parented to this entity
|
||||
Entity Gizmo::createParentEntity()
|
||||
{
|
||||
auto &transformManager = _engine->getTransformManager();
|
||||
auto &entityManager = _engine->getEntityManager();
|
||||
|
||||
auto parent = entityManager.create();
|
||||
|
||||
auto *parentMaterialInstance = _material->createInstance();
|
||||
parentMaterialInstance->setParameter("baseColorFactor", math::float4{0.0f, 1.0f, 1.0f, 1.0f});
|
||||
parentMaterialInstance->setParameter("scale", 4.0f);
|
||||
|
||||
_materialInstances.push_back(parentMaterialInstance);
|
||||
|
||||
// Create center cube vertices
|
||||
float centerCubeSize = 0.1f;
|
||||
float *centerCubeVertices = new float[8 * 3]{
|
||||
-centerCubeSize, -centerCubeSize, -centerCubeSize,
|
||||
centerCubeSize, -centerCubeSize, -centerCubeSize,
|
||||
centerCubeSize, centerCubeSize, -centerCubeSize,
|
||||
-centerCubeSize, centerCubeSize, -centerCubeSize,
|
||||
-centerCubeSize, -centerCubeSize, centerCubeSize,
|
||||
centerCubeSize, -centerCubeSize, centerCubeSize,
|
||||
centerCubeSize, centerCubeSize, centerCubeSize,
|
||||
-centerCubeSize, centerCubeSize, centerCubeSize};
|
||||
|
||||
// Create center cube indices
|
||||
uint16_t *centerCubeIndices = new uint16_t[36]{
|
||||
0, 1, 2, 2, 3, 0,
|
||||
1, 5, 6, 6, 2, 1,
|
||||
5, 4, 7, 7, 6, 5,
|
||||
4, 0, 3, 3, 7, 4,
|
||||
3, 2, 6, 6, 7, 3,
|
||||
4, 5, 1, 1, 0, 4};
|
||||
|
||||
auto centerCubeVb = VertexBuffer::Builder()
|
||||
.vertexCount(8)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.build(*_engine);
|
||||
|
||||
centerCubeVb->setBufferAt(*_engine, 0, VertexBuffer::BufferDescriptor(centerCubeVertices, 8 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<float *>(buffer); }));
|
||||
|
||||
auto centerCubeIb = IndexBuffer::Builder().indexCount(36).bufferType(IndexBuffer::IndexType::USHORT).build(*_engine);
|
||||
centerCubeIb->setBuffer(*_engine, IndexBuffer::BufferDescriptor(
|
||||
centerCubeIndices, 36 * sizeof(uint16_t),
|
||||
[](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<uint16_t *>(buffer); }));
|
||||
|
||||
RenderableManager::Builder(1)
|
||||
.boundingBox({{-centerCubeSize, -centerCubeSize, -centerCubeSize},
|
||||
{centerCubeSize, centerCubeSize, centerCubeSize}})
|
||||
.material(0, parentMaterialInstance)
|
||||
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
.priority(7)
|
||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, centerCubeVb, centerCubeIb, 0, 36)
|
||||
.culling(false)
|
||||
.build(*_engine, parent);
|
||||
|
||||
auto parentTransformInstance = transformManager.getInstance(parent);
|
||||
math::mat4f cubeTransform;
|
||||
transformManager.setTransform(parentTransformInstance, cubeTransform);
|
||||
return parent;
|
||||
}
|
||||
|
||||
Gizmo::Gizmo(Engine *engine, View *view, Scene *scene, Material *material) : _engine(engine), _view(view), _scene(scene), _material(material)
|
||||
{
|
||||
auto parent = createParentEntity();
|
||||
auto x = createAxisEntity(Gizmo::Axis::X, parent);
|
||||
auto y = createAxisEntity(Gizmo::Axis::Y, parent);
|
||||
auto z = createAxisEntity(Gizmo::Axis::Z, parent);
|
||||
|
||||
auto xHitTest = createHitTestEntity(Gizmo::Axis::X, parent);
|
||||
auto yHitTest = createHitTestEntity(Gizmo::Axis::Y, parent);
|
||||
auto zHitTest = createHitTestEntity(Gizmo::Axis::Z, parent);
|
||||
|
||||
_entities = std::vector{parent, x, y, z, xHitTest, yHitTest, zHitTest};
|
||||
_parent = parent;
|
||||
_x = x;
|
||||
_y = y;
|
||||
_z = z;
|
||||
_xHitTest = xHitTest;
|
||||
_yHitTest = yHitTest;
|
||||
_zHitTest = zHitTest;
|
||||
}
|
||||
|
||||
Entity Gizmo::createAxisEntity(Gizmo::Axis axis, Entity parent)
|
||||
{
|
||||
auto &entityManager = _engine->getEntityManager();
|
||||
auto &transformManager = _engine->getTransformManager();
|
||||
auto *materialInstance = _material->createInstance();
|
||||
_materialInstances.push_back(materialInstance);
|
||||
auto entity = entityManager.create();
|
||||
|
||||
auto baseColor = inactiveColors[axis];
|
||||
|
||||
// Line and arrow vertices
|
||||
float lineLength = 0.6f;
|
||||
float lineWidth = 0.008f;
|
||||
float arrowLength = 0.06f;
|
||||
float arrowWidth = 0.02f;
|
||||
float *vertices = new float[13 * 3]{
|
||||
// Line vertices (8 vertices)
|
||||
-lineWidth, -lineWidth, 0.0f,
|
||||
lineWidth, -lineWidth, 0.0f,
|
||||
lineWidth, lineWidth, 0.0f,
|
||||
-lineWidth, lineWidth, 0.0f,
|
||||
-lineWidth, -lineWidth, lineLength,
|
||||
lineWidth, -lineWidth, lineLength,
|
||||
lineWidth, lineWidth, lineLength,
|
||||
-lineWidth, lineWidth, lineLength,
|
||||
// Arrow vertices (5 vertices)
|
||||
0.0f, 0.0f, lineLength + arrowLength, // Tip of the arrow
|
||||
-arrowWidth, -arrowWidth, lineLength, // Base of the arrow
|
||||
arrowWidth, -arrowWidth, lineLength,
|
||||
arrowWidth, arrowWidth, lineLength,
|
||||
-arrowWidth, arrowWidth, lineLength};
|
||||
|
||||
// Line and arrow indices
|
||||
uint16_t *indices = new uint16_t[24 + 18]{
|
||||
// Line indices (24 indices)
|
||||
0, 1, 5, 5, 4, 0,
|
||||
1, 2, 6, 6, 5, 1,
|
||||
2, 3, 7, 7, 6, 2,
|
||||
3, 0, 4, 4, 7, 3,
|
||||
// // Arrow indices (18 indices)
|
||||
8, 9, 10, // Front face
|
||||
8, 10, 11, // Right face
|
||||
8, 11, 12, // Back face
|
||||
8, 12, 9, // Left face
|
||||
9, 12, 11, 11, 10, 9 // Base of the arrow
|
||||
};
|
||||
|
||||
auto vb = VertexBuffer::Builder()
|
||||
.vertexCount(13)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.build(*_engine);
|
||||
|
||||
vb->setBufferAt(*_engine, 0, VertexBuffer::BufferDescriptor(vertices, 13 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<float *>(buffer); }));
|
||||
|
||||
auto ib = IndexBuffer::Builder().indexCount(42).bufferType(IndexBuffer::IndexType::USHORT).build(*_engine);
|
||||
ib->setBuffer(*_engine, IndexBuffer::BufferDescriptor(
|
||||
indices, 42 * sizeof(uint16_t),
|
||||
[](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<uint16_t *>(buffer); }));
|
||||
|
||||
materialInstance->setParameter("baseColorFactor", baseColor);
|
||||
materialInstance->setParameter("scale", 4.0f);
|
||||
materialInstance->setDepthCulling(false);
|
||||
materialInstance->setDepthFunc(MaterialInstance::DepthFunc::A);
|
||||
|
||||
RenderableManager::Builder(1)
|
||||
.boundingBox({{-arrowWidth, -arrowWidth, 0},
|
||||
{arrowWidth, arrowWidth, lineLength + arrowLength}})
|
||||
.material(0, materialInstance)
|
||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vb, ib, 0, 42)
|
||||
.priority(6)
|
||||
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
.culling(false)
|
||||
.receiveShadows(false)
|
||||
.castShadows(false)
|
||||
.build(*_engine, entity);
|
||||
|
||||
auto transformInstance = transformManager.getInstance(entity);
|
||||
|
||||
transformManager.setTransform(transformInstance, getRotationForAxis(axis));
|
||||
|
||||
// parent the axis to the center cube
|
||||
auto parentTransformInstance = transformManager.getInstance(parent);
|
||||
transformManager.setParent(transformInstance, parentTransformInstance);
|
||||
return entity;
|
||||
}
|
||||
|
||||
Gizmo::~Gizmo()
|
||||
{
|
||||
_scene->removeEntities(_entities.data(), _entities.size());
|
||||
|
||||
for (auto entity : _entities)
|
||||
{
|
||||
_engine->destroy(entity);
|
||||
}
|
||||
|
||||
for (auto *materialInstance : _materialInstances)
|
||||
{
|
||||
_engine->destroy(materialInstance);
|
||||
}
|
||||
}
|
||||
|
||||
Entity Gizmo::createHitTestEntity(Gizmo::Axis axis, Entity parent)
|
||||
{
|
||||
auto &entityManager = EntityManager::get();
|
||||
auto &transformManager = _engine->getTransformManager();
|
||||
|
||||
auto parentTransformInstance = transformManager.getInstance(parent);
|
||||
|
||||
float volumeWidth = 0.2f;
|
||||
float volumeLength = 1.2f;
|
||||
float volumeDepth = 0.2f;
|
||||
|
||||
float *volumeVertices = new float[8 * 3]{
|
||||
-volumeWidth / 2, -volumeDepth / 2, 0,
|
||||
volumeWidth / 2, -volumeDepth / 2, 0,
|
||||
volumeWidth / 2, -volumeDepth / 2, volumeLength,
|
||||
-volumeWidth / 2, -volumeDepth / 2, volumeLength,
|
||||
-volumeWidth / 2, volumeDepth / 2, 0,
|
||||
volumeWidth / 2, volumeDepth / 2, 0,
|
||||
volumeWidth / 2, volumeDepth / 2, volumeLength,
|
||||
-volumeWidth / 2, volumeDepth / 2, volumeLength};
|
||||
|
||||
uint16_t *volumeIndices = new uint16_t[36]{
|
||||
0, 1, 2, 2, 3, 0, // Bottom face
|
||||
4, 5, 6, 6, 7, 4, // Top face
|
||||
0, 4, 7, 7, 3, 0, // Left face
|
||||
1, 5, 6, 6, 2, 1, // Right face
|
||||
0, 1, 5, 5, 4, 0, // Front face
|
||||
3, 2, 6, 6, 7, 3 // Back face
|
||||
};
|
||||
|
||||
auto volumeVb = VertexBuffer::Builder()
|
||||
.vertexCount(8)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.build(*_engine);
|
||||
|
||||
volumeVb->setBufferAt(*_engine, 0, VertexBuffer::BufferDescriptor(volumeVertices, 8 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<float *>(buffer); }));
|
||||
|
||||
auto volumeIb = IndexBuffer::Builder()
|
||||
.indexCount(36)
|
||||
.bufferType(IndexBuffer::IndexType::USHORT)
|
||||
.build(*_engine);
|
||||
|
||||
volumeIb->setBuffer(*_engine, IndexBuffer::BufferDescriptor(
|
||||
volumeIndices, 36 * sizeof(uint16_t),
|
||||
[](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<uint16_t *>(buffer); }));
|
||||
|
||||
auto entity = entityManager.create();
|
||||
auto *materialInstance = _material->createInstance();
|
||||
_materialInstances.push_back(materialInstance);
|
||||
materialInstance->setParameter("baseColorFactor", math::float4{0.0f, 0.0f, 0.0f, 0.0f});
|
||||
materialInstance->setParameter("scale", 4.0f);
|
||||
|
||||
RenderableManager::Builder(1)
|
||||
.boundingBox({{-volumeWidth / 2, -volumeDepth / 2, 0}, {volumeWidth / 2, volumeDepth / 2, volumeLength}})
|
||||
.material(0, materialInstance)
|
||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, volumeVb, volumeIb, 0, 36)
|
||||
.priority(7)
|
||||
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
.culling(false)
|
||||
.receiveShadows(false)
|
||||
.castShadows(false)
|
||||
.build(*_engine, entity);
|
||||
|
||||
auto transformInstance = transformManager.getInstance(entity);
|
||||
transformManager.setTransform(transformInstance, getRotationForAxis(axis));
|
||||
// Parent the picking volume to the center cube
|
||||
transformManager.setParent(transformInstance, parentTransformInstance);
|
||||
return entity;
|
||||
}
|
||||
|
||||
void Gizmo::highlight(Gizmo::Axis axis)
|
||||
{
|
||||
auto &rm = _engine->getRenderableManager();
|
||||
auto entity = getEntityForAxis(axis);
|
||||
if (entity.isNull())
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto renderableInstance = rm.getInstance(entity);
|
||||
|
||||
if (!renderableInstance.isValid())
|
||||
{
|
||||
Log("Invalid renderable for axis");
|
||||
return;
|
||||
}
|
||||
auto *materialInstance = rm.getMaterialInstanceAt(renderableInstance, 0);
|
||||
math::float4 baseColor = activeColors[axis];
|
||||
materialInstance->setParameter("baseColorFactor", baseColor);
|
||||
}
|
||||
|
||||
void Gizmo::unhighlight(Gizmo::Axis axis)
|
||||
{
|
||||
auto &rm = _engine->getRenderableManager();
|
||||
auto entity = getEntityForAxis(axis);
|
||||
if (entity.isNull())
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto renderableInstance = rm.getInstance(entity);
|
||||
if (!renderableInstance.isValid())
|
||||
{
|
||||
Log("Invalid renderable for axis");
|
||||
return;
|
||||
}
|
||||
auto *materialInstance = rm.getMaterialInstanceAt(renderableInstance, 0);
|
||||
math::float4 baseColor = inactiveColors[axis];
|
||||
materialInstance->setParameter("baseColorFactor", baseColor);
|
||||
}
|
||||
|
||||
void Gizmo::pick(uint32_t x, uint32_t y, GizmoPickCallback callback)
|
||||
{
|
||||
|
||||
auto handler = new Gizmo::PickCallbackHandler(this, callback);
|
||||
_view->pick(x, y, [=](filament::View::PickingQueryResult const &result)
|
||||
{
|
||||
handler->handle(result);
|
||||
delete handler; });
|
||||
}
|
||||
|
||||
bool Gizmo::isGizmoEntity(Entity e)
|
||||
{
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
if (e == _entities[i])
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
math::mat4f Gizmo::getRotationForAxis(Gizmo::Axis axis)
|
||||
{
|
||||
|
||||
math::mat4f transform;
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case Axis::X:
|
||||
transform = math::mat4f::rotation(math::F_PI_2, math::float3{0, 1, 0});
|
||||
break;
|
||||
case Axis::Y:
|
||||
transform = math::mat4f::rotation(-math::F_PI_2, math::float3{1, 0, 0});
|
||||
break;
|
||||
case Axis::Z:
|
||||
break;
|
||||
}
|
||||
return transform;
|
||||
}
|
||||
|
||||
}
|
||||
61
thermion_dart/native/src/scene/GltfSceneAsset.cpp
Normal file
61
thermion_dart/native/src/scene/GltfSceneAsset.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
|
||||
#include "scene/GltfSceneAsset.hpp"
|
||||
#include "scene/GltfSceneAssetInstance.hpp"
|
||||
#include "gltfio/FilamentInstance.h"
|
||||
#include "Log.hpp"
|
||||
namespace thermion
|
||||
{
|
||||
|
||||
GltfSceneAsset::~GltfSceneAsset()
|
||||
{
|
||||
_instances.clear();
|
||||
_asset->releaseSourceData();
|
||||
_assetLoader->destroyAsset(_asset);
|
||||
}
|
||||
|
||||
SceneAsset *GltfSceneAsset::createInstance(MaterialInstance **materialInstances, size_t materialInstanceCount)
|
||||
{
|
||||
auto instanceNumber = _instances.size();
|
||||
|
||||
if (instanceNumber > _asset->getAssetInstanceCount() - 1)
|
||||
{
|
||||
Log("No instances available for reuse. When loading the asset, you must pre-allocate the number of instances you wish to make available for use. Try increasing this number.");
|
||||
return std::nullptr_t();
|
||||
}
|
||||
Log("Creating instance %d", instanceNumber);
|
||||
auto instance = _asset->getAssetInstances()[instanceNumber];
|
||||
instance->recomputeBoundingBoxes();
|
||||
instance->getAnimator()->updateBoneMatrices();
|
||||
|
||||
auto& rm = _engine->getRenderableManager();
|
||||
|
||||
if(materialInstanceCount > 0) {
|
||||
for(int i = 0; i < instance->getEntityCount(); i++) {
|
||||
auto renderableInstance = rm.getInstance(instance->getEntities()[i]);
|
||||
if(!renderableInstance.isValid()) {
|
||||
Log("Instance is not renderable");
|
||||
} else {
|
||||
for(int i = 0; i < materialInstanceCount; i++) {
|
||||
rm.setMaterialInstanceAt(renderableInstance, i, materialInstances[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<GltfSceneAssetInstance> sceneAssetInstance = std::make_unique<GltfSceneAssetInstance>(
|
||||
instance,
|
||||
_engine,
|
||||
materialInstances,
|
||||
materialInstanceCount
|
||||
);
|
||||
|
||||
auto *raw = sceneAssetInstance.get();
|
||||
|
||||
_instances.push_back(std::move(sceneAssetInstance));
|
||||
return raw;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
14
thermion_dart/native/src/scene/GltfSceneAssetInstance.cpp
Normal file
14
thermion_dart/native/src/scene/GltfSceneAssetInstance.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
#include "scene/GltfSceneAssetInstance.hpp"
|
||||
#include "gltfio/FilamentInstance.h"
|
||||
#include "Log.hpp"
|
||||
namespace thermion
|
||||
{
|
||||
|
||||
GltfSceneAssetInstance::~GltfSceneAssetInstance()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
349
thermion_dart/native/src/scene/RotationGizmo.cpp
Normal file
349
thermion_dart/native/src/scene/RotationGizmo.cpp
Normal file
@@ -0,0 +1,349 @@
|
||||
// #include <filament/Engine.h>
|
||||
// #include <filament/RenderableManager.h>
|
||||
// #include <filament/TransformManager.h>
|
||||
|
||||
// #include <gltfio/math.h>
|
||||
|
||||
// #include <utils/Entity.h>
|
||||
// #include <utils/EntityManager.h>
|
||||
|
||||
// #include <math.h>
|
||||
|
||||
// #include "scene/SceneManager.hpp"
|
||||
|
||||
// namespace thermion {
|
||||
|
||||
// using namespace filament::gltfio;
|
||||
|
||||
// RotationGizmo::RotationGizmo(Engine* engine, View* view, Scene* scene, Material* material)
|
||||
// : _engine(engine), _view(view), _scene(scene), _material(material) {
|
||||
|
||||
// auto& entityManager = EntityManager::get();
|
||||
// auto& transformManager = _engine->getTransformManager();
|
||||
|
||||
// // Create center cube
|
||||
// auto parentEntity = entityManager.create();
|
||||
// auto* parentMaterialInstance = _material->createInstance();
|
||||
// parentMaterialInstance->setParameter("baseColorFactor", math::float4{0.0f, 0.0f, 0.0f, 1.0f});
|
||||
// parentMaterialInstance->setParameter("scale", 4.0f);
|
||||
|
||||
// _entities[0] = parentEntity;
|
||||
// _materialInstances[0] = parentMaterialInstance;
|
||||
|
||||
// // Create center cube geometry
|
||||
// float centerCubeSize = 0.01f;
|
||||
// float* centerCubeVertices = new float[8 * 3]{
|
||||
// -centerCubeSize, -centerCubeSize, -centerCubeSize,
|
||||
// centerCubeSize, -centerCubeSize, -centerCubeSize,
|
||||
// centerCubeSize, centerCubeSize, -centerCubeSize,
|
||||
// -centerCubeSize, centerCubeSize, -centerCubeSize,
|
||||
// -centerCubeSize, -centerCubeSize, centerCubeSize,
|
||||
// centerCubeSize, -centerCubeSize, centerCubeSize,
|
||||
// centerCubeSize, centerCubeSize, centerCubeSize,
|
||||
// -centerCubeSize, centerCubeSize, centerCubeSize
|
||||
// };
|
||||
|
||||
// uint16_t* centerCubeIndices = new uint16_t[36]{
|
||||
// 0, 1, 2, 2, 3, 0,
|
||||
// 1, 5, 6, 6, 2, 1,
|
||||
// 5, 4, 7, 7, 6, 5,
|
||||
// 4, 0, 3, 3, 7, 4,
|
||||
// 3, 2, 6, 6, 7, 3,
|
||||
// 4, 5, 1, 1, 0, 4
|
||||
// };
|
||||
|
||||
// auto centerCubeVb = VertexBuffer::Builder()
|
||||
// .vertexCount(8)
|
||||
// .bufferCount(1)
|
||||
// .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
// .build(*engine);
|
||||
|
||||
// centerCubeVb->setBufferAt(*engine, 0,
|
||||
// VertexBuffer::BufferDescriptor(centerCubeVertices, 8 * sizeof(filament::math::float3),
|
||||
// [](void* buffer, size_t size, void*) { delete[] static_cast<float*>(buffer); }));
|
||||
|
||||
// auto centerCubeIb = IndexBuffer::Builder()
|
||||
// .indexCount(36)
|
||||
// .bufferType(IndexBuffer::IndexType::USHORT)
|
||||
// .build(*engine);
|
||||
|
||||
// centerCubeIb->setBuffer(*engine,
|
||||
// IndexBuffer::BufferDescriptor(centerCubeIndices, 36 * sizeof(uint16_t),
|
||||
// [](void* buffer, size_t size, void*) { delete[] static_cast<uint16_t*>(buffer); }));
|
||||
|
||||
// RenderableManager::Builder(1)
|
||||
// .boundingBox({{-centerCubeSize, -centerCubeSize, -centerCubeSize},
|
||||
// {centerCubeSize, centerCubeSize, centerCubeSize}})
|
||||
// .material(0, parentMaterialInstance)
|
||||
// .layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
// .priority(7)
|
||||
// .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, centerCubeVb, centerCubeIb, 0, 36)
|
||||
// .culling(false)
|
||||
// .build(*engine, parentEntity);
|
||||
|
||||
// // Create rotation circles
|
||||
// constexpr int segments = 32;
|
||||
// float radius = 0.5f;
|
||||
// float* vertices;
|
||||
// uint16_t* indices;
|
||||
// int vertexCount, indexCount;
|
||||
|
||||
// createCircle(radius, segments, vertices, indices, vertexCount, indexCount);
|
||||
|
||||
// auto vb = VertexBuffer::Builder()
|
||||
// .vertexCount(vertexCount)
|
||||
// .bufferCount(1)
|
||||
// .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
// .build(*engine);
|
||||
|
||||
// vb->setBufferAt(*engine, 0,
|
||||
// VertexBuffer::BufferDescriptor(vertices, vertexCount * sizeof(filament::math::float3),
|
||||
// [](void* buffer, size_t size, void*) { delete[] static_cast<float*>(buffer); }));
|
||||
|
||||
// auto ib = IndexBuffer::Builder()
|
||||
// .indexCount(indexCount)
|
||||
// .bufferType(IndexBuffer::IndexType::USHORT)
|
||||
// .build(*engine);
|
||||
|
||||
// ib->setBuffer(*engine,
|
||||
// IndexBuffer::BufferDescriptor(indices, indexCount * sizeof(uint16_t),
|
||||
// [](void* buffer, size_t size, void*) { delete[] static_cast<uint16_t*>(buffer); }));
|
||||
|
||||
// // Create the three circular rotation handles
|
||||
// for (int i = 0; i < 3; i++) {
|
||||
// auto* materialInstance = _material->createInstance();
|
||||
// auto entity = entityManager.create();
|
||||
// _entities[i + 1] = entity;
|
||||
// _materialInstances[i + 1] = materialInstance;
|
||||
|
||||
// auto baseColor = inactiveColors[i];
|
||||
// math::mat4f transform;
|
||||
|
||||
// switch (i) {
|
||||
// case Axis::X:
|
||||
// transform = math::mat4f::rotation(math::F_PI_2, math::float3{0, 1, 0});
|
||||
// break;
|
||||
// case Axis::Y:
|
||||
// transform = math::mat4f::rotation(math::F_PI_2, math::float3{1, 0, 0});
|
||||
// break;
|
||||
// case Axis::Z:
|
||||
// break;
|
||||
// }
|
||||
|
||||
// materialInstance->setParameter("baseColorFactor", baseColor);
|
||||
// materialInstance->setParameter("scale", 4.0f);
|
||||
|
||||
// RenderableManager::Builder(1)
|
||||
// .boundingBox({{-radius, -radius, -0.01f}, {radius, radius, 0.01f}})
|
||||
// .material(0, materialInstance)
|
||||
// .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vb, ib, 0, indexCount)
|
||||
// .priority(6)
|
||||
// .layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
// .culling(false)
|
||||
// .receiveShadows(false)
|
||||
// .castShadows(false)
|
||||
// .build(*engine, entity);
|
||||
|
||||
// auto transformInstance = transformManager.getInstance(entity);
|
||||
// transformManager.setTransform(transformInstance, transform);
|
||||
// transformManager.setParent(transformInstance, transformManager.getInstance(parentEntity));
|
||||
// }
|
||||
|
||||
// createHitTestEntities();
|
||||
// setVisibility(true);
|
||||
// }
|
||||
|
||||
// void RotationGizmo::createCircle(float radius, int segments, float*& vertices, uint16_t*& indices, int& vertexCount, int& indexCount) {
|
||||
// vertexCount = segments * 2;
|
||||
// indexCount = segments * 6;
|
||||
|
||||
// vertices = new float[vertexCount * 3];
|
||||
// indices = new uint16_t[indexCount];
|
||||
|
||||
// float thickness = 0.01f;
|
||||
|
||||
// // Generate vertices for inner and outer circles
|
||||
// for (int i = 0; i < segments; i++) {
|
||||
// float angle = (2.0f * M_PI * i) / segments;
|
||||
// float x = cosf(angle);
|
||||
// float y = sinf(angle);
|
||||
|
||||
// // Inner circle vertex
|
||||
// vertices[i * 6] = x * (radius - thickness);
|
||||
// vertices[i * 6 + 1] = y * (radius - thickness);
|
||||
// vertices[i * 6 + 2] = 0.0f;
|
||||
|
||||
// // Outer circle vertex
|
||||
// vertices[i * 6 + 3] = x * (radius + thickness);
|
||||
// vertices[i * 6 + 4] = y * (radius + thickness);
|
||||
// vertices[i * 6 + 5] = 0.0f;
|
||||
// }
|
||||
|
||||
// // Generate indices for triangles
|
||||
// for (int i = 0; i < segments; i++) {
|
||||
// int next = (i + 1) % segments;
|
||||
|
||||
// // First triangle
|
||||
// indices[i * 6] = i * 2;
|
||||
// indices[i * 6 + 1] = i * 2 + 1;
|
||||
// indices[i * 6 + 2] = next * 2 + 1;
|
||||
|
||||
// // Second triangle
|
||||
// indices[i * 6 + 3] = i * 2;
|
||||
// indices[i * 6 + 4] = next * 2 + 1;
|
||||
// indices[i * 6 + 5] = next * 2;
|
||||
// }
|
||||
// }
|
||||
|
||||
// void RotationGizmo::createHitTestEntities() {
|
||||
// auto& entityManager = EntityManager::get();
|
||||
// auto& transformManager = _engine->getTransformManager();
|
||||
|
||||
// float radius = 0.5f;
|
||||
// float thickness = 0.1f;
|
||||
|
||||
// // Create hit test volumes for each rotation circle
|
||||
// for (int i = 4; i < 7; i++) {
|
||||
// _entities[i] = entityManager.create();
|
||||
// _materialInstances[i] = _material->createInstance();
|
||||
|
||||
// _materialInstances[i]->setParameter("baseColorFactor", math::float4{0.0f, 0.0f, 0.0f, 0.0f});
|
||||
// _materialInstances[i]->setParameter("scale", 4.0f);
|
||||
|
||||
// math::mat4f transform;
|
||||
// switch (i - 4) {
|
||||
// case Axis::X:
|
||||
// transform = math::mat4f::rotation(math::F_PI_2, math::float3{0, 1, 0});
|
||||
// break;
|
||||
// case Axis::Y:
|
||||
// transform = math::mat4f::rotation(math::F_PI_2, math::float3{1, 0, 0});
|
||||
// break;
|
||||
// case Axis::Z:
|
||||
// break;
|
||||
// }
|
||||
|
||||
// // Create a thicker invisible volume aroun
|
||||
|
||||
// // Create a thicker invisible volume around each rotation circle for hit testing
|
||||
// float* volumeVertices;
|
||||
// uint16_t* volumeIndices;
|
||||
// int volumeVertexCount, volumeIndexCount;
|
||||
// createCircle(radius, 32, volumeVertices, volumeIndices, volumeVertexCount, volumeIndexCount);
|
||||
|
||||
// auto volumeVb = VertexBuffer::Builder()
|
||||
// .vertexCount(volumeVertexCount)
|
||||
// .bufferCount(1)
|
||||
// .attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
// .build(*_engine);
|
||||
|
||||
// volumeVb->setBufferAt(*_engine, 0,
|
||||
// VertexBuffer::BufferDescriptor(volumeVertices, volumeVertexCount * sizeof(filament::math::float3),
|
||||
// [](void* buffer, size_t size, void*) { delete[] static_cast<float*>(buffer); }));
|
||||
|
||||
// auto volumeIb = IndexBuffer::Builder()
|
||||
// .indexCount(volumeIndexCount)
|
||||
// .bufferType(IndexBuffer::IndexType::USHORT)
|
||||
// .build(*_engine);
|
||||
|
||||
// volumeIb->setBuffer(*_engine,
|
||||
// IndexBuffer::BufferDescriptor(volumeIndices, volumeIndexCount * sizeof(uint16_t),
|
||||
// [](void* buffer, size_t size, void*) { delete[] static_cast<uint16_t*>(buffer); }));
|
||||
|
||||
// RenderableManager::Builder(1)
|
||||
// .boundingBox({{-radius, -radius, -thickness/2}, {radius, radius, thickness/2}})
|
||||
// .material(0, _materialInstances[i])
|
||||
// .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, volumeVb, volumeIb, 0, volumeIndexCount)
|
||||
// .priority(7)
|
||||
// .layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
// .culling(false)
|
||||
// .receiveShadows(false)
|
||||
// .castShadows(false)
|
||||
// .build(*_engine, _entities[i]);
|
||||
|
||||
// auto instance = transformManager.getInstance(_entities[i]);
|
||||
// transformManager.setTransform(instance, transform);
|
||||
// transformManager.setParent(instance, transformManager.getInstance(_entities[0]));
|
||||
// }
|
||||
// }
|
||||
|
||||
// RotationGizmo::~RotationGizmo() {
|
||||
// _scene->removeEntities(_entities, 7);
|
||||
|
||||
// for (int i = 0; i < 7; i++) {
|
||||
// _engine->destroy(_entities[i]);
|
||||
// _engine->destroy(_materialInstances[i]);
|
||||
// }
|
||||
// }
|
||||
|
||||
// void RotationGizmo::highlight(Entity entity) {
|
||||
// auto& rm = _engine->getRenderableManager();
|
||||
// auto renderableInstance = rm.getInstance(entity);
|
||||
// auto materialInstance = rm.getMaterialInstanceAt(renderableInstance, 0);
|
||||
|
||||
// math::float4 baseColor;
|
||||
// if (entity == x()) {
|
||||
// baseColor = activeColors[Axis::X];
|
||||
// } else if (entity == y()) {
|
||||
// baseColor = activeColors[Axis::Y];
|
||||
// } else if (entity == z()) {
|
||||
// baseColor = activeColors[Axis::Z];
|
||||
// } else {
|
||||
// baseColor = math::float4{1.0f, 1.0f, 1.0f, 1.0f};
|
||||
// }
|
||||
|
||||
// materialInstance->setParameter("baseColorFactor", baseColor);
|
||||
// }
|
||||
|
||||
// void RotationGizmo::unhighlight() {
|
||||
// auto& rm = _engine->getRenderableManager();
|
||||
|
||||
// for (int i = 0; i < 3; i++) {
|
||||
// auto renderableInstance = rm.getInstance(_entities[i + 1]);
|
||||
// auto materialInstance = rm.getMaterialInstanceAt(renderableInstance, 0);
|
||||
// materialInstance->setParameter("baseColorFactor", inactiveColors[i]);
|
||||
// }
|
||||
// }
|
||||
|
||||
// void RotationGizmo::pick(uint32_t x, uint32_t y, PickCallback callback) {
|
||||
// auto handler = new RotationGizmo::PickCallbackHandler(this, callback);
|
||||
// _view->pick(x, y, [=](filament::View::PickingQueryResult const& result) {
|
||||
// handler->handle(result);
|
||||
// delete handler;
|
||||
// });
|
||||
// }
|
||||
|
||||
// void RotationGizmo::PickCallbackHandler::handle(filament::View::PickingQueryResult const& result) {
|
||||
// auto x = static_cast<int32_t>(result.fragCoords.x);
|
||||
// auto y = static_cast<int32_t>(result.fragCoords.y);
|
||||
|
||||
// for (int i = 0; i < 7; i++) {
|
||||
// if (_gizmo->_entities[i] == result.renderable) {
|
||||
// if (i < 4) {
|
||||
// return;
|
||||
// }
|
||||
// _gizmo->highlight(_gizmo->_entities[i - 4]);
|
||||
// _callback(static_cast<Axis>(i - 4), x, y, _gizmo->_view);
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// _gizmo->unhighlight();
|
||||
// }
|
||||
|
||||
// bool RotationGizmo::isGizmoEntity(Entity e) {
|
||||
// for (int i = 0; i < 7; i++) {
|
||||
// if (e == _entities[i]) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
// void RotationGizmo::setVisibility(bool visible) {
|
||||
// if (visible) {
|
||||
// _scene->addEntities(_entities, 7);
|
||||
// } else {
|
||||
// _scene->removeEntities(_entities, 7);
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
946
thermion_dart/native/src/scene/SceneManager.cpp
Normal file
946
thermion_dart/native/src/scene/SceneManager.cpp
Normal file
@@ -0,0 +1,946 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
#include <stack>
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/TransformManager.h>
|
||||
#include <filament/Texture.h>
|
||||
#include <filament/RenderableManager.h>
|
||||
#include <filament/Viewport.h>
|
||||
#include <filament/Frustum.h>
|
||||
|
||||
#include <utils/EntityManager.h>
|
||||
|
||||
#include <gltfio/Animator.h>
|
||||
#include <gltfio/AssetLoader.h>
|
||||
#include <gltfio/FilamentAsset.h>
|
||||
#include <gltfio/ResourceLoader.h>
|
||||
#include <gltfio/TextureProvider.h>
|
||||
#include <gltfio/math.h>
|
||||
#include <gltfio/materials/uberarchive.h>
|
||||
#include <imageio/ImageDecoder.h>
|
||||
|
||||
#include "material/FileMaterialProvider.hpp"
|
||||
#include "material/UnlitMaterialProvider.hpp"
|
||||
#include "material/unlit.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 "UnprojectTexture.hpp"
|
||||
|
||||
|
||||
|
||||
|
||||
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<CollisionComponentManager>(tm);
|
||||
|
||||
_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)
|
||||
.build(*_engine);
|
||||
}
|
||||
|
||||
SceneManager::~SceneManager()
|
||||
{
|
||||
for (auto camera : _cameras)
|
||||
{
|
||||
auto entity = camera->getEntity();
|
||||
_engine->destroyCameraComponent(entity);
|
||||
_engine->getEntityManager().destroy(entity);
|
||||
}
|
||||
|
||||
_engine->destroy(_unlitFixedSizeMaterial);
|
||||
_cameras.clear();
|
||||
|
||||
_gridOverlay->destroy();
|
||||
destroyAll();
|
||||
|
||||
_gltfResourceLoader->asyncCancelLoad();
|
||||
_ubershaderProvider->destroyMaterials();
|
||||
|
||||
_animationManager = std::nullptr_t();
|
||||
_collisionComponentManager = std::nullptr_t();
|
||||
delete _ncm;
|
||||
|
||||
delete _gltfResourceLoader;
|
||||
delete _stbDecoder;
|
||||
delete _ktxDecoder;
|
||||
delete _ubershaderProvider;
|
||||
AssetLoader::destroy(&_assetLoader);
|
||||
}
|
||||
|
||||
Gizmo *SceneManager::createGizmo(View *view, Scene *scene)
|
||||
{
|
||||
auto gizmo = std::make_unique<Gizmo>(_engine, view, scene, _unlitFixedSizeMaterial);
|
||||
auto *raw =gizmo.get();
|
||||
_sceneAssets.push_back(std::move(gizmo));
|
||||
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<FilamentInstance *> 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<ResourceBuffer> 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<GltfSceneAsset>(
|
||||
asset,
|
||||
_assetLoader,
|
||||
_engine);
|
||||
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("Finished loading glTF from %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)
|
||||
{
|
||||
auto &rm = _engine->getRenderableManager();
|
||||
|
||||
std::vector<FilamentInstance *> instances(numInstances);
|
||||
|
||||
FilamentAsset *asset = _assetLoader->createInstancedAsset((const uint8_t *)data, length, instances.data(), numInstances);
|
||||
|
||||
Log("Created instanced asset.");
|
||||
|
||||
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<GltfSceneAsset>(
|
||||
asset,
|
||||
_assetLoader,
|
||||
_engine);
|
||||
|
||||
auto sceneAssetInstance = sceneAsset->createInstance();
|
||||
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()
|
||||
{
|
||||
std::lock_guard lock(_mutex);
|
||||
|
||||
for (auto &asset : _sceneAssets)
|
||||
{
|
||||
asset->removeAllEntities(_scene);
|
||||
}
|
||||
|
||||
_sceneAssets.clear();
|
||||
|
||||
for (auto *texture : _textures)
|
||||
{
|
||||
_engine->destroy(texture);
|
||||
}
|
||||
|
||||
for (auto *materialInstance : _materialInstances)
|
||||
{
|
||||
_engine->destroy(materialInstance);
|
||||
}
|
||||
|
||||
_textures.clear();
|
||||
_materialInstances.clear();
|
||||
}
|
||||
|
||||
void SceneManager::destroy(SceneAsset *asset)
|
||||
{
|
||||
|
||||
std::lock_guard lock(_mutex);
|
||||
|
||||
auto it = std::remove_if(_sceneAssets.begin(), _sceneAssets.end(), [=](auto &sceneAsset)
|
||||
{ return sceneAsset.get() == asset; });
|
||||
if (it != _sceneAssets.end())
|
||||
{
|
||||
auto entity = (*it)->getEntity();
|
||||
_collisionComponentManager->removeComponent(entity);
|
||||
_animationManager->removeAnimationComponent(utils::Entity::smuggle(entity));
|
||||
for (int i = 0; i < (*it)->getChildEntityCount(); i++)
|
||||
{
|
||||
auto childEntity = (*it)->getChildEntities()[i];
|
||||
_collisionComponentManager->removeComponent(childEntity);
|
||||
_animationManager->removeAnimationComponent(utils::Entity::smuggle(childEntity));
|
||||
}
|
||||
(*it)->removeAllEntities(_scene);
|
||||
_sceneAssets.erase(it, _sceneAssets.end());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Texture *SceneManager::createTexture(const uint8_t *data, size_t length, const char *name)
|
||||
{
|
||||
|
||||
// Create an input stream from the data
|
||||
std::istringstream stream(std::string(reinterpret_cast<const char *>(data), length));
|
||||
|
||||
// Decode the image
|
||||
image::LinearImage linearImage = image::ImageDecoder::decode(stream, name, image::ImageDecoder::ColorSpace::SRGB);
|
||||
|
||||
if (!linearImage.isValid())
|
||||
{
|
||||
Log("Failed to decode image.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t w = linearImage.getWidth();
|
||||
uint32_t h = linearImage.getHeight();
|
||||
uint32_t channels = linearImage.getChannels();
|
||||
|
||||
Texture::InternalFormat textureFormat = channels == 3 ? Texture::InternalFormat::RGB16F
|
||||
: Texture::InternalFormat::RGBA16F;
|
||||
Texture::Format bufferFormat = channels == 3 ? Texture::Format::RGB
|
||||
: Texture::Format::RGBA;
|
||||
|
||||
Texture *texture = Texture::Builder()
|
||||
.width(w)
|
||||
.height(h)
|
||||
.levels(1)
|
||||
.format(textureFormat)
|
||||
.sampler(Texture::Sampler::SAMPLER_2D)
|
||||
.build(*_engine);
|
||||
|
||||
if (!texture)
|
||||
{
|
||||
Log("Failed to create texture: ");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Texture::PixelBufferDescriptor buffer(
|
||||
linearImage.getPixelRef(),
|
||||
size_t(w * h * channels * sizeof(float)),
|
||||
bufferFormat,
|
||||
Texture::Type::FLOAT);
|
||||
|
||||
texture->setImage(*_engine, 0, std::move(buffer));
|
||||
|
||||
Log("Created texture: %s (%d x %d, %d channels)", name, w, h, channels);
|
||||
|
||||
_textures.insert(texture);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
bool SceneManager::applyTexture(EntityId entityId, Texture *texture, const char *parameterName, int materialIndex)
|
||||
{
|
||||
auto entity = Entity::import(entityId);
|
||||
|
||||
if (entity.isNull())
|
||||
{
|
||||
Log("Entity %d is null?", entityId);
|
||||
return false;
|
||||
}
|
||||
|
||||
RenderableManager &rm = _engine->getRenderableManager();
|
||||
|
||||
auto renderable = rm.getInstance(entity);
|
||||
|
||||
if (!renderable.isValid())
|
||||
{
|
||||
Log("Renderable not valid, was the entity id correct (%d)?", entityId);
|
||||
return false;
|
||||
}
|
||||
|
||||
MaterialInstance *mi = rm.getMaterialInstanceAt(renderable, materialIndex);
|
||||
|
||||
if (!mi)
|
||||
{
|
||||
Log("ERROR: material index must be less than number of material instances");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto sampler = TextureSampler();
|
||||
mi->setParameter(parameterName, texture, sampler);
|
||||
Log("Applied texture to entity %d", entityId);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SceneManager::destroyTexture(Texture *texture)
|
||||
{
|
||||
if (_textures.find(texture) == _textures.end())
|
||||
{
|
||||
Log("Warning: couldn't find texture");
|
||||
}
|
||||
_textures.erase(texture);
|
||||
_engine->destroy(texture);
|
||||
}
|
||||
|
||||
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<GltfSceneAssetInstance *>(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<GltfSceneAssetInstance *>(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<math::float4, 8> 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<float>::max();
|
||||
float minY = std::numeric_limits<float>::max();
|
||||
float maxX = std::numeric_limits<float>::lowest();
|
||||
float maxY = std::numeric_limits<float>::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();
|
||||
}
|
||||
|
||||
entity = sceneAsset->getEntity();
|
||||
_scene->addEntity(entity);
|
||||
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);
|
||||
_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];
|
||||
}
|
||||
|
||||
void SceneManager::transformToUnitCube(EntityId entityId)
|
||||
{
|
||||
auto entity = utils::Entity::import(entityId);
|
||||
for (auto &asset : _sceneAssets)
|
||||
{
|
||||
auto *instance = reinterpret_cast<GltfSceneAssetInstance *>(asset->getInstanceByEntity(entity));
|
||||
if (instance)
|
||||
{
|
||||
auto &transformManager = _engine->getTransformManager();
|
||||
const auto &entity = utils::Entity::import(entityId);
|
||||
auto transformInstance = transformManager.getInstance(entity);
|
||||
if (!transformInstance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto aabb = instance->getInstance()->getBoundingBox();
|
||||
auto center = aabb.center();
|
||||
auto halfExtent = aabb.extent();
|
||||
auto maxExtent = max(halfExtent) * 2;
|
||||
auto scaleFactor = 2.0f / maxExtent;
|
||||
auto transform = math::mat4f::scaling(scaleFactor) * math::mat4f::translation(-center);
|
||||
transformManager.setTransform(transformManager.getInstance(entity), transform);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace thermion
|
||||
Reference in New Issue
Block a user