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:
Nick Fisher
2024-11-21 15:04:10 +08:00
parent 9ada6aae64
commit ed444b0615
195 changed files with 18061 additions and 12628 deletions

View File

@@ -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");

View File

@@ -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);
}
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -17,7 +17,7 @@
#include <iostream>
#include "CustomGeometry.hpp"
#include "scene/CustomGeometry.hpp"
#include "UnprojectTexture.hpp"
namespace thermion

View 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());
}
}

View File

@@ -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

View 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

View 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

View 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

View 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

View 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);
}
}
}

View 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

View 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);
}
}

View 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);
}
}

View File

@@ -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
}

View 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));
}
}

View File

@@ -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);
}
}

View 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));
}
}

View File

@@ -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);
}

View 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

View 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;
}
}

View 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;
}
}

View File

@@ -0,0 +1,14 @@
#include "scene/GltfSceneAssetInstance.hpp"
#include "gltfio/FilamentInstance.h"
#include "Log.hpp"
namespace thermion
{
GltfSceneAssetInstance::~GltfSceneAssetInstance()
{
}
}

View 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);
// }
// }
// }

View 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