Merge branch 'rc/1.12.6' into release
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
251
filament/backend/test/test_RenderExternalImage.cpp
Normal file
251
filament/backend/test/test_RenderExternalImage.cpp
Normal 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
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
//
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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|
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -5,6 +5,7 @@ material {
|
||||
blending : fade,
|
||||
depthWrite : true,
|
||||
doubleSided : ${DOUBLESIDED},
|
||||
transparency : ${TRANSPARENCY},
|
||||
flipUV : false,
|
||||
specularAmbientOcclusion : simple,
|
||||
specularAntiAliasing : true,
|
||||
|
||||
@@ -4,6 +4,7 @@ material {
|
||||
shadingModel : ${SHADINGMODEL},
|
||||
blending : masked,
|
||||
doubleSided : ${DOUBLESIDED},
|
||||
transparency : ${TRANSPARENCY},
|
||||
flipUV : false,
|
||||
specularAmbientOcclusion : simple,
|
||||
specularAntiAliasing : true,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -4,6 +4,7 @@ material {
|
||||
shadingModel : ${SHADINGMODEL},
|
||||
blending : masked,
|
||||
doubleSided : ${DOUBLESIDED},
|
||||
transparency : ${TRANSPARENCY},
|
||||
flipUV : false,
|
||||
specularAmbientOcclusion : simple,
|
||||
specularAntiAliasing : true,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
2
third_party/cgltf/LICENSE
vendored
2
third_party/cgltf/LICENSE
vendored
@@ -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:
|
||||
|
||||
|
||||
2
third_party/cgltf/README.md
vendored
2
third_party/cgltf/README.md
vendored
@@ -3,7 +3,7 @@
|
||||
|
||||
[](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:
|
||||
|
||||
141
third_party/cgltf/cgltf.h
vendored
141
third_party/cgltf/cgltf.h
vendored
@@ -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
|
||||
|
||||
62
third_party/cgltf/cgltf_write.h
vendored
62
third_party/cgltf/cgltf_write.h
vendored
@@ -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
|
||||
|
||||
2
third_party/cgltf/tnt/README
vendored
2
third_party/cgltf/tnt/README
vendored
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user