Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60d3638f15 | ||
|
|
3e7d3c9035 | ||
|
|
eb360be2ad | ||
|
|
485ac8704d | ||
|
|
eaefaf8e59 | ||
|
|
7873e6f5aa | ||
|
|
251abf0545 | ||
|
|
b5c4b30ff6 | ||
|
|
eb941a0868 | ||
|
|
304ffe0049 | ||
|
|
88edbc7df8 | ||
|
|
6fa82ea73d | ||
|
|
92e7ff3de7 | ||
|
|
2739eb146a | ||
|
|
59ccc3021f | ||
|
|
36e9fa42f4 |
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.15.2'
|
||||
implementation 'com.google.android.filament:filament-android:1.16.0'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -52,7 +52,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```
|
||||
pod 'Filament', '~> 1.15.2'
|
||||
pod 'Filament', '~> 1.16.0'
|
||||
```
|
||||
|
||||
### Snapshots
|
||||
|
||||
@@ -3,7 +3,15 @@
|
||||
This file contains one line summaries of commits that are worthy of mentioning in release notes.
|
||||
A new header is inserted each time a *tag* is created.
|
||||
|
||||
## v1.15.3 (currently main branch)
|
||||
## v1.16.1 (currently main branch)
|
||||
|
||||
## v1.16.0
|
||||
|
||||
- engine: Fixes skinning calculations (#4887) [⚠️ **Material breakage**].
|
||||
- engine: Add support for the glTF extension KHR_materials_emissive_strength.
|
||||
- engine: Improvements and fixes to skinning calculations.
|
||||
- engine: Fix debug checks for compressed textures.
|
||||
- Metal: Fix `readPixels` when dimensions are greater than the render target's.
|
||||
|
||||
## v1.15.2
|
||||
|
||||
|
||||
@@ -86,7 +86,6 @@ JniBufferCallback::JniBufferCallback(JNIEnv* env, jobject handler, jobject callb
|
||||
AutoBuffer&& buffer)
|
||||
: JniCallback(env, handler, callback),
|
||||
mBuffer(std::move(buffer)) {
|
||||
acquireCallbackJni(env, mCallbackUtils);
|
||||
}
|
||||
|
||||
JniBufferCallback::~JniBufferCallback() = default;
|
||||
@@ -109,7 +108,6 @@ JniImageCallback* JniImageCallback::make(filament::Engine*,
|
||||
JniImageCallback::JniImageCallback(JNIEnv* env, jobject handler, jobject callback, long image)
|
||||
: JniCallback(env, handler, callback),
|
||||
mImage(image) {
|
||||
acquireCallbackJni(env, mCallbackUtils);
|
||||
}
|
||||
|
||||
JniImageCallback::~JniImageCallback() = default;
|
||||
|
||||
@@ -39,30 +39,39 @@ void releaseCallbackJni(JNIEnv* env, CallbackJni callbackUtils, jobject handler,
|
||||
struct JniCallback : private filament::backend::CallbackHandler {
|
||||
JniCallback(JniCallback const &) = delete;
|
||||
JniCallback(JniCallback&&) = delete;
|
||||
JniCallback& operator=(JniCallback const &) = delete;
|
||||
JniCallback& operator=(JniCallback&&) = delete;
|
||||
|
||||
// create a JniCallback
|
||||
static JniCallback* make(JNIEnv* env, jobject handler, jobject runnable);
|
||||
|
||||
// execute the callback on the java thread and destroy ourselves
|
||||
static void postToJavaAndDestroy(JniCallback* callback);
|
||||
|
||||
// CallbackHandler interface.
|
||||
void post(void* user, Callback callback) override;
|
||||
|
||||
// Get the CallbackHandler interface
|
||||
filament::backend::CallbackHandler* getHandler() noexcept { return this; }
|
||||
|
||||
jobject getCallbackObject() { return mCallback; }
|
||||
|
||||
protected:
|
||||
JniCallback(JNIEnv* env, jobject handler, jobject runnable);
|
||||
explicit JniCallback() = default; // this version does nothing
|
||||
virtual ~JniCallback();
|
||||
jobject mHandler;
|
||||
jobject mCallback;
|
||||
CallbackJni mCallbackUtils;
|
||||
jobject mHandler{};
|
||||
jobject mCallback{};
|
||||
CallbackJni mCallbackUtils{};
|
||||
};
|
||||
|
||||
|
||||
struct JniBufferCallback : public JniCallback {
|
||||
// create a JniBufferCallback
|
||||
static JniBufferCallback* make(filament::Engine* engine,
|
||||
JNIEnv* env, jobject handler, jobject callback, AutoBuffer&& buffer);
|
||||
|
||||
// execute the callback on the java thread and destroy ourselves
|
||||
static void postToJavaAndDestroy(void*, size_t, void* user);
|
||||
|
||||
private:
|
||||
@@ -72,9 +81,11 @@ private:
|
||||
};
|
||||
|
||||
struct JniImageCallback : public JniCallback {
|
||||
// create a JniImageCallback
|
||||
static JniImageCallback* make(filament::Engine* engine, JNIEnv* env, jobject handler,
|
||||
jobject runnable, long image);
|
||||
|
||||
// execute the callback on the java thread and destroy ourselves
|
||||
static void postToJavaAndDestroy(void*, void* user);
|
||||
|
||||
private:
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include "common/CallbackUtils.h"
|
||||
#include "common/NioUtils.h"
|
||||
|
||||
#include "private/backend/VirtualMachineEnv.h"
|
||||
|
||||
using namespace filament;
|
||||
using namespace backend;
|
||||
|
||||
@@ -480,46 +482,37 @@ Java_com_google_android_filament_Texture_nGeneratePrefilterMipmap(JNIEnv *env, j
|
||||
#define BITMAP_CONFIG_RGBA_F16 4
|
||||
#define BITMAP_CONFIG_HARDWARE 5
|
||||
|
||||
class AutoBitmap {
|
||||
public:
|
||||
class AutoBitmap : public JniCallback {
|
||||
private:
|
||||
|
||||
AutoBitmap(JNIEnv* env, jobject bitmap) noexcept
|
||||
: mEnv(env)
|
||||
, mBitmap(env->NewGlobalRef(bitmap))
|
||||
{
|
||||
: JniCallback(),
|
||||
mBitmap(env->NewGlobalRef(bitmap)) {
|
||||
if (mBitmap) {
|
||||
AndroidBitmap_getInfo(mEnv, mBitmap, &mInfo);
|
||||
AndroidBitmap_lockPixels(mEnv, mBitmap, &mData);
|
||||
AndroidBitmap_getInfo(env, mBitmap, &mInfo);
|
||||
AndroidBitmap_lockPixels(env, mBitmap, &mData);
|
||||
}
|
||||
}
|
||||
|
||||
AutoBitmap(JNIEnv* env, jobject bitmap, jobject handler, jobject runnable) noexcept
|
||||
: mEnv(env)
|
||||
, mBitmap(env->NewGlobalRef(bitmap))
|
||||
, mHandler(env->NewGlobalRef(handler))
|
||||
, mCallback(env->NewGlobalRef(runnable))
|
||||
{
|
||||
acquireCallbackJni(env, mCallbackUtils);
|
||||
: JniCallback(env, handler, runnable),
|
||||
mBitmap(env->NewGlobalRef(bitmap)) {
|
||||
if (mBitmap) {
|
||||
AndroidBitmap_getInfo(mEnv, mBitmap, &mInfo);
|
||||
AndroidBitmap_lockPixels(mEnv, mBitmap, &mData);
|
||||
AndroidBitmap_getInfo(env, mBitmap, &mInfo);
|
||||
AndroidBitmap_lockPixels(env, mBitmap, &mData);
|
||||
}
|
||||
}
|
||||
|
||||
~AutoBitmap() noexcept {
|
||||
releaseCallbackJni(mEnv, mCallbackUtils, mHandler, mCallback);
|
||||
void release(JNIEnv* env) {
|
||||
if (mBitmap) {
|
||||
AndroidBitmap_unlockPixels(mEnv, mBitmap);
|
||||
mEnv->DeleteGlobalRef(mBitmap);
|
||||
AndroidBitmap_unlockPixels(env, mBitmap);
|
||||
env->DeleteGlobalRef(mBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
AutoBitmap(AutoBitmap &&rhs) noexcept {
|
||||
mEnv = rhs.mEnv;
|
||||
std::swap(mData, rhs.mData);
|
||||
std::swap(mBitmap, rhs.mBitmap);
|
||||
std::swap(mInfo, rhs.mInfo);
|
||||
}
|
||||
~AutoBitmap() override = default;
|
||||
|
||||
public:
|
||||
void* getData() const noexcept {
|
||||
return mData;
|
||||
}
|
||||
@@ -546,28 +539,39 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
static void invoke(void* buffer, size_t n, void* user) {
|
||||
AutoBitmap* data = reinterpret_cast<AutoBitmap*>(user);
|
||||
delete data;
|
||||
}
|
||||
|
||||
static AutoBitmap* make(Engine* engine, JNIEnv* env, jobject bitmap) {
|
||||
return new AutoBitmap(env, bitmap);
|
||||
}
|
||||
|
||||
static AutoBitmap* make(Engine* engine, JNIEnv* env, jobject bitmap,
|
||||
jobject handler, jobject runnable) {
|
||||
// create a AutoBitmap
|
||||
static AutoBitmap* make(JNIEnv* env, jobject bitmap, jobject handler, jobject runnable) {
|
||||
return new AutoBitmap(env, bitmap, handler, runnable);
|
||||
}
|
||||
|
||||
// execute the callback on the java thread and destroy ourselves
|
||||
static void invoke(void*, size_t, void* user) {
|
||||
auto* autoBitmap = reinterpret_cast<AutoBitmap*>(user);
|
||||
JNIEnv* env = filament::VirtualMachineEnv::get().getEnvironment();
|
||||
releaseCallbackJni(env, autoBitmap->mCallbackUtils, autoBitmap->mHandler, autoBitmap->mCallback);
|
||||
autoBitmap->release(env);
|
||||
delete autoBitmap;
|
||||
}
|
||||
|
||||
// create a AutoBitmap without a handler
|
||||
static AutoBitmap* make(JNIEnv* env, jobject bitmap) {
|
||||
return new AutoBitmap(env, bitmap);
|
||||
}
|
||||
|
||||
// just destroy ourselves
|
||||
static void invokeNoCallback(void*, size_t, void* user) {
|
||||
auto* autoBitmap = reinterpret_cast<AutoBitmap*>(user);
|
||||
JNIEnv* env = filament::VirtualMachineEnv::get().getEnvironment();
|
||||
autoBitmap->release(env);
|
||||
delete autoBitmap;
|
||||
}
|
||||
|
||||
private:
|
||||
JNIEnv* mEnv;
|
||||
void* mData = nullptr;
|
||||
jobject mBitmap = nullptr;
|
||||
jobject mHandler = nullptr;
|
||||
jobject mCallback = nullptr;
|
||||
AndroidBitmapInfo mInfo{};
|
||||
CallbackJni mCallbackUtils;
|
||||
};
|
||||
|
||||
extern "C"
|
||||
@@ -578,14 +582,14 @@ Java_com_google_android_filament_android_TextureHelper_nSetBitmap(JNIEnv* env, j
|
||||
Texture* texture = (Texture*) nativeTexture;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
|
||||
auto* autoBitmap = AutoBitmap::make(engine, env, bitmap);
|
||||
auto* autoBitmap = AutoBitmap::make(env, bitmap);
|
||||
|
||||
Texture::PixelBufferDescriptor desc(
|
||||
autoBitmap->getData(),
|
||||
autoBitmap->getSizeInBytes(),
|
||||
autoBitmap->getFormat(format),
|
||||
autoBitmap->getType(format),
|
||||
&AutoBitmap::invoke, autoBitmap);
|
||||
&AutoBitmap::invokeNoCallback, autoBitmap);
|
||||
|
||||
texture->setImage(*engine, (size_t) level,
|
||||
(uint32_t) xoffset, (uint32_t) yoffset,
|
||||
@@ -601,14 +605,14 @@ Java_com_google_android_filament_android_TextureHelper_nSetBitmapWithCallback(JN
|
||||
Texture* texture = (Texture*) nativeTexture;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
|
||||
auto* autoBitmap = AutoBitmap::make(engine, env, bitmap, handler, runnable);
|
||||
auto* autoBitmap = AutoBitmap::make(env, bitmap, handler, runnable);
|
||||
|
||||
Texture::PixelBufferDescriptor desc(
|
||||
autoBitmap->getData(),
|
||||
autoBitmap->getSizeInBytes(),
|
||||
autoBitmap->getFormat(format),
|
||||
autoBitmap->getType(format),
|
||||
&AutoBitmap::invoke, autoBitmap);
|
||||
autoBitmap->getHandler(), &AutoBitmap::invoke, autoBitmap);
|
||||
|
||||
texture->setImage(*engine, (size_t) level,
|
||||
(uint32_t) xoffset, (uint32_t) yoffset,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.15.2
|
||||
VERSION_NAME=1.16.0
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -979,6 +979,11 @@ void MetalDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y,
|
||||
id<MTLTexture> srcTexture = color.getTexture();
|
||||
size_t miplevel = color.level;
|
||||
|
||||
// Clamp height and width to actual texture's height and width
|
||||
MTLSize srcTextureSize = MTLSizeMake(srcTexture.width >> miplevel, srcTexture.height >> miplevel, 1);
|
||||
height = std::min(static_cast<uint32_t>(srcTextureSize.height), height);
|
||||
width = std::min(static_cast<uint32_t>(srcTextureSize.width), width);
|
||||
|
||||
const MTLPixelFormat format = getMetalFormat(data.format, data.type);
|
||||
ASSERT_PRECONDITION(format != MTLPixelFormatInvalid,
|
||||
"The chosen combination of PixelDataFormat (%d) and PixelDataType (%d) is not supported for "
|
||||
@@ -994,8 +999,8 @@ void MetalDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y,
|
||||
|
||||
MTLTextureDescriptor* textureDescriptor =
|
||||
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format
|
||||
width:(srcTexture.width >> miplevel)
|
||||
height:(srcTexture.height >> miplevel)
|
||||
width:srcTextureSize.width
|
||||
height:srcTextureSize.height
|
||||
mipmapped:NO];
|
||||
#if defined(IOS)
|
||||
textureDescriptor.storageMode = MTLStorageModeShared;
|
||||
|
||||
@@ -1807,10 +1807,12 @@ void OpenGLDriver::updateCubeImage(Handle<HwTexture> th, uint32_t level,
|
||||
DEBUG_MARKER()
|
||||
|
||||
GLTexture* t = handle_cast<GLTexture *>(th);
|
||||
auto width = std::max(1u, t->width >> level);
|
||||
auto height = std::max(1u, t->height >> level);
|
||||
if (data.type == PixelDataType::COMPRESSED) {
|
||||
setCompressedTextureData(t, level, 0, 0, 0, 0, 0, 0, std::move(data), &faceOffsets);
|
||||
setCompressedTextureData(t, level, 0, 0, 0, width, height, 0, std::move(data), &faceOffsets);
|
||||
} else {
|
||||
setTextureData(t, level, 0, 0, 0, 0, 0, 0, std::move(data), &faceOffsets);
|
||||
setTextureData(t, level, 0, 0, 0, width, height, 0, std::move(data), &faceOffsets);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1907,7 +1909,7 @@ void OpenGLDriver::setTextureData(GLTexture* t,
|
||||
for (size_t face = 0; face < 6; face++) {
|
||||
GLenum target = getCubemapTarget(TextureCubemapFace(face));
|
||||
glTexSubImage2D(target, GLint(level), 0, 0,
|
||||
t->width >> level, t->height >> level, glFormat, glType,
|
||||
width, height, glFormat, glType,
|
||||
static_cast<uint8_t const*>(p.buffer) + offsets[face]);
|
||||
}
|
||||
break;
|
||||
@@ -1938,8 +1940,8 @@ void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level,
|
||||
DEBUG_MARKER()
|
||||
auto& gl = mContext;
|
||||
|
||||
assert_invariant(xoffset + width <= t->width >> level);
|
||||
assert_invariant(yoffset + height <= t->height >> level);
|
||||
assert_invariant(xoffset + width <= std::max(1u, t->width >> level));
|
||||
assert_invariant(yoffset + height <= std::max(1u, t->height >> level));
|
||||
assert_invariant(zoffset + depth <= t->depth);
|
||||
assert_invariant(t->samples <= 1);
|
||||
|
||||
@@ -1992,7 +1994,7 @@ void OpenGLDriver::setCompressedTextureData(GLTexture* t, uint32_t level,
|
||||
for (size_t face = 0; face < 6; face++) {
|
||||
GLenum target = getCubemapTarget(TextureCubemapFace(face));
|
||||
glCompressedTexSubImage2D(target, GLint(level), 0, 0,
|
||||
t->width >> level, t->height >> level, t->gl.internalFormat,
|
||||
width, height, t->gl.internalFormat,
|
||||
imageSize, static_cast<uint8_t const*>(p.buffer) + offsets[face]);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -22,10 +22,9 @@
|
||||
|
||||
#include "FilamentAPI-impl.h"
|
||||
|
||||
#include <math/half.h>
|
||||
#include <math/mat4.h>
|
||||
|
||||
#include <float.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
using namespace backend;
|
||||
@@ -111,55 +110,61 @@ void FSkinningBuffer::setBones(FEngine& engine,
|
||||
setBones(engine, mHandle, transforms, count, offset);
|
||||
}
|
||||
|
||||
static uint32_t packHalf2x16(half2 v) noexcept {
|
||||
uint32_t lo = getBits(v[0]);
|
||||
uint32_t hi = getBits(v[1]);
|
||||
return (hi << 16) | lo;
|
||||
}
|
||||
|
||||
void FSkinningBuffer::setBones(FEngine& engine, Handle<backend::HwBufferObject> handle,
|
||||
RenderableManager::Bone const* transforms, size_t boneCount, size_t offset) noexcept {
|
||||
auto& driverApi = engine.getDriverApi();
|
||||
size_t size = boneCount * sizeof(PerRenderableUibBone);
|
||||
PerRenderableUibBone* UTILS_RESTRICT out = (PerRenderableUibBone*)driverApi.allocate(size);
|
||||
for (size_t i = 0, c = boneCount; i < c; ++i) {
|
||||
out[i].q = transforms[i].unitQuaternion;
|
||||
out[i].t.xyz = transforms[i].translation;
|
||||
out[i].s = out[i].ns = { 1, 1, 1, 0 };
|
||||
// the transform is stored in row-major, last row is not stored.
|
||||
mat4f transform(transforms[i].unitQuaternion);
|
||||
transform[3] = float4{ transforms[i].translation, 1.0f };
|
||||
out[i] = makeBone(transform);
|
||||
}
|
||||
driverApi.updateBufferObject(handle, { out, size },
|
||||
offset * sizeof(PerRenderableUibBone));
|
||||
}
|
||||
|
||||
PerRenderableUibBone FSkinningBuffer::makeBone(mat4f transform) noexcept {
|
||||
const mat3f cofactors = cof(transform.upperLeft());
|
||||
transform = transpose(transform); // row-major conversion
|
||||
return {
|
||||
.bone = {
|
||||
.transform = {
|
||||
transform[0],
|
||||
transform[1],
|
||||
transform[2]
|
||||
},
|
||||
.cof = {
|
||||
packHalf2x16({ cofactors[0].x, cofactors[0].y }),
|
||||
packHalf2x16({ cofactors[0].z, cofactors[1].x }),
|
||||
packHalf2x16({ cofactors[1].y, cofactors[1].z }),
|
||||
packHalf2x16({ cofactors[2].x, cofactors[2].y })
|
||||
// cofactor[2][2] is not stored because we don't have space for it
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void FSkinningBuffer::setBones(FEngine& engine, Handle<backend::HwBufferObject> handle,
|
||||
mat4f const* transforms, size_t boneCount, size_t offset) noexcept {
|
||||
auto& driverApi = engine.getDriverApi();
|
||||
size_t size = boneCount * sizeof(PerRenderableUibBone);
|
||||
PerRenderableUibBone* UTILS_RESTRICT out = (PerRenderableUibBone*)driverApi.allocate(size);
|
||||
for (size_t i = 0, c = boneCount; i < c; ++i) {
|
||||
FSkinningBuffer::makeBone(&out[i], transforms[i]);
|
||||
// the transform is stored in row-major, last row is not stored.
|
||||
out[i] = makeBone(transforms[i]);
|
||||
}
|
||||
driverApi.updateBufferObject(handle, { out, size },
|
||||
offset * sizeof(PerRenderableUibBone));
|
||||
}
|
||||
|
||||
void FSkinningBuffer::makeBone(PerRenderableUibBone* UTILS_RESTRICT out, mat4f const& t) noexcept {
|
||||
mat4f m(t);
|
||||
|
||||
// figure out the scales
|
||||
float4 s = { length(m[0]), length(m[1]), length(m[2]), 0.0f };
|
||||
s = max(s, float4(FLT_EPSILON)); // avoid divide-by-zero when computing inverse scales
|
||||
if (dot(cross(m[0].xyz, m[1].xyz), m[2].xyz) < 0) {
|
||||
s[2] = -s[2];
|
||||
}
|
||||
|
||||
// compute the inverse scales
|
||||
float4 is = { 1.0f/s.x, 1.0f/s.y, 1.0f/s.z, 0.0f };
|
||||
|
||||
// normalize the matrix
|
||||
m[0] *= is[0];
|
||||
m[1] *= is[1];
|
||||
m[2] *= is[2];
|
||||
|
||||
out->s = s;
|
||||
out->q = m.toQuaternion();
|
||||
out->t = m[3];
|
||||
out->ns = is / max(abs(is));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Trampoline calling into private implementation
|
||||
|
||||
@@ -57,14 +57,14 @@ private:
|
||||
friend class SkinningBuffer;
|
||||
friend class FRenderableManager;
|
||||
|
||||
static void makeBone(PerRenderableUibBone* out, math::mat4f const& transforms) noexcept;
|
||||
|
||||
static void setBones(FEngine& engine, backend::Handle<backend::HwBufferObject> handle,
|
||||
RenderableManager::Bone const* transforms, size_t boneCount, size_t offset) noexcept;
|
||||
|
||||
static void setBones(FEngine& engine, backend::Handle<backend::HwBufferObject> handle,
|
||||
math::mat4f const* transforms, size_t boneCount, size_t offset) noexcept;
|
||||
|
||||
static PerRenderableUibBone makeBone(math::mat4f transform) noexcept;
|
||||
|
||||
backend::Handle<backend::HwBufferObject> getHwHandle() const noexcept {
|
||||
return mHandle;
|
||||
}
|
||||
|
||||
@@ -727,139 +727,6 @@ TEST(FilamentTest, FroxelData) {
|
||||
Engine::destroy((Engine **)&engine);
|
||||
}
|
||||
|
||||
TEST(FilamentTest, Bones) {
|
||||
|
||||
struct Shader {
|
||||
static mat3f normal(PerRenderableUibBone const& bone) noexcept {
|
||||
quatf q = bone.q;
|
||||
float3 is = bone.ns.xyz;
|
||||
return mat3f(mat3(q) * mat3::scaling(is));
|
||||
}
|
||||
static mat4f vertice(PerRenderableUibBone const& bone) noexcept {
|
||||
quatf q = bone.q;
|
||||
float3 t = bone.t.xyz;
|
||||
float3 s = bone.s.xyz;
|
||||
return mat4f(mat4::translation(t) * mat4(q) * mat4::scaling(s));
|
||||
}
|
||||
static float3 normal(float3 n, PerRenderableUibBone const& bone) noexcept {
|
||||
quatf q = bone.q;
|
||||
float3 is = bone.ns.xyz;
|
||||
// apply the inverse of the non-uniform scales
|
||||
n *= is;
|
||||
// apply the rigid transform
|
||||
n += 2.0 * cross(q.xyz, cross(q.xyz, n) + q.w * n);
|
||||
return n;
|
||||
}
|
||||
static float3 vertice(float3 v, PerRenderableUibBone const& bone) noexcept {
|
||||
quatf q = bone.q;
|
||||
float3 t = bone.t.xyz;
|
||||
float3 s = bone.s.xyz;
|
||||
// apply the non-uniform scales
|
||||
v *= s;
|
||||
// apply the rigid transform
|
||||
v += 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v);
|
||||
// apply the translation
|
||||
v += t;
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
struct Test {
|
||||
static inline double epsilon(double x, double y) {
|
||||
double maxXYOne = std::max({ 1.0, std::fabs(x), std::fabs(y) });
|
||||
return 1e-5 * maxXYOne;
|
||||
}
|
||||
|
||||
static void expect_eq(mat4f e, mat4f a) noexcept {
|
||||
for (size_t j = 0; j < 4; j++) {
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
EXPECT_NEAR(e[i][j], a[i][j], epsilon(e[i][j], a[i][j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
static void expect_eq(mat3f e, mat3f a) noexcept {
|
||||
for (size_t j = 0; j < 3; j++) {
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
EXPECT_NEAR(e[i][j], a[i][j], epsilon(e[i][j], a[i][j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
static void expect_eq(float3 e, float3 a) noexcept {
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
EXPECT_NEAR(e[i], a[i], epsilon(e[i], a[i]));
|
||||
}
|
||||
}
|
||||
|
||||
static void check(mat4f const& m) noexcept {
|
||||
PerRenderableUibBone b;
|
||||
FSkinningBuffer::makeBone(&b, m);
|
||||
|
||||
expect_eq(Shader::vertice(b), m);
|
||||
|
||||
mat3f n = transpose(inverse(m.upperLeft()));
|
||||
n *= mat3f(1.0f / std::sqrt(max(float3{length2(n[0]), length2(n[1]), length2(n[2])})));
|
||||
expect_eq(Shader::normal(b), n);
|
||||
}
|
||||
|
||||
static void check(mat4f const& m, float3 const& v) noexcept {
|
||||
PerRenderableUibBone b;
|
||||
FSkinningBuffer::makeBone(&b, m);
|
||||
|
||||
expect_eq((m * v).xyz, Shader::vertice(v, b));
|
||||
|
||||
mat3f n = transpose(inverse(m.upperLeft()));
|
||||
n *= mat3f(1.0f / std::sqrt(max(float3{length2(n[0]), length2(n[1]), length2(n[2])})));
|
||||
expect_eq(n * normalize(v), Shader::normal(normalize(v), b));
|
||||
|
||||
float3 normal = n * normalize(v);
|
||||
EXPECT_LE(max(abs(normal)), 1.0);
|
||||
}
|
||||
};
|
||||
|
||||
Test::check(mat4f{});
|
||||
Test::check(mat4f::translation(float3{ 1, 2, 3 }));
|
||||
|
||||
Test::check(mat4f::scaling(float3{ 2, 2, 2 }));
|
||||
|
||||
Test::check(mat4f::scaling(float3{ 4, 2, 3 }));
|
||||
Test::check(mat4f::scaling(float3{ 4, -2, -3 }));
|
||||
Test::check(mat4f::scaling(float3{ -4, 2, -3 }));
|
||||
Test::check(mat4f::scaling(float3{ -4, -2, 3 }));
|
||||
|
||||
Test::check(mat4f::scaling(float3{ -4, -2, -3 }));
|
||||
Test::check(mat4f::scaling(float3{ -4, 2, 3 }));
|
||||
Test::check(mat4f::scaling(float3{ 4, -2, 3 }));
|
||||
Test::check(mat4f::scaling(float3{ 4, 2, -3 }));
|
||||
|
||||
Test::check(mat4f::rotation(F_PI_2, float3{ 0, 0, 1 }));
|
||||
Test::check(mat4f::rotation(F_PI_2, float3{ 0, 1, 0 }));
|
||||
Test::check(mat4f::rotation(F_PI_2, float3{ 1, 0, 0 }));
|
||||
Test::check(mat4f::rotation(F_PI_2, float3{ 0, 1, 1 }));
|
||||
Test::check(mat4f::rotation(F_PI_2, float3{ 1, 0, 1 }));
|
||||
Test::check(mat4f::rotation(F_PI_2, float3{ 1, 1, 0 }));
|
||||
Test::check(mat4f::rotation(-F_PI_2, float3{ 0, 0, 1 }));
|
||||
Test::check(mat4f::rotation(-F_PI_2, float3{ 0, 1, 0 }));
|
||||
Test::check(mat4f::rotation(-F_PI_2, float3{ 1, 0, 0 }));
|
||||
Test::check(mat4f::rotation(-F_PI_2, float3{ 0, 1, 1 }));
|
||||
Test::check(mat4f::rotation(-F_PI_2, float3{ 1, 0, 1 }));
|
||||
Test::check(mat4f::rotation(-F_PI_2, float3{ 1, 1, 0 }));
|
||||
|
||||
mat4f m = mat4f::translation(float3{ 1, 2, 3 }) *
|
||||
mat4f::rotation(-F_PI_2, float3{ 1, 1, 0 }) *
|
||||
mat4f::scaling(float3{ -2, 3, 0.04 });
|
||||
|
||||
Test::check(m);
|
||||
|
||||
std::default_random_engine generator(82828);
|
||||
std::uniform_real_distribution<float> distribution(-100.0f, 100.0f);
|
||||
auto rand_gen = std::bind(distribution, generator);
|
||||
|
||||
for (size_t i = 0; i < 100; ++i) {
|
||||
float3 p(rand_gen(), rand_gen(), rand_gen());
|
||||
Test::check(m, p);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(FilamentTest, GoogleLineDirective) {
|
||||
{
|
||||
char s[512] = "#line 10 \"foobar\"";
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.15.2"
|
||||
spec.version = "1.16.0"
|
||||
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||
spec.homepage = "https://google.github.io/filament"
|
||||
spec.authors = "Google LLC."
|
||||
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
||||
spec.platform = :ios, "11.0"
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.15.2/filament-v1.15.2-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.16.0/filament-v1.16.0-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
namespace filament {
|
||||
|
||||
// update this when a new version of filament wouldn't work with older materials
|
||||
static constexpr size_t MATERIAL_VERSION = 15;
|
||||
static constexpr size_t MATERIAL_VERSION = 16;
|
||||
|
||||
/**
|
||||
* Supported shading models
|
||||
|
||||
@@ -212,10 +212,17 @@ static_assert(sizeof(FroxelRecordUib) == 16384, "FroxelRecordUib should be exact
|
||||
// This is not the UBO proper, but just an element of a bone array.
|
||||
struct PerRenderableUibBone { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
static constexpr utils::StaticString _name{ "BonesUniforms" };
|
||||
math::quatf q = { 1, 0, 0, 0 };
|
||||
math::float4 t = {};
|
||||
math::float4 s = { 1, 1, 1, 0 };
|
||||
math::float4 ns = { 1, 1, 1, 0 };
|
||||
struct alignas(16) BoneData {
|
||||
// bone transform, last row assumed [0,0,0,1]
|
||||
math::float4 transform[3] = {
|
||||
{1,0,0,0},
|
||||
{0,1,0,0},
|
||||
{0,0,1,0}
|
||||
};
|
||||
// 8 first cofactor matrix of transform's upper left
|
||||
math::uint4 cof = {};
|
||||
};
|
||||
BoneData bone;
|
||||
};
|
||||
static_assert(CONFIG_MAX_BONE_COUNT * sizeof(PerRenderableUibBone) <= 16384,
|
||||
"PerRenderableUibBone exceed max UBO size");
|
||||
|
||||
@@ -156,7 +156,7 @@ UniformInterfaceBlock const& UibGenerator::getShadowUib() noexcept {
|
||||
UniformInterfaceBlock const& UibGenerator::getPerRenderableBonesUib() noexcept {
|
||||
static UniformInterfaceBlock uib = UniformInterfaceBlock::Builder()
|
||||
.name(PerRenderableUibBone::_name)
|
||||
.add("bones", CONFIG_MAX_BONE_COUNT * 4, UniformInterfaceBlock::Type::FLOAT4, Precision::MEDIUM)
|
||||
.add("bones", CONFIG_MAX_BONE_COUNT, "BoneData", sizeof(PerRenderableUibBone::BoneData))
|
||||
.build();
|
||||
return uib;
|
||||
}
|
||||
|
||||
@@ -1029,8 +1029,11 @@ MaterialInstance* FAssetLoader::createMaterialInstance(const cgltf_material* inp
|
||||
mi->setMaskThreshold(inputMat->alpha_cutoff);
|
||||
}
|
||||
|
||||
const float* e = inputMat->emissive_factor;
|
||||
mi->setParameter("emissiveFactor", float3(e[0], e[1], e[2]));
|
||||
float3 emissiveFactor(inputMat->emissive_factor[0], inputMat->emissive_factor[1], inputMat->emissive_factor[2]);
|
||||
if (inputMat->has_emissive_strength) {
|
||||
emissiveFactor *= inputMat->emissive_strength.emissive_strength;
|
||||
}
|
||||
mi->setParameter("emissiveFactor", emissiveFactor);
|
||||
|
||||
const float* c = mrConfig.base_color_factor;
|
||||
mi->setParameter("baseColorFactor", float4(c[0], c[1], c[2], c[3]));
|
||||
|
||||
@@ -159,3 +159,27 @@ void toTangentFrame(const highp vec4 q, out highp vec3 n, out highp vec3 t) {
|
||||
vec3(-2.0, 2.0, -2.0) * q.y * q.yxw +
|
||||
vec3(-2.0, 2.0, 2.0) * q.z * q.zwx;
|
||||
}
|
||||
|
||||
highp mat3 cofactor(const highp mat3 m) {
|
||||
highp float a = m[0][0];
|
||||
highp float b = m[1][0];
|
||||
highp float c = m[2][0];
|
||||
highp float d = m[0][1];
|
||||
highp float e = m[1][1];
|
||||
highp float f = m[2][1];
|
||||
highp float g = m[0][2];
|
||||
highp float h = m[1][2];
|
||||
highp float i = m[2][2];
|
||||
|
||||
highp mat3 cof;
|
||||
cof[0][0] = e * i - f * h;
|
||||
cof[0][1] = c * h - b * i;
|
||||
cof[0][2] = b * f - c * e;
|
||||
cof[1][0] = f * g - d * i;
|
||||
cof[1][1] = a * i - c * g;
|
||||
cof[1][2] = c * d - a * f;
|
||||
cof[2][0] = d * h - e * g;
|
||||
cof[2][1] = b * g - a * h;
|
||||
cof[2][2] = a * e - b * d;
|
||||
return cof;
|
||||
}
|
||||
|
||||
@@ -34,3 +34,8 @@ struct ShadowData {
|
||||
float bulbRadiusLs;
|
||||
float nearOverFarMinusNear;
|
||||
};
|
||||
|
||||
struct BoneData {
|
||||
highp mat3x4 transform; // bone transform is mat4x3 stored in row-major (last row [0,0,0,1])
|
||||
highp uvec4 cof; // 8 first cofactor matrix of transform's upper left
|
||||
};
|
||||
|
||||
@@ -22,44 +22,46 @@ mat3 getWorldFromModelNormalMatrix() {
|
||||
|
||||
#if defined(HAS_SKINNING_OR_MORPHING)
|
||||
vec3 mulBoneNormal(vec3 n, uint i) {
|
||||
vec4 q = bonesUniforms.bones[i + 0u];
|
||||
vec3 is = bonesUniforms.bones[i + 3u].xyz;
|
||||
|
||||
// apply the inverse of the non-uniform scales
|
||||
n *= is;
|
||||
// apply the rigid transform (valid only for unit quaternions)
|
||||
n += 2.0 * cross(q.xyz, cross(q.xyz, n) + q.w * n);
|
||||
highp mat3 cof;
|
||||
|
||||
return n;
|
||||
// the first 8 elements of the cofactor matrix are stored as fp16
|
||||
highp vec2 zx = unpackHalf2x16(bonesUniforms.bones[i].cof[1]);
|
||||
cof[0].xy = unpackHalf2x16(bonesUniforms.bones[i].cof[0]);
|
||||
cof[0].z = zx[0];
|
||||
cof[1].x = zx[1];
|
||||
cof[1].yz = unpackHalf2x16(bonesUniforms.bones[i].cof[2]);
|
||||
cof[2].xy = unpackHalf2x16(bonesUniforms.bones[i].cof[3]);
|
||||
|
||||
// the last element must be computed by hand
|
||||
highp float a = bonesUniforms.bones[i].transform[0][0];
|
||||
highp float b = bonesUniforms.bones[i].transform[0][1];
|
||||
highp float d = bonesUniforms.bones[i].transform[1][0];
|
||||
highp float e = bonesUniforms.bones[i].transform[1][1];
|
||||
|
||||
cof[2].z = a * e - b * d;
|
||||
|
||||
return normalize(cof * n);
|
||||
}
|
||||
|
||||
vec3 mulBoneVertex(vec3 v, uint i) {
|
||||
vec4 q = bonesUniforms.bones[i + 0u];
|
||||
vec3 t = bonesUniforms.bones[i + 1u].xyz;
|
||||
vec3 s = bonesUniforms.bones[i + 2u].xyz;
|
||||
|
||||
// apply the non-uniform scales
|
||||
v *= s;
|
||||
// apply the rigid transform (valid only for unit quaternions)
|
||||
v += 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v);
|
||||
// apply the translation
|
||||
v += t;
|
||||
|
||||
return v;
|
||||
// last row of bonesUniforms.transform[i] (row major) is assumed to be [0,0,0,1]
|
||||
highp mat4x3 m = transpose(bonesUniforms.bones[i].transform);
|
||||
return v.x * m[0].xyz + (v.y * m[1].xyz + (v.z * m[2].xyz + m[3].xyz));
|
||||
}
|
||||
|
||||
void skinNormal(inout vec3 n, const uvec4 ids, const vec4 weights) {
|
||||
n = mulBoneNormal(n, ids.x * 4u) * weights.x
|
||||
+ mulBoneNormal(n, ids.y * 4u) * weights.y
|
||||
+ mulBoneNormal(n, ids.z * 4u) * weights.z
|
||||
+ mulBoneNormal(n, ids.w * 4u) * weights.w;
|
||||
n = mulBoneNormal(n, ids.x) * weights.x
|
||||
+ mulBoneNormal(n, ids.y) * weights.y
|
||||
+ mulBoneNormal(n, ids.z) * weights.z
|
||||
+ mulBoneNormal(n, ids.w) * weights.w;
|
||||
}
|
||||
|
||||
void skinPosition(inout vec3 p, const uvec4 ids, const vec4 weights) {
|
||||
p = mulBoneVertex(p, ids.x * 4u) * weights.x
|
||||
+ mulBoneVertex(p, ids.y * 4u) * weights.y
|
||||
+ mulBoneVertex(p, ids.z * 4u) * weights.z
|
||||
+ mulBoneVertex(p, ids.w * 4u) * weights.w;
|
||||
p = mulBoneVertex(p, ids.x) * weights.x
|
||||
+ mulBoneVertex(p, ids.y) * weights.y
|
||||
+ mulBoneVertex(p, ids.z) * weights.z
|
||||
+ mulBoneVertex(p, ids.w) * weights.w;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
2
third_party/cgltf/README.md
vendored
2
third_party/cgltf/README.md
vendored
@@ -112,6 +112,8 @@ cgltf also supports some glTF extensions:
|
||||
- KHR_materials_variants
|
||||
- KHR_materials_volume
|
||||
- KHR_texture_transform
|
||||
- KHR_texture_basisu (requires a library like [Binomial Basisu](https://github.com/BinomialLLC/basis_universal) for transcoding to native compressed texture)
|
||||
- KHR_materials_emissive_strength
|
||||
|
||||
cgltf does **not** yet support unlisted extensions. However, unlisted extensions can be accessed via "extensions" member on objects.
|
||||
|
||||
|
||||
122
third_party/cgltf/cgltf.h
vendored
122
third_party/cgltf/cgltf.h
vendored
@@ -474,6 +474,11 @@ typedef struct cgltf_sheen
|
||||
cgltf_float sheen_roughness_factor;
|
||||
} cgltf_sheen;
|
||||
|
||||
typedef struct cgltf_emissive_strength
|
||||
{
|
||||
cgltf_float emissive_strength;
|
||||
} cgltf_emissive_strength;
|
||||
|
||||
typedef struct cgltf_material
|
||||
{
|
||||
char* name;
|
||||
@@ -485,6 +490,7 @@ typedef struct cgltf_material
|
||||
cgltf_bool has_ior;
|
||||
cgltf_bool has_specular;
|
||||
cgltf_bool has_sheen;
|
||||
cgltf_bool has_emissive_strength;
|
||||
cgltf_pbr_metallic_roughness pbr_metallic_roughness;
|
||||
cgltf_pbr_specular_glossiness pbr_specular_glossiness;
|
||||
cgltf_clearcoat clearcoat;
|
||||
@@ -493,6 +499,7 @@ typedef struct cgltf_material
|
||||
cgltf_sheen sheen;
|
||||
cgltf_transmission transmission;
|
||||
cgltf_volume volume;
|
||||
cgltf_emissive_strength emissive_strength;
|
||||
cgltf_texture_view normal_texture;
|
||||
cgltf_texture_view occlusion_texture;
|
||||
cgltf_texture_view emissive_texture;
|
||||
@@ -779,7 +786,8 @@ cgltf_result cgltf_load_buffers(
|
||||
|
||||
cgltf_result cgltf_load_buffer_base64(const cgltf_options* options, cgltf_size size, const char* base64, void** out_data);
|
||||
|
||||
void cgltf_decode_uri(char* uri);
|
||||
cgltf_size cgltf_decode_string(char* string);
|
||||
cgltf_size cgltf_decode_uri(char* uri);
|
||||
|
||||
cgltf_result cgltf_validate(cgltf_data* data);
|
||||
|
||||
@@ -1265,7 +1273,78 @@ static int cgltf_unhex(char ch)
|
||||
-1;
|
||||
}
|
||||
|
||||
void cgltf_decode_uri(char* uri)
|
||||
cgltf_size cgltf_decode_string(char* string)
|
||||
{
|
||||
char* read = string + strcspn(string, "\\");
|
||||
if (*read == 0)
|
||||
{
|
||||
return read - string;
|
||||
}
|
||||
char* write = string;
|
||||
char* last = string;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
// Copy characters since last escaped sequence
|
||||
cgltf_size written = read - last;
|
||||
memmove(write, last, written);
|
||||
write += written;
|
||||
|
||||
if (*read++ == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// jsmn already checked that all escape sequences are valid
|
||||
switch (*read++)
|
||||
{
|
||||
case '\"': *write++ = '\"'; break;
|
||||
case '/': *write++ = '/'; break;
|
||||
case '\\': *write++ = '\\'; break;
|
||||
case 'b': *write++ = '\b'; break;
|
||||
case 'f': *write++ = '\f'; break;
|
||||
case 'r': *write++ = '\r'; break;
|
||||
case 'n': *write++ = '\n'; break;
|
||||
case 't': *write++ = '\t'; break;
|
||||
case 'u':
|
||||
{
|
||||
// UCS-2 codepoint \uXXXX to UTF-8
|
||||
int character = 0;
|
||||
for (cgltf_size i = 0; i < 4; ++i)
|
||||
{
|
||||
character = (character << 4) + cgltf_unhex(*read++);
|
||||
}
|
||||
|
||||
if (character <= 0x7F)
|
||||
{
|
||||
*write++ = character & 0xFF;
|
||||
}
|
||||
else if (character <= 0x7FF)
|
||||
{
|
||||
*write++ = 0xC0 | ((character >> 6) & 0xFF);
|
||||
*write++ = 0x80 | (character & 0x3F);
|
||||
}
|
||||
else
|
||||
{
|
||||
*write++ = 0xE0 | ((character >> 12) & 0xFF);
|
||||
*write++ = 0x80 | ((character >> 6) & 0x3F);
|
||||
*write++ = 0x80 | (character & 0x3F);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
last = read;
|
||||
read += strcspn(read, "\\");
|
||||
}
|
||||
|
||||
*write = 0;
|
||||
return write - string;
|
||||
}
|
||||
|
||||
cgltf_size cgltf_decode_uri(char* uri)
|
||||
{
|
||||
char* write = uri;
|
||||
char* i = uri;
|
||||
@@ -1293,6 +1372,7 @@ void cgltf_decode_uri(char* uri)
|
||||
}
|
||||
|
||||
*write = 0;
|
||||
return write - uri;
|
||||
}
|
||||
|
||||
cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data, const char* gltf_path)
|
||||
@@ -3771,6 +3851,39 @@ static int cgltf_parse_json_sheen(cgltf_options* options, jsmntok_t const* token
|
||||
return i;
|
||||
}
|
||||
|
||||
static int cgltf_parse_json_emissive_strength(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_emissive_strength* out_emissive_strength)
|
||||
{
|
||||
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
int size = tokens[i].size;
|
||||
++i;
|
||||
|
||||
// Default
|
||||
out_emissive_strength->emissive_strength = 1.f;
|
||||
|
||||
for (int j = 0; j < size; ++j)
|
||||
{
|
||||
CGLTF_CHECK_KEY(tokens[i]);
|
||||
|
||||
if (cgltf_json_strcmp(tokens + i, json_chunk, "emissiveStrength") == 0)
|
||||
{
|
||||
++i;
|
||||
out_emissive_strength->emissive_strength = cgltf_json_to_float(tokens + i, json_chunk);
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
i = cgltf_skip_json(tokens, i + 1);
|
||||
}
|
||||
|
||||
if (i < 0)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_image* out_image)
|
||||
{
|
||||
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
@@ -4145,6 +4258,11 @@ static int cgltf_parse_json_material(cgltf_options* options, jsmntok_t const* to
|
||||
out_material->has_sheen = 1;
|
||||
i = cgltf_parse_json_sheen(options, tokens, i + 1, json_chunk, &out_material->sheen);
|
||||
}
|
||||
else if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_materials_emissive_strength") == 0)
|
||||
{
|
||||
out_material->has_emissive_strength = 1;
|
||||
i = cgltf_parse_json_emissive_strength(tokens, i + 1, json_chunk, &out_material->emissive_strength);
|
||||
}
|
||||
else
|
||||
{
|
||||
i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_material->extensions[out_material->extensions_count++]));
|
||||
|
||||
20
third_party/cgltf/cgltf_write.h
vendored
20
third_party/cgltf/cgltf_write.h
vendored
@@ -59,7 +59,7 @@ cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size si
|
||||
|
||||
#if defined(__INTELLISENSE__) || defined(__JETBRAINS_IDE__)
|
||||
/* This makes MSVC/CLion intellisense work. */
|
||||
#define CGLTF_IMPLEMENTATION
|
||||
#define CGLTF_WRITE_IMPLEMENTATION
|
||||
#endif
|
||||
|
||||
#ifdef CGLTF_WRITE_IMPLEMENTATION
|
||||
@@ -84,6 +84,7 @@ cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size si
|
||||
#define CGLTF_EXTENSION_FLAG_MATERIALS_VARIANTS (1 << 10)
|
||||
#define CGLTF_EXTENSION_FLAG_MATERIALS_VOLUME (1 << 11)
|
||||
#define CGLTF_EXTENSION_FLAG_TEXTURE_BASISU (1 << 12)
|
||||
#define CGLTF_EXTENSION_FLAG_MATERIALS_EMISSIVE_STRENGTH (1 << 13)
|
||||
|
||||
typedef struct {
|
||||
char* buffer;
|
||||
@@ -587,6 +588,11 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater
|
||||
context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_SHEEN;
|
||||
}
|
||||
|
||||
if (material->has_emissive_strength)
|
||||
{
|
||||
context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_EMISSIVE_STRENGTH;
|
||||
}
|
||||
|
||||
if (material->has_pbr_metallic_roughness)
|
||||
{
|
||||
const cgltf_pbr_metallic_roughness* params = &material->pbr_metallic_roughness;
|
||||
@@ -603,7 +609,7 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater
|
||||
cgltf_write_line(context, "}");
|
||||
}
|
||||
|
||||
if (material->unlit || material->has_pbr_specular_glossiness || material->has_clearcoat || material->has_ior || material->has_specular || material->has_transmission || material->has_sheen || material->has_volume)
|
||||
if (material->unlit || material->has_pbr_specular_glossiness || material->has_clearcoat || material->has_ior || material->has_specular || material->has_transmission || material->has_sheen || material->has_volume || material->has_emissive_strength)
|
||||
{
|
||||
cgltf_write_line(context, "\"extensions\": {");
|
||||
if (material->has_clearcoat)
|
||||
@@ -695,6 +701,13 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater
|
||||
{
|
||||
cgltf_write_line(context, "\"KHR_materials_unlit\": {}");
|
||||
}
|
||||
if (material->has_emissive_strength)
|
||||
{
|
||||
cgltf_write_line(context, "\"KHR_materials_emissive_strength\": {");
|
||||
const cgltf_emissive_strength* params = &material->emissive_strength;
|
||||
cgltf_write_floatprop(context, "emissiveStrength", params->emissive_strength, 1.f);
|
||||
cgltf_write_line(context, "}");
|
||||
}
|
||||
cgltf_write_line(context, "}");
|
||||
}
|
||||
|
||||
@@ -1097,6 +1110,9 @@ static void cgltf_write_extensions(cgltf_write_context* context, uint32_t extens
|
||||
if (extension_flags & CGLTF_EXTENSION_FLAG_TEXTURE_BASISU) {
|
||||
cgltf_write_stritem(context, "KHR_texture_basisu");
|
||||
}
|
||||
if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_EMISSIVE_STRENGTH) {
|
||||
cgltf_write_stritem(context, "KHR_materials_emissive_strength");
|
||||
}
|
||||
}
|
||||
|
||||
cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size size, const cgltf_data* data)
|
||||
|
||||
21
third_party/cgltf/test/CMakeLists.txt
vendored
21
third_party/cgltf/test/CMakeLists.txt
vendored
@@ -10,6 +10,8 @@ if(MSVC)
|
||||
add_definitions( -D_CRT_SECURE_NO_WARNINGS)
|
||||
else()
|
||||
target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra -pedantic -Werror)
|
||||
target_compile_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
target_link_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
endif()
|
||||
install( TARGETS ${EXE_NAME} RUNTIME DESTINATION bin )
|
||||
|
||||
@@ -21,6 +23,8 @@ if(MSVC)
|
||||
add_definitions( -D_CRT_SECURE_NO_WARNINGS)
|
||||
else()
|
||||
target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra -pedantic -Werror)
|
||||
target_compile_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
target_link_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
endif()
|
||||
install( TARGETS ${EXE_NAME} RUNTIME DESTINATION bin )
|
||||
|
||||
@@ -32,6 +36,8 @@ if(MSVC)
|
||||
add_definitions( -D_CRT_SECURE_NO_WARNINGS)
|
||||
else()
|
||||
target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra -pedantic -Werror)
|
||||
target_compile_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
target_link_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
endif()
|
||||
install( TARGETS ${EXE_NAME} RUNTIME DESTINATION bin )
|
||||
|
||||
@@ -43,5 +49,20 @@ if(MSVC)
|
||||
add_definitions( -D_CRT_SECURE_NO_WARNINGS)
|
||||
else()
|
||||
target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra -pedantic -Werror)
|
||||
target_compile_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
target_link_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
endif()
|
||||
install( TARGETS ${EXE_NAME} RUNTIME DESTINATION bin )
|
||||
|
||||
set( EXE_NAME test_strings )
|
||||
add_executable( ${EXE_NAME} test_strings.cpp )
|
||||
set_property( TARGET ${EXE_NAME} PROPERTY CXX_STANDARD 11 )
|
||||
if(MSVC)
|
||||
target_compile_options(${EXE_NAME} PRIVATE /W4 /WX)
|
||||
add_definitions( -D_CRT_SECURE_NO_WARNINGS)
|
||||
else()
|
||||
target_compile_options(${EXE_NAME} PRIVATE -Wall -Wextra -pedantic -Werror)
|
||||
target_compile_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
target_link_options(${EXE_NAME} PUBLIC -fsanitize=address)
|
||||
endif()
|
||||
install( TARGETS ${EXE_NAME} RUNTIME DESTINATION bin )
|
||||
|
||||
6
third_party/cgltf/test/test_all.py
vendored
6
third_party/cgltf/test/test_all.py
vendored
@@ -62,5 +62,11 @@ if __name__ == "__main__":
|
||||
print("Error.")
|
||||
sys.exit(1)
|
||||
|
||||
result = os.system(get_executable_path("test_strings"))
|
||||
if result != 0:
|
||||
num_errors = num_errors + 1
|
||||
print("Error.")
|
||||
sys.exit(1)
|
||||
|
||||
print("Tested files: " + str(num_tested))
|
||||
print("Errors: " + str(num_errors))
|
||||
|
||||
8
third_party/cgltf/test/test_conversion.cpp
vendored
8
third_party/cgltf/test/test_conversion.cpp
vendored
@@ -26,7 +26,13 @@ int main(int argc, char** argv)
|
||||
if (result == cgltf_result_success)
|
||||
result = cgltf_load_buffers(&options, data, argv[1]);
|
||||
|
||||
if (result != cgltf_result_success || strstr(argv[1], "Draco"))
|
||||
if (strstr(argv[1], "Draco"))
|
||||
{
|
||||
cgltf_free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (result != cgltf_result_success)
|
||||
return result;
|
||||
|
||||
//const cgltf_accessor* blobs = data->accessors;
|
||||
|
||||
57
third_party/cgltf/test/test_strings.cpp
vendored
Normal file
57
third_party/cgltf/test/test_strings.cpp
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
#define CGLTF_IMPLEMENTATION
|
||||
#include "../cgltf.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
static void check(const char* a, const char* b, cgltf_size size) {
|
||||
if (strcmp(a, b) != 0 || strlen(a) != size) {
|
||||
fprintf(stderr, "Mismatch detected.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
char string[64];
|
||||
cgltf_size size;
|
||||
|
||||
// cgltf_decode_string
|
||||
strcpy(string, "");
|
||||
size = cgltf_decode_string(string);
|
||||
check(string, "", size);
|
||||
|
||||
strcpy(string, "nothing to replace");
|
||||
size = cgltf_decode_string(string);
|
||||
check(string, "nothing to replace", size);
|
||||
|
||||
strcpy(string, "\\\" \\/ \\\\ \\b \\f \\r \\n \\t \\u0030");
|
||||
size = cgltf_decode_string(string);
|
||||
check(string, "\" / \\ \b \f \r \n \t 0", size);
|
||||
|
||||
strcpy(string, "test \\u121b\\u130d\\u1294\\u1276\\u127d test");
|
||||
size = cgltf_decode_string(string);
|
||||
check(string, "test ማግኔቶች test", size);
|
||||
|
||||
// cgltf_decode_uri
|
||||
strcpy(string, "");
|
||||
size = cgltf_decode_uri(string);
|
||||
check(string, "", size);
|
||||
|
||||
strcpy(string, "nothing to replace");
|
||||
size = cgltf_decode_uri(string);
|
||||
check(string, "nothing to replace", size);
|
||||
|
||||
strcpy(string, "%2F%D0%BA%D0%B8%D1%80%D0%B8%D0%BB%D0%BB%D0%B8%D1%86%D0%B0");
|
||||
size = cgltf_decode_uri(string);
|
||||
check(string, "/кириллица", size);
|
||||
|
||||
strcpy(string, "test%20%E1%88%9B%E1%8C%8D%E1%8A%94%E1%89%B6%E1%89%BD%20test");
|
||||
size = cgltf_decode_uri(string);
|
||||
check(string, "test ማግኔቶች test", size);
|
||||
|
||||
strcpy(string, "%%2F%X%AX%%2F%%");
|
||||
size = cgltf_decode_uri(string);
|
||||
check(string, "%/%X%AX%/%%", size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.15.2",
|
||||
"version": "1.16.0",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user