move set/remove stencilHighlight to View and implement via OverlayManager

This commit is contained in:
Nick Fisher
2025-07-01 10:13:47 +08:00
parent 96ef070be7
commit 0f9d2492e6
11 changed files with 382 additions and 140 deletions

View File

@@ -46,113 +46,6 @@ class FFIScene extends Scene<Pointer<TScene>> {
Scene_removeEntity(scene, entity);
}
///
///
///
@override
Future removeStencilHighlight(ThermionAsset asset) async {
if (!_highlightInstances.containsKey(asset)) {
_logger
.warning("No stencil highlight for asset (entity ${asset.entity})");
return;
}
_logger
.info("Removing stencil highlight for asset (entity ${asset.entity})");
final highlight = _highlightInstances[asset]!;
_highlightInstances.remove(asset);
await remove(highlight);
final materialInstance = await highlight.getMaterialInstanceAt();
await FilamentApp.instance!.destroyAsset(highlight);
await materialInstance.destroy();
_logger
.info("Removed stencil highlight for asset (entity ${asset.entity})");
}
final _highlightInstances = <ThermionAsset, ThermionAsset>{};
Future<ThermionAsset?> getAssetForHighlight(ThermionEntity entity) async {
for (final asset in _highlightInstances.keys) {
var highlightAsset = _highlightInstances[asset]!;
if (highlightAsset.entity == entity) {
return asset;
}
for (final child in await highlightAsset.getChildEntities()) {
if (child == entity) {
return asset;
}
}
}
return null;
}
///
///
///
@override
Future setStencilHighlight(ThermionAsset asset,
{double r = 1.0,
double g = 0.0,
double b = 0.0,
int? entity,
int primitiveIndex = 0}) async {
entity ??= asset.entity;
if (_highlightInstances.containsKey(asset)) {
_logger
.info("Stencil highlight exists for asset (entity ${asset.entity})");
var instance = _highlightInstances[asset];
var highlightMaterialInstance = await instance!.getMaterialInstanceAt();
await highlightMaterialInstance.setParameterFloat4(
"baseColorFactor", r, g, b, 1.0);
} else {
var highlightMaterialInstance =
await FilamentApp.instance!.createUnlitMaterialInstance();
var highlightInstance = await asset
.createInstance(materialInstances: [highlightMaterialInstance]);
_highlightInstances[asset] = highlightInstance as FFIAsset;
await highlightInstance.setCastShadows(false);
await highlightInstance.setReceiveShadows(false);
var sourceMaterialInstance =
await asset.getMaterialInstanceAt(entity: entity);
await sourceMaterialInstance.setStencilWriteEnabled(true);
await sourceMaterialInstance.setDepthWriteEnabled(true);
await sourceMaterialInstance
.setStencilOpDepthStencilPass(StencilOperation.REPLACE);
await sourceMaterialInstance
.setStencilCompareFunction(SamplerCompareFunction.A);
await sourceMaterialInstance
.setStencilReferenceValue(View.STENCIL_HIGHLIGHT_REFERENCE_VALUE);
await highlightMaterialInstance
.setStencilCompareFunction(SamplerCompareFunction.NE);
await highlightMaterialInstance
.setStencilReferenceValue(View.STENCIL_HIGHLIGHT_REFERENCE_VALUE);
await highlightMaterialInstance.setDepthCullingEnabled(true);
await highlightMaterialInstance.setParameterFloat4(
"baseColorFactor", r, g, b, 1.0);
await add(highlightInstance);
var transform = await FilamentApp.instance!
.getWorldTransform(highlightInstance.entity);
await FilamentApp.instance!.setTransform(highlightInstance.entity,
Matrix4.diagonal3(Vector3(1.1, 1.1, 1.1)) * transform);
await FilamentApp.instance!.setPriority(highlightInstance.entity, 7);
await FilamentApp.instance!.setParent(highlightInstance.entity, entity);
_logger
.info("Added stencil highlight for asset (entity ${asset.entity})");
}
}
IndirectLight? _indirectLight;
///

View File

@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:io';
import 'package:logging/logging.dart';
import 'package:thermion_dart/src/filament/src/implementation/ffi_texture.dart';
import 'package:thermion_dart/src/filament/src/interface/scene.dart';
@@ -9,18 +10,21 @@ import 'package:thermion_dart/thermion_dart.dart';
import 'ffi_camera.dart';
class FFIView extends View {
class FFIView extends View<Pointer<TView>> {
late final _logger = Logger(this.runtimeType.toString());
int _renderOrder = 0;
int get renderOrder => _renderOrder;
final Pointer<TView> view;
Pointer<TView> getNativeHandle() => view;
final FFIFilamentApp app;
bool _renderable = false;
bool get renderable => _renderable;
FFIRenderTarget? renderTarget;
RenderTarget? renderTarget;
late CallbackHolder<PickCallbackFunction> _onPickResultHolder;
@@ -59,6 +63,7 @@ class FFIView extends View {
@override
Future setViewport(int width, int height) async {
View_setViewport(view, width, height);
// await overlayView?.setViewport(width, height);
}
Future<RenderTarget?> getRenderTarget() async {
@@ -66,18 +71,20 @@ class FFIView extends View {
}
@override
Future setRenderTarget(covariant FFIRenderTarget? renderTarget) async {
Future setRenderTarget(RenderTarget? renderTarget) async {
if (renderTarget != null) {
View_setRenderTarget(view, renderTarget.renderTarget);
View_setRenderTarget(view, renderTarget.getNativeHandle());
this.renderTarget = renderTarget;
} else {
View_setRenderTarget(view, nullptr);
}
// await overlayView?.setRenderTarget(renderTarget);
}
@override
Future setCamera(FFICamera camera) async {
View_setCamera(view, camera.camera);
Future setCamera(Camera camera) async {
View_setCamera(view, camera.getNativeHandle());
// await overlayView?.setCamera(camera.getNativeHandle());
}
@override
@@ -250,4 +257,102 @@ class FFIView extends View {
Future setShadowsEnabled(bool enabled) async {
View_setShadowsEnabled(this.view, enabled);
}
Pointer<TOverlayManager>? overlayManager;
View? overlayView;
Scene? overlayScene;
RenderTarget? overlayRenderTarget;
Material? highlightMaterial;
final _highlighted = <ThermionAsset, MaterialInstance>{};
///
///
///
@override
Future setStencilHighlight(ThermionAsset asset,
{double r = 1.0,
double g = 0.0,
double b = 0.0,
int? entity,
int primitiveIndex = 0}) async {
entity ??= asset.entity;
if (overlayScene == null) {
// overlayView = await FilamentApp.instance!.createView();
overlayScene = await FilamentApp.instance!.createScene();
// await overlayView!.setScene(overlayScene!);
// await overlayView!.setRenderTarget(await this.getRenderTarget());
final vp = await getViewport();
overlayRenderTarget =
await FilamentApp.instance!.createRenderTarget(vp.width, vp.height);
overlayManager = OverlayManager_create(
app.engine,
app.renderer,
getNativeHandle(),
overlayScene!.getNativeHandle(),
overlayRenderTarget!.getNativeHandle());
// await setBlendMode(BlendMode.transparent);
// await overlayView!.setBlendMode(BlendMode.transparent);
// await overlayView!.setCamera(await getCamera());
// await overlayView!.setViewport(vp.width, vp.height);
// await setStencilBufferEnabled(true);
// await overlayView!.setStencilBufferEnabled(true);
RenderTicker_setOverlayManager(app.renderTicker, overlayManager!);
highlightMaterial ??= await FilamentApp.instance!.createMaterial(
File("/Users/nickfisher/Documents/thermion/materials/outline.filamat")
.readAsBytesSync());
}
// await sourceMaterialInstance.setStencilWriteEnabled(true);
// await sourceMaterialInstance
// .setStencilOpDepthStencilPass(StencilOperation.REPLACE);
// await sourceMaterialInstance
// .setStencilReferenceValue(View.STENCIL_HIGHLIGHT_REFERENCE_VALUE);
// await sourceMaterialInstance.setDepthCullingEnabled(false);
// await sourceMaterialInstance.setDepthFunc(SamplerCompareFunction.A);
// await sourceMaterialInstance
// .setStencilCompareFunction(SamplerCompareFunction.A);
var highlightMaterialInstance = await highlightMaterial!.createInstance();
await highlightMaterialInstance.setDepthCullingEnabled(true);
await highlightMaterialInstance.setDepthWriteEnabled(true);
OverlayManager_addComponent(
overlayManager!, entity, highlightMaterialInstance.getNativeHandle());
_highlighted[asset] = highlightMaterialInstance;
_logger.info("Added stencil highlight for asset (entity ${asset.entity})");
}
///
///
///
@override
Future removeStencilHighlight(ThermionAsset asset) async {
if (!_highlighted.containsKey(asset)) {
_logger
.warning("No stencil highlight for asset (entity ${asset.entity})");
return;
}
final materialInstance = _highlighted[asset]!;
_highlighted.remove(asset);
_logger
.info("Removing stencil highlight for asset (entity ${asset.entity})");
OverlayManager_removeComponent(overlayManager!, asset.entity);
await materialInstance.destroy();
_logger
.info("Removed stencil highlight for asset (entity ${asset.entity})");
}
void setName(String name) {
View_setName(getNativeHandle(), name.toNativeUtf8().cast());
}
}

View File

@@ -24,26 +24,6 @@ abstract class Scene<T> extends NativeHandle<T> {
///
Future removeEntity(ThermionEntity entity);
///
///
///
Future<ThermionAsset?> getAssetForHighlight(ThermionEntity entity);
/// Renders an outline around [entity] with the given color.
///
///
Future setStencilHighlight(ThermionAsset asset,
{double r = 1.0,
double g = 0.0,
double b = 0.0,
int? entity,
int primitiveIndex = 0});
/// Removes the outline around [entity]. Noop if there was no highlight.
///
///
Future removeStencilHighlight(ThermionAsset asset);
///
///
///

View File

@@ -1,4 +1,5 @@
import 'package:thermion_dart/src/filament/src/interface/layers.dart';
import 'package:thermion_dart/src/filament/src/interface/native_handle.dart';
import 'package:thermion_dart/src/filament/src/interface/scene.dart';
import 'package:thermion_dart/thermion_dart.dart';
@@ -51,20 +52,24 @@ class Viewport {
enum QualityLevel { LOW, MEDIUM, HIGH, ULTRA }
abstract class View {
abstract class View<T> extends NativeHandle<T> {
static int STENCIL_HIGHLIGHT_REFERENCE_VALUE = 1;
/// Gets the scene currently associated with this View.
///
///
Future<Scene> getScene();
/// Sets the scene currently associated with this View.
///
///
Future setScene(Scene scene);
/// Sets the (debug) name for this View.
///
///
void setName(String name);
Future<Viewport> getViewport();
Future setViewport(int width, int height);
Future<RenderTarget?> getRenderTarget();
@@ -87,6 +92,17 @@ abstract class View {
Future setShadowsEnabled(bool enabled);
Future setLayerVisibility(VisibilityLayers layer, bool visible);
/// Renders an outline around [entity] with the given color.
Future setStencilHighlight(ThermionAsset asset,
{double r = 1.0,
double g = 0.0,
double b = 0.0,
int? entity,
int primitiveIndex = 0});
/// Removes the outline around [entity]. Noop if there was no highlight.
Future removeStencilHighlight(ThermionAsset asset);
/// Sets the fog options for this view.
/// Fog is disabled by default
///