fix: store reference to material instances in ThermionViewer so they can be cleaned up on dispose
This commit is contained in:
@@ -122,7 +122,7 @@ class FFIAsset extends ThermionAsset {
|
|||||||
}
|
}
|
||||||
var sourceMaterialInstance = ThermionFFIMaterialInstance(
|
var sourceMaterialInstance = ThermionFFIMaterialInstance(
|
||||||
RenderableManager_getMaterialInstanceAt(
|
RenderableManager_getMaterialInstanceAt(
|
||||||
renderableManager, targetEntity, 0));
|
renderableManager, targetEntity, 0), sceneManager);
|
||||||
|
|
||||||
await sourceMaterialInstance.setStencilWriteEnabled(true);
|
await sourceMaterialInstance.setStencilWriteEnabled(true);
|
||||||
await sourceMaterialInstance.setDepthWriteEnabled(true);
|
await sourceMaterialInstance.setDepthWriteEnabled(true);
|
||||||
@@ -138,7 +138,7 @@ class FFIAsset extends ThermionAsset {
|
|||||||
_unlitMaterialProvider, key.address, cb);
|
_unlitMaterialProvider, key.address, cb);
|
||||||
});
|
});
|
||||||
final highlightMaterialInstance =
|
final highlightMaterialInstance =
|
||||||
ThermionFFIMaterialInstance(materialInstancePtr);
|
ThermionFFIMaterialInstance(materialInstancePtr, sceneManager);
|
||||||
await highlightMaterialInstance
|
await highlightMaterialInstance
|
||||||
.setStencilCompareFunction(SamplerCompareFunction.NE);
|
.setStencilCompareFunction(SamplerCompareFunction.NE);
|
||||||
await highlightMaterialInstance.setStencilReferenceValue(1);
|
await highlightMaterialInstance.setStencilReferenceValue(1);
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ import 'package:thermion_dart/thermion_dart.dart';
|
|||||||
|
|
||||||
class ThermionFFIMaterialInstance extends MaterialInstance {
|
class ThermionFFIMaterialInstance extends MaterialInstance {
|
||||||
final Pointer<TMaterialInstance> pointer;
|
final Pointer<TMaterialInstance> pointer;
|
||||||
|
final Pointer<TSceneManager> sceneManager;
|
||||||
|
|
||||||
ThermionFFIMaterialInstance(this.pointer) {
|
ThermionFFIMaterialInstance(this.pointer, this.sceneManager) {
|
||||||
if (pointer == nullptr) {
|
if (pointer == nullptr) {
|
||||||
throw Exception("MaterialInstance not found");
|
throw Exception("MaterialInstance not found");
|
||||||
}
|
}
|
||||||
@@ -50,14 +51,17 @@ class ThermionFFIMaterialInstance extends MaterialInstance {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future setDepthFunc(SamplerCompareFunction depthFunc) async {
|
Future setDepthFunc(SamplerCompareFunction depthFunc) async {
|
||||||
MaterialInstance_setDepthFunc(pointer, TSamplerCompareFunc.values[depthFunc.index]);
|
MaterialInstance_setDepthFunc(
|
||||||
|
pointer, TSamplerCompareFunc.values[depthFunc.index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future setStencilCompareFunction(SamplerCompareFunction func,
|
Future setStencilCompareFunction(SamplerCompareFunction func,
|
||||||
[StencilFace face = StencilFace.FRONT_AND_BACK]) async {
|
[StencilFace face = StencilFace.FRONT_AND_BACK]) async {
|
||||||
MaterialInstance_setStencilCompareFunction(
|
MaterialInstance_setStencilCompareFunction(
|
||||||
pointer, TSamplerCompareFunc.values[func.index], TStencilFace.values[face.index]);
|
pointer,
|
||||||
|
TSamplerCompareFunc.values[func.index],
|
||||||
|
TStencilFace.values[face.index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -113,4 +117,8 @@ class ThermionFFIMaterialInstance extends MaterialInstance {
|
|||||||
Future setStencilWriteMask(int mask) async {
|
Future setStencilWriteMask(int mask) async {
|
||||||
MaterialInstance_setStencilWriteMask(pointer, mask);
|
MaterialInstance_setStencilWriteMask(pointer, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future dispose() async {
|
||||||
|
SceneManager_destroyMaterialInstance(sceneManager, pointer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -282,6 +282,8 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
final _onDispose = <Future Function()>[];
|
final _onDispose = <Future Function()>[];
|
||||||
bool _disposing = false;
|
bool _disposing = false;
|
||||||
|
|
||||||
|
final _materialInstances = <ThermionFFIMaterialInstance>[];
|
||||||
|
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
@@ -291,12 +293,13 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
throw Exception("Viewer has already been disposed.");
|
throw Exception("Viewer has already been disposed.");
|
||||||
}
|
}
|
||||||
_disposing = true;
|
_disposing = true;
|
||||||
|
|
||||||
await setRendering(false);
|
await setRendering(false);
|
||||||
await clearEntities();
|
await clearEntities();
|
||||||
|
for (final mInstance in _materialInstances) {
|
||||||
|
await mInstance.dispose();
|
||||||
|
}
|
||||||
await clearLights();
|
await clearLights();
|
||||||
|
|
||||||
// await _sceneUpdateEventController.close();
|
|
||||||
Viewer_destroyOnRenderThread(_viewer!);
|
Viewer_destroyOnRenderThread(_viewer!);
|
||||||
_sceneManager = null;
|
_sceneManager = null;
|
||||||
_viewer = null;
|
_viewer = null;
|
||||||
@@ -984,9 +987,6 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
_sceneManager!, asset.pointer, callback));
|
_sceneManager!, asset.pointer, callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
|
||||||
///
|
|
||||||
///
|
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
@@ -1880,7 +1880,10 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
throw Exception("Failed to create material instance");
|
throw Exception("Failed to create material instance");
|
||||||
}
|
}
|
||||||
|
|
||||||
return ThermionFFIMaterialInstance(materialInstance);
|
var instance =
|
||||||
|
ThermionFFIMaterialInstance(materialInstance, _sceneManager!);
|
||||||
|
_materialInstances.add(instance);
|
||||||
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -1888,21 +1891,20 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
///
|
///
|
||||||
Future destroyMaterialInstance(
|
Future destroyMaterialInstance(
|
||||||
ThermionFFIMaterialInstance materialInstance) async {
|
ThermionFFIMaterialInstance materialInstance) async {
|
||||||
SceneManager_destroyMaterialInstance(
|
await materialInstance.dispose();
|
||||||
_sceneManager!, materialInstance.pointer);
|
_materialInstances.remove(materialInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
Future<ThermionFFIMaterialInstance> createUnlitMaterialInstance() async {
|
Future<ThermionFFIMaterialInstance> createUnlitMaterialInstance() async {
|
||||||
var instance = await withPointerCallback<TMaterialInstance>((cb) {
|
var instancePtr = await withPointerCallback<TMaterialInstance>((cb) {
|
||||||
SceneManager_createUnlitMaterialInstanceRenderThread(_sceneManager!, cb);
|
SceneManager_createUnlitMaterialInstanceRenderThread(_sceneManager!, cb);
|
||||||
});
|
});
|
||||||
if (instance == nullptr) {
|
final instance = ThermionFFIMaterialInstance(instancePtr, _sceneManager!);
|
||||||
throw Exception("Failed to create material instance");
|
_materialInstances.add(instance);
|
||||||
}
|
return instance;
|
||||||
return ThermionFFIMaterialInstance(instance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -1910,14 +1912,13 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
///
|
///
|
||||||
Future<ThermionFFIMaterialInstance>
|
Future<ThermionFFIMaterialInstance>
|
||||||
createUnlitFixedSizeMaterialInstance() async {
|
createUnlitFixedSizeMaterialInstance() async {
|
||||||
var instance = await withPointerCallback<TMaterialInstance>((cb) {
|
var instancePtr = await withPointerCallback<TMaterialInstance>((cb) {
|
||||||
SceneManager_createUnlitFixedSizeMaterialInstanceRenderThread(
|
SceneManager_createUnlitFixedSizeMaterialInstanceRenderThread(
|
||||||
_sceneManager!, cb);
|
_sceneManager!, cb);
|
||||||
});
|
});
|
||||||
if (instance == nullptr) {
|
final instance = ThermionFFIMaterialInstance(instancePtr, _sceneManager!);
|
||||||
throw Exception("Failed to create material instance");
|
_materialInstances.add(instance);
|
||||||
}
|
return instance;
|
||||||
return ThermionFFIMaterialInstance(instance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -1925,12 +1926,11 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
///
|
///
|
||||||
Future<MaterialInstance> getMaterialInstanceAt(
|
Future<MaterialInstance> getMaterialInstanceAt(
|
||||||
ThermionEntity entity, int index) async {
|
ThermionEntity entity, int index) async {
|
||||||
final instance = RenderableManager_getMaterialInstanceAt(
|
final instancePtr = RenderableManager_getMaterialInstanceAt(
|
||||||
_renderableManager!, entity, index);
|
_renderableManager!, entity, index);
|
||||||
if (instance == nullptr) {
|
|
||||||
throw Exception("Failed to get material instance");
|
final instance = ThermionFFIMaterialInstance(instancePtr, _sceneManager!);
|
||||||
}
|
return instance;
|
||||||
return ThermionFFIMaterialInstance(instance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -2036,8 +2036,8 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
SceneManager_getOverlayEntityCount(_sceneManager!);
|
SceneManager_getOverlayEntityCount(_sceneManager!);
|
||||||
final overlayEntities = List<ThermionEntity>.generate(overlayEntityCount,
|
final overlayEntities = List<ThermionEntity>.generate(overlayEntityCount,
|
||||||
(i) => SceneManager_getOverlayEntityAt(_sceneManager!, i)).toSet();
|
(i) => SceneManager_getOverlayEntityAt(_sceneManager!, i)).toSet();
|
||||||
return FFIGizmo(
|
return FFIGizmo(view, gizmo.cast<TSceneAsset>(), _sceneManager!, _engine!,
|
||||||
view, gizmo.cast<TSceneAsset>(), _sceneManager!, _engine!, nullptr, overlayEntities);
|
nullptr, overlayEntities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ enum StencilFace {
|
|||||||
BACK,
|
BACK,
|
||||||
|
|
||||||
/// Both front and back faces
|
/// Both front and back faces
|
||||||
FRONT_AND_BACK
|
FRONT_AND_BACK
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AlphaMode { OPAQUE, MASK, BLEND }
|
enum AlphaMode { OPAQUE, MASK, BLEND }
|
||||||
@@ -109,4 +109,5 @@ abstract class MaterialInstance {
|
|||||||
|
|
||||||
Future setStencilReadMask(int mask);
|
Future setStencilReadMask(int mask);
|
||||||
Future setStencilWriteMask(int mask);
|
Future setStencilWriteMask(int mask);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -792,28 +792,28 @@ abstract class ThermionViewer {
|
|||||||
AlphaMode alphaMode = AlphaMode.OPAQUE,
|
AlphaMode alphaMode = AlphaMode.OPAQUE,
|
||||||
bool enableDiagnostics = false,
|
bool enableDiagnostics = false,
|
||||||
bool hasMetallicRoughnessTexture = false,
|
bool hasMetallicRoughnessTexture = false,
|
||||||
int metallicRoughnessUV = 0,
|
int metallicRoughnessUV = -1,
|
||||||
int baseColorUV = 0,
|
int baseColorUV = -1,
|
||||||
bool hasClearCoatTexture = false,
|
bool hasClearCoatTexture = false,
|
||||||
int clearCoatUV = 0,
|
int clearCoatUV = -1,
|
||||||
bool hasClearCoatRoughnessTexture = false,
|
bool hasClearCoatRoughnessTexture = false,
|
||||||
int clearCoatRoughnessUV = 0,
|
int clearCoatRoughnessUV = -1,
|
||||||
bool hasClearCoatNormalTexture = false,
|
bool hasClearCoatNormalTexture = false,
|
||||||
int clearCoatNormalUV = 0,
|
int clearCoatNormalUV = -1,
|
||||||
bool hasClearCoat = false,
|
bool hasClearCoat = false,
|
||||||
bool hasTransmission = false,
|
bool hasTransmission = false,
|
||||||
bool hasTextureTransforms = false,
|
bool hasTextureTransforms = false,
|
||||||
int emissiveUV = 0,
|
int emissiveUV = -1,
|
||||||
int aoUV = 0,
|
int aoUV = -1,
|
||||||
int normalUV = 0,
|
int normalUV = -1,
|
||||||
bool hasTransmissionTexture = false,
|
bool hasTransmissionTexture = false,
|
||||||
int transmissionUV = 0,
|
int transmissionUV = -1,
|
||||||
bool hasSheenColorTexture = false,
|
bool hasSheenColorTexture = false,
|
||||||
int sheenColorUV = 0,
|
int sheenColorUV = -1,
|
||||||
bool hasSheenRoughnessTexture = false,
|
bool hasSheenRoughnessTexture = false,
|
||||||
int sheenRoughnessUV = 0,
|
int sheenRoughnessUV = -1,
|
||||||
bool hasVolumeThicknessTexture = false,
|
bool hasVolumeThicknessTexture = false,
|
||||||
int volumeThicknessUV = 0,
|
int volumeThicknessUV = -1,
|
||||||
bool hasSheen = false,
|
bool hasSheen = false,
|
||||||
bool hasIOR = false,
|
bool hasIOR = false,
|
||||||
bool hasVolume = false,
|
bool hasVolume = false,
|
||||||
|
|||||||
@@ -41,9 +41,6 @@
|
|||||||
#include "scene/GeometrySceneAssetBuilder.hpp"
|
#include "scene/GeometrySceneAssetBuilder.hpp"
|
||||||
#include "UnprojectTexture.hpp"
|
#include "UnprojectTexture.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
#include "material/image.h"
|
#include "material/image.h"
|
||||||
@@ -130,11 +127,12 @@ namespace thermion
|
|||||||
_engine->getEntityManager().destroy(entity);
|
_engine->getEntityManager().destroy(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
destroyAll();
|
||||||
|
|
||||||
_engine->destroy(_unlitFixedSizeMaterial);
|
_engine->destroy(_unlitFixedSizeMaterial);
|
||||||
_cameras.clear();
|
_cameras.clear();
|
||||||
|
|
||||||
_gridOverlay->destroy();
|
_gridOverlay->destroy();
|
||||||
destroyAll();
|
|
||||||
|
|
||||||
_gltfResourceLoader->asyncCancelLoad();
|
_gltfResourceLoader->asyncCancelLoad();
|
||||||
_ubershaderProvider->destroyMaterials();
|
_ubershaderProvider->destroyMaterials();
|
||||||
@@ -153,7 +151,7 @@ namespace thermion
|
|||||||
Gizmo *SceneManager::createGizmo(View *view, Scene *scene)
|
Gizmo *SceneManager::createGizmo(View *view, Scene *scene)
|
||||||
{
|
{
|
||||||
auto gizmo = std::make_unique<Gizmo>(_engine, view, scene, _unlitFixedSizeMaterial);
|
auto gizmo = std::make_unique<Gizmo>(_engine, view, scene, _unlitFixedSizeMaterial);
|
||||||
auto *raw =gizmo.get();
|
auto *raw = gizmo.get();
|
||||||
_sceneAssets.push_back(std::move(gizmo));
|
_sceneAssets.push_back(std::move(gizmo));
|
||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
@@ -682,7 +680,6 @@ namespace thermion
|
|||||||
math::float4 entityPlaneInClipSpace = Camera::inverseProjection(camera.getProjectionMatrix()) * ndcEntityPlanePos;
|
math::float4 entityPlaneInClipSpace = Camera::inverseProjection(camera.getProjectionMatrix()) * ndcEntityPlanePos;
|
||||||
auto entityPlaneInCameraSpace = entityPlaneInClipSpace / entityPlaneInClipSpace.w;
|
auto entityPlaneInCameraSpace = entityPlaneInClipSpace / entityPlaneInClipSpace.w;
|
||||||
auto entityPlaneInWorldSpace = camera.getModelMatrix() * entityPlaneInCameraSpace;
|
auto entityPlaneInWorldSpace = camera.getModelMatrix() * entityPlaneInCameraSpace;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneManager::queueTransformUpdates(EntityId *entities, math::mat4 *transforms, int numEntities)
|
void SceneManager::queueTransformUpdates(EntityId *entities, math::mat4 *transforms, int numEntities)
|
||||||
|
|||||||
@@ -13,16 +13,30 @@ import 'helpers.dart';
|
|||||||
void main() async {
|
void main() async {
|
||||||
final testHelper = TestHelper("geometry");
|
final testHelper = TestHelper("geometry");
|
||||||
group("custom geometry", () {
|
group("custom geometry", () {
|
||||||
test('create cube', () async {
|
test('create cube (no normals/uvs)', () async {
|
||||||
await testHelper.withViewer((viewer) async {
|
await testHelper.withViewer((viewer) async {
|
||||||
final cube = await viewer
|
final cube = await viewer
|
||||||
.createGeometry(GeometryHelper.cube(normals: false, uvs: false));
|
.createGeometry(GeometryHelper.cube(normals: false, uvs: false));
|
||||||
await testHelper.capture(viewer, "geometry_add_cube");
|
await testHelper.capture(viewer, "geometry_cube_no_normals_uvs");
|
||||||
await viewer.removeEntity(cube);
|
await viewer.removeEntity(cube);
|
||||||
await testHelper.capture(viewer, "geometry_remove_cube");
|
await testHelper.capture(viewer, "geometry_remove_cube");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('create cube with unlit ubershader material (no normals/uvs)',
|
||||||
|
() async {
|
||||||
|
await testHelper.withViewer((viewer) async {
|
||||||
|
final materialInstance =
|
||||||
|
await viewer.createUbershaderMaterialInstance(unlit: true);
|
||||||
|
await materialInstance.setParameterFloat4(
|
||||||
|
"baseColorFactor", 1.0, 0.0, 0.0, 1.0);
|
||||||
|
final cube = await viewer.createGeometry(
|
||||||
|
GeometryHelper.cube(normals: false, uvs: false),
|
||||||
|
materialInstances: [materialInstance]);
|
||||||
|
await testHelper.capture(viewer, "geometry_cube_ubershader");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('create cube (with normals)', () async {
|
test('create cube (with normals)', () async {
|
||||||
var viewer = await testHelper.createViewer();
|
var viewer = await testHelper.createViewer();
|
||||||
await viewer
|
await viewer
|
||||||
@@ -30,6 +44,36 @@ void main() async {
|
|||||||
await testHelper.capture(viewer, "geometry_cube_with_normals");
|
await testHelper.capture(viewer, "geometry_cube_with_normals");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('create cube with lit ubershader material (normals/ no uvs)',
|
||||||
|
() async {
|
||||||
|
await testHelper.withViewer((viewer) async {
|
||||||
|
final materialInstance =
|
||||||
|
await viewer.createUbershaderMaterialInstance(
|
||||||
|
unlit: false,
|
||||||
|
alphaMode: AlphaMode.BLEND,
|
||||||
|
hasVertexColors:false);
|
||||||
|
await materialInstance.setParameterFloat4(
|
||||||
|
"baseColorFactor", 1.0, 0.0, 0.0, 1.0);
|
||||||
|
final cube = await viewer.createGeometry(
|
||||||
|
GeometryHelper.cube(normals: true, uvs: false),
|
||||||
|
materialInstances: [materialInstance]
|
||||||
|
);
|
||||||
|
|
||||||
|
await viewer.addDirectLight(DirectLight.sun(
|
||||||
|
intensity: 100000,
|
||||||
|
castShadows: false,
|
||||||
|
direction: Vector3(0,-0.5,-1)));
|
||||||
|
// await viewer.addDirectLight(DirectLight.spot(
|
||||||
|
// intensity: 1000000,
|
||||||
|
// position: Vector3(0,3,3),
|
||||||
|
// direction: Vector3(0,-1.5,-1),
|
||||||
|
// falloffRadius: 10));
|
||||||
|
await materialInstance.setParameterFloat4(
|
||||||
|
"baseColorFactor", 1.0, 0.0, 0.0, 1.0);
|
||||||
|
await testHelper.capture(viewer, "geometry_cube_lit_ubershader");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('create instance', () async {
|
test('create instance', () async {
|
||||||
await testHelper.withViewer((viewer) async {
|
await testHelper.withViewer((viewer) async {
|
||||||
final cube = await viewer
|
final cube = await viewer
|
||||||
|
|||||||
Reference in New Issue
Block a user