fix texture/material methods

This commit is contained in:
Nick Fisher
2025-03-03 15:52:03 +08:00
parent 2a8931e1ac
commit 8d52690c97
10 changed files with 742 additions and 163 deletions

View File

@@ -1,4 +1,5 @@
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_texture.dart';
import 'package:thermion_dart/thermion_dart.dart';
class FFIMaterial extends Material {
@@ -149,4 +150,11 @@ class FFIMaterialInstance extends MaterialInstance {
MaterialInstance_setTransparencyMode(
pointer, TTransparencyMode.values[mode.index]);
}
@override
Future setParameterTexture(String name, covariant FFITexture texture,
covariant FFITextureSampler sampler) async {
MaterialInstance_setParameterTexture(
pointer, name.toNativeUtf8().cast<Char>(), texture.pointer, sampler.pointer);
}
}

View File

@@ -949,6 +949,166 @@ external int Image_getChannels(
ffi.Pointer<TLinearImage> tLinearImage,
);
@ffi.Native<ffi.Pointer<TTextureSampler> Function()>(isLeaf: true)
external ffi.Pointer<TTextureSampler> TextureSampler_create();
@ffi.Native<
ffi.Pointer<TTextureSampler> Function(ffi.UnsignedInt, ffi.UnsignedInt,
ffi.UnsignedInt, ffi.UnsignedInt, ffi.UnsignedInt)>(
symbol: "TextureSampler_createWithFiltering", isLeaf: true)
external ffi.Pointer<TTextureSampler> _TextureSampler_createWithFiltering(
int minFilter,
int magFilter,
int wrapS,
int wrapT,
int wrapR,
);
ffi.Pointer<TTextureSampler> TextureSampler_createWithFiltering(
TSamplerMinFilter minFilter,
TSamplerMagFilter magFilter,
TSamplerWrapMode wrapS,
TSamplerWrapMode wrapT,
TSamplerWrapMode wrapR,
) =>
_TextureSampler_createWithFiltering(
minFilter.value,
magFilter.value,
wrapS.value,
wrapT.value,
wrapR.value,
);
@ffi.Native<
ffi.Pointer<TTextureSampler> Function(
ffi.UnsignedInt, ffi.UnsignedInt)>(
symbol: "TextureSampler_createWithComparison", isLeaf: true)
external ffi.Pointer<TTextureSampler> _TextureSampler_createWithComparison(
int compareMode,
int compareFunc,
);
ffi.Pointer<TTextureSampler> TextureSampler_createWithComparison(
TSamplerCompareMode compareMode,
TSamplerCompareFunc compareFunc,
) =>
_TextureSampler_createWithComparison(
compareMode.value,
compareFunc.value,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TTextureSampler>, ffi.UnsignedInt)>(
symbol: "TextureSampler_setMinFilter", isLeaf: true)
external void _TextureSampler_setMinFilter(
ffi.Pointer<TTextureSampler> sampler,
int filter,
);
void TextureSampler_setMinFilter(
ffi.Pointer<TTextureSampler> sampler,
TSamplerMinFilter filter,
) =>
_TextureSampler_setMinFilter(
sampler,
filter.value,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TTextureSampler>, ffi.UnsignedInt)>(
symbol: "TextureSampler_setMagFilter", isLeaf: true)
external void _TextureSampler_setMagFilter(
ffi.Pointer<TTextureSampler> sampler,
int filter,
);
void TextureSampler_setMagFilter(
ffi.Pointer<TTextureSampler> sampler,
TSamplerMagFilter filter,
) =>
_TextureSampler_setMagFilter(
sampler,
filter.value,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TTextureSampler>, ffi.UnsignedInt)>(
symbol: "TextureSampler_setWrapModeS", isLeaf: true)
external void _TextureSampler_setWrapModeS(
ffi.Pointer<TTextureSampler> sampler,
int mode,
);
void TextureSampler_setWrapModeS(
ffi.Pointer<TTextureSampler> sampler,
TSamplerWrapMode mode,
) =>
_TextureSampler_setWrapModeS(
sampler,
mode.value,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TTextureSampler>, ffi.UnsignedInt)>(
symbol: "TextureSampler_setWrapModeT", isLeaf: true)
external void _TextureSampler_setWrapModeT(
ffi.Pointer<TTextureSampler> sampler,
int mode,
);
void TextureSampler_setWrapModeT(
ffi.Pointer<TTextureSampler> sampler,
TSamplerWrapMode mode,
) =>
_TextureSampler_setWrapModeT(
sampler,
mode.value,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TTextureSampler>, ffi.UnsignedInt)>(
symbol: "TextureSampler_setWrapModeR", isLeaf: true)
external void _TextureSampler_setWrapModeR(
ffi.Pointer<TTextureSampler> sampler,
int mode,
);
void TextureSampler_setWrapModeR(
ffi.Pointer<TTextureSampler> sampler,
TSamplerWrapMode mode,
) =>
_TextureSampler_setWrapModeR(
sampler,
mode.value,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TTextureSampler>, ffi.Double)>(
isLeaf: true)
external void TextureSampler_setAnisotropy(
ffi.Pointer<TTextureSampler> sampler,
double anisotropy,
);
@ffi.Native<
ffi.Void Function(ffi.Pointer<TTextureSampler>, ffi.UnsignedInt,
ffi.UnsignedInt)>(symbol: "TextureSampler_setCompareMode", isLeaf: true)
external void _TextureSampler_setCompareMode(
ffi.Pointer<TTextureSampler> sampler,
int mode,
int func,
);
void TextureSampler_setCompareMode(
ffi.Pointer<TTextureSampler> sampler,
TSamplerCompareMode mode,
TSamplerCompareFunc func,
) =>
_TextureSampler_setCompareMode(
sampler,
mode.value,
func.value,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TTextureSampler>)>(isLeaf: true)
external void TextureSampler_destroy(
ffi.Pointer<TTextureSampler> sampler,
);
@ffi.Native<
ffi.Void Function(ffi.Pointer<TGizmo>, ffi.Uint32, ffi.Uint32,
GizmoPickCallback)>(isLeaf: true)
@@ -3596,6 +3756,73 @@ enum TPixelDataType {
};
}
enum TSamplerWrapMode {
WRAP_CLAMP_TO_EDGE(0),
WRAP_REPEAT(1),
WRAP_MIRRORED_REPEAT(2);
final int value;
const TSamplerWrapMode(this.value);
static TSamplerWrapMode fromValue(int value) => switch (value) {
0 => WRAP_CLAMP_TO_EDGE,
1 => WRAP_REPEAT,
2 => WRAP_MIRRORED_REPEAT,
_ => throw ArgumentError("Unknown value for TSamplerWrapMode: $value"),
};
}
enum TSamplerMinFilter {
FILTER_NEAREST(0),
FILTER_LINEAR(1),
FILTER_NEAREST_MIPMAP_NEAREST(2),
FILTER_LINEAR_MIPMAP_NEAREST(3),
FILTER_NEAREST_MIPMAP_LINEAR(4),
FILTER_LINEAR_MIPMAP_LINEAR(5);
final int value;
const TSamplerMinFilter(this.value);
static TSamplerMinFilter fromValue(int value) => switch (value) {
0 => FILTER_NEAREST,
1 => FILTER_LINEAR,
2 => FILTER_NEAREST_MIPMAP_NEAREST,
3 => FILTER_LINEAR_MIPMAP_NEAREST,
4 => FILTER_NEAREST_MIPMAP_LINEAR,
5 => FILTER_LINEAR_MIPMAP_LINEAR,
_ => throw ArgumentError("Unknown value for TSamplerMinFilter: $value"),
};
}
enum TSamplerMagFilter {
MAG_FILTER_NEAREST(0),
MAG_FILTER_LINEAR(1);
final int value;
const TSamplerMagFilter(this.value);
static TSamplerMagFilter fromValue(int value) => switch (value) {
0 => MAG_FILTER_NEAREST,
1 => MAG_FILTER_LINEAR,
_ => throw ArgumentError("Unknown value for TSamplerMagFilter: $value"),
};
}
enum TSamplerCompareMode {
COMPARE_MODE_NONE(0),
COMPARE_MODE_COMPARE_TO_TEXTURE(1);
final int value;
const TSamplerCompareMode(this.value);
static TSamplerCompareMode fromValue(int value) => switch (value) {
0 => COMPARE_MODE_NONE,
1 => COMPARE_MODE_COMPARE_TO_TEXTURE,
_ =>
throw ArgumentError("Unknown value for TSamplerCompareMode: $value"),
};
}
enum TGizmoAxis {
X(0),
Y(1),

View File

@@ -1865,6 +1865,38 @@ class ThermionViewerFFI extends ThermionViewer {
);
}
Future<TextureSampler> createTextureSampler(
{TextureMinFilter minFilter = TextureMinFilter.LINEAR,
TextureMagFilter magFilter = TextureMagFilter.LINEAR,
TextureWrapMode wrapS = TextureWrapMode.CLAMP_TO_EDGE,
TextureWrapMode wrapT = TextureWrapMode.CLAMP_TO_EDGE,
TextureWrapMode wrapR = TextureWrapMode.CLAMP_TO_EDGE,
double anisotropy = 0.0,
TextureCompareMode compareMode = TextureCompareMode.NONE,
TextureCompareFunc compareFunc = TextureCompareFunc.LESS_EQUAL}) async {
final samplerPtr = TextureSampler_create();
TextureSampler_setMinFilter(
samplerPtr, TSamplerMinFilter.values[minFilter.index]);
TextureSampler_setMagFilter(
samplerPtr, TSamplerMagFilter.values[magFilter.index]);
TextureSampler_setWrapModeS(
samplerPtr, TSamplerWrapMode.values[wrapS.index]);
TextureSampler_setWrapModeT(
samplerPtr, TSamplerWrapMode.values[wrapT.index]);
TextureSampler_setWrapModeR(
samplerPtr, TSamplerWrapMode.values[wrapR.index]);
if (anisotropy > 0) {
TextureSampler_setAnisotropy(samplerPtr, anisotropy);
}
if (compareMode != TextureCompareMode.NONE) {
TextureSampler_setCompareMode(
samplerPtr,
TSamplerCompareMode.values[compareMode.index],
TSamplerCompareFunc.values[compareFunc.index]);
}
return FFITextureSampler(samplerPtr);
}
Future<LinearImage> decodeImage(Uint8List data) async {
final name = "image";
var ptr = Image_decode(

View File

@@ -1,3 +1,5 @@
import 'package:thermion_dart/thermion_dart.dart';
enum SamplerCompareFunction {
/// !< Less or equal
LE,
@@ -70,27 +72,23 @@ enum StencilFace {
FRONT_AND_BACK
}
enum AlphaMode {
OPAQUE,
MASK,
BLEND
}
enum AlphaMode { OPAQUE, MASK, BLEND }
enum TransparencyMode {
//! the transparent object is drawn honoring the raster state
DEFAULT,
/**
enum TransparencyMode {
//! the transparent object is drawn honoring the raster state
DEFAULT,
/**
* the transparent object is first drawn in the depth buffer,
* then in the color buffer, honoring the culling mode, but ignoring the depth test function
*/
TWO_PASSES_ONE_SIDE,
TWO_PASSES_ONE_SIDE,
/**
/**
* the transparent object is drawn twice in the color buffer,
* first with back faces only, then with front faces; the culling
* mode is ignored. Can be combined with two-sided lighting
*/
TWO_PASSES_TWO_SIDES
TWO_PASSES_TWO_SIDES
}
abstract class Material {
@@ -108,6 +106,8 @@ abstract class MaterialInstance {
Future setParameterFloat2(String name, double x, double y);
Future setParameterFloat(String name, double x);
Future setParameterInt(String name, int value);
Future setParameterTexture(
String name, covariant Texture texture, covariant TextureSampler sampler);
/// Sets the stencil operation to be performed when the stencil test fails
Future setStencilOpStencilFail(StencilOperation op,

View File

@@ -1,5 +1,6 @@
import 'dart:typed_data';
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart';
import 'package:thermion_dart/thermion_dart.dart';
/// Defines the type of sampler to use with a texture
@@ -173,40 +174,82 @@ enum TextureUsage {
SAMPLEABLE
}
/// Defines texture filter types for magnification and minification
enum TextureFilter {
/// Defines texture wrapping modes for texture coordinates
enum TextureWrapMode {
/// Clamps texture coordinates to edge, extending edge pixels
CLAMP_TO_EDGE,
/// Repeats the texture (tiles)
REPEAT,
/// Mirrors the texture at each repeat
MIRRORED_REPEAT
}
/// Defines texture minification filter types
enum TextureMinFilter {
/// Nearest neighbor sampling (pixelated look)
NEAREST,
/// Linear interpolation between texels
LINEAR,
/// Nearest neighbor filtering but uses mipmaps for minification
/// Nearest neighbor filtering with nearest mipmap
NEAREST_MIPMAP_NEAREST,
/// Linear filtering and uses nearest mipmap level
/// Linear filtering with nearest mipmap
LINEAR_MIPMAP_NEAREST,
/// Nearest filtering but linearly interpolates between mipmap levels
/// Nearest filtering with linear mipmap interpolation
NEAREST_MIPMAP_LINEAR,
/// Linear filtering and linear interpolation between mipmap levels (best quality)
/// Linear filtering with linear mipmap interpolation (best quality)
LINEAR_MIPMAP_LINEAR
}
/// Defines texture wrapping modes for when texture coordinates exceed [0,1]
enum TextureWrapMode {
/// Repeats the texture (tiles)
REPEAT,
/// Defines texture magnification filter types
enum TextureMagFilter {
/// Nearest neighbor sampling (pixelated look)
NEAREST,
/// Mirrors the texture at each repeat
MIRRORED_REPEAT,
/// Linear interpolation between texels
LINEAR
}
/// Clamps texture coordinates to edge, extending edge pixels
CLAMP_TO_EDGE,
/// Defines texture comparison modes
enum TextureCompareMode {
/// No comparison is performed
NONE,
/// Clamps to border color (usually transparent or black)
CLAMP_TO_BORDER
/// Compare texture values to reference value
COMPARE_TO_TEXTURE
}
/// Defines texture comparison functions
enum TextureCompareFunc {
/// Less than or equal
LESS_EQUAL,
/// Greater than or equal
GREATER_EQUAL,
/// Less than
LESS,
/// Greater than
GREATER,
/// Equal
EQUAL,
/// Not equal
NOT_EQUAL,
/// Always passes
ALWAYS,
/// Never passes
NEVER
}
/// Defines swizzle operations for texture components
@@ -235,20 +278,6 @@ enum TextureSwizzle {
/// Defines the texture sampler configuration
abstract class TextureSampler {
/// Creates a new texture sampler with specified filtering and wrapping modes
Future<TextureSampler> create(TextureFilter minFilter,
TextureFilter magFilter, TextureWrapMode wrapS, TextureWrapMode wrapT,
[TextureWrapMode wrapR = TextureWrapMode.CLAMP_TO_EDGE]);
/// Creates a texture sampler with comparison mode for shadow mapping
Future<TextureSampler> createComparisonSampler(
TextureFilter minFilter,
TextureFilter magFilter,
TextureWrapMode wrapS,
TextureWrapMode wrapT,
SamplerCompareFunction compareMode,
[TextureWrapMode wrapR = TextureWrapMode.CLAMP_TO_EDGE]);
/// Disposes the sampler resources
Future dispose();
}
@@ -273,7 +302,8 @@ abstract class Texture {
/// Returns the internal format of this texture
Future<TextureFormat> getFormat();
Future setLinearImage(covariant LinearImage image, PixelDataFormat format, PixelDataType type);
Future setLinearImage(
covariant LinearImage image, PixelDataFormat format, PixelDataType type);
/// Sets the image data for a 2D texture or a texture level
Future setImage(
@@ -307,34 +337,82 @@ abstract class Texture {
}
enum PixelDataFormat {
R, /// One Red channel, float
R_INTEGER, /// One Red channel, integer
RG, /// Two Red and Green channels, float
RG_INTEGER, /// Two Red and Green channels, integer
RGB, /// Three Red, Green and Blue channels, float
RGB_INTEGER, /// Three Red, Green and Blue channels, integer
RGBA, /// Four Red, Green, Blue and Alpha channels, float
RGBA_INTEGER, /// Four Red, Green, Blue and Alpha channels, integer
UNUSED, /// Used to be rgbm
DEPTH_COMPONENT, /// Depth, 16-bit or 24-bits usually
DEPTH_STENCIL, /// Two Depth (24-bits) + Stencil (8-bits) channels
ALPHA /// One Alpha channel, float
R,
/// One Red channel, float
R_INTEGER,
/// One Red channel, integer
RG,
/// Two Red and Green channels, float
RG_INTEGER,
/// Two Red and Green channels, integer
RGB,
/// Three Red, Green and Blue channels, float
RGB_INTEGER,
/// Three Red, Green and Blue channels, integer
RGBA,
/// Four Red, Green, Blue and Alpha channels, float
RGBA_INTEGER,
/// Four Red, Green, Blue and Alpha channels, integer
UNUSED,
/// Used to be rgbm
DEPTH_COMPONENT,
/// Depth, 16-bit or 24-bits usually
DEPTH_STENCIL,
/// Two Depth (24-bits) + Stencil (8-bits) channels
ALPHA
/// One Alpha channel, float
}
/// Pixel Data Type
enum PixelDataType {
UBYTE, /// Unsigned byte
BYTE, /// Signed byte
USHORT, /// Unsigned short (16-bit)
SHORT, /// Signed short (16-bit)
UINT, /// Unsigned int (32-bit)
INT, /// Signed int (32-bit)
HALF, /// Half-float (16-bit float)
FLOAT, /// Float (32-bits float)
COMPRESSED, /// Compressed pixels, see CompressedPixelDataType
UINT_10F_11F_11F_REV, /// Three low precision floating-point numbers
USHORT_565, /// Unsigned int (16-bit), encodes 3 RGB channels
UINT_2_10_10_10_REV, /// Unsigned normalized 10 bits RGB, 2 bits alpha
UBYTE,
/// Unsigned byte
BYTE,
/// Signed byte
USHORT,
/// Unsigned short (16-bit)
SHORT,
/// Signed short (16-bit)
UINT,
/// Unsigned int (32-bit)
INT,
/// Signed int (32-bit)
HALF,
/// Half-float (16-bit float)
FLOAT,
/// Float (32-bits float)
COMPRESSED,
/// Compressed pixels, see CompressedPixelDataType
UINT_10F_11F_11F_REV,
/// Three low precision floating-point numbers
USHORT_565,
/// Unsigned int (16-bit), encodes 3 RGB channels
UINT_2_10_10_10_REV,
/// Unsigned normalized 10 bits RGB, 2 bits alpha
}
@deprecated
@@ -346,3 +424,11 @@ abstract class LinearImage {
Future<int> getHeight();
Future<int> getChannels();
}
class FFITextureSampler extends TextureSampler {
final Pointer<TTextureSampler> pointer;
FFITextureSampler(this.pointer);
@override
Future dispose() async {}
}

View File

@@ -778,6 +778,17 @@ abstract class ThermionViewer {
Future<Texture> createTexture(int width, int height,
{TextureSamplerType textureSamplerType = TextureSamplerType.SAMPLER_2D,
TextureFormat textureFormat = TextureFormat.RGBA16F});
Future<TextureSampler> createTextureSampler({
TextureMinFilter minFilter = TextureMinFilter.LINEAR,
TextureMagFilter magFilter = TextureMagFilter.LINEAR,
TextureWrapMode wrapS = TextureWrapMode.CLAMP_TO_EDGE,
TextureWrapMode wrapT = TextureWrapMode.CLAMP_TO_EDGE,
TextureWrapMode wrapR = TextureWrapMode.CLAMP_TO_EDGE,
double anisotropy = 0.0,
TextureCompareMode compareMode = TextureCompareMode.NONE,
TextureCompareFunc compareFunc = TextureCompareFunc.LESS_EQUAL
});
///
/// Decodes the specified image data.

View File

@@ -197,6 +197,70 @@ EMSCRIPTEN_KEEPALIVE void Image_destroy(TLinearImage* tLinearImage);
EMSCRIPTEN_KEEPALIVE uint32_t Image_getWidth(TLinearImage* tLinearImage);
EMSCRIPTEN_KEEPALIVE uint32_t Image_getHeight(TLinearImage* tLinearImage);
EMSCRIPTEN_KEEPALIVE uint32_t Image_getChannels(TLinearImage* tLinearImage);
// Texture Sampler related enums
enum TSamplerWrapMode {
WRAP_CLAMP_TO_EDGE, // Clamp to edge wrapping mode
WRAP_REPEAT, // Repeat wrapping mode
WRAP_MIRRORED_REPEAT // Mirrored repeat wrapping mode
};
enum TSamplerMinFilter {
FILTER_NEAREST, // Nearest filtering
FILTER_LINEAR, // Linear filtering
FILTER_NEAREST_MIPMAP_NEAREST, // Nearest mipmap nearest filtering
FILTER_LINEAR_MIPMAP_NEAREST, // Linear mipmap nearest filtering
FILTER_NEAREST_MIPMAP_LINEAR, // Nearest mipmap linear filtering
FILTER_LINEAR_MIPMAP_LINEAR // Linear mipmap linear filtering
};
enum TSamplerMagFilter {
MAG_FILTER_NEAREST, // Nearest filtering
MAG_FILTER_LINEAR // Linear filtering
};
enum TSamplerCompareMode {
COMPARE_MODE_NONE, // No comparison
COMPARE_MODE_COMPARE_TO_TEXTURE // Compare to texture
};
typedef TSamplerCompareFunc TTextureSamplerCompareFunc ;
EMSCRIPTEN_KEEPALIVE TTextureSampler* TextureSampler_create();
EMSCRIPTEN_KEEPALIVE TTextureSampler* TextureSampler_createWithFiltering(
TSamplerMinFilter minFilter,
TSamplerMagFilter magFilter,
TSamplerWrapMode wrapS,
TSamplerWrapMode wrapT,
TSamplerWrapMode wrapR);
EMSCRIPTEN_KEEPALIVE TTextureSampler* TextureSampler_createWithComparison(
TSamplerCompareMode compareMode,
TSamplerCompareFunc compareFunc);
EMSCRIPTEN_KEEPALIVE void TextureSampler_setMinFilter(
TTextureSampler* sampler,
TSamplerMinFilter filter);
EMSCRIPTEN_KEEPALIVE void TextureSampler_setMagFilter(
TTextureSampler* sampler,
TSamplerMagFilter filter);
EMSCRIPTEN_KEEPALIVE void TextureSampler_setWrapModeS(
TTextureSampler* sampler,
TSamplerWrapMode mode);
EMSCRIPTEN_KEEPALIVE void TextureSampler_setWrapModeT(
TTextureSampler* sampler,
TSamplerWrapMode mode);
EMSCRIPTEN_KEEPALIVE void TextureSampler_setWrapModeR(
TTextureSampler* sampler,
TSamplerWrapMode mode);
EMSCRIPTEN_KEEPALIVE void TextureSampler_setAnisotropy(
TTextureSampler* sampler,
double anisotropy);
EMSCRIPTEN_KEEPALIVE void TextureSampler_setCompareMode(
TTextureSampler* sampler,
TSamplerCompareMode mode,
TTextureSamplerCompareFunc func);
EMSCRIPTEN_KEEPALIVE void TextureSampler_destroy(TTextureSampler* sampler);
#ifdef __cplusplus

View File

@@ -19,10 +19,11 @@ namespace thermion
extern "C"
{
using namespace filament::backend;
#endif
EMSCRIPTEN_KEEPALIVE TLinearImage* Image_decode(uint8_t* data, size_t length, const char* name = "image") {
EMSCRIPTEN_KEEPALIVE TLinearImage *Image_decode(uint8_t *data, size_t length, const char *name = "image")
{
std::istringstream stream(std::string(reinterpret_cast<const char *>(data), length));
auto *linearImage = new image::LinearImage(::image::ImageDecoder::decode(stream, name, ::image::ImageDecoder::ColorSpace::SRGB));
@@ -32,57 +33,60 @@ namespace thermion
Log("Failed to decode image.");
return nullptr;
}
return reinterpret_cast<TLinearImage*>(linearImage);
return reinterpret_cast<TLinearImage *>(linearImage);
}
EMSCRIPTEN_KEEPALIVE uint32_t Image_getWidth(TLinearImage* tLinearImage) {
auto *linearImage = reinterpret_cast<::image::LinearImage*>(tLinearImage);
EMSCRIPTEN_KEEPALIVE uint32_t Image_getWidth(TLinearImage *tLinearImage)
{
auto *linearImage = reinterpret_cast<::image::LinearImage *>(tLinearImage);
return linearImage->getWidth();
}
EMSCRIPTEN_KEEPALIVE uint32_t Image_getHeight(TLinearImage* tLinearImage) {
auto *linearImage = reinterpret_cast<::image::LinearImage*>(tLinearImage);
EMSCRIPTEN_KEEPALIVE uint32_t Image_getHeight(TLinearImage *tLinearImage)
{
auto *linearImage = reinterpret_cast<::image::LinearImage *>(tLinearImage);
return linearImage->getHeight();
}
EMSCRIPTEN_KEEPALIVE uint32_t Image_getChannels(TLinearImage* tLinearImage) {
auto *linearImage = reinterpret_cast<::image::LinearImage*>(tLinearImage);
EMSCRIPTEN_KEEPALIVE uint32_t Image_getChannels(TLinearImage *tLinearImage)
{
auto *linearImage = reinterpret_cast<::image::LinearImage *>(tLinearImage);
return linearImage->getChannels();
}
EMSCRIPTEN_KEEPALIVE void Image_destroy(TLinearImage* tLinearImage) {
auto *linearImage = reinterpret_cast<::image::LinearImage*>(tLinearImage);
EMSCRIPTEN_KEEPALIVE void Image_destroy(TLinearImage *tLinearImage)
{
auto *linearImage = reinterpret_cast<::image::LinearImage *>(tLinearImage);
delete linearImage;
}
EMSCRIPTEN_KEEPALIVE bool Texture_loadImage(TEngine *tEngine, TTexture *tTexture, TLinearImage *tImage, TPixelDataFormat tBufferFormat, TPixelDataType tPixelDataType)
{
auto engine = reinterpret_cast<filament::Engine*>(tEngine);
auto image = reinterpret_cast<::image::LinearImage*>(tImage);
auto texture = reinterpret_cast<filament::Texture*>(tTexture);
auto engine = reinterpret_cast<filament::Engine *>(tEngine);
auto image = reinterpret_cast<::image::LinearImage *>(tImage);
auto texture = reinterpret_cast<filament::Texture *>(tTexture);
auto bufferFormat = static_cast<PixelBufferDescriptor::PixelDataFormat>(static_cast<int>(tBufferFormat));
auto pixelDataType = static_cast<PixelBufferDescriptor::PixelDataType>(static_cast<int>(tPixelDataType));
uint32_t w = image->getWidth();
uint32_t h = image->getHeight();
uint32_t channels = image->getChannels();
size_t size;
switch(bufferFormat) {
case PixelBufferDescriptor::PixelDataFormat::RGB:
case PixelBufferDescriptor::PixelDataFormat::RGBA:
size = w * h * channels * sizeof(float);
break;
case PixelBufferDescriptor::PixelDataFormat::RGB_INTEGER:
case PixelBufferDescriptor::PixelDataFormat::RGBA_INTEGER:
size = w * h * channels * sizeof(uint8_t);
break;
default:
Log("Unsupported buffer format type : %d", bufferFormat);
return false;
switch (bufferFormat)
{
case PixelBufferDescriptor::PixelDataFormat::RGB:
case PixelBufferDescriptor::PixelDataFormat::RGBA:
size = w * h * channels * sizeof(float);
break;
case PixelBufferDescriptor::PixelDataFormat::RGB_INTEGER:
case PixelBufferDescriptor::PixelDataFormat::RGBA_INTEGER:
size = w * h * channels * sizeof(uint8_t);
break;
default:
Log("Unsupported buffer format type : %d", bufferFormat);
return false;
}
Log("Dimensions %d x %d, channels %d, size %d, buffer format %d and pixel data type %d", w, h,channels, size, bufferFormat, pixelDataType);
Log("Dimensions %d x %d, channels %d, size %d, buffer format %d and pixel data type %d", w, h, channels, size, bufferFormat, pixelDataType);
filament::Texture::PixelBufferDescriptor buffer(
image->getPixelRef(),
@@ -92,7 +96,126 @@ namespace thermion
texture->setImage(*engine, 0, std::move(buffer));
return true;
}
EMSCRIPTEN_KEEPALIVE TTextureSampler *TextureSampler_create()
{
auto *sampler = new filament::TextureSampler();
return reinterpret_cast<TTextureSampler *>(sampler);
}
EMSCRIPTEN_KEEPALIVE TTextureSampler *TextureSampler_createWithFiltering(
TSamplerMinFilter minFilter,
TSamplerMagFilter magFilter,
TSamplerWrapMode wrapS,
TSamplerWrapMode wrapT,
TSamplerWrapMode wrapR)
{
filament::TextureSampler::MinFilter min = static_cast<filament::TextureSampler::MinFilter>(minFilter);
filament::TextureSampler::MagFilter mag = static_cast<filament::TextureSampler::MagFilter>(magFilter);
filament::TextureSampler::WrapMode s = static_cast<filament::TextureSampler::WrapMode>(wrapS);
filament::TextureSampler::WrapMode t = static_cast<filament::TextureSampler::WrapMode>(wrapT);
filament::TextureSampler::WrapMode r = static_cast<filament::TextureSampler::WrapMode>(wrapR);
auto *sampler = new filament::TextureSampler(min, mag, s, t, r);
return reinterpret_cast<TTextureSampler *>(sampler);
}
EMSCRIPTEN_KEEPALIVE TTextureSampler *TextureSampler_createWithComparison(
TSamplerCompareMode compareMode,
TSamplerCompareFunc compareFunc)
{
filament::TextureSampler::CompareMode mode = static_cast<filament::TextureSampler::CompareMode>(compareMode);
filament::TextureSampler::CompareFunc func = static_cast<filament::TextureSampler::CompareFunc>(compareFunc);
auto *sampler = new filament::TextureSampler(mode, func);
return reinterpret_cast<TTextureSampler *>(sampler);
}
EMSCRIPTEN_KEEPALIVE void TextureSampler_setMinFilter(
TTextureSampler *sampler,
TSamplerMinFilter filter)
{
if (sampler)
{
auto *textureSampler = reinterpret_cast<filament::TextureSampler *>(sampler);
textureSampler->setMinFilter(static_cast<filament::TextureSampler::MinFilter>(filter));
}
}
EMSCRIPTEN_KEEPALIVE void TextureSampler_setMagFilter(
TTextureSampler *sampler,
TSamplerMagFilter filter)
{
if (sampler)
{
auto *textureSampler = reinterpret_cast<filament::TextureSampler *>(sampler);
textureSampler->setMagFilter(static_cast<filament::TextureSampler::MagFilter>(filter));
}
}
EMSCRIPTEN_KEEPALIVE void TextureSampler_setWrapModeS(
TTextureSampler *sampler,
TSamplerWrapMode mode)
{
if (sampler)
{
auto *textureSampler = reinterpret_cast<filament::TextureSampler *>(sampler);
textureSampler->setWrapModeS(static_cast<filament::TextureSampler::WrapMode>(mode));
}
}
EMSCRIPTEN_KEEPALIVE void TextureSampler_setWrapModeT(
TTextureSampler *sampler,
TSamplerWrapMode mode)
{
if (sampler)
{
auto *textureSampler = reinterpret_cast<filament::TextureSampler *>(sampler);
textureSampler->setWrapModeT(static_cast<filament::TextureSampler::WrapMode>(mode));
}
}
EMSCRIPTEN_KEEPALIVE void TextureSampler_setWrapModeR(
TTextureSampler *sampler,
TSamplerWrapMode mode)
{
if (sampler)
{
auto *textureSampler = reinterpret_cast<filament::TextureSampler *>(sampler);
textureSampler->setWrapModeR(static_cast<filament::TextureSampler::WrapMode>(mode));
}
}
EMSCRIPTEN_KEEPALIVE void TextureSampler_setCompareMode(
TTextureSampler *sampler,
TSamplerCompareMode mode,
TSamplerCompareFunc func)
{
if (sampler)
{
auto *textureSampler = reinterpret_cast<filament::TextureSampler *>(sampler);
textureSampler->setCompareMode(
static_cast<filament::TextureSampler::CompareMode>(mode),
static_cast<filament::TextureSampler::CompareFunc>(func));
}
}
EMSCRIPTEN_KEEPALIVE void TextureSampler_destroy(TTextureSampler *sampler)
{
if (sampler)
{
auto *textureSampler = reinterpret_cast<filament::TextureSampler *>(sampler);
delete textureSampler;
}
}
#ifdef __cplusplus

View File

@@ -42,7 +42,7 @@ Future<
void main() async {
final testHelper = TestHelper("material");
group("material tests", () {
group("unlit material tests", () {
test('unlit material with color only', () async {
await testHelper.withViewer((viewer) async {
await viewer.setPostProcessing(true);
@@ -77,7 +77,6 @@ void main() async {
await testHelper.capture(viewer, "unlit_material_base_color_alpha");
await viewer.destroyMaterialInstance(materialInstance);
}, bg: kRed);
});
test('unlit fixed size material', () async {
@@ -103,8 +102,10 @@ void main() async {
await viewer.dispose();
});
});
test('ubershader material with color only', () async {
group("ubershader material tests", () {
test('ubershader material with color only', () async {
await testHelper.withViewer((viewer) async {
var materialInstance = await viewer.createUbershaderMaterialInstance();
await viewer
@@ -121,29 +122,38 @@ void main() async {
}, bg: kRed, postProcessing: true);
});
test('apply texture to custom ubershader material instance', () async {
var viewer = await testHelper.createViewer();
await viewer.addLight(LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1);
await viewer.setCameraPosition(0, 2, 6);
await viewer
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
await viewer.setBackgroundColor(1.0, 0.0, 0.0, 1.0);
test('set ubershader texture', () async {
await testHelper.withViewer((viewer) async {
await viewer.addLight(LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1);
await viewer.setCameraPosition(0, 2, 6);
await viewer
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
var materialInstance = await viewer.createUbershaderMaterialInstance();
final cube = await viewer.createGeometry(
GeometryHelper.cube(uvs: true, normals: true),
materialInstances: [materialInstance]);
var textureData =
File("${testHelper.testDir}/assets/cube_texture_512x512.png")
.readAsBytesSync();
var texture = await viewer.createTexture(textureData);
await viewer.applyTexture(texture as ThermionFFITexture, cube.entity);
await testHelper.capture(
viewer, "geometry_cube_with_custom_material_ubershader_texture");
await viewer.destroyAsset(cube);
await viewer.destroyMaterialInstance(materialInstance);
await viewer.destroyTexture(texture);
await viewer.dispose();
var materialInstance = await viewer.createUbershaderMaterialInstance();
final cube = await viewer.createGeometry(
GeometryHelper.cube(uvs: true, normals: true),
materialInstances: [materialInstance]);
var data = File("${testHelper.testDir}/assets/cube_texture_512x512.png")
.readAsBytesSync();
final image = await viewer.decodeImage(data);
final texture = await viewer.createTexture(
await image.getWidth(), await image.getHeight(),
textureFormat: TextureFormat.RGBA32F);
await texture.setLinearImage(
image, PixelDataFormat.RGBA, PixelDataType.FLOAT);
final sampler = await viewer.createTextureSampler();
await materialInstance.setParameterFloat4(
"baseColorFactor", 1.0, 1.0, 1.0, 0.0);
await materialInstance.setParameterInt("baseColorIndex", 0);
await materialInstance.setParameterTexture(
"baseColorMap", texture, sampler);
await testHelper.capture(
viewer, "geometry_cube_with_custom_material_ubershader_texture");
await viewer.destroyAsset(cube);
await viewer.destroyMaterialInstance(materialInstance);
await viewer.destroyTexture(texture);
});
});
test('create cube with custom material instance (unlit)', () async {
@@ -162,51 +172,42 @@ void main() async {
var textureData =
File("${testHelper.testDir}/assets/cube_texture_512x512.png")
.readAsBytesSync();
var texture = await viewer.createTexture(textureData);
await viewer.applyTexture(texture, cube.entity);
await testHelper.capture(
viewer, "geometry_cube_with_custom_material_unlit_texture_only");
await viewer.destroyAsset(cube);
throw UnimplementedError();
// var texture = await viewer.createTexture(textureData);
// await viewer.applyTexture(texture, cube.entity);
// await testHelper.capture(
// viewer, "geometry_cube_with_custom_material_unlit_texture_only");
// await viewer.destroyAsset(cube);
cube = await viewer.createGeometry(GeometryHelper.cube(),
materialInstances: [materialInstance]);
// reusing same material instance, so set baseColorIndex to -1 to disable the texture
await materialInstance.setParameterInt("baseColorIndex", -1);
await materialInstance.setParameterFloat4(
"baseColorFactor", 0.0, 1.0, 0.0, 1.0);
await testHelper.capture(
viewer, "geometry_cube_with_custom_material_unlit_color_only");
await viewer.destroyAsset(cube);
// cube = await viewer.createGeometry(GeometryHelper.cube(),
// materialInstances: [materialInstance]);
// // reusing same material instance, so set baseColorIndex to -1 to disable the texture
// await materialInstance.setParameterInt("baseColorIndex", -1);
// await materialInstance.setParameterFloat4(
// "baseColorFactor", 0.0, 1.0, 0.0, 1.0);
// await testHelper.capture(
// viewer, "geometry_cube_with_custom_material_unlit_color_only");
// await viewer.destroyAsset(cube);
cube = await viewer.createGeometry(GeometryHelper.cube(),
materialInstances: [materialInstance]);
// now set baseColorIndex to 0 to enable the texture and the base color
await materialInstance.setParameterInt("baseColorIndex", 0);
await materialInstance.setParameterFloat4(
"baseColorFactor", 0.0, 1.0, 0.0, 0.5);
await viewer.applyTexture(texture, cube.entity);
// cube = await viewer.createGeometry(GeometryHelper.cube(),
// materialInstances: [materialInstance]);
// // now set baseColorIndex to 0 to enable the texture and the base color
// await materialInstance.setParameterInt("baseColorIndex", 0);
// await materialInstance.setParameterFloat4(
// "baseColorFactor", 0.0, 1.0, 0.0, 0.5);
// await viewer.applyTexture(texture, cube.entity);
await testHelper.capture(
viewer, "geometry_cube_with_custom_material_unlit_color_and_texture");
// await testHelper.capture(
// viewer, "geometry_cube_with_custom_material_unlit_color_and_texture");
await viewer.destroyAsset(cube);
// await viewer.destroyAsset(cube);
await viewer.destroyTexture(texture);
await viewer.destroyMaterialInstance(materialInstance);
await viewer.dispose();
// await viewer.destroyTexture(texture);
// await viewer.destroyMaterialInstance(materialInstance);
// await viewer.dispose();
});
test('create sphere (no normals)', () async {
var viewer = await testHelper.createViewer();
await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0);
await viewer.setCameraPosition(0, 0, 6);
await viewer
.createGeometry(GeometryHelper.sphere(normals: false, uvs: false));
await testHelper.capture(viewer, "geometry_sphere_no_normals");
await viewer.dispose();
});
});
group('depth & stencil', () {
test('set depth func to always', () async {
await testHelper.withViewer((viewer) async {
final (
@@ -338,6 +339,23 @@ void main() async {
}, postProcessing: true);
});
});
group('projection', () {
test('apply projection material', () async {
await testHelper.withViewer((viewer) async {
var materialData = File(
"/Users/nickfisher/Documents/thermion/materials/capture_uv.filamat")
.readAsBytesSync();
var material = await viewer.createMaterial(materialData);
var instance = await material.createInstance();
final cube = await viewer.createGeometry(GeometryHelper.cube(),
materialInstances: [instance]);
await cube.addToScene();
await testHelper.capture(viewer, "projection");
}, cameraPosition: Vector3(0, 0, 100));
});
});
}
// group("MaterialInstance", () {

View File

@@ -18,8 +18,18 @@ void main() async {
expect(await image.getHeight(), 512);
final texture = await viewer.createTexture(
await image.getWidth(), await image.getHeight(), textureFormat: TextureFormat.RGBA32F);
await texture.setLinearImage(image, PixelDataFormat.RGBA, PixelDataType.FLOAT);
await image.getWidth(), await image.getHeight(),
textureFormat: TextureFormat.RGBA32F);
await texture.setLinearImage(
image, PixelDataFormat.RGBA, PixelDataType.FLOAT);
}, bg: kRed);
});
});
group("sampler", () {
test('create sampler', () async {
await testHelper.withViewer((viewer) async {
final sampler = viewer.createTextureSampler();
}, bg: kRed);
});
});