diff --git a/thermion_dart/lib/src/utils/src/texture_projection.dart b/thermion_dart/lib/src/utils/src/texture_projection.dart new file mode 100644 index 00000000..b6850335 --- /dev/null +++ b/thermion_dart/lib/src/utils/src/texture_projection.dart @@ -0,0 +1,118 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart'; +import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_view.dart'; +import 'package:thermion_dart/thermion_dart.dart'; + +class TextureProjection { + final SwapChain swapChain; + final Material projectionMaterial; + final MaterialInstance projectionMaterialInstance; + final Material depthWriteMaterial; + final MaterialInstance depthWriteMaterialInstance; + final Texture texture; + final View depthView; + final View projectionView; + + TextureProjection._( + {required this.swapChain, + required this.projectionMaterial, + required this.projectionMaterialInstance, + required this.depthWriteMaterial, + required this.depthWriteMaterialInstance, + required this.texture, + required this.depthView, + required this.projectionView}) {} + + static Future create( + View sourceView, SwapChain swapChain) async { + final viewport = await sourceView.getViewport(); + var depthWriteMat = await FilamentApp.instance!.createMaterial( + File( + "/Users/nickfisher/Documents/thermion/materials/linear_depth.filamat", + ).readAsBytesSync(), + ); + var depthWriteMi = await depthWriteMat.createInstance(); + + final depthWriteView = await FilamentApp.instance!.createView() as FFIView; + await depthWriteView.setFrustumCullingEnabled(false); + await depthWriteView.setPostProcessing(false); + await depthWriteView.setViewport(viewport.width, viewport.height); + + await depthWriteView.setBlendMode(BlendMode.opaque); + + final color = await (await sourceView.getRenderTarget())!.getColorTexture(); + final depth = + await (await depthWriteView.getRenderTarget())!.getColorTexture(); + + var captureMat = await FilamentApp.instance!.createMaterial( + File( + "/Users/nickfisher/Documents/thermion/materials/capture_uv.filamat", + ).readAsBytesSync(), + ); + var captureMi = await captureMat.createInstance(); + await captureMi.setParameterBool("flipUVs", true); + await captureMi.setParameterTexture( + "color", color, await FilamentApp.instance!.createTextureSampler()); + await captureMi.setParameterTexture( + "depth", depth, await FilamentApp.instance!.createTextureSampler()); + await captureMi.setParameterBool("useDepth", true); + + final projectionView = await FilamentApp.instance!.createView() as FFIView; + await projectionView.setFrustumCullingEnabled(false); + await projectionView.setPostProcessing(false); + await projectionView.setViewport(viewport.width, viewport.height); + + final depthWriteColorTexture = await FilamentApp.instance! + .createTexture(viewport.width, viewport.height, + flags: { + TextureUsage.TEXTURE_USAGE_COLOR_ATTACHMENT, + TextureUsage.TEXTURE_USAGE_SAMPLEABLE, + TextureUsage.TEXTURE_USAGE_BLIT_SRC + }, + textureFormat: TextureFormat.R32F); + await depthWriteView + .setRenderTarget(await FilamentApp.instance!.createRenderTarget( + viewport.width, + viewport.height, + color: depthWriteColorTexture, + ) as FFIRenderTarget); + + await FilamentApp.instance!.register(swapChain, depthWriteView); + await FilamentApp.instance!.register(swapChain, projectionView); + + return TextureProjection._( + swapChain: swapChain, + depthView: depthWriteView, + projectionView: projectionView, + projectionMaterial: captureMat, + projectionMaterialInstance: captureMi, + depthWriteMaterial: depthWriteMat, + depthWriteMaterialInstance: depthWriteMi, + texture: depthWriteColorTexture); + } + + Future destroy() async { + await projectionMaterialInstance.destroy(); + await projectionMaterial.destroy(); + await FilamentApp.instance!.destroyView(depthView); + await FilamentApp.instance!.destroyView(projectionView); + } + + Future execute(ThermionAsset target, View view) async { + var originalMi = await target.getMaterialInstanceAt(); + var pixelBuffers = await FilamentApp.instance! + .capture(swapChain, view: view, beforeRender: (view) async { + if (view == depthView) { + await target.setMaterialInstanceAt(depthWriteMaterialInstance); + } else if (view == projectionView) { + await target.setMaterialInstanceAt(projectionMaterialInstance); + } + }, + pixelDataFormat: PixelDataFormat.RGBA, + pixelDataType: PixelDataType.FLOAT); + await target.setMaterialInstanceAt(originalMi); + return pixelBuffers.firstWhere((pb) => pb.$1 == projectionView).$2; + } +}