Merge branch 'rc/1.12.6' into release

This commit is contained in:
Benjamin Doherty
2021-09-27 11:12:42 -07:00
56 changed files with 762 additions and 130 deletions

View File

@@ -31,7 +31,7 @@ repositories {
}
dependencies {
implementation 'com.google.android.filament:filament-android:1.12.5'
implementation 'com.google.android.filament:filament-android:1.12.6'
}
```
@@ -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.12.5'
pod 'Filament', '~> 1.12.6'
```
### Snapshots

View File

@@ -5,6 +5,16 @@ A new header is inserted each time a *tag* is created.
## v1.12.6 (currently main branch)
- engine: Added concept of lod bias to materials.
[⚠️ **Materials need to be rebuilt to access this new feature**].
- engine: Fix, BGRA ordering respected for external images with OpenGL on iOS.
- engine: Use more sensible defaults for spot light inner outer cone angles.
- engine: Fix potential race condition that caused stalls in `endFrame`.
- gltfio: Improved handling of transparent materials.
- Metal: Fix potential crash on earlier versions of iOS (<= 13.0).
- Android: Fix `filament-utils-android` 'lite' flavor.
- Java: Fix potential crash with `IBLPrefilter`.
## v1.12.5
- engine: work around a job scheduling issue in `endFrame` that caused stuttering on some Android

View File

@@ -78,7 +78,7 @@ public class MaterialInstance {
public static MaterialInstance duplicate(@NonNull MaterialInstance other, String name) {
long nativeInstance = nDuplicate(other.mNativeObject, name);
if (nativeInstance == 0) throw new IllegalStateException("Couldn't duplicate MaterialInstance");
return new MaterialInstance(other.mMaterial, nativeInstance);
return new MaterialInstance(other.getMaterial(), nativeInstance);
}
/** @return the {@link Material} associated with this instance */

View File

@@ -9,6 +9,13 @@ android {
lite {
dimension "functionality"
externalNativeBuild {
cmake {
// hack: this is needed because filament-utils-android/CMakeLists.txt builds
// gltfio from source, which needs this defined
arguments.add("-DGLTFIO_LITE=ON")
}
}
}
}

View File

@@ -32,9 +32,13 @@ import com.google.android.filament.Texture;
* Texture equirect = HDRLoader.createTexture("foo.hdr");
* Texture skyboxTexture = equirectangularToCubemap.run(equirect);
* engine.destroy(equirect);
* equirectangularToCubemap.destroy();
*
* specularFilter = new IBLPrefilterContext.SpecularFilter(context);
* Texture reflections = specularFilter.run(skyboxTexture);
* specularFilter.destroy();
*
* context.destroy();
*
* IndirectLight ibl = IndirectLight.Builder()
* .reflections(reflections)
@@ -43,81 +47,74 @@ import com.google.android.filament.Texture;
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
public class IBLPrefilterContext {
private final long mNativeObject;
private long mNativeObject;
public IBLPrefilterContext(Engine engine) {
mNativeObject = nCreate(engine.getNativeObject());
if (mNativeObject == 0) throw new IllegalStateException("Couldn't create IBLPrefilterContext");
}
@Override
protected void finalize() throws Throwable {
nDestroy(mNativeObject);
super.finalize();
public void destroy() {
nDestroy(getNativeObject());
mNativeObject = 0;
}
public static class EquirectangularToCubemap {
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources
private final HelperFinalizer mFinalizer;
private final long mNativeHelper;
private long mNativeObject;
public EquirectangularToCubemap(IBLPrefilterContext context) {
mNativeHelper = nCreateEquirectHelper(context.mNativeObject);
mFinalizer = new HelperFinalizer(mNativeHelper);
mNativeObject = nCreateEquirectHelper(context.getNativeObject());
}
public Texture run(Texture equirect) {
long nativeTexture = nEquirectHelperRun(mNativeHelper, equirect.getNativeObject());
long nativeTexture = nEquirectHelperRun(getNativeObject(), equirect.getNativeObject());
return new Texture(nativeTexture);
}
private static class HelperFinalizer {
private final long mNativeObject;
public void destroy() {
nDestroyEquirectHelper(getNativeObject());
mNativeObject = 0;
}
HelperFinalizer(long nativeObject) { mNativeObject = nativeObject; }
@Override
public void finalize() {
try {
super.finalize();
} catch (Throwable t) { // Ignore
} finally {
nDestroyEquirectHelper(mNativeObject);
}
protected long getNativeObject() {
if (mNativeObject == 0) {
throw new IllegalStateException("Calling method on destroyed EquirectangularToCubemap");
}
return mNativeObject;
}
}
public static class SpecularFilter {
@SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources
private final HelperFinalizer mFinalizer;
private final long mNativeHelper;
private long mNativeObject;
public SpecularFilter(IBLPrefilterContext context) {
mNativeHelper = nCreateSpecularFilter(context.mNativeObject);
mFinalizer = new HelperFinalizer(mNativeHelper);
mNativeObject = nCreateSpecularFilter(context.getNativeObject());
}
public Texture run(Texture skybox) {
long nativeTexture = nSpecularFilterRun(mNativeHelper, skybox.getNativeObject());
long nativeTexture = nSpecularFilterRun(getNativeObject(), skybox.getNativeObject());
return new Texture(nativeTexture);
}
private static class HelperFinalizer {
private final long mNativeObject;
HelperFinalizer(long nativeObject) { mNativeObject = nativeObject; }
@Override
public void finalize() {
try {
super.finalize();
} catch (Throwable t) { // Ignore
} finally {
nDestroySpecularFilter(mNativeObject);
}
}
public void destroy() {
nDestroySpecularFilter(getNativeObject());
mNativeObject = 0;
}
protected long getNativeObject() {
if (mNativeObject == 0) {
throw new IllegalStateException("Calling method on destroyed SpecularFilter");
}
return mNativeObject;
}
}
protected long getNativeObject() {
if (mNativeObject == 0) {
throw new IllegalStateException("Calling method on destroyed IBLPrefilterContext");
}
return mNativeObject;
}
private static native long nCreate(long nativeEngine);

View File

@@ -1,5 +1,5 @@
GROUP=com.google.android.filament
VERSION_NAME=1.12.5
VERSION_NAME=1.12.6
POM_DESCRIPTION=Real-time physically based rendering engine for Android.

View File

@@ -10,6 +10,7 @@ filamentTools {
iblOutputDir = project.layout.projectDirectory.dir("src/main/assets/envs")
}
// don't forget to update MainACtivity.kt when/if changing this.
task copyMesh(type: Copy) {
from "../../../third_party/models/BusterDrone"
into "src/main/assets/models"
@@ -36,5 +37,5 @@ dependencies {
implementation project(':filament-android')
implementation project(':gltfio-android')
implementation project(':filament-utils-android')
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0'
}

View File

@@ -196,6 +196,10 @@ class MainActivity : Activity() {
val sky = Skybox.Builder().environment(skyboxTexture).build(engine)
specularFilter.destroy();
equirectToCubemap.destroy();
context.destroy();
modelViewer.scene.skybox = sky
modelViewer.scene.indirectLight = ibl
}

View File

@@ -379,6 +379,7 @@ if (APPLE)
test/test_BufferUpdates.cpp
test/test_MRT.cpp
test/test_LoadImage.cpp
test/test_RenderExternalImage.cpp
)
target_link_libraries(backend_test PRIVATE

View File

@@ -20,13 +20,6 @@
#include <utils/Panic.h>
#define NSERROR_CHECK(message) \
if (error) { \
auto description = [error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding]; \
utils::slog.e << description << utils::io::endl; \
} \
ASSERT_POSTCONDITION(error == nil, message);
namespace filament {
namespace backend {
namespace metal {
@@ -477,7 +470,14 @@ id<MTLFunction> MetalBlitter::compileFragmentFunction(BlitFunctionKey key) {
options:options
error:&error];
id<MTLFunction> function = [library newFunctionWithName:@"blitterFrag"];
NSERROR_CHECK("Unable to compile shading library for MetalBlitter.");
if (!library || !function) {
if (error) {
auto description = [error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding];
utils::slog.e << description << utils::io::endl;
}
}
ASSERT_POSTCONDITION(library && function, "Unable to compile fragment shader for MetalBlitter.");
return function;
}
@@ -494,7 +494,14 @@ id<MTLFunction> MetalBlitter::getBlitVertexFunction() {
options:nil
error:&error];
id<MTLFunction> function = [library newFunctionWithName:@"blitterVertex"];
NSERROR_CHECK("Unable to compile shading library for MetalBlitter.");
if (!library || !function) {
if (error) {
auto description = [error.localizedDescription cStringUsingEncoding:NSUTF8StringEncoding];
utils::slog.e << description << utils::io::endl;
}
}
ASSERT_POSTCONDITION(library && function, "Unable to compile vertex shader for MetalBlitter.");
mVertexFunction = function;

View File

@@ -100,6 +100,7 @@ private:
CVMetalTextureRef createTextureFromImage(CVPixelBufferRef image, MTLPixelFormat format,
size_t plane);
id<MTLTexture> createRgbTexture(size_t width, size_t height);
id<MTLTexture> createSwizzledTextureView(id<MTLTexture> texture) const;
id<MTLTexture> createSwizzledTextureView(CVMetalTextureRef texture) const;
void ensureComputePipelineState();
id<MTLCommandBuffer> encodeColorConversionPass(id<MTLTexture> inYPlane, id<MTLTexture>
@@ -125,7 +126,7 @@ private:
struct {
TextureSwizzle r, g, b, a;
} swizzle;
} mSwizzle;
};
} // namespace metal

View File

@@ -72,7 +72,7 @@ ycbcrToRgb(texture2d<half, access::read> inYTexture [[texture(0)]],
)";
MetalExternalImage::MetalExternalImage(MetalContext& context, TextureSwizzle r, TextureSwizzle g,
TextureSwizzle b, TextureSwizzle a) noexcept : mContext(context), swizzle{r, g, b ,a} { }
TextureSwizzle b, TextureSwizzle a) noexcept : mContext(context), mSwizzle{r, g, b, a} { }
bool MetalExternalImage::isValid() const noexcept {
return mRgbTexture != nil || mImage != nullptr;
@@ -113,13 +113,12 @@ void MetalExternalImage::set(CVPixelBufferRef image) noexcept {
mHeight = CVPixelBufferGetHeightOfPlane(image, Y_PLANE);
id<MTLTexture> rgbTexture = createRgbTexture(mWidth, mHeight);
id <MTLCommandBuffer> commandBuffer = encodeColorConversionPass(
id<MTLCommandBuffer> commandBuffer = encodeColorConversionPass(
CVMetalTextureGetTexture(yPlane),
CVMetalTextureGetTexture(cbcrPlane),
rgbTexture);
mRgbTexture = createTextureViewWithSwizzle(rgbTexture,
getSwizzleChannels(swizzle.r, swizzle.g, swizzle.b, swizzle.a));
mRgbTexture = createSwizzledTextureView(rgbTexture);
[commandBuffer addCompletedHandler:^(id <MTLCommandBuffer> o) {
CVBufferRelease(yPlane);
@@ -230,24 +229,28 @@ id<MTLTexture> MetalExternalImage::createRgbTexture(size_t width, size_t height)
return [mContext.device newTextureWithDescriptor:descriptor];
}
id<MTLTexture> MetalExternalImage::createSwizzledTextureView(CVMetalTextureRef ref) const {
id<MTLTexture> texture = CVMetalTextureGetTexture(ref);
id<MTLTexture> MetalExternalImage::createSwizzledTextureView(id<MTLTexture> texture) const {
const bool isDefaultSwizzle =
swizzle.r == TextureSwizzle::CHANNEL_0 &&
swizzle.g == TextureSwizzle::CHANNEL_1 &&
swizzle.b == TextureSwizzle::CHANNEL_2 &&
swizzle.a == TextureSwizzle::CHANNEL_3;
mSwizzle.r == TextureSwizzle::CHANNEL_0 &&
mSwizzle.g == TextureSwizzle::CHANNEL_1 &&
mSwizzle.b == TextureSwizzle::CHANNEL_2 &&
mSwizzle.a == TextureSwizzle::CHANNEL_3;
if (!isDefaultSwizzle && mContext.supportsTextureSwizzling) {
// Even though we've already checked supportsTextureSwizzling, we still need to guard these
// calls with @availability, otherwise the API usage will generate compiler warnings.
if (@available(iOS 13, *)) {
texture = createTextureViewWithSwizzle(texture,
getSwizzleChannels(swizzle.r, swizzle.g, swizzle.b, swizzle.a));
getSwizzleChannels(mSwizzle.r, mSwizzle.g, mSwizzle.b, mSwizzle.a));
}
}
return texture;
}
id<MTLTexture> MetalExternalImage::createSwizzledTextureView(CVMetalTextureRef ref) const {
id<MTLTexture> texture = CVMetalTextureGetTexture(ref);
return createSwizzledTextureView(texture);
}
void MetalExternalImage::ensureComputePipelineState() {
if (mContext.externalImageComputePipelineState != nil) {
return;

View File

@@ -63,7 +63,7 @@ private:
void release() noexcept;
CVOpenGLESTextureRef createTextureFromImage(CVPixelBufferRef image, GLuint glFormat,
size_t plane) noexcept;
GLenum format, size_t plane) noexcept;
GLuint encodeColorConversionPass(GLuint yPlaneTexture, GLuint colorTexture, size_t width,
size_t height) noexcept;

View File

@@ -150,13 +150,14 @@ bool CocoaTouchExternalImage::set(CVPixelBufferRef image) noexcept {
if (planeCount == 0) {
mImage = image;
mTexture = createTextureFromImage(image, GL_RGBA, 0);
mTexture = createTextureFromImage(image, GL_RGBA, GL_BGRA, 0);
mEncodedToRgb = false;
}
if (planeCount == 2) {
CVOpenGLESTextureRef yPlane = createTextureFromImage(image, GL_LUMINANCE, 0);
CVOpenGLESTextureRef colorPlane = createTextureFromImage(image, GL_LUMINANCE_ALPHA, 1);
CVOpenGLESTextureRef yPlane = createTextureFromImage(image, GL_LUMINANCE, GL_LUMINANCE, 0);
CVOpenGLESTextureRef colorPlane = createTextureFromImage(image, GL_LUMINANCE_ALPHA,
GL_LUMINANCE_ALPHA, 1);
size_t width, height;
width = CVPixelBufferGetWidthOfPlane(image, 0);
@@ -214,7 +215,7 @@ void CocoaTouchExternalImage::release() noexcept {
}
CVOpenGLESTextureRef CocoaTouchExternalImage::createTextureFromImage(CVPixelBufferRef image, GLuint
glFormat, size_t plane) noexcept {
glFormat, GLenum format, size_t plane) noexcept {
const size_t width = CVPixelBufferGetWidthOfPlane(image, plane);
const size_t height = CVPixelBufferGetHeightOfPlane(image, plane);
@@ -222,7 +223,7 @@ CVOpenGLESTextureRef CocoaTouchExternalImage::createTextureFromImage(CVPixelBuff
UTILS_UNUSED_IN_RELEASE CVReturn success =
CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
mTextureCache, image, nullptr, GL_TEXTURE_2D, glFormat, width, height,
glFormat, GL_UNSIGNED_BYTE, plane, &texture);
format, GL_UNSIGNED_BYTE, plane, &texture);
assert_invariant(success == kCVReturnSuccess);
return texture;

View File

@@ -54,8 +54,8 @@ void VulkanContext::selectPhysicalDevice() {
}
// Does the device have any command queues that support graphics?
// In theory we should also ensure that the device supports presentation of our
// particular VkSurface, but we don't have a VkSurface yet so we'll skip this requirement.
// In theory, we should also ensure that the device supports presentation of our
// particular VkSurface, but we don't have a VkSurface yet, so we'll skip this requirement.
uint32_t queueFamiliesCount;
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamiliesCount, nullptr);
if (queueFamiliesCount == 0) {

View File

@@ -939,7 +939,8 @@ bool VulkanDriver::getTimerQueryValue(Handle<HwTimerQuery> tqh, uint64_t* elapse
// However there are plans for implementing this properly. See the following GitHub ticket.
// https://github.com/KhronosGroup/MoltenVK/issues/773
uint64_t delta = timestamp1 - timestamp0;
float period = mContext.physicalDeviceProperties.limits.timestampPeriod;
uint64_t delta = uint64_t(float(timestamp1 - timestamp0) * period);
*elapsedTime = delta;
return true;
}

View File

@@ -0,0 +1,251 @@
/*
* 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 "BackendTest.h"
#include "ShaderGenerator.h"
#include "TrianglePrimitive.h"
#include <CoreVideo/CoreVideo.h>
namespace {
////////////////////////////////////////////////////////////////////////////////////////////////////
// Shaders
////////////////////////////////////////////////////////////////////////////////////////////////////
std::string vertex (R"(#version 450 core
layout(location = 0) in vec4 mesh_position;
layout(location = 0) out vec2 uv;
void main() {
gl_Position = vec4(mesh_position.xy, 0.0, 1.0);
uv = (mesh_position.xy * 0.5 + 0.5);
}
)");
std::string fragment (R"(#version 450 core
layout(location = 0) out vec4 fragColor;
layout(location = 0) in vec2 uv;
layout(set = 1, binding = 6) uniform sampler2D tex;
void main() {
fragColor = texture(tex, uv);
}
)");
}
namespace test {
using namespace filament;
using namespace filament::backend;
// Rendering an external image without setting any data should not crash.
TEST_F(BackendTest, RenderExternalImageWithoutSet) {
TrianglePrimitive triangle(getDriverApi());
auto swapChain = createSwapChain();
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
// Create a program that samples a texture.
Program p = shaderGen.getProgram();
Program::Sampler sampler { utils::CString("tex"), 6 };
p.setSamplerGroup(0, &sampler, 1);
backend::Handle<HwProgram> program = getDriverApi().createProgram(std::move(p));
backend::Handle<HwRenderTarget> defaultRenderTarget = getDriverApi().createDefaultRenderTarget(0);
// Create a texture that will be backed by an external image.
auto usage = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE;
const NativeView& view = getNativeView();
backend::Handle<HwTexture> texture = getDriverApi().createTexture(
SamplerType::SAMPLER_EXTERNAL, // target
1, // levels
TextureFormat::RGBA8, // format
1, // samples
view.width, // width
view.height, // height
1, // depth
usage); // usage
RenderPassParams params = {};
fullViewport(params);
params.flags.clear = TargetBufferFlags::COLOR;
params.clearColor = {0.f, 1.f, 0.f, 1.f};
params.flags.discardStart = TargetBufferFlags::ALL;
params.flags.discardEnd = TargetBufferFlags::NONE;
PipelineState state;
state.program = program;
state.rasterState.colorWrite = true;
state.rasterState.depthWrite = false;
state.rasterState.depthFunc = RasterState::DepthFunc::A;
state.rasterState.culling = CullingMode::NONE;
getDriverApi().startCapture(0);
getDriverApi().makeCurrent(swapChain, swapChain);
getDriverApi().beginFrame(0, 0);
SamplerGroup mSamplers(1);
mSamplers.setSampler(0, { texture, {} });
backend::Handle<HwSamplerGroup> samplerGroup = getDriverApi().createSamplerGroup(1);
getDriverApi().updateSamplerGroup(samplerGroup, std::move(mSamplers.toCommandStream()));
getDriverApi().bindSamplers(0, samplerGroup);
// Render a triangle.
getDriverApi().beginRenderPass(defaultRenderTarget, params);
getDriverApi().draw(state, triangle.getRenderPrimitive());
getDriverApi().endRenderPass();
getDriverApi().flush();
getDriverApi().commit(swapChain);
getDriverApi().endFrame(0);
getDriverApi().stopCapture(0);
// Delete our resources.
getDriverApi().destroyTexture(texture);
getDriverApi().destroySamplerGroup(samplerGroup);
// Destroy frame resources.
getDriverApi().destroyProgram(program);
getDriverApi().destroyRenderTarget(defaultRenderTarget);
executeCommands();
}
TEST_F(BackendTest, RenderExternalImage) {
TrianglePrimitive triangle(getDriverApi());
auto swapChain = createSwapChain();
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
// Create a program that samples a texture.
Program p = shaderGen.getProgram();
Program::Sampler sampler { utils::CString("tex"), 6 };
p.setSamplerGroup(0, &sampler, 1);
auto program = getDriverApi().createProgram(std::move(p));
backend::Handle<HwRenderTarget> defaultRenderTarget = getDriverApi().createDefaultRenderTarget(0);
// require users to create two Filament textures and have two material parameters
// add a "plane" parameter to setExternalImage
// Create a texture that will be backed by an external image.
auto usage = TextureUsage::COLOR_ATTACHMENT | TextureUsage::SAMPLEABLE;
const NativeView& view = getNativeView();
backend::Handle<HwTexture> texture = getDriverApi().createTexture(
SamplerType::SAMPLER_EXTERNAL, // target
1, // levels
TextureFormat::RGBA8, // format
1, // samples
view.width, // width
view.height, // height
1, // depth
usage); // usage
// Create an external image.
CFStringRef keys[4];
keys[0] = kCVPixelBufferCGBitmapContextCompatibilityKey;
keys[1] = kCVPixelBufferCGImageCompatibilityKey;
keys[2] = kCVPixelBufferOpenGLCompatibilityKey;
keys[3] = kCVPixelBufferMetalCompatibilityKey;
CFTypeRef values[4];
int yes = 1;
values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &yes);
values[1] = values[0];
values[2] = values[0];
values[3] = values[0];
CFDictionaryRef options = CFDictionaryCreate(kCFAllocatorDefault, (const void**) keys, (const void**) values, 4, nullptr, nullptr);
CVPixelBufferRef pixBuffer = nullptr;
CVReturn status =
CVPixelBufferCreate(kCFAllocatorDefault, 1024, 1024, kCVPixelFormatType_32BGRA, options, &pixBuffer);
assert(status == kCVReturnSuccess);
// Fill image with checker-pattern.
const size_t tileSize = 64;
const uint32_t blue = 0xFF0000FF; // BGRA format
const uint32_t black = 0xFF000000;
CVReturn lockStatus = CVPixelBufferLockBaseAddress(pixBuffer, 0);
assert(lockStatus == kCVReturnSuccess);
uint32_t* pix = (uint32_t*) CVPixelBufferGetBaseAddressOfPlane(pixBuffer, 0);
assert(pix);
for (size_t r = 0; r < 1024; r++) {
for (size_t c = 0; c < 1024; c++) {
size_t idx = r * 1024 + c;
pix[idx] = (idx + tileSize * (r / tileSize % 2)) / tileSize % 2 == 0 ? blue : black;
}
}
getDriverApi().setupExternalImage(pixBuffer);
getDriverApi().setExternalImage(texture, pixBuffer);
// We're now free to release the buffer.
CVBufferRelease(pixBuffer);
RenderPassParams params = {};
fullViewport(params);
params.flags.clear = TargetBufferFlags::COLOR;
params.clearColor = {0.f, 1.f, 0.f, 1.f};
params.flags.discardStart = TargetBufferFlags::ALL;
params.flags.discardEnd = TargetBufferFlags::NONE;
PipelineState state;
state.program = program;
state.rasterState.colorWrite = true;
state.rasterState.depthWrite = false;
state.rasterState.depthFunc = RasterState::DepthFunc::A;
state.rasterState.culling = CullingMode::NONE;
getDriverApi().startCapture(0);
getDriverApi().makeCurrent(swapChain, swapChain);
getDriverApi().beginFrame(0, 0);
SamplerGroup mSamplers(1);
mSamplers.setSampler(0, { texture, {} });
backend::Handle<HwSamplerGroup> samplerGroup = getDriverApi().createSamplerGroup(1);
getDriverApi().updateSamplerGroup(samplerGroup, std::move(mSamplers.toCommandStream()));
getDriverApi().bindSamplers(0, samplerGroup);
// Render a triangle.
getDriverApi().beginRenderPass(defaultRenderTarget, params);
getDriverApi().draw(state, triangle.getRenderPrimitive());
getDriverApi().endRenderPass();
getDriverApi().flush();
getDriverApi().commit(swapChain);
getDriverApi().endFrame(0);
getDriverApi().stopCapture(0);
// Delete our resources.
getDriverApi().destroyTexture(texture);
getDriverApi().destroySamplerGroup(samplerGroup);
// Destroy frame resources.
getDriverApi().destroyProgram(program);
getDriverApi().destroyRenderTarget(defaultRenderTarget);
executeCommands();
}
} // namespace test

View File

@@ -20,6 +20,8 @@
#include <filament/FilamentAPI.h>
#include <filament/Color.h>
#include <filament/MaterialEnums.h>
#include <backend/DriverEnums.h>
#include <utils/compiler.h>
@@ -37,6 +39,7 @@ class UniformInterfaceBlock;
class UTILS_PUBLIC MaterialInstance : public FilamentAPI {
public:
using CullingMode = filament::backend::CullingMode;
using TransparencyMode = filament::TransparencyMode;
template<typename T>
using is_supported_parameter_t = typename std::enable_if<
@@ -197,6 +200,11 @@ public:
*/
void setDoubleSided(bool doubleSided) noexcept;
/**
* Specifies how transparent objects should be rendered (default is DEFAULT).
*/
void setTransparencyMode(TransparencyMode mode) noexcept;
/**
* Overrides the default triangle culling state that was set on the material.
*/

View File

@@ -204,6 +204,8 @@ FMaterialInstance::FMaterialInstance(FEngine& engine,
mMaterialSortingKey = RenderPass::makeMaterialSortingKey(
material->getId(), material->generateMaterialInstanceId());
setTransparencyMode(material->getTransparencyMode());
}
FMaterialInstance* FMaterialInstance::duplicate(
@@ -253,6 +255,8 @@ void FMaterialInstance::initDefaultInstance(FEngine& engine, FMaterial const* ma
setSpecularAntiAliasingVariance(material->getSpecularAntiAliasingVariance());
setSpecularAntiAliasingThreshold(material->getSpecularAntiAliasingThreshold());
}
setTransparencyMode(material->getTransparencyMode());
}
FMaterialInstance::~FMaterialInstance() noexcept = default;
@@ -327,6 +331,10 @@ void FMaterialInstance::setDoubleSided(bool doubleSided) noexcept {
}
}
void FMaterialInstance::setTransparencyMode(TransparencyMode mode) noexcept {
mTransparencyMode = mode;
}
void FMaterialInstance::setDepthCulling(bool enable) noexcept {
mDepthFunc = enable ? RasterState::DepthFunc::GE : RasterState::DepthFunc::A;
}
@@ -393,6 +401,10 @@ void MaterialInstance::setDoubleSided(bool doubleSided) noexcept {
upcast(this)->setDoubleSided(doubleSided);
}
void MaterialInstance::setTransparencyMode(TransparencyMode mode) noexcept {
upcast(this)->setTransparencyMode(mode);
}
void MaterialInstance::setCullingMode(CullingMode culling) noexcept {
upcast(this)->setCullingMode(culling);
}

View File

@@ -87,6 +87,16 @@ void PerViewUniforms::prepareCamera(const CameraInfo& camera) noexcept {
s.clipControl = mClipControl;
}
void PerViewUniforms::prepareUpscaler(math::float2 scale,
DynamicResolutionOptions const& options) noexcept {
auto& s = mPerViewUb.edit();
if (options.quality >= QualityLevel::HIGH) {
s.lodBias = std::log2(std::min(scale.x, scale.y));
} else {
s.lodBias = 0.0f;
}
}
void PerViewUniforms::prepareExposure(float ev100) noexcept {
const float exposure = Exposure::exposure(ev100);
auto& s = mPerViewUb.edit();

View File

@@ -31,6 +31,7 @@
namespace filament {
struct FogOptions;
struct DynamicResolutionOptions;
struct AmbientOcclusionOptions;
struct VsmShadowOptions;
@@ -53,6 +54,7 @@ public:
void terminate(FEngine& engine);
void prepareCamera(const CameraInfo& camera) noexcept;
void prepareUpscaler(math::float2 scale, DynamicResolutionOptions const& options) noexcept;
void prepareViewport(const filament::Viewport& viewport) noexcept;
void prepareTime(FEngine& engine, math::float4 const& userTime) noexcept;
void prepareExposure(float ev100) noexcept;

View File

@@ -392,7 +392,7 @@ void RenderPass::generateCommandsImpl(uint32_t extraFlags,
cmdColor.key |= makeField(primitive.getBlendOrder(),
BLEND_ORDER_MASK, BLEND_ORDER_SHIFT);
const TransparencyMode mode = mi->getMaterial()->getTransparencyMode();
const TransparencyMode mode = mi->getTransparencyMode();
// handle transparent objects, two techniques:
//

View File

@@ -258,6 +258,8 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
view.prepare(engine, driver, arena, svp, getShaderUserTime());
view.prepareUpscaler(scale);
// start froxelization immediately, it has no dependencies
JobSystem::Job* jobFroxelize = nullptr;
if (view.hasDynamicLighting()) {

View File

@@ -554,6 +554,11 @@ UTILS_NOINLINE
});
}
void FView::prepareUpscaler(float2 scale) const noexcept {
SYSTRACE_CALL();
mPerViewUniforms.prepareUpscaler(scale, mDynamicResolution);
}
void FView::prepareCamera(const CameraInfo& camera) const noexcept {
SYSTRACE_CALL();
mPerViewUniforms.prepareCamera(camera);

View File

@@ -45,7 +45,7 @@ struct LightManager::BuilderDetails {
float mIntensity = 100000.0f;
FLightManager::IntensityUnit mIntensityUnit = FLightManager::IntensityUnit::LUMEN_LUX;
float3 mDirection = { 0.0f, -1.0f, 0.0f };
float2 mSpotInnerOuter = { f::PI, f::PI };
float2 mSpotInnerOuter = { f::PI_4 * 0.75f, f::PI_4 };
float mSunAngle = 0.00951f; // 0.545° in radians
float mSunHaloSize = 10.0f;
float mSunHaloFalloff = 80.0f;

View File

@@ -91,6 +91,8 @@ public:
bool getDepthWrite() const noexcept { return mDepthWrite; }
TransparencyMode getTransparencyMode() const noexcept { return mTransparencyMode; }
backend::RasterState::DepthFunc getDepthFunc() const noexcept { return mDepthFunc; }
void setPolygonOffset(float scale, float constant) noexcept {
@@ -108,6 +110,8 @@ public:
void setDoubleSided(bool doubleSided) noexcept;
void setTransparencyMode(TransparencyMode mode) noexcept;
void setCullingMode(CullingMode culling) noexcept { mCulling = culling; }
void setColorWrite(bool enable) noexcept { mColorWrite = enable; }
@@ -159,6 +163,7 @@ private:
bool mColorWrite;
bool mDepthWrite;
backend::RasterState::DepthFunc mDepthFunc;
TransparencyMode mTransparencyMode;
uint64_t mMaterialSortingKey = 0;

View File

@@ -159,6 +159,7 @@ public:
return mName.c_str();
}
void prepareUpscaler(math::float2 scale) const noexcept;
void prepareCamera(const CameraInfo& camera) const noexcept;
void prepareViewport(const Viewport& viewport) const noexcept;
void prepareShadowing(FEngine& engine, backend::DriverApi& driver,

View File

@@ -1,12 +1,12 @@
Pod::Spec.new do |spec|
spec.name = "Filament"
spec.version = "1.12.5"
spec.version = "1.12.6"
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.12.5/filament-v1.12.5-ios.tgz" }
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.12.6/filament-v1.12.6-ios.tgz" }
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
spec.pod_target_xcconfig = {
@@ -83,9 +83,15 @@ Pod::Spec.new do |spec|
end
spec.subspec "utils" do |ss|
ss.source_files = "include/utils/*.h"
ss.source_files = "include/utils/**/*.h"
ss.header_mappings_dir = "include"
ss.vendored_libraries = "lib/universal/libutils.a"
ss.header_dir = "utils"
ss.dependency "Filament/tsl"
end
spec.subspec "tsl" do |ss|
ss.source_files = "include/tsl/*.h"
ss.header_dir = "tsl"
end
spec.subspec "math" do |ss|

View File

@@ -128,8 +128,13 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
float vsmLightBleedReduction;
float vsmReserved0;
float lodBias;
float reserved1;
float reserved2;
float reserved3;
// bring PerViewUib to 2 KiB
math::float4 padding2[59];
math::float4 padding2[58];
};
// 2 KiB == 128 float4s

View File

@@ -30,6 +30,7 @@
#include "sca/GLSLTools.h"
#include <utils/Log.h>
#include <filament/MaterialEnums.h>
using namespace glslang;
using namespace spirv_cross;
@@ -203,6 +204,12 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co
return false;
}
// add texture lod bias
if (config.shaderType == filament::backend::FRAGMENT &&
config.domain == filament::MaterialDomain::SURFACE) {
GLSLTools::textureLodBias(tShader);
}
program.addShader(&tShader);
// Even though we only have a single shader stage, linking is still necessary to finalize
// SPIR-V types

View File

@@ -50,6 +50,7 @@ public:
struct Config {
filament::backend::ShaderType shaderType;
filament::backend::ShaderModel shaderModel;
filament::MaterialDomain domain;
bool hasFramebufferFetch;
struct {
std::vector<std::pair<uint32_t, uint32_t>> subpassInputToColorLocation;

View File

@@ -726,7 +726,8 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector<Va
GLSLPostProcessor::Config config{
.shaderType = v.stage,
.shaderModel = shaderModel,
.glsl = {}
.domain = mMaterialDomain,
.glsl = {},
};
config.hasFramebufferFetch = mEnableFramebufferFetch;

View File

@@ -109,8 +109,13 @@ UniformInterfaceBlock const& UibGenerator::getPerViewUib() noexcept {
.add("vsmLightBleedReduction", 1, UniformInterfaceBlock::Type::FLOAT)
.add("vsmReserved0", 1, UniformInterfaceBlock::Type::FLOAT)
.add("lodBias", 1, UniformInterfaceBlock::Type::FLOAT)
.add("reserved1", 1, UniformInterfaceBlock::Type::FLOAT)
.add("reserved2", 1, UniformInterfaceBlock::Type::FLOAT)
.add("reserved3", 1, UniformInterfaceBlock::Type::FLOAT)
// bring PerViewUib to 2 KiB
.add("padding2", 59, UniformInterfaceBlock::Type::FLOAT4)
.add("padding2", 58, UniformInterfaceBlock::Type::FLOAT4)
.build();
return uib;
}

View File

@@ -359,4 +359,105 @@ void getFunctionParameters(TIntermAggregate* func, std::vector<FunctionParameter
}
}
template <typename F>
class TraverserAdapter: public TIntermTraverser {
F closure;
public:
explicit TraverserAdapter(F closure)
: TIntermTraverser(true, false, false, false),
closure(closure) {
}
bool visitAggregate(TVisit visit, TIntermAggregate* node) override {
return closure(visit, node);
}
};
void textureLodBias(TIntermediate* intermediate, TIntermNode* root,
const char* entryPointSignatureish, const char* lodBiasSymbolName) {
// First, find the "lodBias" symbol and entry point
const std::string functionName{ entryPointSignatureish };
TIntermSymbol* pIntermSymbolLodBias = nullptr;
TIntermNode* pEntryPointRoot = nullptr;
TraverserAdapter findLodBiasSymbol(
[&](TVisit visit, TIntermAggregate* node) {
if (node->getOp() == glslang::EOpSequence) {
return true;
}
if (node->getOp() == glslang::EOpFunction) {
if (node->getName().rfind(functionName, 0) == 0) {
pEntryPointRoot = node;
}
return false;
}
if (node->getOp() == glslang::EOpLinkerObjects) {
for (TIntermNode* item: node->getSequence()) {
TIntermSymbol* symbol = item->getAsSymbolNode();
if (symbol && symbol->getBasicType() == TBasicType::EbtFloat) {
if (symbol->getName() == lodBiasSymbolName) {
pIntermSymbolLodBias = symbol;
break;
}
}
}
}
return true;
});
root->traverse(&findLodBiasSymbol);
if (!pEntryPointRoot) {
// This can happen if the material doesn't have user defined code,
// e.g. with the depth material. We just do nothing then.
return;
}
if (!pIntermSymbolLodBias) {
// something went wrong
utils::slog.e << "lod bias ignored because \"" << lodBiasSymbolName << "\" was not found!"
<< utils::io::endl;
return;
}
// add lod bias to texture calls
TraverserAdapter addLodBiasToTextureCalls(
[&](TVisit visit, TIntermAggregate* node) {
// skip everything that's not a texture() call
if (node->getOp() != glslang::EOpTexture) {
return true;
}
TIntermSequence& sequence = node->getSequence();
// first check that we have the correct sampler
TIntermTyped* pTyped = sequence[0]->getAsTyped();
if (!pTyped) {
return false;
}
TSampler const& sampler = pTyped->getType().getSampler();
if (sampler.isArrayed() && sampler.isShadow()) {
// sampler2DArrayShadow is not supported
return false;
}
// Then add the lod bias to the texture() call
if (sequence.size() == 2) {
// we only have 2 parameters, add the 3rd one
TIntermSymbol* symbol = intermediate->addSymbol(*pIntermSymbolLodBias);
sequence.push_back(symbol);
} else if (sequence.size() == 3) {
// load bias is already specified
TIntermSymbol* symbol = intermediate->addSymbol(*pIntermSymbolLodBias);
TIntermTyped* pAdd = intermediate->addBinaryMath(TOperator::EOpAdd,
sequence[2]->getAsTyped(), symbol,
node->getLoc());
sequence[2] = pAdd;
}
return false;
});
// we need to run this only from the user's main entry point
pEntryPointRoot->traverse(&addLodBiasToTextureCalls);
}
} // namespace ASTHelpers

View File

@@ -71,5 +71,10 @@ struct FunctionParameter {
void getFunctionParameters(glslang::TIntermAggregate* func, std::vector<FunctionParameter>& output)
noexcept;
// add lod bias to texture() calls
void textureLodBias(glslang::TIntermediate* intermediate, TIntermNode* root,
const char* entryPointSignatureish, const char* lodBiasSymbolName);
} // namespace ASTutils
#endif //TNT_SCAHELPERS_H_H

View File

@@ -359,4 +359,12 @@ void GLSLTools::prepareShaderParser(MaterialBuilder::TargetApi targetApi, glslan
}
}
void GLSLTools::textureLodBias(TShader& shader) {
TIntermediate* intermediate = shader.getIntermediate();
TIntermNode* root = intermediate->getTreeRoot();
ASTUtils::textureLodBias(intermediate, root,
"material(struct-MaterialInputs",
"filament_lodBias");
}
} // namespace filamat

View File

@@ -150,6 +150,8 @@ public:
static void prepareShaderParser(MaterialBuilder::TargetApi targetApi, glslang::TShader& shader,
EShLanguage language, int version, MaterialBuilder::Optimization optimization);
static void textureLodBias(glslang::TShader& shader);
private:

View File

@@ -434,6 +434,8 @@ std::string ShaderGenerator::createFragmentProgram(filament::backend::ShaderMode
material.samplerBindings.getBlockOffset(BindingPoints::PER_MATERIAL_INSTANCE),
material.sib);
fs << "float filament_lodBias;\n";
// shading code
cg.generateCommon(fs, ShaderType::FRAGMENT);
cg.generateGetters(fs, ShaderType::FRAGMENT);

View File

@@ -54,6 +54,7 @@ endif()
function(generate_mat TEMPLATE SHADINGMODEL BLENDING)
set(DOUBLESIDED false)
set(TRANSPARENCY default)
set(GENERATED_MAT "${RESOURCE_DIR}/${SHADINGMODEL}_${BLENDING}.mat")
configure_file(materials/${TEMPLATE}.mat.in ${GENERATED_MAT})
set(MATERIAL_SRCS ${MATERIAL_SRCS} ${GENERATED_MAT} PARENT_SCOPE)
@@ -116,6 +117,7 @@ set(LITE_DIR ${CMAKE_CURRENT_BINARY_DIR}/lite)
function(generate_lite_mat BLENDING)
set(DOUBLESIDED false)
set(TRANSPARENCY default)
set(SHADINGMODEL lit)
set(GENERATED_MAT "${LITE_DIR}/${SHADINGMODEL}_${BLENDING}.mat")
configure_file(materials/gltflite.mat.in ${GENERATED_MAT})

View File

@@ -3,8 +3,8 @@ material {
requires : [ uv0, uv1, color ],
shadingModel : ${SHADINGMODEL},
blending : ${BLENDING},
depthWrite : true,
doubleSided : ${DOUBLESIDED},
transparency : ${TRANSPARENCY},
flipUV : false,
specularAmbientOcclusion : simple,
specularAntiAliasing : true,

View File

@@ -5,6 +5,7 @@ material {
blending : fade,
depthWrite : true,
doubleSided : ${DOUBLESIDED},
transparency : ${TRANSPARENCY},
flipUV : false,
specularAmbientOcclusion : simple,
specularAntiAliasing : true,

View File

@@ -4,6 +4,7 @@ material {
shadingModel : ${SHADINGMODEL},
blending : masked,
doubleSided : ${DOUBLESIDED},
transparency : ${TRANSPARENCY},
flipUV : false,
specularAmbientOcclusion : simple,
specularAntiAliasing : true,

View File

@@ -3,8 +3,8 @@ material {
requires : [ uv0, uv1, color ],
shadingModel : ${SHADINGMODEL},
blending : ${BLENDING},
depthWrite : true,
doubleSided : ${DOUBLESIDED},
transparency : ${TRANSPARENCY},
flipUV : false,
specularAmbientOcclusion : simple,
specularAntiAliasing : true,

View File

@@ -4,6 +4,7 @@ material {
shadingModel : ${SHADINGMODEL},
blending : masked,
doubleSided : ${DOUBLESIDED},
transparency : ${TRANSPARENCY},
flipUV : false,
specularAmbientOcclusion : simple,
specularAntiAliasing : true,

View File

@@ -321,6 +321,9 @@ static Material* createMaterial(Engine* engine, const MaterialKey& config, const
.clearCoatIorChange(false)
.material(shader.c_str())
.doubleSided(config.doubleSided)
.transparencyMode(config.doubleSided ?
MaterialBuilder::TransparencyMode::TWO_PASSES_TWO_SIDES :
MaterialBuilder::TransparencyMode::DEFAULT)
.targetApi(filamat::targetApiFromBackend(engine->getBackend()));
if (!optimizeShaders) {
@@ -483,7 +486,6 @@ static Material* createMaterial(Engine* engine, const MaterialKey& config, const
break;
case AlphaMode::BLEND:
builder.blending(MaterialBuilder::BlendingMode::FADE);
builder.depthWrite(true);
break;
default:
// Ignore

View File

@@ -208,6 +208,9 @@ MaterialInstance* UbershaderLoader::createMaterialInstance(MaterialKey* config,
mi->setDoubleSided(config->doubleSided);
mi->setCullingMode(config->doubleSided ? CullingMode::NONE : CullingMode::BACK);
mi->setTransparencyMode(config->doubleSided ?
MaterialInstance::TransparencyMode::TWO_PASSES_TWO_SIDES :
MaterialInstance::TransparencyMode::DEFAULT);
#if !GLTFIO_LITE

View File

@@ -62,7 +62,7 @@ public:
* Creates an IBLPrefilter context.
* @param engine filament engine to use
*/
IBLPrefilterContext(filament::Engine& engine);
explicit IBLPrefilterContext(filament::Engine& engine);
/**
* Destroys all GPU resources created during initialization.
@@ -75,7 +75,7 @@ public:
// movable
IBLPrefilterContext(IBLPrefilterContext&& rhs) noexcept;
IBLPrefilterContext& operator=(IBLPrefilterContext&& rhs);
IBLPrefilterContext& operator=(IBLPrefilterContext&& rhs) noexcept;
// -------------------------------------------------------------------------------------------
@@ -98,7 +98,7 @@ public:
EquirectangularToCubemap(EquirectangularToCubemap const&) = delete;
EquirectangularToCubemap& operator=(EquirectangularToCubemap const&) = delete;
EquirectangularToCubemap(EquirectangularToCubemap&& rhs) noexcept;
EquirectangularToCubemap& operator=(EquirectangularToCubemap&& rhs);
EquirectangularToCubemap& operator=(EquirectangularToCubemap&& rhs) noexcept;
/**
* Converts an equirectangular image to a cubemap.
@@ -175,7 +175,7 @@ public:
SpecularFilter(SpecularFilter const&) = delete;
SpecularFilter& operator=(SpecularFilter const&) = delete;
SpecularFilter(SpecularFilter&& rhs) noexcept;
SpecularFilter& operator=(SpecularFilter&& rhs);
SpecularFilter& operator=(SpecularFilter&& rhs) noexcept;
/**
* Generates a prefiltered cubemap.

View File

@@ -142,7 +142,7 @@ IBLPrefilterContext::IBLPrefilterContext(IBLPrefilterContext&& rhs) noexcept
this->operator=(std::move(rhs));
}
IBLPrefilterContext& IBLPrefilterContext::operator=(IBLPrefilterContext&& rhs) {
IBLPrefilterContext& IBLPrefilterContext::operator=(IBLPrefilterContext&& rhs) noexcept {
using std::swap;
if (this != & rhs) {
swap(mRenderer, rhs.mRenderer);
@@ -182,7 +182,7 @@ IBLPrefilterContext::EquirectangularToCubemap::EquirectangularToCubemap(
IBLPrefilterContext::EquirectangularToCubemap&
IBLPrefilterContext::EquirectangularToCubemap::operator=(
IBLPrefilterContext::EquirectangularToCubemap&& rhs) {
IBLPrefilterContext::EquirectangularToCubemap&& rhs) noexcept {
using std::swap;
if (this != &rhs) {
swap(mEquirectMaterial, rhs.mEquirectMaterial);
@@ -332,7 +332,8 @@ IBLPrefilterContext::SpecularFilter::SpecularFilter(SpecularFilter&& rhs) noexce
this->operator=(std::move(rhs));
}
IBLPrefilterContext::SpecularFilter& IBLPrefilterContext::SpecularFilter::operator=(SpecularFilter&& rhs) {
IBLPrefilterContext::SpecularFilter&
IBLPrefilterContext::SpecularFilter::operator=(SpecularFilter&& rhs) noexcept {
using std::swap;
if (this != & rhs) {
swap(mKernelMaterial, rhs.mKernelMaterial);

View File

@@ -7,6 +7,8 @@ layout(location = 0) out vec4 fragColor;
//------------------------------------------------------------------------------
void main() {
filament_lodBias = frameUniforms.lodBias;
#if defined(BLEND_MODE_MASKED) || (defined(BLEND_MODE_TRANSPARENT) && defined(HAS_TRANSPARENT_SHADOW))
MaterialInputs inputs;
initMaterial(inputs);

View File

@@ -17,6 +17,8 @@ void blendPostLightingColor(const MaterialInputs material, inout vec4 color) {
#endif
void main() {
filament_lodBias = frameUniforms.lodBias;
// See shading_parameters.fs
// Computes global variables we need to evaluate material and lighting
computeShadingParams();

View File

@@ -1,4 +1,4 @@
Copyright (c) 2018 Johannes Kuhlmann
Copyright (c) 2018-2021 Johannes Kuhlmann
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View File

@@ -3,7 +3,7 @@
[![Build Status](https://github.com/jkuhlmann/cgltf/workflows/build/badge.svg)](https://github.com/jkuhlmann/cgltf/actions)
Used in: [bgfx](https://github.com/bkaradzic/bgfx), [Filament](https://github.com/google/filament), [gltfpack](https://github.com/zeux/meshoptimizer/tree/master/gltf), [raylib](https://github.com/raysan5/raylib), and more!
Used in: [bgfx](https://github.com/bkaradzic/bgfx), [Filament](https://github.com/google/filament), [gltfpack](https://github.com/zeux/meshoptimizer/tree/master/gltf), [raylib](https://github.com/raysan5/raylib), [Unigine](https://developer.unigine.com/en/docs/2.14.1/third_party?rlang=cpp#cgltf), and more!
## Usage: Loading
Loading from file:

View File

@@ -1,7 +1,7 @@
/**
* cgltf - a single-file glTF 2.0 parser written in C99.
*
* Version: 1.10
* Version: 1.11
*
* Website: https://github.com/jkuhlmann/cgltf
*
@@ -234,6 +234,12 @@ typedef enum cgltf_light_type {
cgltf_light_type_spot,
} cgltf_light_type;
typedef enum cgltf_data_free_method {
cgltf_data_free_method_none,
cgltf_data_free_method_file_release,
cgltf_data_free_method_memory_free,
} cgltf_data_free_method;
typedef struct cgltf_extras {
cgltf_size start_offset;
cgltf_size end_offset;
@@ -250,6 +256,7 @@ typedef struct cgltf_buffer
cgltf_size size;
char* uri;
void* data; /* loaded by cgltf_load_buffers */
cgltf_data_free_method data_free_method;
cgltf_extras extras;
cgltf_size extensions_count;
cgltf_extension* extensions;
@@ -372,6 +379,8 @@ typedef struct cgltf_texture
char* name;
cgltf_image* image;
cgltf_sampler* sampler;
cgltf_bool has_basisu;
cgltf_image* basisu_image;
cgltf_extras extras;
cgltf_size extensions_count;
cgltf_extension* extensions;
@@ -382,6 +391,7 @@ typedef struct cgltf_texture_transform
cgltf_float offset[2];
cgltf_float rotation;
cgltf_float scale[2];
cgltf_bool has_texcoord;
cgltf_int texcoord;
} cgltf_texture_transform;
@@ -595,6 +605,7 @@ typedef struct cgltf_light {
cgltf_float range;
cgltf_float spot_inner_cone_angle;
cgltf_float spot_outer_cone_angle;
cgltf_extras extras;
} cgltf_light;
struct cgltf_node {
@@ -813,7 +824,7 @@ cgltf_result cgltf_copy_extras_json(const cgltf_data* data, const cgltf_extras*
#include <limits.h> /* For UINT_MAX etc */
#include <float.h> /* For FLT_MAX */
#if !defined(CGLTF_MALLOC) || !defined(CGLTF_FREE) || !defined(CGLTF_ATOI) || !defined(CGLTF_ATOF)
#if !defined(CGLTF_MALLOC) || !defined(CGLTF_FREE) || !defined(CGLTF_ATOI) || !defined(CGLTF_ATOF) || !defined(CGLTF_ATOLL)
#include <stdlib.h> /* For malloc, free, atoi, atof */
#endif
@@ -883,6 +894,9 @@ static const uint32_t GlbMagicBinChunk = 0x004E4942;
#ifndef CGLTF_ATOF
#define CGLTF_ATOF(str) atof(str)
#endif
#ifndef CGLTF_ATOLL
#define CGLTF_ATOLL(str) atoll(str)
#endif
#ifndef CGLTF_VALIDATE_ENABLE_ASSERTS
#define CGLTF_VALIDATE_ENABLE_ASSERTS 0
#endif
@@ -932,7 +946,12 @@ static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* m
{
fseek(file, 0, SEEK_END);
#ifdef _WIN32
__int64 length = _ftelli64(file);
#else
long length = ftell(file);
#endif
if (length < 0)
{
fclose(file);
@@ -1120,8 +1139,8 @@ cgltf_result cgltf_parse_file(const cgltf_options* options, const char* path, cg
return cgltf_result_invalid_options;
}
void (*memory_free)(void*, void*) = options->memory.free ? options->memory.free : &cgltf_default_free;
cgltf_result (*file_read)(const struct cgltf_memory_options*, const struct cgltf_file_options*, const char*, cgltf_size*, void**) = options->file.read ? options->file.read : &cgltf_default_file_read;
void (*file_release)(const struct cgltf_memory_options*, const struct cgltf_file_options*, void* data) = options->file.release ? options->file.release : cgltf_default_file_release;
void* file_data = NULL;
cgltf_size file_size = 0;
@@ -1135,7 +1154,7 @@ cgltf_result cgltf_parse_file(const cgltf_options* options, const char* path, cg
if (result != cgltf_result_success)
{
memory_free(options->memory.user_data, file_data);
file_release(&options->memory, &options->file, file_data);
return result;
}
@@ -1291,6 +1310,7 @@ cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data,
}
data->buffers[0].data = (void*)data->bin;
data->buffers[0].data_free_method = cgltf_data_free_method_none;
}
for (cgltf_size i = 0; i < data->buffers_count; ++i)
@@ -1314,6 +1334,7 @@ cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data,
if (comma && comma - uri >= 7 && strncmp(comma - 7, ";base64", 7) == 0)
{
cgltf_result res = cgltf_load_buffer_base64(options, data->buffers[i].size, comma + 1, &data->buffers[i].data);
data->buffers[i].data_free_method = cgltf_data_free_method_memory_free;
if (res != cgltf_result_success)
{
@@ -1328,6 +1349,7 @@ cgltf_result cgltf_load_buffers(const cgltf_options* options, cgltf_data* data,
else if (strstr(uri, "://") == NULL && gltf_path)
{
cgltf_result res = cgltf_load_buffer_file(options, data->buffers[i].size, uri, gltf_path, &data->buffers[i].data);
data->buffers[i].data_free_method = cgltf_data_free_method_file_release;
if (res != cgltf_result_success)
{
@@ -1655,10 +1677,15 @@ void cgltf_free(cgltf_data* data)
{
data->memory.free(data->memory.user_data, data->buffers[i].name);
if (data->buffers[i].data != data->bin)
if (data->buffers[i].data_free_method == cgltf_data_free_method_file_release)
{
file_release(&data->memory, &data->file, data->buffers[i].data);
}
else if (data->buffers[i].data_free_method == cgltf_data_free_method_memory_free)
{
data->memory.free(data->memory.user_data, data->buffers[i].data);
}
data->memory.free(data->memory.user_data, data->buffers[i].uri);
cgltf_free_extensions(data, data->buffers[i].extensions, data->buffers[i].extensions_count);
@@ -2259,6 +2286,7 @@ cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size
#define CGLTF_ERROR_LEGACY -3
#define CGLTF_CHECK_TOKTYPE(tok_, type_) if ((tok_).type != (type_)) { return CGLTF_ERROR_JSON; }
#define CGLTF_CHECK_TOKTYPE_RETTYPE(tok_, type_, ret_) if ((tok_).type != (type_)) { return (ret_)CGLTF_ERROR_JSON; }
#define CGLTF_CHECK_KEY(tok_) if ((tok_).type != JSMN_STRING || (tok_).size == 0) { return CGLTF_ERROR_JSON; } /* checking size for 0 verifies that a value follows the key */
#define CGLTF_PTRINDEX(type, idx) (type*)((cgltf_size)idx + 1)
@@ -2283,6 +2311,16 @@ static int cgltf_json_to_int(jsmntok_t const* tok, const uint8_t* json_chunk)
return CGLTF_ATOI(tmp);
}
static cgltf_size cgltf_json_to_size(jsmntok_t const* tok, const uint8_t* json_chunk)
{
CGLTF_CHECK_TOKTYPE_RETTYPE(*tok, JSMN_PRIMITIVE, cgltf_size);
char tmp[128];
int size = (cgltf_size)(tok->end - tok->start) < sizeof(tmp) ? tok->end - tok->start : (int)(sizeof(tmp) - 1);
strncpy(tmp, (const char*)json_chunk + tok->start, size);
tmp[size] = 0;
return (cgltf_size)CGLTF_ATOLL(tmp);
}
static cgltf_float cgltf_json_to_float(jsmntok_t const* tok, const uint8_t* json_chunk)
{
CGLTF_CHECK_TOKTYPE(*tok, JSMN_PRIMITIVE);
@@ -3024,7 +3062,7 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co
else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0)
{
++i;
out_sparse->indices_byte_offset = cgltf_json_to_int(tokens + i, json_chunk);
out_sparse->indices_byte_offset = cgltf_json_to_size(tokens + i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "componentType") == 0)
@@ -3073,7 +3111,7 @@ static int cgltf_parse_json_accessor_sparse(cgltf_options* options, jsmntok_t co
else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0)
{
++i;
out_sparse->values_byte_offset = cgltf_json_to_int(tokens + i, json_chunk);
out_sparse->values_byte_offset = cgltf_json_to_size(tokens + i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
@@ -3142,7 +3180,7 @@ static int cgltf_parse_json_accessor(cgltf_options* options, jsmntok_t const* to
{
++i;
out_accessor->offset =
cgltf_json_to_int(tokens+i, json_chunk);
cgltf_json_to_size(tokens+i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "componentType") == 0)
@@ -3268,6 +3306,7 @@ static int cgltf_parse_json_texture_transform(jsmntok_t const* tokens, int i, co
else if (cgltf_json_strcmp(tokens + i, json_chunk, "texCoord") == 0)
{
++i;
out_texture_transform->has_texcoord = 1;
out_texture_transform->texcoord = cgltf_json_to_int(tokens + i, json_chunk);
++i;
}
@@ -3885,7 +3924,62 @@ static int cgltf_parse_json_texture(cgltf_options* options, jsmntok_t const* tok
}
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0)
{
i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_texture->extensions_count, &out_texture->extensions);
++i;
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
if (out_texture->extensions)
{
return CGLTF_ERROR_JSON;
}
int extensions_size = tokens[i].size;
++i;
out_texture->extensions = (cgltf_extension*)cgltf_calloc(options, sizeof(cgltf_extension), extensions_size);
out_texture->extensions_count = 0;
if (!out_texture->extensions)
{
return CGLTF_ERROR_NOMEM;
}
for (int k = 0; k < extensions_size; ++k)
{
CGLTF_CHECK_KEY(tokens[i]);
if (cgltf_json_strcmp(tokens + i, json_chunk, "KHR_texture_basisu") == 0)
{
out_texture->has_basisu = 1;
++i;
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
int num_properties = tokens[i].size;
++i;
for (int t = 0; t < num_properties; ++t)
{
CGLTF_CHECK_KEY(tokens[i]);
if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0)
{
++i;
out_texture->basisu_image = CGLTF_PTRINDEX(cgltf_image, cgltf_json_to_int(tokens + i, json_chunk));
++i;
}
else
{
i = cgltf_skip_json(tokens, i + 1);
}
}
}
else
{
i = cgltf_parse_json_unprocessed_extension(options, tokens, i, json_chunk, &(out_texture->extensions[out_texture->extensions_count++]));
}
if (i < 0)
{
return i;
}
}
}
else
{
@@ -4192,19 +4286,19 @@ static int cgltf_parse_json_meshopt_compression(cgltf_options* options, jsmntok_
else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteOffset") == 0)
{
++i;
out_meshopt_compression->offset = cgltf_json_to_int(tokens+i, json_chunk);
out_meshopt_compression->offset = cgltf_json_to_size(tokens+i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteLength") == 0)
{
++i;
out_meshopt_compression->size = cgltf_json_to_int(tokens+i, json_chunk);
out_meshopt_compression->size = cgltf_json_to_size(tokens+i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteStride") == 0)
{
++i;
out_meshopt_compression->stride = cgltf_json_to_int(tokens+i, json_chunk);
out_meshopt_compression->stride = cgltf_json_to_size(tokens+i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "count") == 0)
@@ -4290,21 +4384,21 @@ static int cgltf_parse_json_buffer_view(cgltf_options* options, jsmntok_t const*
{
++i;
out_buffer_view->offset =
cgltf_json_to_int(tokens+i, json_chunk);
cgltf_json_to_size(tokens+i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteLength") == 0)
{
++i;
out_buffer_view->size =
cgltf_json_to_int(tokens+i, json_chunk);
cgltf_json_to_size(tokens+i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "byteStride") == 0)
{
++i;
out_buffer_view->stride =
cgltf_json_to_int(tokens+i, json_chunk);
cgltf_json_to_size(tokens+i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "target") == 0)
@@ -4422,7 +4516,7 @@ static int cgltf_parse_json_buffer(cgltf_options* options, jsmntok_t const* toke
{
++i;
out_buffer->size =
cgltf_json_to_int(tokens+i, json_chunk);
cgltf_json_to_size(tokens+i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "uri") == 0)
@@ -4737,6 +4831,14 @@ static int cgltf_parse_json_light(cgltf_options* options, jsmntok_t const* token
{
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
out_light->color[0] = 1.f;
out_light->color[1] = 1.f;
out_light->color[2] = 1.f;
out_light->intensity = 1.f;
out_light->spot_inner_cone_angle = 0.f;
out_light->spot_outer_cone_angle = 3.1415926535f / 4.0f;
int size = tokens[i].size;
++i;
@@ -4817,6 +4919,10 @@ static int cgltf_parse_json_light(cgltf_options* options, jsmntok_t const* token
}
}
}
else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0)
{
i = cgltf_parse_json_extras(tokens, i + 1, json_chunk, &out_light->extras);
}
else
{
i = cgltf_skip_json(tokens, i+1);
@@ -5851,6 +5957,7 @@ static int cgltf_fixup_pointers(cgltf_data* data)
for (cgltf_size i = 0; i < data->textures_count; ++i)
{
CGLTF_PTRFIXUP(data->textures[i].image, data->images, data->images_count);
CGLTF_PTRFIXUP(data->textures[i].basisu_image, data->images, data->images_count);
CGLTF_PTRFIXUP(data->textures[i].sampler, data->samplers, data->samplers_count);
}
@@ -6305,7 +6412,7 @@ static void jsmn_init(jsmn_parser *parser) {
/* cgltf is distributed under MIT license:
*
* Copyright (c) 2018 Johannes Kuhlmann
* Copyright (c) 2018-2021 Johannes Kuhlmann
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,7 +1,7 @@
/**
* cgltf_write - a single-file glTF 2.0 writer written in C99.
*
* Version: 1.10
* Version: 1.11
*
* Website: https://github.com/jkuhlmann/cgltf
*
@@ -64,6 +64,7 @@ cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size si
#ifdef CGLTF_WRITE_IMPLEMENTATION
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@@ -82,6 +83,7 @@ cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size si
#define CGLTF_EXTENSION_FLAG_MATERIALS_SHEEN (1 << 9)
#define CGLTF_EXTENSION_FLAG_MATERIALS_VARIANTS (1 << 10)
#define CGLTF_EXTENSION_FLAG_MATERIALS_VOLUME (1 << 11)
#define CGLTF_EXTENSION_FLAG_TEXTURE_BASISU (1 << 12)
typedef struct {
char* buffer;
@@ -108,6 +110,7 @@ typedef struct {
#endif
#define CGLTF_SPRINTF(...) { \
assert(context->cursor || (!context->cursor && context->remaining == 0)); \
context->tmp = snprintf ( context->cursor, context->remaining, __VA_ARGS__ ); \
context->chars_written += context->tmp; \
if (context->cursor) { \
@@ -116,6 +119,7 @@ typedef struct {
} }
#define CGLTF_SNPRINTF(length, ...) { \
assert(context->cursor || (!context->cursor && context->remaining == 0)); \
context->tmp = snprintf ( context->cursor, CGLTF_MIN(length + 1, context->remaining), __VA_ARGS__ ); \
context->chars_written += length; \
if (context->cursor) { \
@@ -229,6 +233,16 @@ static void cgltf_write_intprop(cgltf_write_context* context, const char* label,
}
}
static void cgltf_write_sizeprop(cgltf_write_context* context, const char* label, cgltf_size val, cgltf_size def)
{
if (val != def)
{
cgltf_write_indent(context);
CGLTF_SPRINTF("\"%s\": %zu", label, val);
context->needs_comma = 1;
}
}
static void cgltf_write_floatprop(cgltf_write_context* context, const char* label, float val, float def)
{
if (val != def)
@@ -377,7 +391,10 @@ static void cgltf_write_texture_transform(cgltf_write_context* context, const cg
{
cgltf_write_floatarrayprop(context, "scale", transform->scale, 2);
}
cgltf_write_intprop(context, "texCoord", transform->texcoord, 0);
if (transform->has_texcoord)
{
cgltf_write_intprop(context, "texCoord", transform->texcoord, -1);
}
cgltf_write_line(context, "}");
cgltf_write_line(context, "}");
}
@@ -500,9 +517,9 @@ static void cgltf_write_buffer_view(cgltf_write_context* context, const cgltf_bu
cgltf_write_line(context, "{");
cgltf_write_strprop(context, "name", view->name);
CGLTF_WRITE_IDXPROP("buffer", view->buffer, context->data->buffers);
cgltf_write_intprop(context, "byteLength", (int)view->size, -1);
cgltf_write_intprop(context, "byteOffset", (int)view->offset, 0);
cgltf_write_intprop(context, "byteStride", (int)view->stride, 0);
cgltf_write_sizeprop(context, "byteLength", view->size, (cgltf_size)-1);
cgltf_write_sizeprop(context, "byteOffset", view->offset, 0);
cgltf_write_sizeprop(context, "byteStride", view->stride, 0);
// NOTE: We skip writing "target" because the spec says its usage can be inferred.
cgltf_write_extras(context, &view->extras);
cgltf_write_line(context, "}");
@@ -514,7 +531,7 @@ static void cgltf_write_buffer(cgltf_write_context* context, const cgltf_buffer*
cgltf_write_line(context, "{");
cgltf_write_strprop(context, "name", buffer->name);
cgltf_write_strprop(context, "uri", buffer->uri);
cgltf_write_intprop(context, "byteLength", (int)buffer->size, -1);
cgltf_write_sizeprop(context, "byteLength", buffer->size, (cgltf_size)-1);
cgltf_write_extras(context, &buffer->extras);
cgltf_write_line(context, "}");
}
@@ -523,7 +540,10 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater
{
cgltf_write_line(context, "{");
cgltf_write_strprop(context, "name", material->name);
cgltf_write_floatprop(context, "alphaCutoff", material->alpha_cutoff, 0.5f);
if (material->alpha_mode == cgltf_alpha_mode_mask)
{
cgltf_write_floatprop(context, "alphaCutoff", material->alpha_cutoff, 0.5f);
}
cgltf_write_boolprop_optional(context, "doubleSided", material->double_sided, false);
// cgltf_write_boolprop_optional(context, "unlit", material->unlit, false);
@@ -662,7 +682,7 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater
CGLTF_WRITE_TEXTURE_INFO("specularGlossinessTexture", params->specular_glossiness_texture);
if (cgltf_check_floatarray(params->diffuse_factor, 4, 1.0f))
{
cgltf_write_floatarrayprop(context, "dffuseFactor", params->diffuse_factor, 4);
cgltf_write_floatarrayprop(context, "diffuseFactor", params->diffuse_factor, 4);
}
if (cgltf_check_floatarray(params->specular_factor, 3, 1.0f))
{
@@ -707,6 +727,18 @@ static void cgltf_write_texture(cgltf_write_context* context, const cgltf_textur
cgltf_write_strprop(context, "name", texture->name);
CGLTF_WRITE_IDXPROP("source", texture->image, context->data->images);
CGLTF_WRITE_IDXPROP("sampler", texture->sampler, context->data->samplers);
if (texture->has_basisu)
{
cgltf_write_line(context, "\"extensions\": {");
{
context->extension_flags |= CGLTF_EXTENSION_FLAG_TEXTURE_BASISU;
cgltf_write_line(context, "\"KHR_texture_basisu\": {");
CGLTF_WRITE_IDXPROP("source", texture->basisu_image, context->data->images);
cgltf_write_line(context, "}");
}
cgltf_write_line(context, "}");
}
cgltf_write_extras(context, &texture->extras);
cgltf_write_line(context, "}");
}
@@ -894,7 +926,7 @@ static void cgltf_write_accessor(cgltf_write_context* context, const cgltf_acces
cgltf_write_strprop(context, "type", cgltf_str_from_type(accessor->type));
cgltf_size dim = cgltf_dim_from_type(accessor->type);
cgltf_write_boolprop_optional(context, "normalized", accessor->normalized, false);
cgltf_write_intprop(context, "byteOffset", (int)accessor->offset, 0);
cgltf_write_sizeprop(context, "byteOffset", (int)accessor->offset, 0);
cgltf_write_intprop(context, "count", (int)accessor->count, -1);
if (accessor->has_min)
{
@@ -909,13 +941,13 @@ static void cgltf_write_accessor(cgltf_write_context* context, const cgltf_acces
cgltf_write_line(context, "\"sparse\": {");
cgltf_write_intprop(context, "count", (int)accessor->sparse.count, 0);
cgltf_write_line(context, "\"indices\": {");
cgltf_write_intprop(context, "byteOffset", (int)accessor->sparse.indices_byte_offset, 0);
cgltf_write_sizeprop(context, "byteOffset", (int)accessor->sparse.indices_byte_offset, 0);
CGLTF_WRITE_IDXPROP("bufferView", accessor->sparse.indices_buffer_view, context->data->buffer_views);
cgltf_write_intprop(context, "componentType", cgltf_int_from_component_type(accessor->sparse.indices_component_type), 0);
cgltf_write_extras(context, &accessor->sparse.indices_extras);
cgltf_write_line(context, "}");
cgltf_write_line(context, "\"values\": {");
cgltf_write_intprop(context, "byteOffset", (int)accessor->sparse.values_byte_offset, 0);
cgltf_write_sizeprop(context, "byteOffset", (int)accessor->sparse.values_byte_offset, 0);
CGLTF_WRITE_IDXPROP("bufferView", accessor->sparse.values_buffer_view, context->data->buffer_views);
cgltf_write_extras(context, &accessor->sparse.values_extras);
cgltf_write_line(context, "}");
@@ -1059,6 +1091,12 @@ static void cgltf_write_extensions(cgltf_write_context* context, uint32_t extens
if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_VARIANTS) {
cgltf_write_stritem(context, "KHR_materials_variants");
}
if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_VOLUME) {
cgltf_write_stritem(context, "KHR_materials_volume");
}
if (extension_flags & CGLTF_EXTENSION_FLAG_TEXTURE_BASISU) {
cgltf_write_stritem(context, "KHR_texture_basisu");
}
}
cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size size, const cgltf_data* data)
@@ -1273,7 +1311,7 @@ cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size si
/* cgltf is distributed under MIT license:
*
* Copyright (c) 2019 Philip Rideout
* Copyright (c) 2019-2021 Philip Rideout
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,6 +1,6 @@
This folder was last updated as follows:
export sha=1bdc84d
export sha=aef41ea
cd third_party
curl -L -O https://github.com/jkuhlmann/cgltf/archive/${sha}.zip
unzip ${sha}.zip

View File

@@ -1,6 +1,6 @@
{
"name": "filament",
"version": "1.12.5",
"version": "1.12.6",
"description": "Real-time physically based rendering engine",
"main": "filament.js",
"module": "filament.js",