separate IBL from skybox and add setBackgroundImage method
This commit is contained in:
@@ -14,7 +14,43 @@ add_library(
|
|||||||
src/main/cpp/StbProvider.cpp
|
src/main/cpp/StbProvider.cpp
|
||||||
src/main/cpp/JobSystem.cpp
|
src/main/cpp/JobSystem.cpp
|
||||||
../ios/src/FilamentViewer.cpp
|
../ios/src/FilamentViewer.cpp
|
||||||
|
../ios/src/streambuf.cpp
|
||||||
|
../ios/src/imagematerial.c
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(filament_interop -landroid -llog -lfilament -lbackend -lfilameshio -lviewer -lfilamat -lgeometry -lutils -lfilabridge -lgltfio_core -lfilament-iblprefilter -limage -lcamutils -lfilaflat -ldracodec -libl -lktxreader -lstb -lEGL -lGLESv3 -lbluevk -lvkshaders -luberzlib -lsmol-v -luberarchive -lzstd)
|
target_link_libraries(
|
||||||
|
filament_interop
|
||||||
|
-landroid
|
||||||
|
-llog
|
||||||
|
-lfilament
|
||||||
|
-lbackend
|
||||||
|
-lfilameshio
|
||||||
|
-lviewer
|
||||||
|
-lfilamat
|
||||||
|
-lgeometry
|
||||||
|
-lutils
|
||||||
|
-lfilabridge
|
||||||
|
-lgltfio_core
|
||||||
|
-lfilament-iblprefilter
|
||||||
|
-limage
|
||||||
|
-lcamutils
|
||||||
|
-lfilaflat
|
||||||
|
-ldracodec
|
||||||
|
-libl
|
||||||
|
-lktxreader
|
||||||
|
-limageio
|
||||||
|
-lpng
|
||||||
|
-ltinyexr
|
||||||
|
-lz
|
||||||
|
-lstb
|
||||||
|
-lEGL
|
||||||
|
-lGLESv3
|
||||||
|
-lbluevk
|
||||||
|
-lvkshaders
|
||||||
|
-luberzlib
|
||||||
|
-lsmol-v
|
||||||
|
-luberarchive
|
||||||
|
-lzstd
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -47,14 +47,27 @@ static void freeResource(ResourceBuffer rb) {
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
void load_skybox(void* viewer, const char* skyboxPath, const char* iblPath) {
|
void set_background_image(void* viewer, const char* path) {
|
||||||
((FilamentViewer*)viewer)->loadSkybox(skyboxPath, iblPath);
|
((FilamentViewer*)viewer)->setBackgroundImage(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_skybox(void* viewer, const char* skyboxPath) {
|
||||||
|
((FilamentViewer*)viewer)->loadSkybox(skyboxPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_ibl(void* viewer, const char* iblPath) {
|
||||||
|
((FilamentViewer*)viewer)->loadIbl(iblPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_skybox(void* viewer) {
|
void remove_skybox(void* viewer) {
|
||||||
((FilamentViewer*)viewer)->removeSkybox();
|
((FilamentViewer*)viewer)->removeSkybox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void remove_ibl(void* viewer) {
|
||||||
|
((FilamentViewer*)viewer)->removeIbl();
|
||||||
|
}
|
||||||
|
|
||||||
void load_glb(void* viewer, const char* assetPath) {
|
void load_glb(void* viewer, const char* assetPath) {
|
||||||
((FilamentViewer*)viewer)->loadGlb(assetPath);
|
((FilamentViewer*)viewer)->loadGlb(assetPath);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ interface FilamentInterop : Library {
|
|||||||
am:AssetManager
|
am:AssetManager
|
||||||
) : Pointer;
|
) : Pointer;
|
||||||
|
|
||||||
fun load_skybox(viewer:Pointer, skyboxPath:String, iblPath:String) : Pointer;
|
fun load_skybox(viewer:Pointer, skyboxPath:String) : Pointer;
|
||||||
|
|
||||||
|
fun load_ibl(viewer:Pointer, skyboxPath:String) : Pointer;
|
||||||
|
|
||||||
fun load_glb(viewer:Pointer, uri:String) : Pointer;
|
fun load_glb(viewer:Pointer, uri:String) : Pointer;
|
||||||
|
|
||||||
@@ -66,5 +68,7 @@ interface FilamentInterop : Library {
|
|||||||
|
|
||||||
fun remove_skybox(viewer:Pointer);
|
fun remove_skybox(viewer:Pointer);
|
||||||
|
|
||||||
|
fun remove_ibl(viewer:Pointer);
|
||||||
|
|
||||||
|
fun set_background_image(viewer:Pointer, path:String);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ PlatformView {
|
|||||||
|
|
||||||
private lateinit var assetManager : AssetManager
|
private lateinit var assetManager : AssetManager
|
||||||
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
MethodChannel(binaryMessenger, PolyvoxFilamentPlugin.VIEW_TYPE + '_' + viewId).also {
|
MethodChannel(binaryMessenger, PolyvoxFilamentPlugin.VIEW_TYPE + '_' + viewId).also {
|
||||||
_methodChannel = it
|
_methodChannel = it
|
||||||
@@ -157,12 +158,29 @@ PlatformView {
|
|||||||
// val flutterJNI = FlutterJNI.Factory.provideFlutterJNI()
|
// val flutterJNI = FlutterJNI.Factory.provideFlutterJNI()
|
||||||
// flutterJNI.updateJavaAssetManager(assetManager, flutterApplicationInfo.flutterAssetsDir)
|
// flutterJNI.updateJavaAssetManager(assetManager, flutterApplicationInfo.flutterAssetsDir)
|
||||||
}
|
}
|
||||||
"loadSkybox" -> {
|
"setBackgroundImage" -> {
|
||||||
val args = call.arguments as ArrayList<Any?>
|
val args = call.arguments as String
|
||||||
val loader = FlutterInjector.instance().flutterLoader()
|
val loader = FlutterInjector.instance().flutterLoader()
|
||||||
_lib.load_skybox(_viewer!!, loader.getLookupKeyForAsset(args[0] as String), loader.getLookupKeyForAsset(args[1] as String))
|
_lib.set_background_image(_viewer!!, loader.getLookupKeyForAsset(args))
|
||||||
result.success("OK");
|
result.success("OK");
|
||||||
}
|
}
|
||||||
|
"loadSkybox" -> {
|
||||||
|
val args = call.arguments as String
|
||||||
|
val loader = FlutterInjector.instance().flutterLoader()
|
||||||
|
_lib.load_skybox(_viewer!!, loader.getLookupKeyForAsset(args))
|
||||||
|
result.success("OK");
|
||||||
|
}
|
||||||
|
"loadIbl" -> {
|
||||||
|
val args = call.arguments as String
|
||||||
|
val loader = FlutterInjector.instance().flutterLoader()
|
||||||
|
|
||||||
|
_lib.load_ibl(_viewer!!, loader.getLookupKeyForAsset(args))
|
||||||
|
result.success("OK");
|
||||||
|
}
|
||||||
|
"removeIbl" -> {
|
||||||
|
_lib.remove_ibl(_viewer!!)
|
||||||
|
result.success(true);
|
||||||
|
}
|
||||||
"removeSkybox" -> {
|
"removeSkybox" -> {
|
||||||
_lib.remove_skybox(_viewer!!)
|
_lib.remove_skybox(_viewer!!)
|
||||||
result.success(true);
|
result.success(true);
|
||||||
|
|||||||
@@ -39,11 +39,17 @@ using namespace std;
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if([@"loadSkybox" isEqualToString:call.method]) {
|
if([@"loadSkybox" isEqualToString:call.method]) {
|
||||||
_viewer->loadSkybox([call.arguments[0] UTF8String], [call.arguments[1] UTF8String]);
|
_viewer->loadSkybox([call.arguments UTF8String]);
|
||||||
result(@"OK");
|
result(@"OK");
|
||||||
} else if([@"loadSkybox" isEqualToString:call.method]) {
|
} else if([@"removeSkybox" isEqualToString:call.method]) {
|
||||||
_viewer->removeSkybox();
|
_viewer->removeSkybox();
|
||||||
result(@"OK");
|
result(@"OK");
|
||||||
|
} else if([@"loadIbl" isEqualToString:call.method]) {
|
||||||
|
_viewer->loadIbl([call.arguments UTF8String]);
|
||||||
|
result(@"OK");
|
||||||
|
} else if([@"removeIbl" isEqualToString:call.method]) {
|
||||||
|
_viewer->removeIbl();
|
||||||
|
result(@"OK");
|
||||||
} else if([@"loadGlb" isEqualToString:call.method]) {
|
} else if([@"loadGlb" isEqualToString:call.method]) {
|
||||||
_viewer->loadGlb([call.arguments UTF8String]);
|
_viewer->loadGlb([call.arguments UTF8String]);
|
||||||
result(@"OK");
|
result(@"OK");
|
||||||
|
|||||||
170
ios/include/imageio/BasisEncoder.h
Normal file
170
ios/include/imageio/BasisEncoder.h
Normal file
@@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IMAGE_BASISENCODER_H_
|
||||||
|
#define IMAGE_BASISENCODER_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <utils/compiler.h>
|
||||||
|
|
||||||
|
#include <image/LinearImage.h>
|
||||||
|
|
||||||
|
namespace image {
|
||||||
|
|
||||||
|
struct BasisEncoderBuilderImpl;
|
||||||
|
struct BasisEncoderImpl;
|
||||||
|
|
||||||
|
class UTILS_PUBLIC BasisEncoder {
|
||||||
|
public:
|
||||||
|
enum class IntermediateFormat {
|
||||||
|
UASTC,
|
||||||
|
ETC1S,
|
||||||
|
};
|
||||||
|
|
||||||
|
class Builder {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructs a Ktx2 builder with a fixed number of miplevels and layers.
|
||||||
|
*
|
||||||
|
* The number of mips and layers is required up front to allow pre-allocation of the
|
||||||
|
* appropriate BasisU input vectors.
|
||||||
|
*
|
||||||
|
* @param mipCount number of mipmap levels, including the base; must be at least 1.
|
||||||
|
* @param layerCount either 1 or the number of layers in an array texture.
|
||||||
|
*
|
||||||
|
* For cubemaps and cubemap arrays, multiply the layer count by 6 and pack the faces in
|
||||||
|
* standard GL order.
|
||||||
|
*/
|
||||||
|
Builder(size_t mipCount, size_t layerCount) noexcept;
|
||||||
|
|
||||||
|
~Builder() noexcept;
|
||||||
|
Builder(Builder&& that) noexcept;
|
||||||
|
Builder& operator=(Builder&& that) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables the linear flag. (default value: FALSE)
|
||||||
|
*
|
||||||
|
* This does two things:
|
||||||
|
* (1) Specifies that the image should be encoded without a transfer function.
|
||||||
|
* (2) Adds a tag to the ktx file that tells the loader that no transfer function was used.
|
||||||
|
*
|
||||||
|
* Note that the tag does not actually affect the compression process, it's basically just a
|
||||||
|
* hint to the reader. At the time of this writing, BasisU does not make a distinction
|
||||||
|
* between sRGB targets and linear targets.
|
||||||
|
*/
|
||||||
|
Builder& linear(bool enabled) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables cubemap or cubemap array mode. (default value: FALSE)
|
||||||
|
*
|
||||||
|
* When this is enabled the number of layers should be divisible by 6.
|
||||||
|
*/
|
||||||
|
Builder& cubemap(bool enabled) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chooses the intermediate format as described in the BasisU docs. (default value: UASTC)
|
||||||
|
*
|
||||||
|
* For highest quality, use UASTC.
|
||||||
|
*/
|
||||||
|
Builder& intermediateFormat(IntermediateFormat format) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies that only the first component of the incoming LinearImage should be honored.
|
||||||
|
*
|
||||||
|
* default value: FALSE
|
||||||
|
*/
|
||||||
|
Builder& grayscale(bool enabled) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies that the incoming image should be transfored from [-1, +1] to [0, 1] before it
|
||||||
|
* passed to the Basis encoder.
|
||||||
|
*
|
||||||
|
* default value: FALSE
|
||||||
|
*/
|
||||||
|
Builder& normals(bool enabled) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the basis encoder with the given number of jobs.
|
||||||
|
*
|
||||||
|
* default value: 4
|
||||||
|
*/
|
||||||
|
Builder& jobs(size_t count) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supresses status messages.
|
||||||
|
*
|
||||||
|
* default value: FALSE
|
||||||
|
*/
|
||||||
|
Builder& quiet(bool enabled) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submits image data in linear floating-point format.
|
||||||
|
*
|
||||||
|
* This must be called for every miplevel.
|
||||||
|
*/
|
||||||
|
Builder& miplevel(size_t mipIndex, size_t layerIndex, const LinearImage& image) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a BasisU encoder and returns null if an error occurred.
|
||||||
|
*/
|
||||||
|
BasisEncoder* build();
|
||||||
|
|
||||||
|
private:
|
||||||
|
BasisEncoderBuilderImpl* mImpl;
|
||||||
|
Builder(const Builder&) = delete;
|
||||||
|
Builder& operator=(const Builder&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
~BasisEncoder() noexcept;
|
||||||
|
BasisEncoder(BasisEncoder&& that) noexcept;
|
||||||
|
BasisEncoder& operator=(BasisEncoder&& that) noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers compression of all miplevels and waits until all jobs are done.
|
||||||
|
*
|
||||||
|
* The resulting KTX2 contents can be retrieved using the getters below.
|
||||||
|
*
|
||||||
|
* @returns false if an error occurred.
|
||||||
|
*/
|
||||||
|
bool encode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of bytes in the generated KTX2 file.
|
||||||
|
*
|
||||||
|
* This can only be called if encode() is successfully called first.
|
||||||
|
*/
|
||||||
|
size_t getKtx2ByteCount() const noexcept;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the content of the generated KTX2 file.
|
||||||
|
*
|
||||||
|
* This memory is owned by BasisEncoder and is freed when the encoder is freed.
|
||||||
|
* This can only be called if encode() is successfully called first.
|
||||||
|
*/
|
||||||
|
uint8_t const* getKtx2Data() const noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BasisEncoder(BasisEncoderImpl*) noexcept;
|
||||||
|
BasisEncoder(const BasisEncoder&) = delete;
|
||||||
|
BasisEncoder& operator=(const BasisEncoder&) = delete;
|
||||||
|
BasisEncoderImpl* mImpl;
|
||||||
|
friend struct BasisEncoderBuilderImpl;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace image
|
||||||
|
|
||||||
|
#endif // IMAGE_BASISENCODER_H_
|
||||||
47
ios/include/imageio/HDRDecoder.h
Normal file
47
ios/include/imageio/HDRDecoder.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IMAGE_HDRDECODER_H_
|
||||||
|
#define IMAGE_HDRDECODER_H_
|
||||||
|
|
||||||
|
#include <imageio/ImageDecoder.h>
|
||||||
|
|
||||||
|
namespace image {
|
||||||
|
|
||||||
|
class HDRDecoder : public ImageDecoder::Decoder {
|
||||||
|
public:
|
||||||
|
static HDRDecoder* create(std::istream& stream);
|
||||||
|
static bool checkSignature(char const* buf);
|
||||||
|
|
||||||
|
HDRDecoder(const HDRDecoder&) = delete;
|
||||||
|
HDRDecoder& operator=(const HDRDecoder&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
explicit HDRDecoder(std::istream& stream);
|
||||||
|
~HDRDecoder() override;
|
||||||
|
|
||||||
|
// ImageDecoder::Decoder interface
|
||||||
|
LinearImage decode() override;
|
||||||
|
|
||||||
|
static const char sigRadiance[];
|
||||||
|
static const char sigRGBE[];
|
||||||
|
std::istream& mStream;
|
||||||
|
std::streampos mStreamStartPos;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace image
|
||||||
|
|
||||||
|
#endif /* IMAGE_IMAGEDECODER_H_ */
|
||||||
69
ios/include/imageio/ImageDecoder.h
Normal file
69
ios/include/imageio/ImageDecoder.h
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IMAGE_IMAGEDECODER_H_
|
||||||
|
#define IMAGE_IMAGEDECODER_H_
|
||||||
|
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <image/LinearImage.h>
|
||||||
|
|
||||||
|
#include <utils/compiler.h>
|
||||||
|
|
||||||
|
namespace image {
|
||||||
|
|
||||||
|
class UTILS_PUBLIC ImageDecoder {
|
||||||
|
public:
|
||||||
|
enum class ColorSpace {
|
||||||
|
LINEAR,
|
||||||
|
SRGB
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns linear floating-point data, or a non-valid image if an error occured.
|
||||||
|
static LinearImage decode(std::istream& stream, const std::string& sourceName,
|
||||||
|
ColorSpace sourceSpace = ColorSpace::SRGB);
|
||||||
|
|
||||||
|
class Decoder {
|
||||||
|
public:
|
||||||
|
virtual LinearImage decode() = 0;
|
||||||
|
virtual ~Decoder() = default;
|
||||||
|
|
||||||
|
ColorSpace getColorSpace() const noexcept {
|
||||||
|
return mColorSpace;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setColorSpace(ColorSpace colorSpace) noexcept {
|
||||||
|
mColorSpace = colorSpace;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ColorSpace mColorSpace = ColorSpace::SRGB;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class Format {
|
||||||
|
NONE,
|
||||||
|
PNG,
|
||||||
|
HDR,
|
||||||
|
PSD,
|
||||||
|
EXR
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace image
|
||||||
|
|
||||||
|
#endif /* IMAGE_IMAGEDECODER_H_ */
|
||||||
34
ios/include/imageio/ImageDiffer.h
Normal file
34
ios/include/imageio/ImageDiffer.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <image/LinearImage.h>
|
||||||
|
|
||||||
|
#include <utils/Path.h>
|
||||||
|
|
||||||
|
namespace image {
|
||||||
|
|
||||||
|
enum class ComparisonMode {
|
||||||
|
SKIP,
|
||||||
|
COMPARE,
|
||||||
|
UPDATE,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Saves an image to disk or does a load-and-compare, depending on comparison mode.
|
||||||
|
// This makes it easy for unit tests to have compare / update commands.
|
||||||
|
// The passed-in image is the "result image" and the expected image is the "golden image".
|
||||||
|
void updateOrCompare(LinearImage result, const utils::Path& golden, ComparisonMode, float epsilon);
|
||||||
|
|
||||||
|
} // namespace image
|
||||||
64
ios/include/imageio/ImageEncoder.h
Normal file
64
ios/include/imageio/ImageEncoder.h
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef IMAGE_IMAGEENCODER_H_
|
||||||
|
#define IMAGE_IMAGEENCODER_H_
|
||||||
|
|
||||||
|
#include <iosfwd>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <image/LinearImage.h>
|
||||||
|
|
||||||
|
#include <utils/compiler.h>
|
||||||
|
|
||||||
|
namespace image {
|
||||||
|
|
||||||
|
class UTILS_PUBLIC ImageEncoder {
|
||||||
|
public:
|
||||||
|
enum class Format {
|
||||||
|
PNG, // 8-bit sRGB, 1 or 3 channels
|
||||||
|
PNG_LINEAR, // 8-bit linear RGB, 1 or 3 channels
|
||||||
|
HDR, // 8-bit linear RGBE, 3 channels only
|
||||||
|
RGBM, // 8-bit RGBM, as PNG, 3 channels only
|
||||||
|
PSD, // 16-bit sRGB or 32-bit linear RGB, 3 channels only
|
||||||
|
// Default: 16 bit
|
||||||
|
EXR, // 16-bit linear RGB (half-float), 3 channels only
|
||||||
|
// Default: PIZ compression
|
||||||
|
DDS, // 8-bit sRGB, 1, 2 or 3 channels;
|
||||||
|
// 16-bit or 32-bit linear RGB, 1, 2 or 3 channels
|
||||||
|
// Default: 16 bit
|
||||||
|
DDS_LINEAR, // 8-bit, 16-bit or 32-bit linear RGB, 1, 2 or 3 channels
|
||||||
|
// Default: 16 bit
|
||||||
|
RGB_10_11_11_REV, // RGBA PNG file, but containing 11_11_10 data
|
||||||
|
};
|
||||||
|
|
||||||
|
// Consumes linear floating-point data, returns false if unable to encode.
|
||||||
|
static bool encode(std::ostream& stream, Format format, const LinearImage& image,
|
||||||
|
const std::string& compression, const std::string& destName);
|
||||||
|
|
||||||
|
static Format chooseFormat(const std::string& name, bool forceLinear = false);
|
||||||
|
static std::string chooseExtension(Format format);
|
||||||
|
|
||||||
|
class Encoder {
|
||||||
|
public:
|
||||||
|
virtual bool encode(const LinearImage& image) = 0;
|
||||||
|
virtual ~Encoder() = default;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace image
|
||||||
|
|
||||||
|
#endif /* IMAGE_IMAGEENCODER_H_ */
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "FilamentViewer.hpp"
|
#include "FilamentViewer.hpp"
|
||||||
|
|
||||||
|
#include "streambuf.hpp"
|
||||||
|
|
||||||
#include <filament/Camera.h>
|
#include <filament/Camera.h>
|
||||||
#include <filament/ColorGrading.h>
|
#include <filament/ColorGrading.h>
|
||||||
@@ -46,6 +47,8 @@
|
|||||||
|
|
||||||
#include <utils/NameComponentManager.h>
|
#include <utils/NameComponentManager.h>
|
||||||
|
|
||||||
|
#include <imageio/ImageDecoder.h>
|
||||||
|
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
|
||||||
#include <math/mat4.h>
|
#include <math/mat4.h>
|
||||||
@@ -63,11 +66,14 @@
|
|||||||
|
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include "imagematerial.h"
|
||||||
|
|
||||||
using namespace filament;
|
using namespace filament;
|
||||||
using namespace filament::math;
|
using namespace filament::math;
|
||||||
using namespace gltfio;
|
using namespace gltfio;
|
||||||
using namespace utils;
|
using namespace utils;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
using namespace image;
|
||||||
|
|
||||||
namespace filament
|
namespace filament
|
||||||
{
|
{
|
||||||
@@ -170,15 +176,161 @@ namespace polyvox
|
|||||||
|
|
||||||
// Always add a direct light source since it is required for shadowing.
|
// Always add a direct light source since it is required for shadowing.
|
||||||
_sun = EntityManager::get().create();
|
_sun = EntityManager::get().create();
|
||||||
LightManager::Builder(LightManager::Type::DIRECTIONAL)
|
LightManager::Builder(LightManager::Type::SUN)
|
||||||
.color(Color::cct(6500.0f))
|
.color(Color::cct(6500.0f))
|
||||||
.intensity(100000.0f)
|
.intensity(150000.0f)
|
||||||
.direction(math::float3(0.0f, 1.0f, 0.0f))
|
.direction(math::float3(0.0f, 0.0f, -1.0f))
|
||||||
.castShadows(false)
|
.castShadows(false)
|
||||||
// .castShadows(true)
|
// .castShadows(true)
|
||||||
.build(*_engine, _sun);
|
.build(*_engine, _sun);
|
||||||
_scene->addEntity(_sun);
|
_scene->addEntity(_sun);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr float4 sFullScreenTriangleVertices[3] = {
|
||||||
|
{-1.0f, -1.0f, 1.0f, 1.0f},
|
||||||
|
{3.0f, -1.0f, 1.0f, 1.0f},
|
||||||
|
{-1.0f, 3.0f, 1.0f, 1.0f}};
|
||||||
|
|
||||||
|
static const uint16_t sFullScreenTriangleIndices[3] = {0, 1, 2};
|
||||||
|
|
||||||
|
void FilamentViewer::createImageRenderable()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (_imageEntity)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto &em = EntityManager::get();
|
||||||
|
_imageMaterial = Material::Builder()
|
||||||
|
.package(IMAGEMATERIAL_IMAGE_DATA, IMAGEMATERIAL_IMAGE_SIZE)
|
||||||
|
.build(*_engine);
|
||||||
|
|
||||||
|
_imageVb = VertexBuffer::Builder()
|
||||||
|
.vertexCount(3)
|
||||||
|
.bufferCount(1)
|
||||||
|
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT4, 0)
|
||||||
|
.build(*_engine);
|
||||||
|
|
||||||
|
_imageVb->setBufferAt(
|
||||||
|
*_engine, 0, {sFullScreenTriangleVertices, sizeof(sFullScreenTriangleVertices)});
|
||||||
|
|
||||||
|
_imageIb = IndexBuffer::Builder()
|
||||||
|
.indexCount(3)
|
||||||
|
.bufferType(IndexBuffer::IndexType::USHORT)
|
||||||
|
.build(*_engine);
|
||||||
|
|
||||||
|
_imageIb->setBuffer(*_engine,
|
||||||
|
{sFullScreenTriangleIndices, sizeof(sFullScreenTriangleIndices)});
|
||||||
|
|
||||||
|
Entity imageEntity = em.create();
|
||||||
|
RenderableManager::Builder(1)
|
||||||
|
.boundingBox({{}, {1.0f, 1.0f, 1.0f}})
|
||||||
|
.material(0, _imageMaterial->getDefaultInstance())
|
||||||
|
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, _imageVb, _imageIb, 0, 3)
|
||||||
|
.culling(false)
|
||||||
|
.build(*_engine, imageEntity);
|
||||||
|
|
||||||
|
_scene->addEntity(imageEntity);
|
||||||
|
|
||||||
|
_imageEntity = &imageEntity;
|
||||||
|
|
||||||
|
Texture *texture = Texture::Builder()
|
||||||
|
.width(1)
|
||||||
|
.height(1)
|
||||||
|
.levels(1)
|
||||||
|
.format(Texture::InternalFormat::RGBA8)
|
||||||
|
.sampler(Texture::Sampler::SAMPLER_2D)
|
||||||
|
.build(*_engine);
|
||||||
|
static uint32_t pixel = 0;
|
||||||
|
Texture::PixelBufferDescriptor buffer(&pixel, 4, Texture::Format::RGBA, Texture::Type::UBYTE);
|
||||||
|
texture->setImage(*_engine, 0, std::move(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilamentViewer::setBackgroundImage(const char *resourcePath)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (colorGrading)
|
||||||
|
{
|
||||||
|
_engine->destroy(colorGrading);
|
||||||
|
}
|
||||||
|
ToneMapper *tm = new LinearToneMapper();
|
||||||
|
colorGrading = ColorGrading::Builder()
|
||||||
|
.toneMapper(tm)
|
||||||
|
.build(*_engine);
|
||||||
|
delete tm;
|
||||||
|
|
||||||
|
_view->setColorGrading(colorGrading);
|
||||||
|
|
||||||
|
createImageRenderable();
|
||||||
|
|
||||||
|
if (_imageTexture)
|
||||||
|
{
|
||||||
|
_engine->destroy(_imageTexture);
|
||||||
|
_imageTexture = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceBuffer bg = _loadResource(resourcePath);
|
||||||
|
|
||||||
|
polyvox::streambuf sb((char *)bg.data, (char *)bg.data + bg.size);
|
||||||
|
|
||||||
|
std::istream *inputStream = new std::istream(&sb);
|
||||||
|
|
||||||
|
LinearImage *image = new LinearImage(ImageDecoder::decode(
|
||||||
|
*inputStream, resourcePath, ImageDecoder::ColorSpace::SRGB));
|
||||||
|
|
||||||
|
if (!image->isValid())
|
||||||
|
{
|
||||||
|
Log("Invalid image : %s", resourcePath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete inputStream;
|
||||||
|
|
||||||
|
_freeResource(bg);
|
||||||
|
|
||||||
|
uint32_t channels = image->getChannels();
|
||||||
|
uint32_t w = image->getWidth();
|
||||||
|
uint32_t h = image->getHeight();
|
||||||
|
_imageTexture = Texture::Builder()
|
||||||
|
.width(w)
|
||||||
|
.height(h)
|
||||||
|
.levels(0xff)
|
||||||
|
.format(channels == 3 ? Texture::InternalFormat::RGB16F : Texture::InternalFormat::RGBA16F)
|
||||||
|
.sampler(Texture::Sampler::SAMPLER_2D)
|
||||||
|
.build(*_engine);
|
||||||
|
|
||||||
|
Texture::PixelBufferDescriptor::Callback freeCallback = [](void *buf, size_t, void *data)
|
||||||
|
{
|
||||||
|
delete reinterpret_cast<LinearImage *>(data);
|
||||||
|
};
|
||||||
|
|
||||||
|
Texture::PixelBufferDescriptor buffer(
|
||||||
|
image->getPixelRef(),
|
||||||
|
size_t(w * h * channels * sizeof(float)),
|
||||||
|
channels == 3 ? Texture::Format::RGB : Texture::Format::RGBA,
|
||||||
|
Texture::Type::FLOAT,
|
||||||
|
freeCallback);
|
||||||
|
|
||||||
|
_imageTexture->setImage(*_engine, 0, std::move(buffer));
|
||||||
|
// _imageTexture->generateMipmaps(*_engine);
|
||||||
|
|
||||||
|
float srcWidth = _imageTexture->getWidth();
|
||||||
|
float srcHeight = _imageTexture->getHeight();
|
||||||
|
float dstWidth = _view->getViewport().width;
|
||||||
|
float dstHeight = _view->getViewport().height;
|
||||||
|
|
||||||
|
mat3f transform(
|
||||||
|
1.0f, 0.0f, 0.0f,
|
||||||
|
0.0f, 1.0f, 0.0f,
|
||||||
|
0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
_imageMaterial->setDefaultParameter("transform", transform);
|
||||||
|
_imageMaterial->setDefaultParameter(
|
||||||
|
"image", _imageTexture, _imageSampler);
|
||||||
|
|
||||||
|
_imageMaterial->setDefaultParameter("showImage", 1);
|
||||||
|
|
||||||
|
_imageMaterial->setDefaultParameter(
|
||||||
|
"backgroundColor", RgbType::sRGB, float3(1.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
FilamentViewer::~FilamentViewer()
|
FilamentViewer::~FilamentViewer()
|
||||||
@@ -231,7 +383,7 @@ namespace polyvox
|
|||||||
for (size_t i = 0; i < resourceUriCount; i++)
|
for (size_t i = 0; i < resourceUriCount; i++)
|
||||||
{
|
{
|
||||||
string uri = relativeResourcePath + string(resourceUris[i]);
|
string uri = relativeResourcePath + string(resourceUris[i]);
|
||||||
Log("Creating resource buffer for resource at %s",uri.c_str());
|
Log("Creating resource buffer for resource at %s", uri.c_str());
|
||||||
ResourceBuffer buf = _loadResource(uri.c_str());
|
ResourceBuffer buf = _loadResource(uri.c_str());
|
||||||
|
|
||||||
// using FunctionCallback = std::function<void(void*, unsigned int, void *)>;
|
// using FunctionCallback = std::function<void(void*, unsigned int, void *)>;
|
||||||
@@ -313,7 +465,7 @@ namespace polyvox
|
|||||||
_asset = nullptr;
|
_asset = nullptr;
|
||||||
_animator = nullptr;
|
_animator = nullptr;
|
||||||
|
|
||||||
ResourceBuffer rbuf = _loadResource(uri);
|
ResourceBuffer rbuf = _loadResource(uri);
|
||||||
|
|
||||||
// Parse the glTF file and create Filament entities.
|
// Parse the glTF file and create Filament entities.
|
||||||
Log("Creating asset from JSON");
|
Log("Creating asset from JSON");
|
||||||
@@ -335,14 +487,16 @@ namespace polyvox
|
|||||||
// transformToUnitCube();
|
// transformToUnitCube();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilamentViewer::removeAsset() {
|
void FilamentViewer::removeAsset()
|
||||||
if (!_asset) {
|
{
|
||||||
|
if (!_asset)
|
||||||
|
{
|
||||||
Log("No asset loaded, ignoring call.");
|
Log("No asset loaded, ignoring call.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mtx.lock();
|
mtx.lock();
|
||||||
|
|
||||||
_resourceLoader->evictResourceData();
|
_resourceLoader->evictResourceData();
|
||||||
_scene->removeEntities(_asset->getEntities(), _asset->getEntityCount());
|
_scene->removeEntities(_asset->getEntities(), _asset->getEntityCount());
|
||||||
_assetLoader->destroyAsset(_asset);
|
_assetLoader->destroyAsset(_asset);
|
||||||
@@ -354,11 +508,6 @@ namespace polyvox
|
|||||||
mtx.unlock();
|
mtx.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilamentViewer::removeSkybox() {
|
|
||||||
_scene->setSkybox(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Sets the active camera to the GLTF camera node specified by [name].
|
/// Sets the active camera to the GLTF camera node specified by [name].
|
||||||
/// N.B. Blender will generally export a three-node hierarchy - Camera1->Camera_Orientation->Camera2.
|
/// N.B. Blender will generally export a three-node hierarchy - Camera1->Camera_Orientation->Camera2.
|
||||||
@@ -368,23 +517,26 @@ namespace polyvox
|
|||||||
{
|
{
|
||||||
Log("Attempting to set camera to %s.", cameraName);
|
Log("Attempting to set camera to %s.", cameraName);
|
||||||
size_t count = _asset->getCameraEntityCount();
|
size_t count = _asset->getCameraEntityCount();
|
||||||
if(count == 0) {
|
if (count == 0)
|
||||||
Log("Failed, no cameras found in current asset.");
|
{
|
||||||
|
Log("Failed, no cameras found in current asset.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const utils::Entity* cameras = _asset->getCameraEntities();
|
const utils::Entity *cameras = _asset->getCameraEntities();
|
||||||
Log("%zu cameras found in current asset", count);
|
Log("%zu cameras found in current asset", count);
|
||||||
for(int i=0; i < count; i++) {
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
auto inst = _ncm->getInstance(cameras[i]);
|
|
||||||
const char* name = _ncm->getName(inst);
|
|
||||||
Log("Camera %d : %s", i, name);
|
|
||||||
if (strcmp(name, cameraName) == 0) {
|
|
||||||
|
|
||||||
Camera* camera = _engine->getCameraComponent(cameras[i]);
|
auto inst = _ncm->getInstance(cameras[i]);
|
||||||
|
const char *name = _ncm->getName(inst);
|
||||||
|
Log("Camera %d : %s", i, name);
|
||||||
|
if (strcmp(name, cameraName) == 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
Camera *camera = _engine->getCameraComponent(cameras[i]);
|
||||||
_view->setCamera(camera);
|
_view->setCamera(camera);
|
||||||
|
|
||||||
const Viewport &vp = _view->getViewport();
|
const Viewport &vp = _view->getViewport();
|
||||||
const double aspect = (double)vp.width / vp.height;
|
const double aspect = (double)vp.width / vp.height;
|
||||||
|
|
||||||
@@ -400,7 +552,8 @@ namespace polyvox
|
|||||||
|
|
||||||
unique_ptr<vector<string>> FilamentViewer::getAnimationNames()
|
unique_ptr<vector<string>> FilamentViewer::getAnimationNames()
|
||||||
{
|
{
|
||||||
if(!_asset) {
|
if (!_asset)
|
||||||
|
{
|
||||||
Log("No asset, ignoring call.");
|
Log("No asset, ignoring call.");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -420,7 +573,8 @@ namespace polyvox
|
|||||||
|
|
||||||
unique_ptr<vector<string>> FilamentViewer::getTargetNames(const char *meshName)
|
unique_ptr<vector<string>> FilamentViewer::getTargetNames(const char *meshName)
|
||||||
{
|
{
|
||||||
if(!_asset) {
|
if (!_asset)
|
||||||
|
{
|
||||||
Log("No asset, ignoring call.");
|
Log("No asset, ignoring call.");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -432,12 +586,14 @@ namespace polyvox
|
|||||||
{
|
{
|
||||||
Entity e = entities[i];
|
Entity e = entities[i];
|
||||||
auto inst = _ncm->getInstance(e);
|
auto inst = _ncm->getInstance(e);
|
||||||
const char* name = _ncm->getName(inst);
|
const char *name = _ncm->getName(inst);
|
||||||
Log("Got entity instance name %s", name);
|
Log("Got entity instance name %s", name);
|
||||||
if(strcmp(name, meshName) == 0) {
|
if (strcmp(name, meshName) == 0)
|
||||||
|
{
|
||||||
size_t count = _asset->getMorphTargetCountAt(e);
|
size_t count = _asset->getMorphTargetCountAt(e);
|
||||||
for(int j=0; j< count; j++) {
|
for (int j = 0; j < count; j++)
|
||||||
const char* morphName = _asset->getMorphTargetNameAt(e, j);
|
{
|
||||||
|
const char *morphName = _asset->getMorphTargetNameAt(e, j);
|
||||||
names->push_back(morphName);
|
names->push_back(morphName);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -446,39 +602,66 @@ namespace polyvox
|
|||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilamentViewer::loadSkybox(const char *const skyboxPath, const char *const iblPath)
|
void FilamentViewer::loadSkybox(const char *const skyboxPath)
|
||||||
{
|
{
|
||||||
|
if (!skyboxPath)
|
||||||
|
{
|
||||||
|
_scene->setSkybox(nullptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ResourceBuffer skyboxBuffer = _loadResource(skyboxPath);
|
||||||
|
|
||||||
ResourceBuffer skyboxBuffer = _loadResource(skyboxPath);
|
image::Ktx1Bundle *skyboxBundle =
|
||||||
|
new image::Ktx1Bundle(static_cast<const uint8_t *>(skyboxBuffer.data), static_cast<uint32_t>(skyboxBuffer.size));
|
||||||
|
_skyboxTexture = ktxreader::Ktx1Reader::createTexture(_engine, skyboxBundle, false);
|
||||||
|
_skybox = filament::Skybox::Builder().environment(_skyboxTexture).build(*_engine);
|
||||||
|
|
||||||
image::Ktx1Bundle *skyboxBundle =
|
_scene->setSkybox(_skybox);
|
||||||
new image::Ktx1Bundle(static_cast<const uint8_t *>(skyboxBuffer.data), static_cast<uint32_t>(skyboxBuffer.size));
|
_freeResource(skyboxBuffer);
|
||||||
_skyboxTexture = ktxreader::Ktx1Reader::createTexture(_engine, skyboxBundle, false);
|
}
|
||||||
_skybox = filament::Skybox::Builder().environment(_skyboxTexture).build(*_engine);
|
}
|
||||||
|
|
||||||
_scene->setSkybox(_skybox);
|
void FilamentViewer::removeSkybox()
|
||||||
_freeResource(skyboxBuffer);
|
{
|
||||||
|
_scene->setSkybox(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
Log("Loading IBL from %s", iblPath);
|
void FilamentViewer::removeIbl()
|
||||||
|
{
|
||||||
|
_scene->setIndirectLight(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
// Load IBL.
|
void FilamentViewer::loadIbl(const char *const iblPath)
|
||||||
ResourceBuffer iblBuffer = _loadResource(iblPath);
|
{
|
||||||
|
if (!iblPath)
|
||||||
|
{
|
||||||
|
_scene->setIndirectLight(nullptr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
image::Ktx1Bundle *iblBundle = new image::Ktx1Bundle(
|
Log("Loading IBL from %s", iblPath);
|
||||||
static_cast<const uint8_t *>(iblBuffer.data), static_cast<uint32_t>(iblBuffer.size));
|
|
||||||
math::float3 harmonics[9];
|
|
||||||
iblBundle->getSphericalHarmonics(harmonics);
|
|
||||||
_iblTexture = ktxreader::Ktx1Reader::createTexture(_engine, iblBundle, false);
|
|
||||||
_indirectLight = IndirectLight::Builder()
|
|
||||||
.reflections(_iblTexture)
|
|
||||||
.irradiance(3, harmonics)
|
|
||||||
.intensity(30000.0f)
|
|
||||||
.build(*_engine);
|
|
||||||
_scene->setIndirectLight(_indirectLight);
|
|
||||||
|
|
||||||
_freeResource(iblBuffer);
|
// Load IBL.
|
||||||
|
ResourceBuffer iblBuffer = _loadResource(iblPath);
|
||||||
|
|
||||||
Log("Skybox/IBL load complete.");
|
image::Ktx1Bundle *iblBundle = new image::Ktx1Bundle(
|
||||||
|
static_cast<const uint8_t *>(iblBuffer.data), static_cast<uint32_t>(iblBuffer.size));
|
||||||
|
math::float3 harmonics[9];
|
||||||
|
iblBundle->getSphericalHarmonics(harmonics);
|
||||||
|
_iblTexture = ktxreader::Ktx1Reader::createTexture(_engine, iblBundle, false);
|
||||||
|
_indirectLight = IndirectLight::Builder()
|
||||||
|
.reflections(_iblTexture)
|
||||||
|
.irradiance(3, harmonics)
|
||||||
|
.intensity(30000.0f)
|
||||||
|
.build(*_engine);
|
||||||
|
_scene->setIndirectLight(_indirectLight);
|
||||||
|
|
||||||
|
_freeResource(iblBuffer);
|
||||||
|
|
||||||
|
Log("Skybox/IBL load complete.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilamentViewer::transformToUnitCube()
|
void FilamentViewer::transformToUnitCube()
|
||||||
@@ -514,13 +697,13 @@ namespace polyvox
|
|||||||
Log("Not ready for rendering");
|
Log("Not ready for rendering");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mtx.lock();
|
mtx.lock();
|
||||||
if(_asset) {
|
if (_asset)
|
||||||
|
{
|
||||||
updateMorphAnimation();
|
updateMorphAnimation();
|
||||||
updateEmbeddedAnimation();
|
updateEmbeddedAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
math::float3 eye, target, upward;
|
math::float3 eye, target, upward;
|
||||||
manipulator->getLookAt(&eye, &target, &upward);
|
manipulator->getLookAt(&eye, &target, &upward);
|
||||||
@@ -532,7 +715,7 @@ namespace polyvox
|
|||||||
_renderer->render(_view);
|
_renderer->render(_view);
|
||||||
_renderer->endFrame();
|
_renderer->endFrame();
|
||||||
}
|
}
|
||||||
mtx.unlock();
|
mtx.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilamentViewer::updateViewportAndCameraProjection(int width, int height, float contentScaleFactor)
|
void FilamentViewer::updateViewportAndCameraProjection(int width, int height, float contentScaleFactor)
|
||||||
@@ -561,11 +744,13 @@ namespace polyvox
|
|||||||
|
|
||||||
void FilamentViewer::updateMorphAnimation()
|
void FilamentViewer::updateMorphAnimation()
|
||||||
{
|
{
|
||||||
if(!_morphAnimationBuffer) {
|
if (!_morphAnimationBuffer)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_morphAnimationBuffer->frameIndex == -1) {
|
if (_morphAnimationBuffer->frameIndex == -1)
|
||||||
|
{
|
||||||
_morphAnimationBuffer->frameIndex++;
|
_morphAnimationBuffer->frameIndex++;
|
||||||
_morphAnimationBuffer->startTime = high_resolution_clock::now();
|
_morphAnimationBuffer->startTime = high_resolution_clock::now();
|
||||||
applyWeights(_morphAnimationBuffer->frameData, _morphAnimationBuffer->numWeights);
|
applyWeights(_morphAnimationBuffer->frameData, _morphAnimationBuffer->numWeights);
|
||||||
@@ -580,7 +765,9 @@ namespace polyvox
|
|||||||
duration<double, std::milli> dur = high_resolution_clock::now() - _morphAnimationBuffer->startTime;
|
duration<double, std::milli> dur = high_resolution_clock::now() - _morphAnimationBuffer->startTime;
|
||||||
Log("Morph animation completed in %f ms (%d frames at framerate %f), final frame was %d", dur.count(), _morphAnimationBuffer->numFrames, 1000 / _morphAnimationBuffer->frameLengthInMs, _morphAnimationBuffer->frameIndex);
|
Log("Morph animation completed in %f ms (%d frames at framerate %f), final frame was %d", dur.count(), _morphAnimationBuffer->numFrames, 1000 / _morphAnimationBuffer->frameLengthInMs, _morphAnimationBuffer->frameIndex);
|
||||||
_morphAnimationBuffer = nullptr;
|
_morphAnimationBuffer = nullptr;
|
||||||
} else if (frameIndex != _morphAnimationBuffer->frameIndex) {
|
}
|
||||||
|
else if (frameIndex != _morphAnimationBuffer->frameIndex)
|
||||||
|
{
|
||||||
Log("Rendering frame %d (of a total %d)", frameIndex, _morphAnimationBuffer->numFrames);
|
Log("Rendering frame %d (of a total %d)", frameIndex, _morphAnimationBuffer->numFrames);
|
||||||
_morphAnimationBuffer->frameIndex = frameIndex;
|
_morphAnimationBuffer->frameIndex = frameIndex;
|
||||||
auto framePtrOffset = frameIndex * _morphAnimationBuffer->numWeights;
|
auto framePtrOffset = frameIndex * _morphAnimationBuffer->numWeights;
|
||||||
@@ -589,43 +776,56 @@ namespace polyvox
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilamentViewer::playAnimation(int index, bool loop) {
|
void FilamentViewer::playAnimation(int index, bool loop)
|
||||||
if(index > _animator->getAnimationCount() - 1) {
|
{
|
||||||
|
if (index > _animator->getAnimationCount() - 1)
|
||||||
|
{
|
||||||
Log("Asset does not contain an animation at index %d", index);
|
Log("Asset does not contain an animation at index %d", index);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
_embeddedAnimationBuffer = make_unique<EmbeddedAnimationBuffer>(index, _animator->getAnimationDuration(index), loop);
|
_embeddedAnimationBuffer = make_unique<EmbeddedAnimationBuffer>(index, _animator->getAnimationDuration(index), loop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilamentViewer::stopAnimation() {
|
void FilamentViewer::stopAnimation()
|
||||||
|
{
|
||||||
// TODO - does this need to be threadsafe?
|
// TODO - does this need to be threadsafe?
|
||||||
_embeddedAnimationBuffer = nullptr;
|
_embeddedAnimationBuffer = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilamentViewer::updateEmbeddedAnimation() {
|
void FilamentViewer::updateEmbeddedAnimation()
|
||||||
if(!_embeddedAnimationBuffer) {
|
{
|
||||||
|
if (!_embeddedAnimationBuffer)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
duration<double> dur = duration_cast<duration<double>>(high_resolution_clock::now() - _embeddedAnimationBuffer->lastTime);
|
duration<double> dur = duration_cast<duration<double>>(high_resolution_clock::now() - _embeddedAnimationBuffer->lastTime);
|
||||||
float startTime = 0;
|
float startTime = 0;
|
||||||
if(!_embeddedAnimationBuffer->hasStarted) {
|
if (!_embeddedAnimationBuffer->hasStarted)
|
||||||
|
{
|
||||||
_embeddedAnimationBuffer->hasStarted = true;
|
_embeddedAnimationBuffer->hasStarted = true;
|
||||||
_embeddedAnimationBuffer->lastTime = high_resolution_clock::now();
|
_embeddedAnimationBuffer->lastTime = high_resolution_clock::now();
|
||||||
} else if(dur.count() >= _embeddedAnimationBuffer->duration) {
|
}
|
||||||
if(_embeddedAnimationBuffer->loop) {
|
else if (dur.count() >= _embeddedAnimationBuffer->duration)
|
||||||
|
{
|
||||||
|
if (_embeddedAnimationBuffer->loop)
|
||||||
|
{
|
||||||
_embeddedAnimationBuffer->lastTime = high_resolution_clock::now();
|
_embeddedAnimationBuffer->lastTime = high_resolution_clock::now();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
_embeddedAnimationBuffer = nullptr;
|
_embeddedAnimationBuffer = nullptr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
startTime = dur.count();
|
startTime = dur.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
_animator->applyAnimation(_embeddedAnimationBuffer->animationIndex, startTime);
|
_animator->applyAnimation(_embeddedAnimationBuffer->animationIndex, startTime);
|
||||||
_animator->updateBoneMatrices();
|
_animator->updateBoneMatrices();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,8 +93,11 @@ namespace polyvox {
|
|||||||
FilamentViewer(void* layer, LoadResource loadResource, FreeResource freeResource);
|
FilamentViewer(void* layer, LoadResource loadResource, FreeResource freeResource);
|
||||||
~FilamentViewer();
|
~FilamentViewer();
|
||||||
|
|
||||||
void loadSkybox(const char* const skyboxUri, const char* const iblUri);
|
void loadSkybox(const char* const skyboxUri);
|
||||||
void removeSkybox();
|
void removeSkybox();
|
||||||
|
|
||||||
|
void loadIbl(const char* const iblUri);
|
||||||
|
void removeIbl();
|
||||||
|
|
||||||
void loadGlb(const char* const uri);
|
void loadGlb(const char* const uri);
|
||||||
void loadGltf(const char* const uri, const char* relativeResourcePath);
|
void loadGltf(const char* const uri, const char* relativeResourcePath);
|
||||||
@@ -137,8 +140,10 @@ namespace polyvox {
|
|||||||
|
|
||||||
Renderer* getRenderer();
|
Renderer* getRenderer();
|
||||||
|
|
||||||
|
void setBackgroundImage(const char* resourcePath);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void createImageRenderable();
|
||||||
void loadResources(std::string relativeResourcePath);
|
void loadResources(std::string relativeResourcePath);
|
||||||
void transformToUnitCube();
|
void transformToUnitCube();
|
||||||
void cleanup();
|
void cleanup();
|
||||||
@@ -187,6 +192,16 @@ namespace polyvox {
|
|||||||
unique_ptr<MorphAnimationBuffer> _morphAnimationBuffer;
|
unique_ptr<MorphAnimationBuffer> _morphAnimationBuffer;
|
||||||
unique_ptr<EmbeddedAnimationBuffer> _embeddedAnimationBuffer;
|
unique_ptr<EmbeddedAnimationBuffer> _embeddedAnimationBuffer;
|
||||||
|
|
||||||
|
Texture* _imageTexture = nullptr;
|
||||||
|
Entity* _imageEntity = nullptr;
|
||||||
|
VertexBuffer* _imageVb = nullptr;
|
||||||
|
IndexBuffer* _imageIb = nullptr;
|
||||||
|
Material* _imageMaterial = nullptr;
|
||||||
|
TextureSampler _imageSampler;
|
||||||
|
|
||||||
|
ColorGrading *colorGrading = nullptr;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
91
ios/src/HDRLoader.cpp
Normal file
91
ios/src/HDRLoader.cpp
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
#include <filament/Engine.h>
|
||||||
|
#include <filament/Texture.h>
|
||||||
|
|
||||||
|
#include <imageio/HDRDecoder.h>
|
||||||
|
|
||||||
|
#include <utils/Log.h>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "common/NioUtils.h"
|
||||||
|
|
||||||
|
using namespace filament;
|
||||||
|
using namespace image;
|
||||||
|
using namespace utils;
|
||||||
|
|
||||||
|
using PixelBufferDescriptor = Texture::PixelBufferDescriptor;
|
||||||
|
|
||||||
|
jlong nCreateHDRTexture(JNIEnv* env, jclass,
|
||||||
|
jlong nativeEngine, jobject javaBuffer, jint remaining, jint internalFormat) {
|
||||||
|
slog.e << "Creating HDR texture." << io::endl;
|
||||||
|
Engine* engine = (Engine*) nativeEngine;
|
||||||
|
AutoBuffer buffer(env, javaBuffer, remaining);
|
||||||
|
Texture::InternalFormat textureFormat = (Texture::InternalFormat) internalFormat;
|
||||||
|
|
||||||
|
auto dataPtr = (char const*) buffer.getData();
|
||||||
|
const size_t byteCount = buffer.getSize();
|
||||||
|
|
||||||
|
// This creates a copy but it's the easest way to create a memory stream.
|
||||||
|
std::string ins(dataPtr, byteCount);
|
||||||
|
std::istringstream in(ins);
|
||||||
|
|
||||||
|
LinearImage* image = new LinearImage(ImageDecoder::decode(in, "memory.hdr"));
|
||||||
|
|
||||||
|
// This can happen if a decoding error occurs.
|
||||||
|
if (image->getChannels() != 3) {
|
||||||
|
delete image;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture* texture = Texture::Builder()
|
||||||
|
.width(image->getWidth())
|
||||||
|
.height(image->getHeight())
|
||||||
|
.levels(0xff)
|
||||||
|
.sampler(Texture::Sampler::SAMPLER_2D)
|
||||||
|
.format(textureFormat)
|
||||||
|
.build(*engine);
|
||||||
|
|
||||||
|
if (texture == nullptr) {
|
||||||
|
slog.e << "Unable to create Filament Texture from HDR image." << io::endl;
|
||||||
|
delete image;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PixelBufferDescriptor::Callback freeCallback = [](void* buf, size_t, void* userdata) {
|
||||||
|
delete (LinearImage*) userdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
PixelBufferDescriptor pbd(
|
||||||
|
(void const* ) image->getPixelRef(),
|
||||||
|
image->getWidth() * image->getHeight() * 3 * sizeof(float),
|
||||||
|
PixelBufferDescriptor::PixelDataFormat::RGB,
|
||||||
|
PixelBufferDescriptor::PixelDataType::FLOAT,
|
||||||
|
freeCallback,
|
||||||
|
image);
|
||||||
|
|
||||||
|
// Note that the setImage call could fail (e.g. due to an invalid combination of internal format
|
||||||
|
// and PixelDataFormat) but there is no way of detecting such a failure.
|
||||||
|
texture->setImage(*engine, 0, std::move(pbd));
|
||||||
|
|
||||||
|
texture->generateMipmaps(*engine);
|
||||||
|
|
||||||
|
return (jlong) texture;
|
||||||
|
}
|
||||||
160
ios/src/Utils.cpp
Normal file
160
ios/src/Utils.cpp
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
#include <filament/Engine.h>
|
||||||
|
#include <filament/IndirectLight.h>
|
||||||
|
#include <filament/Skybox.h>
|
||||||
|
|
||||||
|
#include <image/KtxUtility.h>
|
||||||
|
|
||||||
|
#include <android/asset_manager.h>
|
||||||
|
#include <android/asset_manager_jni.h>
|
||||||
|
|
||||||
|
#include "common/NioUtils.h"
|
||||||
|
|
||||||
|
#include <android/log.h>
|
||||||
|
|
||||||
|
using namespace filament;
|
||||||
|
using namespace filament::math;
|
||||||
|
using namespace image;
|
||||||
|
|
||||||
|
jlong nCreateHDRTexture(JNIEnv* env, jclass,
|
||||||
|
jlong nativeEngine, jobject javaBuffer, jint remaining, jint internalFormat);
|
||||||
|
|
||||||
|
static jlong nCreateKTXTexture(JNIEnv* env, jclass,
|
||||||
|
jlong nativeEngine, jobject javaBuffer, jint remaining, jboolean srgb) {
|
||||||
|
Engine* engine = (Engine*) nativeEngine;
|
||||||
|
AutoBuffer buffer(env, javaBuffer, remaining);
|
||||||
|
KtxBundle* bundle = new KtxBundle((const uint8_t*) buffer.getData(), buffer.getSize());
|
||||||
|
return (jlong) ktx::createTexture(engine, *bundle, srgb, [](void* userdata) {
|
||||||
|
KtxBundle* bundle = (KtxBundle*) userdata;
|
||||||
|
delete bundle;
|
||||||
|
}, bundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static jlong nCreateIndirectLight(JNIEnv* env, jclass,
|
||||||
|
jlong nativeEngine, jobject javaBuffer, jint remaining, jboolean srgb) {
|
||||||
|
Engine* engine = (Engine*) nativeEngine;
|
||||||
|
AutoBuffer buffer(env, javaBuffer, remaining);
|
||||||
|
KtxBundle* bundle = new KtxBundle((const uint8_t*) buffer.getData(), buffer.getSize());
|
||||||
|
Texture* cubemap = ktx::createTexture(engine, *bundle, srgb, [](void* userdata) {
|
||||||
|
KtxBundle* bundle = (KtxBundle*) userdata;
|
||||||
|
delete bundle;
|
||||||
|
}, bundle);
|
||||||
|
|
||||||
|
float3 harmonics[9];
|
||||||
|
bundle->getSphericalHarmonics(harmonics);
|
||||||
|
|
||||||
|
IndirectLight* indirectLight = IndirectLight::Builder()
|
||||||
|
.reflections(cubemap)
|
||||||
|
.irradiance(3, harmonics)
|
||||||
|
.intensity(30000)
|
||||||
|
.build(*engine);
|
||||||
|
|
||||||
|
return (jlong) indirectLight;
|
||||||
|
}
|
||||||
|
|
||||||
|
static jlong nCreateSkybox(JNIEnv* env, jclass,
|
||||||
|
jlong nativeEngine, jobject javaBuffer, jint remaining, jboolean srgb, jobject assetManager, jstring outpath) {
|
||||||
|
|
||||||
|
AAssetManager *mgr = AAssetManager_fromJava(env, assetManager);
|
||||||
|
|
||||||
|
AAsset *asset = AAssetManager_open(mgr, "envs/default_env/default_env_skybox.ktx", AASSET_MODE_BUFFER);
|
||||||
|
if(asset == nullptr) {
|
||||||
|
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Couldn't open asset");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t length = AAsset_getLength(asset);
|
||||||
|
const void * buffer = AAsset_getBuffer(asset);
|
||||||
|
jboolean isCopy = (jboolean)false;
|
||||||
|
const char* out_cstr = env->GetStringUTFChars(outpath, &isCopy);
|
||||||
|
|
||||||
|
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Opening outfile %s for writing", out_cstr);
|
||||||
|
|
||||||
|
FILE* outfile = fopen(out_cstr, "w");
|
||||||
|
|
||||||
|
fwrite(buffer, 1, length, outfile);
|
||||||
|
|
||||||
|
fclose(outfile);
|
||||||
|
|
||||||
|
__android_log_print(ANDROID_LOG_VERBOSE, "filament_api", "Closed outfile %s", out_cstr);
|
||||||
|
|
||||||
|
Engine* engine = (Engine*) nativeEngine;
|
||||||
|
// __android_log_print(ANDROID_LOG_VERBOSE, "UTILS", "CREATing autobuffer");
|
||||||
|
// AutoBuffer buffer(env, javaBuffer, remaining);
|
||||||
|
// __android_log_print(ANDROID_LOG_VERBOSE, "UTILS", "CREATied autobuffer");
|
||||||
|
|
||||||
|
KtxBundle* bundle = new KtxBundle((const uint8_t*) buffer, length);
|
||||||
|
// KtxBundle* bundle = new KtxBundle((const uint8_t*) buffer.getData(), buffer.getSize());
|
||||||
|
__android_log_print(ANDROID_LOG_VERBOSE, "UTILS", "CREATED BUNDLE FROM API");
|
||||||
|
|
||||||
|
|
||||||
|
Texture* cubemap = ktx::createTexture(engine, *bundle, srgb, [](void* userdata) {
|
||||||
|
KtxBundle* bundle = (KtxBundle*) userdata;
|
||||||
|
delete bundle;
|
||||||
|
}, bundle);
|
||||||
|
__android_log_print(ANDROID_LOG_VERBOSE, "UTILS", "CREATED TEXTURE");
|
||||||
|
return (jlong) Skybox::Builder().environment(cubemap).showSun(true).build(*engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
static jboolean nGetSphericalHarmonics(JNIEnv* env, jclass, jobject javaBuffer, jint remaining,
|
||||||
|
jfloatArray outSphericalHarmonics_) {
|
||||||
|
AutoBuffer buffer(env, javaBuffer, remaining);
|
||||||
|
KtxBundle bundle((const uint8_t*) buffer.getData(), buffer.getSize());
|
||||||
|
|
||||||
|
jfloat* outSphericalHarmonics = env->GetFloatArrayElements(outSphericalHarmonics_, nullptr);
|
||||||
|
const auto success = bundle.getSphericalHarmonics(
|
||||||
|
reinterpret_cast<filament::math::float3*>(outSphericalHarmonics)
|
||||||
|
);
|
||||||
|
env->ReleaseFloatArrayElements(outSphericalHarmonics_, outSphericalHarmonics, JNI_ABORT);
|
||||||
|
|
||||||
|
return success ? JNI_TRUE : JNI_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
|
||||||
|
JNIEnv* env;
|
||||||
|
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
// KTXLoader
|
||||||
|
jclass ktxloaderClass = env->FindClass("app/polyvox/filament/KTXLoader2");
|
||||||
|
if (ktxloaderClass == nullptr) return JNI_ERR;
|
||||||
|
static const JNINativeMethod ktxMethods[] = {
|
||||||
|
{(char*)"nCreateKTXTexture", (char*)"(JLjava/nio/Buffer;IZ)J", reinterpret_cast<void*>(nCreateKTXTexture)},
|
||||||
|
{(char*)"nCreateIndirectLight", (char*)"(JLjava/nio/Buffer;IZ)J", reinterpret_cast<void*>(nCreateIndirectLight)},
|
||||||
|
{(char*)"nCreateSkybox", (char*)"(JLjava/nio/Buffer;IZLandroid/content/res/AssetManager;Ljava/lang/String;)J", reinterpret_cast<void*>(nCreateSkybox)},
|
||||||
|
{(char*)"nGetSphericalHarmonics", (char*)"(Ljava/nio/Buffer;I[F)Z", reinterpret_cast<void*>(nGetSphericalHarmonics)},
|
||||||
|
};
|
||||||
|
rc = env->RegisterNatives(ktxloaderClass, ktxMethods, sizeof(ktxMethods) / sizeof(JNINativeMethod));
|
||||||
|
if (rc != JNI_OK) return rc;
|
||||||
|
|
||||||
|
// HDRLoader
|
||||||
|
jclass hdrloaderClass = env->FindClass("com/google/android/filament/utils/HDRLoader");
|
||||||
|
if (hdrloaderClass == nullptr) return JNI_ERR;
|
||||||
|
static const JNINativeMethod hdrMethods[] = {
|
||||||
|
{(char*)"nCreateHDRTexture", (char*)"(JLjava/nio/Buffer;II)J", reinterpret_cast<void*>(nCreateHDRTexture)},
|
||||||
|
};
|
||||||
|
rc = env->RegisterNatives(hdrloaderClass, hdrMethods, sizeof(hdrMethods) / sizeof(JNINativeMethod));
|
||||||
|
if (rc != JNI_OK) return rc;
|
||||||
|
|
||||||
|
return JNI_VERSION_1_6;
|
||||||
|
}
|
||||||
BIN
ios/src/materials/image.filamat
Normal file
BIN
ios/src/materials/image.filamat
Normal file
Binary file not shown.
54
ios/src/materials/image.mat
Normal file
54
ios/src/materials/image.mat
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
material {
|
||||||
|
name : Image,
|
||||||
|
parameters : [
|
||||||
|
{
|
||||||
|
type : sampler2d,
|
||||||
|
name : image
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type : mat3,
|
||||||
|
name : transform,
|
||||||
|
precision : high
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type : float3,
|
||||||
|
name : backgroundColor
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type : int,
|
||||||
|
name : showImage
|
||||||
|
}
|
||||||
|
],
|
||||||
|
variables : [
|
||||||
|
imageUV
|
||||||
|
],
|
||||||
|
vertexDomain : device,
|
||||||
|
depthWrite : false,
|
||||||
|
shadingModel : unlit,
|
||||||
|
variantFilter : [ skinning, shadowReceiver, vsm ],
|
||||||
|
culling: none
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex {
|
||||||
|
void materialVertex(inout MaterialVertexInputs material) {
|
||||||
|
material.imageUV.st = getPosition().st * 0.5 + 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment {
|
||||||
|
void material(inout MaterialInputs material) {
|
||||||
|
prepareMaterial(material);
|
||||||
|
|
||||||
|
vec4 bg = vec4(materialParams.backgroundColor, 1.0);
|
||||||
|
highp vec2 uv = (materialParams.transform * vec3(saturate(variable_imageUV.st), 1.0)).st;
|
||||||
|
if (materialParams.showImage == 0 || uv.s > 1.0 || uv.s < 0.0 || uv.t < 0.0 || uv.t > 1.0) {
|
||||||
|
material.baseColor = bg;
|
||||||
|
} else {
|
||||||
|
uv.t = 1.0 - uv.t;
|
||||||
|
vec4 color = max(texture(materialParams_image, uv.st), 0.0);
|
||||||
|
color.rgb *= color.a;
|
||||||
|
// Manual, pre-multiplied srcOver with opaque destination optimization
|
||||||
|
material.baseColor.rgb = color.rgb + bg.rgb * (1.0 - color.a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user