refactoring + texture projection
This commit is contained in:
@@ -42,6 +42,11 @@ abstract class ThermionAsset {
|
||||
///
|
||||
Future<ThermionEntity?> getChildEntity(String childName);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<MaterialInstance> getMaterialInstanceAt({ThermionEntity? entity, int index = 0});
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'dart:typed_data';
|
||||
import 'package:thermion_dart/src/filament/src/engine.dart';
|
||||
import 'package:thermion_dart/src/filament/src/scene.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_material.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
|
||||
class FilamentConfig<T, U> {
|
||||
@@ -59,6 +61,16 @@ abstract class FilamentApp<T> {
|
||||
///
|
||||
Future<SwapChain> createSwapChain(T handle, {bool hasStencilBuffer = false});
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<View> createView();
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<Scene> createScene();
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@@ -98,7 +110,7 @@ abstract class FilamentApp<T> {
|
||||
int levels = 1,
|
||||
Set<TextureUsage> flags = const {TextureUsage.TEXTURE_USAGE_SAMPLEABLE},
|
||||
TextureSamplerType textureSamplerType = TextureSamplerType.SAMPLER_2D,
|
||||
TextureFormat textureFormat = TextureFormat.RGBA16F,
|
||||
TextureFormat textureFormat = TextureFormat.RGBA32F,
|
||||
int? importedTextureHandle});
|
||||
|
||||
///
|
||||
@@ -185,12 +197,17 @@ abstract class FilamentApp<T> {
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setRenderable(covariant View view, bool renderable);
|
||||
Future register(covariant SwapChain swapChain, covariant View view);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future register(covariant SwapChain swapChain, covariant View view);
|
||||
Future unregister(covariant SwapChain swapChain, covariant View view);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future updateRenderOrder();
|
||||
|
||||
///
|
||||
///
|
||||
@@ -239,10 +256,19 @@ abstract class FilamentApp<T> {
|
||||
Future<MaterialInstance> createImageMaterialInstance();
|
||||
|
||||
///
|
||||
/// Returns pixel buffer(s) for [view] (or, if null, all views associated
|
||||
/// with [swapChain] by calling [register]).
|
||||
///
|
||||
/// Pixel buffers will be returned in RGBA float32 format.
|
||||
///
|
||||
///
|
||||
Future<Uint8List> capture(covariant View view,
|
||||
{bool captureRenderTarget = false});
|
||||
Future<List<(View,Uint8List)>> capture(covariant SwapChain swapChain,
|
||||
{
|
||||
covariant View? view,
|
||||
bool captureRenderTarget = false,
|
||||
PixelDataFormat pixelDataFormat = PixelDataFormat.RGBA,
|
||||
PixelDataType pixelDataType = PixelDataType.UBYTE,
|
||||
Future Function(View)? beforeRender}
|
||||
);
|
||||
|
||||
///
|
||||
///
|
||||
@@ -269,5 +295,14 @@ abstract class FilamentApp<T> {
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<GizmoAsset> createGizmo(covariant View view, T animationManager, GizmoType type);
|
||||
Future<GizmoAsset> createGizmo(
|
||||
covariant View view, T animationManager, GizmoType type);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<ThermionAsset> createGeometry(Geometry geometry, T animationManager,
|
||||
{List<MaterialInstance>? materialInstances,
|
||||
bool keepData = false});
|
||||
|
||||
}
|
||||
|
||||
@@ -363,85 +363,113 @@ abstract class Texture {
|
||||
Future dispose();
|
||||
}
|
||||
|
||||
/// Pixel data format enum, representing different channel combinations
|
||||
enum PixelDataFormat {
|
||||
R,
|
||||
|
||||
/// One Red channel, float
|
||||
R_INTEGER,
|
||||
R(0),
|
||||
|
||||
/// One Red channel, integer
|
||||
RG,
|
||||
R_INTEGER(1),
|
||||
|
||||
/// Two Red and Green channels, float
|
||||
RG_INTEGER,
|
||||
RG(2),
|
||||
|
||||
/// Two Red and Green channels, integer
|
||||
RGB,
|
||||
RG_INTEGER(3),
|
||||
|
||||
/// Three Red, Green and Blue channels, float
|
||||
RGB_INTEGER,
|
||||
RGB(4),
|
||||
|
||||
/// Three Red, Green and Blue channels, integer
|
||||
RGBA,
|
||||
RGB_INTEGER(5),
|
||||
|
||||
/// Four Red, Green, Blue and Alpha channels, float
|
||||
RGBA_INTEGER,
|
||||
RGBA(6),
|
||||
|
||||
/// Four Red, Green, Blue and Alpha channels, integer
|
||||
UNUSED,
|
||||
RGBA_INTEGER(7),
|
||||
|
||||
/// Used to be rgbm
|
||||
DEPTH_COMPONENT,
|
||||
/// Unused format
|
||||
UNUSED(8),
|
||||
|
||||
/// Depth, 16-bit or 24-bits usually
|
||||
DEPTH_STENCIL,
|
||||
DEPTH_COMPONENT(9),
|
||||
|
||||
/// Two Depth (24-bits) + Stencil (8-bits) channels
|
||||
ALPHA
|
||||
DEPTH_STENCIL(10),
|
||||
|
||||
/// One Alpha channel, float
|
||||
/// Alpha channel only
|
||||
ALPHA(11);
|
||||
|
||||
/// The integer value of the enum
|
||||
final int value;
|
||||
|
||||
/// Constructor with the integer value
|
||||
const PixelDataFormat(this.value);
|
||||
|
||||
/// Factory constructor to create a PixelDataFormat from an integer value
|
||||
factory PixelDataFormat.fromValue(int value) {
|
||||
return PixelDataFormat.values.firstWhere(
|
||||
(format) => format.value == value,
|
||||
orElse: () => throw ArgumentError('Invalid PixelDataFormat value: $value'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Pixel Data Type
|
||||
/// Pixel data type enum, representing different data types for pixel values
|
||||
enum PixelDataType {
|
||||
UBYTE,
|
||||
|
||||
/// Unsigned byte
|
||||
BYTE,
|
||||
UBYTE(0),
|
||||
|
||||
/// Signed byte
|
||||
USHORT,
|
||||
BYTE(1),
|
||||
|
||||
/// Unsigned short (16-bit)
|
||||
SHORT,
|
||||
USHORT(2),
|
||||
|
||||
/// Signed short (16-bit)
|
||||
UINT,
|
||||
SHORT(3),
|
||||
|
||||
/// Unsigned int (32-bit)
|
||||
INT,
|
||||
UINT(4),
|
||||
|
||||
/// Signed int (32-bit)
|
||||
HALF,
|
||||
INT(5),
|
||||
|
||||
/// Half-float (16-bit float)
|
||||
FLOAT,
|
||||
HALF(6),
|
||||
|
||||
/// Float (32-bits float)
|
||||
COMPRESSED,
|
||||
FLOAT(7),
|
||||
|
||||
/// Compressed pixels, see CompressedPixelDataType
|
||||
UINT_10F_11F_11F_REV,
|
||||
/// Compressed pixels
|
||||
COMPRESSED(8),
|
||||
|
||||
/// Three low precision floating-point numbers
|
||||
USHORT_565,
|
||||
UINT_10F_11F_11F_REV(9),
|
||||
|
||||
/// Unsigned int (16-bit), encodes 3 RGB channels
|
||||
UINT_2_10_10_10_REV,
|
||||
USHORT_565(10),
|
||||
|
||||
/// Unsigned normalized 10 bits RGB, 2 bits alpha
|
||||
UINT_2_10_10_10_REV(11);
|
||||
|
||||
/// The integer value of the enum
|
||||
final int value;
|
||||
|
||||
/// Constructor with the integer value
|
||||
const PixelDataType(this.value);
|
||||
|
||||
/// Factory constructor to create a PixelDataType from an integer value
|
||||
factory PixelDataType.fromValue(int value) {
|
||||
return PixelDataType.values.firstWhere(
|
||||
(type) => type.value == value,
|
||||
orElse: () => throw ArgumentError('Invalid PixelDataType value: $value'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@deprecated
|
||||
typedef ThermionTexture = Texture;
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ abstract class View {
|
||||
Future setViewport(int width, int height);
|
||||
Future<RenderTarget?> getRenderTarget();
|
||||
Future setRenderTarget(covariant RenderTarget? renderTarget);
|
||||
int get renderOrder;
|
||||
Future setRenderOrder(int order);
|
||||
Future setCamera(covariant Camera camera);
|
||||
Future<Camera> getCamera();
|
||||
Future setPostProcessing(bool enabled);
|
||||
|
||||
@@ -5,8 +5,8 @@ import '../../../thermion_dart.dart';
|
||||
|
||||
class GeometryHelper {
|
||||
static Geometry fullscreenQuad() {
|
||||
final vertices = Float32List.fromList(
|
||||
[-1.0, -1.0, 1.0, 3.0, -1.0, 1.0, -1.0, 3.0, 1.0]);
|
||||
final vertices =
|
||||
Float32List.fromList([-1.0, -1.0, 1.0, 3.0, -1.0, 1.0, -1.0, 3.0, 1.0]);
|
||||
final indices = [0, 1, 2];
|
||||
return Geometry(vertices, indices);
|
||||
}
|
||||
@@ -59,7 +59,8 @@ class GeometryHelper {
|
||||
return Geometry(vertices, indices, normals: _normals, uvs: _uvs);
|
||||
}
|
||||
|
||||
static Geometry cube({bool normals = true, bool uvs = true}) {
|
||||
static Geometry cube(
|
||||
{bool normals = true, bool uvs = true, bool flipUvs = true}) {
|
||||
final vertices = Float32List.fromList([
|
||||
// Front face
|
||||
-1, -1, 1, // 0
|
||||
@@ -175,44 +176,49 @@ class GeometryHelper {
|
||||
])
|
||||
: null;
|
||||
|
||||
// Original UV coordinates
|
||||
var originalUvs = <double>[
|
||||
// front
|
||||
1 / 3, 3 / 4, // 0
|
||||
2 / 3, 3 / 4, // 1
|
||||
2 / 3, 1, // 2
|
||||
1 / 3, 1, // 3
|
||||
|
||||
// back
|
||||
1 / 3, 1 / 4, // 4
|
||||
2 / 3, 1 / 4, // 5
|
||||
2 / 3, 1 / 2, // 6
|
||||
1 / 3, 1 / 2, // 7
|
||||
|
||||
// top
|
||||
2 / 3, 1 / 2, // 8
|
||||
1, 1 / 2, // 9
|
||||
1, 3 / 4, // 10
|
||||
2 / 3, 3 / 4, // 11
|
||||
|
||||
// bottom
|
||||
0, 1 / 2, // 12
|
||||
1 / 3, 1 / 2, // 13
|
||||
1 / 3, 3 / 4, // 14
|
||||
0, 3 / 4, // 15
|
||||
|
||||
// right
|
||||
1 / 3, 1 / 2, // 16
|
||||
2 / 3, 1 / 2, // 17
|
||||
2 / 3, 3 / 4, // 18
|
||||
1 / 3, 3 / 4, // 19
|
||||
|
||||
// left
|
||||
1 / 3, 0, // 20
|
||||
2 / 3, 0, // 21
|
||||
2 / 3, 1 / 4, // 22
|
||||
1 / 3, 1 / 4 // 23
|
||||
];
|
||||
|
||||
// Apply UV flipping if requested
|
||||
final _uvs = uvs
|
||||
? Float32List.fromList([
|
||||
// front
|
||||
1 / 3, 3 / 4, // 0
|
||||
2 / 3, 3 / 4, // 1
|
||||
2 / 3, 1, // 2
|
||||
1 / 3, 1, // 3
|
||||
|
||||
// back
|
||||
1 / 3, 1 / 4, // 4
|
||||
2 / 3, 1 / 4, // 5
|
||||
2 / 3, 1 / 2, // 6
|
||||
1 / 3, 1 / 2, // 7
|
||||
|
||||
// top
|
||||
2 / 3, 1 / 2, // 8
|
||||
1, 1 / 2, // 9
|
||||
1, 3 / 4, // 10
|
||||
2 / 3, 3 / 4, // 11
|
||||
|
||||
// bottom
|
||||
0, 1 / 2, // 12
|
||||
1 / 3, 1 / 2, // 13
|
||||
1 / 3, 3 / 4, // 14
|
||||
0, 3 / 4, // 15
|
||||
|
||||
// right
|
||||
1 / 3, 1 / 2, // 16
|
||||
2 / 3, 1 / 2, // 17
|
||||
2 / 3, 3 / 4, // 18
|
||||
1 / 3, 3 / 4, // 19
|
||||
|
||||
// left
|
||||
1 / 3, 0, // 20
|
||||
2 / 3, 0, // 21
|
||||
2 / 3, 1 / 4, // 22
|
||||
1 / 3, 1 / 4 // 23
|
||||
])
|
||||
? Float32List.fromList(
|
||||
flipUvs ? _flipUvCoordinates(originalUvs) : originalUvs)
|
||||
: null;
|
||||
|
||||
final indices = [
|
||||
@@ -229,9 +235,19 @@ class GeometryHelper {
|
||||
// Left face
|
||||
20, 21, 22, 20, 22, 23 // 4,0,3,4,3,7
|
||||
];
|
||||
|
||||
return Geometry(vertices, indices, normals: _normals, uvs: _uvs);
|
||||
}
|
||||
|
||||
// Helper function to flip the Y coordinate of UV coordinates (y = 1.0 - y)
|
||||
static List<double> _flipUvCoordinates(List<double> uvs) {
|
||||
var flippedUvs = List<double>.from(uvs);
|
||||
for (var i = 1; i < flippedUvs.length; i += 2) {
|
||||
flippedUvs[i] = 1.0 - flippedUvs[i];
|
||||
}
|
||||
return flippedUvs;
|
||||
}
|
||||
|
||||
static Geometry cylinder(
|
||||
{double radius = 1.0,
|
||||
double length = 1.0,
|
||||
|
||||
@@ -2,8 +2,8 @@ import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
import 'package:image/image.dart' as img;
|
||||
|
||||
Future<Uint8List> pixelBufferToBmp(
|
||||
Uint8List pixelBuffer, int width, int height) async {
|
||||
Future<Uint8List> pixelBufferToBmp(Uint8List pixelBuffer, int width, int height,
|
||||
{bool hasAlpha = true, bool isFloat = false}) async {
|
||||
final rowSize = (width * 3 + 3) & ~3;
|
||||
final padding = rowSize - (width * 3);
|
||||
final fileSize = 54 + rowSize * height;
|
||||
@@ -28,14 +28,29 @@ Future<Uint8List> pixelBufferToBmp(
|
||||
bd.setInt32(38, 2835, Endian.little); // X pixels per meter
|
||||
bd.setInt32(42, 2835, Endian.little); // Y pixels per meter
|
||||
|
||||
Float32List? floatData;
|
||||
|
||||
if (isFloat) {
|
||||
floatData = pixelBuffer.buffer.asFloat32List(
|
||||
pixelBuffer.offsetInBytes, width * height * (hasAlpha ? 4 : 3));
|
||||
}
|
||||
|
||||
// Pixel data (BMP stores in BGR format)
|
||||
for (var y = 0; y < height; y++) {
|
||||
for (var x = 0; x < width; x++) {
|
||||
final srcIndex = (y * width + x) * 4; // RGBA format
|
||||
final srcIndex = (y * width + x) * (hasAlpha ? 4 : 3); // RGBA format
|
||||
final dstIndex = 54 + y * rowSize + x * 3; // BGR format
|
||||
data[dstIndex] = pixelBuffer[srcIndex + 2]; // Blue
|
||||
data[dstIndex + 1] = pixelBuffer[srcIndex + 1]; // Green
|
||||
data[dstIndex + 2] = pixelBuffer[srcIndex]; // Red
|
||||
|
||||
data[dstIndex] = isFloat
|
||||
? (floatData![srcIndex + 2] * 255).toInt()
|
||||
: pixelBuffer[srcIndex + 2]; // Blue
|
||||
data[dstIndex + 1] = isFloat
|
||||
? (floatData![srcIndex + 1] * 255).toInt()
|
||||
: pixelBuffer[srcIndex + 1]; // Green
|
||||
data[dstIndex + 2] = isFloat
|
||||
? (floatData![srcIndex] * 255).toInt()
|
||||
: pixelBuffer[srcIndex]; // Red
|
||||
|
||||
// Alpha channel is discarded
|
||||
}
|
||||
// Add padding to the end of each row
|
||||
|
||||
@@ -342,4 +342,10 @@ class BackgroundImage extends ThermionAsset {
|
||||
// TODO: implement transformToUnitCube
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MaterialInstance> getMaterialInstanceAt({ThermionEntity? entity, int index = 0}) {
|
||||
// TODO: implement getMaterialInstanceAt
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,6 +370,14 @@ class FFIAsset extends ThermionAsset {
|
||||
// }
|
||||
}
|
||||
|
||||
Future<MaterialInstance> getMaterialInstanceAt(
|
||||
{ThermionEntity? entity, int index = 0}) async {
|
||||
entity ??= this.entity;
|
||||
var ptr = RenderableManager_getMaterialInstanceAt(
|
||||
Engine_getRenderableManager(app.engine), entity, 0);
|
||||
return FFIMaterialInstance(ptr, app);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
|
||||
@@ -120,12 +120,7 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setRenderable(covariant FFIView view, bool renderable) async {
|
||||
await view.setRenderable(renderable);
|
||||
await _updateRenderableSwapChains();
|
||||
}
|
||||
|
||||
Future _updateRenderableSwapChains() async {
|
||||
Future updateRenderOrder() async {
|
||||
for (final swapChain in _swapChains.keys) {
|
||||
final views = _swapChains[swapChain];
|
||||
if (views == null) {
|
||||
@@ -174,6 +169,28 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
|
||||
return FFISwapChain(swapChain);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<View> createView() async {
|
||||
final view = await FFIView(
|
||||
await withPointerCallback<TView>(
|
||||
(cb) => Engine_createViewRenderThread(engine, cb)),
|
||||
this);
|
||||
await view.setFrustumCullingEnabled(true);
|
||||
View_setBlendMode(view.view, TBlendMode.TRANSLUCENT);
|
||||
View_setShadowsEnabled(view.view, false);
|
||||
View_setStencilBufferEnabled(view.view, false);
|
||||
View_setAntiAliasing(view.view, false, false, false);
|
||||
View_setDitheringEnabled(view.view, false);
|
||||
View_setRenderQuality(view.view, TQualityLevel.MEDIUM);
|
||||
return view;
|
||||
}
|
||||
|
||||
Future<Scene> createScene() async {
|
||||
return FFIScene(Engine_createScene(engine));
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@@ -195,7 +212,7 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
|
||||
continue;
|
||||
}
|
||||
for (final view in _swapChains[swapChain]!) {
|
||||
await setRenderable(view, false);
|
||||
await view.setRenderable(false);
|
||||
}
|
||||
}
|
||||
for (final swapChain in _swapChains.keys.toList()) {
|
||||
@@ -224,10 +241,30 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
|
||||
///
|
||||
Future<RenderTarget> createRenderTarget(int width, int height,
|
||||
{covariant FFITexture? color, covariant FFITexture? depth}) async {
|
||||
if (color == null) {
|
||||
color = await createTexture(width, height,
|
||||
flags: {
|
||||
TextureUsage.TEXTURE_USAGE_SAMPLEABLE,
|
||||
TextureUsage.TEXTURE_USAGE_COLOR_ATTACHMENT,
|
||||
TextureUsage.TEXTURE_USAGE_BLIT_SRC
|
||||
},
|
||||
textureFormat: TextureFormat.RGBA8) as FFITexture;
|
||||
}
|
||||
if (depth == null) {
|
||||
depth = await createTexture(width, height,
|
||||
flags: {
|
||||
TextureUsage.TEXTURE_USAGE_SAMPLEABLE,
|
||||
TextureUsage.TEXTURE_USAGE_DEPTH_ATTACHMENT
|
||||
},
|
||||
textureFormat: TextureFormat.DEPTH32F) as FFITexture;
|
||||
}
|
||||
final renderTarget = await withPointerCallback<TRenderTarget>((cb) {
|
||||
RenderTarget_createRenderThread(engine, width, height,
|
||||
color?.pointer ?? nullptr, depth?.pointer ?? nullptr, cb);
|
||||
RenderTarget_createRenderThread(
|
||||
engine, width, height, color!.pointer, depth!.pointer, cb);
|
||||
});
|
||||
if (renderTarget == nullptr) {
|
||||
throw Exception("Failed to create RenderTarget");
|
||||
}
|
||||
|
||||
return FFIRenderTarget(renderTarget, this);
|
||||
}
|
||||
@@ -488,7 +525,24 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
|
||||
_swapChains[swapChain] = [];
|
||||
}
|
||||
_swapChains[swapChain]!.add(view);
|
||||
await _updateRenderableSwapChains();
|
||||
_swapChains[swapChain]!
|
||||
.sort((a, b) => a.renderOrder.compareTo(b.renderOrder));
|
||||
await updateRenderOrder();
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future unregister(
|
||||
covariant FFISwapChain swapChain, covariant FFIView view) async {
|
||||
if (!_swapChains.containsKey(swapChain)) {
|
||||
_swapChains[swapChain] = [];
|
||||
}
|
||||
_swapChains[swapChain]!.remove(view);
|
||||
_swapChains[swapChain]!
|
||||
.sort((a, b) => a.renderOrder.compareTo(b.renderOrder));
|
||||
await updateRenderOrder();
|
||||
}
|
||||
|
||||
final _hooks = <Future Function()>[];
|
||||
@@ -603,38 +657,59 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<Uint8List> capture(covariant FFIView view,
|
||||
{bool captureRenderTarget = false}) async {
|
||||
final viewport = await view.getViewport();
|
||||
final swapChain = _swapChains.keys
|
||||
.firstWhere((x) => _swapChains[x]?.contains(view) == true);
|
||||
final out = Uint8List(viewport.width * viewport.height * 4);
|
||||
Future<List<(View, Uint8List)>> capture(covariant FFISwapChain swapChain,
|
||||
{covariant FFIView? view,
|
||||
bool captureRenderTarget = false,
|
||||
PixelDataFormat pixelDataFormat = PixelDataFormat.RGBA,
|
||||
PixelDataType pixelDataType = PixelDataType.FLOAT,
|
||||
Future Function(View)? beforeRender}) async {
|
||||
await updateRenderOrder();
|
||||
|
||||
await withBoolCallback((cb) {
|
||||
Renderer_beginFrameRenderThread(renderer, swapChain.swapChain, 0, cb);
|
||||
});
|
||||
await withVoidCallback((cb) {
|
||||
Renderer_renderRenderThread(
|
||||
renderer,
|
||||
view.view,
|
||||
cb,
|
||||
);
|
||||
});
|
||||
|
||||
if (captureRenderTarget && view.renderTarget == null) {
|
||||
throw Exception();
|
||||
final views = <FFIView>[];
|
||||
if (view != null) {
|
||||
views.add(view);
|
||||
} else {
|
||||
views.addAll(_swapChains[swapChain]!);
|
||||
}
|
||||
await withVoidCallback((cb) {
|
||||
Renderer_readPixelsRenderThread(
|
||||
renderer,
|
||||
view.view,
|
||||
captureRenderTarget ? view.renderTarget!.renderTarget : nullptr,
|
||||
TPixelDataFormat.PIXELDATAFORMAT_RGBA,
|
||||
TPixelDataType.PIXELDATATYPE_UBYTE,
|
||||
out.address,
|
||||
cb,
|
||||
);
|
||||
});
|
||||
|
||||
final pixelBuffers = <(View, Uint8List)>[];
|
||||
|
||||
for (final view in views) {
|
||||
beforeRender?.call(view);
|
||||
|
||||
final viewport = await view.getViewport();
|
||||
final pixelBuffer = Uint8List(viewport.width * viewport.height * 4 * sizeOf<Float>());
|
||||
await withVoidCallback((cb) {
|
||||
Renderer_renderRenderThread(
|
||||
renderer,
|
||||
view.view,
|
||||
cb,
|
||||
);
|
||||
});
|
||||
|
||||
if (captureRenderTarget && view.renderTarget == null) {
|
||||
throw Exception();
|
||||
}
|
||||
await withVoidCallback((cb) {
|
||||
Renderer_readPixelsRenderThread(
|
||||
renderer,
|
||||
view.view,
|
||||
view.renderTarget == null ? nullptr : view.renderTarget!.renderTarget,
|
||||
// TPixelDataFormat.PIXELDATAFORMAT_RGBA,
|
||||
// TPixelDataType.PIXELDATATYPE_UBYTE,
|
||||
pixelDataFormat.value,
|
||||
pixelDataType.value,
|
||||
pixelBuffer.address,
|
||||
pixelBuffer.length,
|
||||
cb
|
||||
);
|
||||
});
|
||||
pixelBuffers.add((view, pixelBuffer));
|
||||
}
|
||||
|
||||
await withVoidCallback((cb) {
|
||||
Renderer_endFrameRenderThread(renderer, cb);
|
||||
});
|
||||
@@ -642,7 +717,7 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
|
||||
await withVoidCallback((cb) {
|
||||
Engine_flushAndWaitRenderThead(engine, cb);
|
||||
});
|
||||
return out;
|
||||
return pixelBuffers;
|
||||
}
|
||||
|
||||
///
|
||||
@@ -761,8 +836,15 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
|
||||
(cb) => GltfResourceLoader_createRenderThread(engine, nullptr, cb));
|
||||
|
||||
final gizmo = await withPointerCallback<TGizmo>((cb) {
|
||||
Gizmo_createRenderThread(engine, gltfAssetLoader, gltfResourceLoader, nameComponentManager,
|
||||
view.view, _gizmoMaterial!.pointer, TGizmoType.values[gizmoType.index], cb);
|
||||
Gizmo_createRenderThread(
|
||||
engine,
|
||||
gltfAssetLoader,
|
||||
gltfResourceLoader,
|
||||
nameComponentManager,
|
||||
view.view,
|
||||
_gizmoMaterial!.pointer,
|
||||
TGizmoType.values[gizmoType.index],
|
||||
cb);
|
||||
});
|
||||
if (gizmo == nullptr) {
|
||||
throw Exception("Failed to create gizmo");
|
||||
@@ -779,6 +861,48 @@ class FFIFilamentApp extends FilamentApp<Pointer> {
|
||||
entities: gizmoEntities.toSet()
|
||||
..add(SceneAsset_getEntity(gizmo.cast<TSceneAsset>())));
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future<ThermionAsset> createGeometry(Geometry geometry, Pointer animationManager,
|
||||
{List<MaterialInstance>? materialInstances,
|
||||
bool keepData = false,
|
||||
bool addToScene = true}) async {
|
||||
var assetPtr = await withPointerCallback<TSceneAsset>((callback) {
|
||||
var ptrList = Int64List(materialInstances?.length ?? 0);
|
||||
if (materialInstances != null && materialInstances.isNotEmpty) {
|
||||
ptrList.setRange(
|
||||
0,
|
||||
materialInstances.length,
|
||||
materialInstances
|
||||
.cast<FFIMaterialInstance>()
|
||||
.map((mi) => mi.pointer.address)
|
||||
.toList());
|
||||
}
|
||||
|
||||
return SceneAsset_createGeometryRenderThread(
|
||||
engine,
|
||||
geometry.vertices.address,
|
||||
geometry.vertices.length,
|
||||
geometry.normals.address,
|
||||
geometry.normals.length,
|
||||
geometry.uvs.address,
|
||||
geometry.uvs.length,
|
||||
geometry.indices.address,
|
||||
geometry.indices.length,
|
||||
geometry.primitiveType.index,
|
||||
ptrList.address.cast<Pointer<TMaterialInstance>>(),
|
||||
ptrList.length,
|
||||
callback);
|
||||
});
|
||||
if (assetPtr == nullptr) {
|
||||
throw Exception("Failed to create geometry");
|
||||
}
|
||||
|
||||
return FFIAsset(assetPtr, this, animationManager.cast<TAnimationManager>());
|
||||
}
|
||||
}
|
||||
|
||||
class FinalizableUint8List implements Finalizable {
|
||||
|
||||
@@ -9,6 +9,9 @@ import 'callbacks.dart';
|
||||
import 'ffi_camera.dart';
|
||||
|
||||
class FFIView extends View {
|
||||
int _renderOrder = 0;
|
||||
int get renderOrder => _renderOrder;
|
||||
|
||||
final Pointer<TView> view;
|
||||
final FFIFilamentApp app;
|
||||
|
||||
@@ -24,6 +27,17 @@ class FFIView extends View {
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setRenderOrder(int order) async {
|
||||
this._renderOrder = order;
|
||||
await FilamentApp.instance!.updateRenderOrder();
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setRenderable(bool renderable) async {
|
||||
this._renderable = renderable;
|
||||
}
|
||||
@@ -138,6 +152,10 @@ class FFIView extends View {
|
||||
View_setLayerEnabled(view, layer.value, visible);
|
||||
}
|
||||
|
||||
Future setBlendMode(TBlendMode blendMode) async {
|
||||
View_setBlendMode(view, blendMode);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Scene> getScene() async {
|
||||
final ptr = View_getScene(view);
|
||||
|
||||
@@ -659,6 +659,12 @@ external void View_setScene(
|
||||
ffi.Pointer<TScene> tScene,
|
||||
);
|
||||
|
||||
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Bool)>(isLeaf: true)
|
||||
external void View_setFrontFaceWindingInverted(
|
||||
ffi.Pointer<TView> tView,
|
||||
bool inverted,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Void Function(ffi.Pointer<TView>, ffi.Uint32, ffi.Uint32, ffi.Uint32,
|
||||
PickCallback)>(isLeaf: true)
|
||||
@@ -1471,7 +1477,8 @@ external void Renderer_renderStandaloneView(
|
||||
ffi.Pointer<TRenderTarget>,
|
||||
ffi.Int,
|
||||
ffi.Int,
|
||||
ffi.Pointer<ffi.Uint8>)>(isLeaf: true)
|
||||
ffi.Pointer<ffi.Uint8>,
|
||||
ffi.Size)>(isLeaf: true)
|
||||
external void Renderer_readPixels(
|
||||
ffi.Pointer<TRenderer> tRenderer,
|
||||
ffi.Pointer<TView> tView,
|
||||
@@ -1479,6 +1486,7 @@ external void Renderer_readPixels(
|
||||
int tPixelBufferFormat,
|
||||
int tPixelDataType,
|
||||
ffi.Pointer<ffi.Uint8> out,
|
||||
int outLength,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
@@ -1976,6 +1984,7 @@ external void Renderer_renderStandaloneViewRenderThread(
|
||||
ffi.UnsignedInt,
|
||||
ffi.UnsignedInt,
|
||||
ffi.Pointer<ffi.Uint8>,
|
||||
ffi.Size,
|
||||
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
|
||||
external void Renderer_readPixelsRenderThread(
|
||||
ffi.Pointer<TRenderer> tRenderer,
|
||||
@@ -1984,6 +1993,7 @@ external void Renderer_readPixelsRenderThread(
|
||||
int tPixelBufferFormat,
|
||||
int tPixelDataType,
|
||||
ffi.Pointer<ffi.Uint8> out,
|
||||
int outLength,
|
||||
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>> onComplete,
|
||||
);
|
||||
|
||||
|
||||
@@ -79,20 +79,11 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
|
||||
Future _initialize() async {
|
||||
_logger.info("Initializing ThermionViewerFFI");
|
||||
view = FFIView(
|
||||
await withPointerCallback<TView>(
|
||||
(cb) => Engine_createViewRenderThread(app.engine, cb)),
|
||||
app);
|
||||
await view.setFrustumCullingEnabled(true);
|
||||
View_setBlendMode(view.view, TBlendMode.TRANSLUCENT);
|
||||
View_setShadowsEnabled(view.view, false);
|
||||
View_setStencilBufferEnabled(view.view, false);
|
||||
View_setAntiAliasing(view.view, false, false, false);
|
||||
View_setDitheringEnabled(view.view, false);
|
||||
View_setRenderQuality(view.view, TQualityLevel.MEDIUM);
|
||||
view = await FilamentApp.instance!.createView() as FFIView;
|
||||
|
||||
await FilamentApp.instance!.setClearOptions(0.0, 0.0, 0.0, 0.0);
|
||||
scene = FFIScene(Engine_createScene(app.engine));
|
||||
scene = await FilamentApp.instance!.createScene() as FFIScene;
|
||||
|
||||
await view.setScene(scene);
|
||||
final camera = FFICamera(
|
||||
await withPointerCallback<TCamera>(
|
||||
@@ -125,7 +116,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
@override
|
||||
Future setRendering(bool render) async {
|
||||
_rendering = render;
|
||||
await app.setRenderable(view, render);
|
||||
await view.setRenderable(render);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -684,38 +675,9 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
{List<MaterialInstance>? materialInstances,
|
||||
bool keepData = false,
|
||||
bool addToScene = true}) async {
|
||||
var assetPtr = await withPointerCallback<TSceneAsset>((callback) {
|
||||
var ptrList = Int64List(materialInstances?.length ?? 0);
|
||||
if (materialInstances != null && materialInstances.isNotEmpty) {
|
||||
ptrList.setRange(
|
||||
0,
|
||||
materialInstances.length,
|
||||
materialInstances
|
||||
.cast<FFIMaterialInstance>()
|
||||
.map((mi) => mi.pointer.address)
|
||||
.toList());
|
||||
}
|
||||
final asset =
|
||||
await FilamentApp.instance!.createGeometry(geometry, animationManager, materialInstances: materialInstances) as FFIAsset;
|
||||
|
||||
return SceneAsset_createGeometryRenderThread(
|
||||
app.engine,
|
||||
geometry.vertices.address,
|
||||
geometry.vertices.length,
|
||||
geometry.normals.address,
|
||||
geometry.normals.length,
|
||||
geometry.uvs.address,
|
||||
geometry.uvs.length,
|
||||
geometry.indices.address,
|
||||
geometry.indices.length,
|
||||
geometry.primitiveType.index,
|
||||
ptrList.address.cast<Pointer<TMaterialInstance>>(),
|
||||
ptrList.length,
|
||||
callback);
|
||||
});
|
||||
if (assetPtr == nullptr) {
|
||||
throw Exception("Failed to create geometry");
|
||||
}
|
||||
|
||||
var asset = FFIAsset(assetPtr, app, animationManager);
|
||||
if (addToScene) {
|
||||
await scene.add(asset);
|
||||
}
|
||||
@@ -730,8 +692,8 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
@override
|
||||
Future<GizmoAsset> getGizmo(GizmoType gizmoType) async {
|
||||
if (_gizmos[gizmoType] == null) {
|
||||
_gizmos[gizmoType] =
|
||||
await FilamentApp.instance!.createGizmo(view, animationManager, gizmoType);
|
||||
_gizmos[gizmoType] = await FilamentApp.instance!
|
||||
.createGizmo(view, animationManager, gizmoType);
|
||||
}
|
||||
return _gizmos[gizmoType]!;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user