Introduce libs/viewer and serializable view settings.
This introduces the `viewer::Settings` struct, and a JSON reader / writer. This will be used for automated testing and for client / server communication. Note that `viewer::Settings` is closely associated with the `filament::View` API; when updating the latter we will often need to update the former, as well as some serialization code. This increases the maintenance burden and I think we should consider using a parser library like libclang or a macro-based reflection utility. This PR also migrates SimpleViewer into libs/viewer and un-inlines its implementation. It does not belong in gltfio because it has an imgui dependency.
This commit is contained in:
@@ -593,7 +593,6 @@ set(FILAMENT_SAMPLES_BINARY_DIR ${PROJECT_BINARY_DIR}/samples)
|
||||
if (WEBGL)
|
||||
add_subdirectory(web/filament-js)
|
||||
add_subdirectory(web/samples)
|
||||
add_subdirectory(${EXTERNAL}/imgui/tnt)
|
||||
endif()
|
||||
|
||||
if (IS_HOST_PLATFORM)
|
||||
@@ -601,6 +600,7 @@ if (IS_HOST_PLATFORM)
|
||||
add_subdirectory(${LIBRARIES}/filamentapp)
|
||||
add_subdirectory(${LIBRARIES}/filagui)
|
||||
add_subdirectory(${LIBRARIES}/imageio)
|
||||
add_subdirectory(${LIBRARIES}/viewer)
|
||||
|
||||
add_subdirectory(${FILAMENT}/java/filamat)
|
||||
add_subdirectory(${FILAMENT}/java/filament)
|
||||
|
||||
@@ -29,7 +29,6 @@ set(GLTFIO_SRCS
|
||||
${GLTFIO_DIR}/include/gltfio/AssetLoader.h
|
||||
${GLTFIO_DIR}/include/gltfio/MaterialProvider.h
|
||||
${GLTFIO_DIR}/include/gltfio/ResourceLoader.h
|
||||
${GLTFIO_DIR}/include/gltfio/SimpleViewer.h
|
||||
${GLTFIO_DIR}/include/gltfio/FilamentAsset.h
|
||||
${GLTFIO_DIR}/include/gltfio/FilamentInstance.h
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
libs/viewer/test_settings
|
||||
filament/test/test_filament --gtest_filter=-FilamentTest.FroxelData:FilamentExposureWithEngineTest.SetExposure:FilamentExposureWithEngineTest.ComputeEV100:RenderingTest.*
|
||||
filament/test/test_material_parser
|
||||
libs/math/test_math
|
||||
|
||||
@@ -12,7 +12,6 @@ set(PUBLIC_HDRS
|
||||
include/gltfio/AssetLoader.h
|
||||
include/gltfio/MaterialProvider.h
|
||||
include/gltfio/ResourceLoader.h
|
||||
include/gltfio/SimpleViewer.h
|
||||
include/gltfio/FilamentAsset.h
|
||||
include/gltfio/FilamentInstance.h
|
||||
)
|
||||
|
||||
49
libs/viewer/CMakeLists.txt
Normal file
49
libs/viewer/CMakeLists.txt
Normal file
@@ -0,0 +1,49 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(viewer)
|
||||
|
||||
set(TARGET viewer)
|
||||
set(PUBLIC_HDR_DIR include)
|
||||
|
||||
# ==================================================================================================
|
||||
# Sources and headers
|
||||
# ==================================================================================================
|
||||
set(PUBLIC_HDRS
|
||||
include/viewer/SimpleViewer.h
|
||||
include/viewer/Settings.h
|
||||
)
|
||||
|
||||
set(SRCS
|
||||
src/SimpleViewer.cpp
|
||||
src/Settings.cpp
|
||||
)
|
||||
|
||||
# ==================================================================================================
|
||||
# Include and target definitions
|
||||
# ==================================================================================================
|
||||
add_library(${TARGET} STATIC ${PUBLIC_HDRS} ${SRCS})
|
||||
target_link_libraries(${TARGET} PUBLIC imgui cgltf filament gltfio filagui)
|
||||
target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR})
|
||||
|
||||
# ==================================================================================================
|
||||
# Compiler flags
|
||||
# ==================================================================================================
|
||||
if (MSVC)
|
||||
target_compile_options(${TARGET} PRIVATE $<$<CONFIG:Release>:/fp:fast>)
|
||||
else()
|
||||
target_compile_options(${TARGET} PRIVATE $<$<CONFIG:Release>:-ffast-math>)
|
||||
target_compile_options(${TARGET} PRIVATE -Wno-deprecated-register)
|
||||
endif()
|
||||
|
||||
# ==================================================================================================
|
||||
# Installation
|
||||
# ==================================================================================================
|
||||
install(TARGETS ${TARGET} ARCHIVE DESTINATION lib/${DIST_DIR})
|
||||
install(DIRECTORY ${PUBLIC_HDR_DIR}/viewer DESTINATION include)
|
||||
|
||||
# ==================================================================================================
|
||||
# Tests
|
||||
# ==================================================================================================
|
||||
if (NOT ANDROID AND NOT WEBGL AND NOT IOS)
|
||||
add_executable(test_settings tests/test_settings.cpp)
|
||||
target_link_libraries(test_settings PRIVATE ${TARGET} gtest)
|
||||
endif()
|
||||
121
libs/viewer/include/viewer/Settings.h
Normal file
121
libs/viewer/include/viewer/Settings.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by mIcable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef VIEWER_SETTINGS_H
|
||||
#define VIEWER_SETTINGS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <filament/ColorGrading.h>
|
||||
#include <filament/View.h>
|
||||
|
||||
namespace filament {
|
||||
namespace viewer {
|
||||
|
||||
struct ColorGradingSettings;
|
||||
struct DynamicLightingSettings;
|
||||
struct Settings;
|
||||
struct ViewSettings;
|
||||
|
||||
using AmbientOcclusionOptions = filament::View::AmbientOcclusionOptions;
|
||||
using AntiAliasing = filament::View::AntiAliasing;
|
||||
using BloomOptions = filament::View::BloomOptions;
|
||||
using DepthOfFieldOptions = filament::View::DepthOfFieldOptions;
|
||||
using Dithering = filament::View::Dithering;
|
||||
using FogOptions = filament::View::FogOptions;
|
||||
using RenderQuality = filament::View::RenderQuality;
|
||||
using ShadowType = filament::View::ShadowType;
|
||||
using TemporalAntiAliasingOptions = filament::View::TemporalAntiAliasingOptions;
|
||||
using ToneMapping = filament::ColorGrading::ToneMapping;
|
||||
using VignetteOptions = filament::View::VignetteOptions;
|
||||
|
||||
// Reads the given JSON blob and updates the corresponding fields in the given Settings object.
|
||||
//
|
||||
// - The given JSON blob need not specify all settings.
|
||||
// - Returns true if successful.
|
||||
// - This function writes warnings and error messages into the utils log.
|
||||
bool readJson(const char* jsonChunk, size_t size, Settings* out);
|
||||
|
||||
// Generates human-readable JSON strings from settings objects.
|
||||
std::string writeJson(const AmbientOcclusionOptions& out);
|
||||
std::string writeJson(const BloomOptions& out);
|
||||
std::string writeJson(const ColorGradingSettings& out);
|
||||
std::string writeJson(const DepthOfFieldOptions& out);
|
||||
std::string writeJson(const DynamicLightingSettings& out);
|
||||
std::string writeJson(const FogOptions& out);
|
||||
std::string writeJson(const RenderQuality& out);
|
||||
std::string writeJson(const Settings& out);
|
||||
std::string writeJson(const TemporalAntiAliasingOptions& out);
|
||||
std::string writeJson(const ViewSettings& out);
|
||||
std::string writeJson(const VignetteOptions& out);
|
||||
|
||||
struct ColorGradingSettings {
|
||||
bool enabled = true;
|
||||
filament::ColorGrading::QualityLevel quality = filament::ColorGrading::QualityLevel::MEDIUM;
|
||||
ToneMapping toneMapping = ToneMapping::ACES_LEGACY;
|
||||
int temperature = 0;
|
||||
int tint = 0;
|
||||
math::float3 outRed{1.0f, 0.0f, 0.0f};
|
||||
math::float3 outGreen{0.0f, 1.0f, 0.0f};
|
||||
math::float3 outBlue{0.0f, 0.0f, 1.0f};
|
||||
math::float4 shadows{1.0f, 1.0f, 1.0f, 0.0f};
|
||||
math::float4 midtones{1.0f, 1.0f, 1.0f, 0.0f};
|
||||
math::float4 highlights{1.0f, 1.0f, 1.0f, 0.0f};
|
||||
math::float4 ranges{0.0f, 0.333f, 0.550f, 1.0f};
|
||||
float contrast = 1.0f;
|
||||
float vibrance = 1.0f;
|
||||
float saturation = 1.0f;
|
||||
math::float3 slope{1.0f};
|
||||
math::float3 offset{0.0f};
|
||||
math::float3 power{1.0f};
|
||||
math::float3 gamma{1.0f};
|
||||
math::float3 midPoint{1.0f};
|
||||
math::float3 scale{1.0f};
|
||||
bool linkedCurves = false;
|
||||
};
|
||||
|
||||
struct DynamicLightingSettings {
|
||||
float zLightNear = 5;
|
||||
float zLightFar = 100;
|
||||
};
|
||||
|
||||
// This defines fields in the same order as the setter methods in filament::View.
|
||||
struct ViewSettings {
|
||||
uint8_t sampleCount = 1;
|
||||
AntiAliasing antiAliasing = AntiAliasing::FXAA;
|
||||
TemporalAntiAliasingOptions taa;
|
||||
ColorGradingSettings colorGrading;
|
||||
AmbientOcclusionOptions ssao;
|
||||
BloomOptions bloom;
|
||||
FogOptions fog;
|
||||
DepthOfFieldOptions dof;
|
||||
VignetteOptions vignette;
|
||||
Dithering dithering = Dithering::TEMPORAL;
|
||||
RenderQuality renderQuality;
|
||||
DynamicLightingSettings dynamicLighting;
|
||||
ShadowType shadowType = ShadowType::PCF;
|
||||
bool postProcessingEnabled = true;
|
||||
};
|
||||
|
||||
struct Settings {
|
||||
ViewSettings view;
|
||||
};
|
||||
|
||||
} // namespace viewer
|
||||
} // namespace filament
|
||||
|
||||
#endif // VIEWER_SETTINGS_H
|
||||
217
libs/viewer/include/viewer/SimpleViewer.h
Normal file
217
libs/viewer/include/viewer/SimpleViewer.h
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by mIcable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef VIEWER_SIMPLEVIEWER_H
|
||||
#define VIEWER_SIMPLEVIEWER_H
|
||||
|
||||
#include <filament/Box.h>
|
||||
#include <filament/DebugRegistry.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/IndirectLight.h>
|
||||
#include <filament/Scene.h>
|
||||
#include <filament/View.h>
|
||||
|
||||
#include <gltfio/Animator.h>
|
||||
#include <gltfio/FilamentAsset.h>
|
||||
|
||||
#include <utils/Entity.h>
|
||||
|
||||
#include <math/vec3.h>
|
||||
|
||||
namespace filament {
|
||||
namespace viewer {
|
||||
|
||||
/**
|
||||
* \class SimpleViewer SimpleViewer.h gltfio/SimpleViewer.h
|
||||
* \brief Manages the state for a simple glTF viewer with imgui controls and a tree view.
|
||||
*
|
||||
* This is a utility that can be used across multiple platforms, including web.
|
||||
*
|
||||
* \note If you don't need ImGui controls, there is no need to use this class, just use AssetLoader
|
||||
* instead.
|
||||
*/
|
||||
class SimpleViewer {
|
||||
public:
|
||||
using Animator = gltfio::Animator;
|
||||
using FilamentAsset = gltfio::FilamentAsset;
|
||||
using FilamentInstance = gltfio::FilamentInstance;
|
||||
|
||||
static constexpr int DEFAULT_SIDEBAR_WIDTH = 350;
|
||||
|
||||
/**
|
||||
* Constructs a SimpleViewer that has a fixed association with the given Filament objects.
|
||||
*
|
||||
* Upon construction, the simple viewer may create some additional Filament objects (such as
|
||||
* light sources) that it owns.
|
||||
*/
|
||||
SimpleViewer(filament::Engine* engine, filament::Scene* scene, filament::View* view,
|
||||
int sidebarWidth = DEFAULT_SIDEBAR_WIDTH);
|
||||
|
||||
/**
|
||||
* Destroys the SimpleViewer and any Filament entities that it owns.
|
||||
*/
|
||||
~SimpleViewer();
|
||||
|
||||
/**
|
||||
* Adds the asset's ready-to-render entities into the scene and optionally transforms the root
|
||||
* node to make it fit into a unit cube at the origin.
|
||||
*
|
||||
* The viewer does not claim ownership over the asset or its entities. Clients should use
|
||||
* AssetLoader and ResourceLoader to load an asset before passing it in.
|
||||
*
|
||||
* @param asset The asset to view.
|
||||
* @param scale Adds a transform to the root to fit the asset into a unit cube at the origin.
|
||||
* @param instanceToAnimate Optional instance from which to get the animator.
|
||||
*/
|
||||
void populateScene(FilamentAsset* asset, bool scale,
|
||||
FilamentInstance* instanceToAnimate = nullptr);
|
||||
|
||||
/**
|
||||
* Removes the current asset from the viewer.
|
||||
*
|
||||
* This removes all the asset entities from the Scene, but does not destroy them.
|
||||
*/
|
||||
void removeAsset();
|
||||
|
||||
/**
|
||||
* Sets or changes the current scene's IBL to allow the UI manipulate it.
|
||||
*/
|
||||
void setIndirectLight(filament::IndirectLight* ibl, filament::math::float3 const* sh3);
|
||||
|
||||
/**
|
||||
* Applies the currently-selected glTF animation to the transformation hierarchy and updates
|
||||
* the bone matrices on all renderables.
|
||||
*/
|
||||
void applyAnimation(double currentTime);
|
||||
|
||||
/**
|
||||
* Constructs ImGui controls for the current frame and responds to everything that the user has
|
||||
* changed since the previous frame.
|
||||
*
|
||||
* If desired this can be used in conjunction with the filagui library, which allows clients to
|
||||
* render ImGui controls with Filament.
|
||||
*/
|
||||
void updateUserInterface();
|
||||
|
||||
/**
|
||||
* Retrieves the current width of the ImGui "window" which we are using as a sidebar.
|
||||
* Clients can monitor this value to adjust the size of the view.
|
||||
*/
|
||||
int getSidebarWidth() const { return mSidebarWidth; }
|
||||
|
||||
/**
|
||||
* Allows clients to inject custom UI.
|
||||
*/
|
||||
void setUiCallback(std::function<void()> callback) { mCustomUI = callback; }
|
||||
|
||||
/**
|
||||
* Draws the bounding box of each renderable.
|
||||
* Defaults to false.
|
||||
*/
|
||||
void enableWireframe(bool b) { mEnableWireframe = b; }
|
||||
|
||||
/**
|
||||
* Enables a built-in light source (useful for creating shadows).
|
||||
* Defaults to true.
|
||||
*/
|
||||
void enableSunlight(bool b) { mEnableSunlight = b; }
|
||||
|
||||
/**
|
||||
* Enables dithering on the view.
|
||||
* Defaults to true.
|
||||
*/
|
||||
void enableDithering(bool b) { mEnableDithering = b; }
|
||||
|
||||
/**
|
||||
* Enables FXAA antialiasing in the post-process pipeline.
|
||||
* Defaults to true.
|
||||
*/
|
||||
void enableFxaa(bool b) { mEnableFxaa = b; }
|
||||
|
||||
/**
|
||||
* Enables hardware-based MSAA antialiasing.
|
||||
* Defaults to true.
|
||||
*/
|
||||
void enableMsaa(bool b) { mEnableMsaa = b; }
|
||||
|
||||
/**
|
||||
* Enables screen-space ambient occlusion in the post-process pipeline.
|
||||
* Defaults to true.
|
||||
*/
|
||||
void enableSSAO(bool b) { mSSAOOptions.enabled = b; }
|
||||
|
||||
/**
|
||||
* Enables Bloom.
|
||||
* Defaults to true.
|
||||
*/
|
||||
void enableBloom(bool bloom) {
|
||||
mBloomOptions.enabled = bloom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the intensity of the IBL.
|
||||
* See also filament::IndirectLight::setIntensity().
|
||||
* Defaults to 30000.0.
|
||||
*/
|
||||
void setIBLIntensity(float brightness) { mIblIntensity = brightness; }
|
||||
|
||||
private:
|
||||
void updateIndirectLight();
|
||||
|
||||
// Immutable properties set from the constructor.
|
||||
filament::Engine* const mEngine;
|
||||
filament::Scene* const mScene;
|
||||
filament::View* const mView;
|
||||
const utils::Entity mSunlight;
|
||||
|
||||
// Properties that can be changed from the application.
|
||||
FilamentAsset* mAsset = nullptr;
|
||||
Animator* mAnimator = nullptr;
|
||||
filament::IndirectLight* mIndirectLight = nullptr;
|
||||
std::function<void()> mCustomUI;
|
||||
|
||||
// Properties that can be changed from the UI.
|
||||
int mCurrentAnimation = 1;
|
||||
bool mResetAnimation = true;
|
||||
float mIblIntensity = 30000.0f;
|
||||
float mIblRotation = 0.0f;
|
||||
float mSunlightIntensity = 100000.0f; // <-- This value is overridden when loading an IBL.
|
||||
filament::math::float3 mSunlightColor = filament::Color::toLinear<filament::ACCURATE>({ 0.98, 0.92, 0.89});
|
||||
filament::math::float3 mSunlightDirection = {0.6, -1.0, -0.8};
|
||||
bool mEnableWireframe = false;
|
||||
bool mEnableSunlight = true;
|
||||
bool mEnableVsm = false;
|
||||
bool mEnableShadows = true;
|
||||
int mShadowCascades = 1;
|
||||
bool mEnableContactShadows = false;
|
||||
std::array<float, 3> mSplitPositions = {0.25f, 0.50f, 0.75f};
|
||||
bool mEnableDithering = true;
|
||||
bool mEnableFxaa = true;
|
||||
bool mEnableMsaa = true;
|
||||
filament::View::AmbientOcclusionOptions mSSAOOptions = { .enabled = true };
|
||||
filament::View::BloomOptions mBloomOptions = { .enabled = true };
|
||||
filament::View::FogOptions mFogOptions = {};
|
||||
filament::View::TemporalAntiAliasingOptions mTAAOptions = {};
|
||||
int mSidebarWidth;
|
||||
uint32_t mFlags;
|
||||
};
|
||||
|
||||
filament::math::mat4f fitIntoUnitCube(const filament::Aabb& bounds);
|
||||
|
||||
} // namespace viewer
|
||||
} // namespace filament
|
||||
|
||||
#endif // VIEWER_SIMPLEVIEWER_H
|
||||
834
libs/viewer/src/Settings.cpp
Normal file
834
libs/viewer/src/Settings.cpp
Normal file
@@ -0,0 +1,834 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by mIcable 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 <viewer/Settings.h>
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
// NOTE: We are including cgltf only to get JSMN. We should consider adding jsmn to third_party.
|
||||
#define CGLTF_IMPLEMENTATION
|
||||
#include <cgltf.h>
|
||||
|
||||
#define CHECK_TOKTYPE(tok_, type_) if ((tok_).type != (type_)) { return -1; }
|
||||
#define CHECK_KEY(tok_) if ((tok_).type != JSMN_STRING || (tok_).size == 0) { return -1; }
|
||||
#define STR(tok, jsonChunk) std::string(jsonChunk + tok.start, tok.end - tok.start)
|
||||
|
||||
using namespace utils;
|
||||
|
||||
namespace filament {
|
||||
namespace viewer {
|
||||
|
||||
// Compares a JSON string token against a C string.
|
||||
static int compare(jsmntok_t tok, const char* jsonChunk, const char* str) {
|
||||
size_t slen = strlen(str);
|
||||
size_t tlen = tok.end - tok.start;
|
||||
return (slen == tlen) ? strncmp(jsonChunk + tok.start, str, slen) : 128;
|
||||
}
|
||||
|
||||
// Skips over an unused token.
|
||||
static int parse(jsmntok_t const* tokens, int i) {
|
||||
int end = i + 1;
|
||||
while (i < end) {
|
||||
switch (tokens[i].type) {
|
||||
case JSMN_OBJECT:
|
||||
end += tokens[i].size * 2; break;
|
||||
case JSMN_ARRAY:
|
||||
end += tokens[i].size; break;
|
||||
case JSMN_PRIMITIVE:
|
||||
case JSMN_STRING:
|
||||
break;
|
||||
default: return -1;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, uint8_t* val) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
|
||||
*val = strtol(jsonChunk + tokens[i].start, nullptr, 10);
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, uint32_t* val) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
|
||||
*val = strtol(jsonChunk + tokens[i].start, nullptr, 10);
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, int* val) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
|
||||
*val = strtol(jsonChunk + tokens[i].start, nullptr, 10);
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, float* val) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
|
||||
*val = strtod(jsonChunk + tokens[i].start, nullptr);
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, float* vals, int size) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_ARRAY);
|
||||
if (tokens[i].size != size) {
|
||||
slog.w << "Expected " << size << " floats, got " << tokens[i].size << io::endl;
|
||||
return i + 1 + tokens[i].size;
|
||||
}
|
||||
++i;
|
||||
for (int j = 0; j < size; ++j) {
|
||||
i = parse(tokens, i, jsonChunk, &vals[j]);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, bool* val) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_PRIMITIVE);
|
||||
*val = 0 == compare(tokens[i], jsonChunk, "true");
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, math::float3* val) {
|
||||
float values[3];
|
||||
i = parse(tokens, i, jsonChunk, values, 3);
|
||||
*val = {values[0], values[1], values[2]};
|
||||
return i;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, math::float4* val) {
|
||||
float values[4];
|
||||
i = parse(tokens, i, jsonChunk, values, 4);
|
||||
*val = {values[0], values[1], values[2], values[3]};
|
||||
return i;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, AntiAliasing* out) {
|
||||
if (0 == compare(tokens[i], jsonChunk, "NONE")) { *out = AntiAliasing::NONE; }
|
||||
else if (0 == compare(tokens[i], jsonChunk, "FXAA")) { *out = AntiAliasing::FXAA; }
|
||||
else {
|
||||
slog.w << "Invalid AntiAliasing: '" << STR(tokens[i], jsonChunk) << "'" << io::endl;
|
||||
}
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
using BlendMode = BloomOptions::BlendMode;
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, BlendMode* out) {
|
||||
if (0 == compare(tokens[i], jsonChunk, "ADD")) { *out = BlendMode::ADD; }
|
||||
else if (0 == compare(tokens[i], jsonChunk, "INTERPOLATE")) { *out = BlendMode::INTERPOLATE; }
|
||||
else {
|
||||
slog.w << "Invalid BlendMode: '" << STR(tokens[i], jsonChunk) << "'" << io::endl;
|
||||
}
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
using VQL = filament::View::QualityLevel;
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, VQL* out) {
|
||||
if (0 == compare(tokens[i], jsonChunk, "LOW")) { *out = VQL::LOW; }
|
||||
else if (0 == compare(tokens[i], jsonChunk, "MEDIUM")) { *out = VQL::MEDIUM; }
|
||||
else if (0 == compare(tokens[i], jsonChunk, "HIGH")) { *out = VQL::HIGH; }
|
||||
else if (0 == compare(tokens[i], jsonChunk, "ULTRA")) { *out = VQL::ULTRA; }
|
||||
else {
|
||||
slog.w << "Invalid QualityLevel: '" << STR(tokens[i], jsonChunk) << "'" << io::endl;
|
||||
}
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
using CGQL = filament::ColorGrading::QualityLevel;
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, CGQL* out) {
|
||||
if (0 == compare(tokens[i], jsonChunk, "LOW")) { *out = CGQL::LOW; }
|
||||
else if (0 == compare(tokens[i], jsonChunk, "MEDIUM")) { *out = CGQL::MEDIUM; }
|
||||
else if (0 == compare(tokens[i], jsonChunk, "HIGH")) { *out = CGQL::HIGH; }
|
||||
else if (0 == compare(tokens[i], jsonChunk, "ULTRA")) { *out = CGQL::ULTRA; }
|
||||
else {
|
||||
slog.w << "Invalid QualityLevel: '" << STR(tokens[i], jsonChunk) << "'" << io::endl;
|
||||
}
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, ToneMapping* out) {
|
||||
if (0 == compare(tokens[i], jsonChunk, "LINEAR")) { *out = ToneMapping::LINEAR; }
|
||||
else if (0 == compare(tokens[i], jsonChunk, "ACES_LEGACY")) { *out = ToneMapping::ACES_LEGACY; }
|
||||
else if (0 == compare(tokens[i], jsonChunk, "ACES")) { *out = ToneMapping::ACES; }
|
||||
else if (0 == compare(tokens[i], jsonChunk, "FILMIC")) { *out = ToneMapping::FILMIC; }
|
||||
else if (0 == compare(tokens[i], jsonChunk, "UCHIMURA")) { *out = ToneMapping::UCHIMURA; }
|
||||
else if (0 == compare(tokens[i], jsonChunk, "REINHARD")) { *out = ToneMapping::REINHARD; }
|
||||
else if (0 == compare(tokens[i], jsonChunk, "DISPLAY_RANGE")) { *out = ToneMapping::DISPLAY_RANGE; }
|
||||
else {
|
||||
slog.w << "Invalid ToneMapping: '" << STR(tokens[i], jsonChunk) << "'" << io::endl;
|
||||
}
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, Dithering* out) {
|
||||
if (0 == compare(tokens[i], jsonChunk, "NONE")) { *out = Dithering::NONE; }
|
||||
else if (0 == compare(tokens[i], jsonChunk, "TEMPORAL")) { *out = Dithering::TEMPORAL; }
|
||||
else {
|
||||
slog.w << "Invalid Dithering: '" << STR(tokens[i], jsonChunk) << "'" << io::endl;
|
||||
}
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, ShadowType* out) {
|
||||
if (0 == compare(tokens[i], jsonChunk, "PCF")) { *out = ShadowType::PCF; }
|
||||
else if (0 == compare(tokens[i], jsonChunk, "VSM")) { *out = ShadowType::VSM; }
|
||||
else {
|
||||
slog.w << "Invalid ShadowType: '" << STR(tokens[i], jsonChunk) << "'" << io::endl;
|
||||
}
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk,
|
||||
TemporalAntiAliasingOptions* out) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
int size = tokens[i++].size;
|
||||
for (int j = 0; j < size; ++j) {
|
||||
const jsmntok_t tok = tokens[i];
|
||||
CHECK_KEY(tok);
|
||||
if (compare(tok, jsonChunk, "filterWidth") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->filterWidth);
|
||||
} else if (compare(tok, jsonChunk, "feedback") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->feedback);
|
||||
} else if (compare(tok, jsonChunk, "enabled") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->enabled);
|
||||
} else {
|
||||
slog.w << "Invalid taa key: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
i = parse(tokens, i + 1);
|
||||
}
|
||||
if (i < 0) {
|
||||
slog.e << "Invalid taa value: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, ColorGradingSettings* out) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
int size = tokens[i++].size;
|
||||
for (int j = 0; j < size; ++j) {
|
||||
const jsmntok_t tok = tokens[i];
|
||||
CHECK_KEY(tok);
|
||||
if (compare(tok, jsonChunk, "enabled") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->enabled);
|
||||
} else if (compare(tok, jsonChunk, "quality") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->quality);
|
||||
} else if (compare(tok, jsonChunk, "toneMapping") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->toneMapping);
|
||||
} else if (compare(tok, jsonChunk, "temperature") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->temperature);
|
||||
} else if (compare(tok, jsonChunk, "tint") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->tint);
|
||||
} else if (compare(tok, jsonChunk, "outRed") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->outRed);
|
||||
} else if (compare(tok, jsonChunk, "outGreen") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->outGreen);
|
||||
} else if (compare(tok, jsonChunk, "outBlue") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->outBlue);
|
||||
} else if (compare(tok, jsonChunk, "shadows") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->shadows);
|
||||
} else if (compare(tok, jsonChunk, "midtones") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->midtones);
|
||||
} else if (compare(tok, jsonChunk, "highlights") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->highlights);
|
||||
} else if (compare(tok, jsonChunk, "ranges") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->ranges);
|
||||
} else if (compare(tok, jsonChunk, "contrast") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->contrast);
|
||||
} else if (compare(tok, jsonChunk, "vibrance") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->vibrance);
|
||||
} else if (compare(tok, jsonChunk, "saturation") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->saturation);
|
||||
} else if (compare(tok, jsonChunk, "slope") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->slope);
|
||||
} else if (compare(tok, jsonChunk, "offset") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->offset);
|
||||
} else if (compare(tok, jsonChunk, "power") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->power);
|
||||
} else if (compare(tok, jsonChunk, "gamma") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->gamma);
|
||||
} else if (compare(tok, jsonChunk, "midPoint") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->midPoint);
|
||||
} else if (compare(tok, jsonChunk, "scale") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->scale);
|
||||
} else if (compare(tok, jsonChunk, "linkedCurves") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->linkedCurves);
|
||||
} else {
|
||||
slog.w << "Invalid color grading key: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
i = parse(tokens, i + 1);
|
||||
}
|
||||
if (i < 0) {
|
||||
slog.e << "Invalid color grading value: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk,
|
||||
AmbientOcclusionOptions* out) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
int size = tokens[i++].size;
|
||||
for (int j = 0; j < size; ++j) {
|
||||
const jsmntok_t tok = tokens[i];
|
||||
CHECK_KEY(tok);
|
||||
if (compare(tok, jsonChunk, "radius") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->radius);
|
||||
} else if (compare(tok, jsonChunk, "power") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->power);
|
||||
} else if (compare(tok, jsonChunk, "bias") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->bias);
|
||||
} else if (compare(tok, jsonChunk, "resolution") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->resolution);
|
||||
} else if (compare(tok, jsonChunk, "intensity") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->intensity);
|
||||
} else if (compare(tok, jsonChunk, "quality") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->quality);
|
||||
} else if (compare(tok, jsonChunk, "upsampling") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->upsampling);
|
||||
} else if (compare(tok, jsonChunk, "enabled") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->enabled);
|
||||
} else if (compare(tok, jsonChunk, "minHorizonAngleRad") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->minHorizonAngleRad);
|
||||
} else {
|
||||
slog.w << "Invalid AO key: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
i = parse(tokens, i + 1);
|
||||
}
|
||||
if (i < 0) {
|
||||
slog.e << "Invalid AO value: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, BloomOptions* out) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
int size = tokens[i++].size;
|
||||
for (int j = 0; j < size; ++j) {
|
||||
const jsmntok_t tok = tokens[i];
|
||||
CHECK_KEY(tok);
|
||||
if (compare(tok, jsonChunk, "strength") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->strength);
|
||||
} else if (compare(tok, jsonChunk, "resolution") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->resolution);
|
||||
} else if (compare(tok, jsonChunk, "anamorphism") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->anamorphism);
|
||||
} else if (compare(tok, jsonChunk, "levels") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->levels);
|
||||
} else if (compare(tok, jsonChunk, "blendMode") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->blendMode);
|
||||
} else if (compare(tok, jsonChunk, "threshold") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->threshold);
|
||||
} else if (compare(tok, jsonChunk, "enabled") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->enabled);
|
||||
} else if (compare(tok, jsonChunk, "highlight") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->highlight);
|
||||
} else {
|
||||
slog.w << "Invalid bloom options key: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
i = parse(tokens, i + 1);
|
||||
}
|
||||
if (i < 0) {
|
||||
slog.e << "Invalid bloom options value: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, FogOptions* out) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
int size = tokens[i++].size;
|
||||
for (int j = 0; j < size; ++j) {
|
||||
const jsmntok_t tok = tokens[i];
|
||||
CHECK_KEY(tok);
|
||||
if (0 == compare(tok, jsonChunk, "distance")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->distance);
|
||||
} else if (0 == compare(tok, jsonChunk, "maximumOpacity")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->maximumOpacity);
|
||||
} else if (0 == compare(tok, jsonChunk, "height")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->height);
|
||||
} else if (0 == compare(tok, jsonChunk, "heightFalloff")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->heightFalloff);
|
||||
} else if (0 == compare(tok, jsonChunk, "color")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->color);
|
||||
} else if (0 == compare(tok, jsonChunk, "density")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->density);
|
||||
} else if (0 == compare(tok, jsonChunk, "inScatteringStart")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->inScatteringStart);
|
||||
} else if (0 == compare(tok, jsonChunk, "inScatteringSize")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->inScatteringSize);
|
||||
} else if (0 == compare(tok, jsonChunk, "fogColorFromIbl")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->fogColorFromIbl);
|
||||
} else if (0 == compare(tok, jsonChunk, "enabled")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->enabled);
|
||||
} else {
|
||||
slog.w << "Invalid fog options key: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
i = parse(tokens, i + 1);
|
||||
}
|
||||
if (i < 0) {
|
||||
slog.e << "Invalid fog options value: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, DepthOfFieldOptions* out) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
int size = tokens[i++].size;
|
||||
for (int j = 0; j < size; ++j) {
|
||||
const jsmntok_t tok = tokens[i];
|
||||
CHECK_KEY(tok);
|
||||
if (0 == compare(tok, jsonChunk, "focusDistance")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->focusDistance);
|
||||
} else if (0 == compare(tok, jsonChunk, "cocScale")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->cocScale);
|
||||
} else if (0 == compare(tok, jsonChunk, "maxApertureDiameter")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->maxApertureDiameter);
|
||||
} else if (0 == compare(tok, jsonChunk, "enabled")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->enabled);
|
||||
} else {
|
||||
slog.w << "Invalid dof options key: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
i = parse(tokens, i + 1);
|
||||
}
|
||||
if (i < 0) {
|
||||
slog.e << "Invalid dof options value: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, VignetteOptions* out) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
int size = tokens[i++].size;
|
||||
for (int j = 0; j < size; ++j) {
|
||||
const jsmntok_t tok = tokens[i];
|
||||
CHECK_KEY(tok);
|
||||
if (0 == compare(tok, jsonChunk, "midPoint")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->midPoint);
|
||||
} else if (0 == compare(tok, jsonChunk, "roundness")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->roundness);
|
||||
} else if (0 == compare(tok, jsonChunk, "feather")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->feather);
|
||||
} else if (0 == compare(tok, jsonChunk, "color")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->color);
|
||||
} else if (0 == compare(tok, jsonChunk, "enabled")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->enabled);
|
||||
} else {
|
||||
slog.w << "Invalid vignette options key: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
i = parse(tokens, i + 1);
|
||||
}
|
||||
if (i < 0) {
|
||||
slog.e << "Invalid vignette options value: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, RenderQuality* out) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
int size = tokens[i++].size;
|
||||
for (int j = 0; j < size; ++j) {
|
||||
const jsmntok_t tok = tokens[i];
|
||||
CHECK_KEY(tok);
|
||||
if (0 == compare(tok, jsonChunk, "hdrColorBuffer")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->hdrColorBuffer);
|
||||
} else {
|
||||
slog.w << "Invalid render quality key: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
i = parse(tokens, i + 1);
|
||||
}
|
||||
if (i < 0) {
|
||||
slog.e << "Invalid render quality value: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk,
|
||||
DynamicLightingSettings* out) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
int size = tokens[i++].size;
|
||||
for (int j = 0; j < size; ++j) {
|
||||
const jsmntok_t tok = tokens[i];
|
||||
CHECK_KEY(tok);
|
||||
if (0 == compare(tok, jsonChunk, "zLightNear")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->zLightNear);
|
||||
} else if (0 == compare(tok, jsonChunk, "zLightFar")) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->zLightFar);
|
||||
} else {
|
||||
slog.w << "Invalid dynamic lighting key: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
i = parse(tokens, i + 1);
|
||||
}
|
||||
if (i < 0) {
|
||||
slog.e << "Invalid dynamic lighting value: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, ViewSettings* out) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
int size = tokens[i++].size;
|
||||
for (int j = 0; j < size; ++j) {
|
||||
const jsmntok_t tok = tokens[i];
|
||||
CHECK_KEY(tok);
|
||||
if (compare(tok, jsonChunk, "sampleCount") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->sampleCount);
|
||||
} else if (compare(tok, jsonChunk, "antiAliasing") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->antiAliasing);
|
||||
} else if (compare(tok, jsonChunk, "taa") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->taa);
|
||||
} else if (compare(tok, jsonChunk, "colorGrading") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->colorGrading);
|
||||
} else if (compare(tok, jsonChunk, "ssao") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->ssao);
|
||||
} else if (compare(tok, jsonChunk, "bloom") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->bloom);
|
||||
} else if (compare(tok, jsonChunk, "fog") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->fog);
|
||||
} else if (compare(tok, jsonChunk, "dof") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->dof);
|
||||
} else if (compare(tok, jsonChunk, "vignette") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->vignette);
|
||||
} else if (compare(tok, jsonChunk, "dithering") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->dithering);
|
||||
} else if (compare(tok, jsonChunk, "renderQuality") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->renderQuality);
|
||||
} else if (compare(tok, jsonChunk, "dynamicLighting") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->dynamicLighting);
|
||||
} else if (compare(tok, jsonChunk, "shadowType") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->shadowType);
|
||||
} else if (compare(tok, jsonChunk, "postProcessingEnabled") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->postProcessingEnabled);
|
||||
} else {
|
||||
slog.w << "Invalid view setting key: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
i = parse(tokens, i + 1);
|
||||
}
|
||||
if (i < 0) {
|
||||
slog.e << "Invalid view setting value: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int parse(jsmntok_t const* tokens, int i, const char* jsonChunk, Settings* out) {
|
||||
CHECK_TOKTYPE(tokens[i], JSMN_OBJECT);
|
||||
int size = tokens[i++].size;
|
||||
for (int j = 0; j < size; ++j) {
|
||||
const jsmntok_t tok = tokens[i];
|
||||
CHECK_KEY(tok);
|
||||
if (compare(tok, jsonChunk, "view") == 0) {
|
||||
i = parse(tokens, i + 1, jsonChunk, &out->view);
|
||||
} else {
|
||||
slog.w << "Invalid group key: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
i = parse(tokens, i + 1);
|
||||
}
|
||||
if (i < 0) {
|
||||
slog.e << "Invalid group value: '" << STR(tok, jsonChunk) << "'" << io::endl;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
bool readJson(const char* jsonChunk, size_t size, Settings* out) {
|
||||
jsmn_parser parser = { 0, 0, 0 };
|
||||
|
||||
int tokenCount = jsmn_parse(&parser, jsonChunk, size, nullptr, 0);
|
||||
if (tokenCount <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
jsmntok_t* tokens = (jsmntok_t*) malloc(sizeof(jsmntok_t) * tokenCount);
|
||||
assert(tokens);
|
||||
|
||||
jsmn_init(&parser);
|
||||
tokenCount = jsmn_parse(&parser, jsonChunk, size, tokens, tokenCount);
|
||||
|
||||
if (tokenCount <= 0) {
|
||||
free(tokens);
|
||||
return false;
|
||||
}
|
||||
|
||||
int i = parse(tokens, 0, jsonChunk, out);
|
||||
free(tokens);
|
||||
return i >= 0;
|
||||
}
|
||||
|
||||
static std::string writeJson(bool v) { return v ? "true" : "false"; }
|
||||
static std::string writeJson(float v) { return std::to_string(v); }
|
||||
static std::string writeJson(int v) { return std::to_string(v); }
|
||||
static std::string writeJson(uint32_t v) { return std::to_string(v); }
|
||||
static std::string writeJson(uint8_t v) { return std::to_string((int)v); }
|
||||
|
||||
static const char* writeJson(AntiAliasing in) {
|
||||
switch (in) {
|
||||
case AntiAliasing::NONE: return "NONE";
|
||||
case AntiAliasing::FXAA: return "FXAA";
|
||||
}
|
||||
return "INVALID";
|
||||
}
|
||||
|
||||
static const char* writeJson(Dithering in) {
|
||||
switch (in) {
|
||||
case Dithering::NONE: return "NONE";
|
||||
case Dithering::TEMPORAL: return "TEMPORAL";
|
||||
}
|
||||
return "INVALID";
|
||||
}
|
||||
|
||||
static const char* writeJson(ShadowType in) {
|
||||
switch (in) {
|
||||
case ShadowType::PCF: return "PCF";
|
||||
case ShadowType::VSM: return "VSM";
|
||||
}
|
||||
return "INVALID";
|
||||
}
|
||||
|
||||
static const char* writeJson(BlendMode in) {
|
||||
switch (in) {
|
||||
case BlendMode::ADD: return "ADD";
|
||||
case BlendMode::INTERPOLATE: return "INTERPOLATE";
|
||||
}
|
||||
return "INVALID";
|
||||
}
|
||||
|
||||
static const char* writeJson(VQL in) {
|
||||
switch (in) {
|
||||
case VQL::LOW: return "LOW";
|
||||
case VQL::MEDIUM: return "MEDIUM";
|
||||
case VQL::HIGH: return "HIGH";
|
||||
case VQL::ULTRA: return "ULTRA";
|
||||
}
|
||||
return "INVALID";
|
||||
}
|
||||
|
||||
static const char* writeJson(CGQL in) {
|
||||
switch (in) {
|
||||
case CGQL::LOW: return "LOW";
|
||||
case CGQL::MEDIUM: return "MEDIUM";
|
||||
case CGQL::HIGH: return "HIGH";
|
||||
case CGQL::ULTRA: return "ULTRA";
|
||||
}
|
||||
return "INVALID";
|
||||
}
|
||||
|
||||
static const char* writeJson(ToneMapping in) {
|
||||
switch (in) {
|
||||
case ToneMapping::LINEAR: return "LINEAR";
|
||||
case ToneMapping::ACES_LEGACY: return "ACES_LEGACY";
|
||||
case ToneMapping::ACES: return "ACES";
|
||||
case ToneMapping::FILMIC: return "FILMIC";
|
||||
case ToneMapping::UCHIMURA: return "UCHIMURA";
|
||||
case ToneMapping::REINHARD: return "REINHARD";
|
||||
case ToneMapping::DISPLAY_RANGE: return "DISPLAY_RANGE";
|
||||
}
|
||||
return "INVALID";
|
||||
}
|
||||
|
||||
static std::string writeJson(const float* v, int count) {
|
||||
std::ostringstream oss;
|
||||
oss << "[";
|
||||
for (int i = 0; i < count; i++) {
|
||||
oss << v;
|
||||
if (i < count - 1) {
|
||||
oss << ", ";
|
||||
}
|
||||
}
|
||||
oss << "]";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
static std::string writeJson(math::float3 v) {
|
||||
return writeJson(&v.x, 3);
|
||||
}
|
||||
|
||||
static std::string writeJson(math::float4 v) {
|
||||
return writeJson(&v.x, 4);
|
||||
}
|
||||
|
||||
std::string writeJson(const Settings& in) {
|
||||
std::ostringstream oss;
|
||||
oss << "{\n"
|
||||
<< "\"view\": "
|
||||
<< writeJson(in.view)
|
||||
<< "}";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string writeJson(const TemporalAntiAliasingOptions& in) {
|
||||
std::ostringstream oss;
|
||||
oss << "{\n"
|
||||
<< "\"filterWidth\": " << writeJson(in.filterWidth) << ",\n"
|
||||
<< "\"feedback\": " << writeJson(in.feedback) << ",\n"
|
||||
<< "\"enabled\": " << writeJson(in.enabled) << "\n"
|
||||
<< "}";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string writeJson(const ColorGradingSettings& in) {
|
||||
std::ostringstream oss;
|
||||
oss << "{\n"
|
||||
<< "\"enabled\": " << writeJson(in.enabled) << ",\n"
|
||||
<< "\"quality\": " << writeJson(in.quality) << ",\n"
|
||||
<< "\"toneMapping\": " << writeJson(in.toneMapping) << ",\n"
|
||||
<< "\"temperature\": " << writeJson(in.temperature) << ",\n"
|
||||
<< "\"tint\": " << writeJson(in.tint) << ",\n"
|
||||
<< "\"outRed\": " << writeJson(in.outRed) << ",\n"
|
||||
<< "\"outGreen\": " << writeJson(in.outGreen) << ",\n"
|
||||
<< "\"outBlue\": " << writeJson(in.outBlue) << ",\n"
|
||||
<< "\"shadows\": " << writeJson(in.shadows) << ",\n"
|
||||
<< "\"midtones\": " << writeJson(in.midtones) << ",\n"
|
||||
<< "\"highlights\": " << writeJson(in.highlights) << ",\n"
|
||||
<< "\"ranges\": " << writeJson(in.ranges) << ",\n"
|
||||
<< "\"contrast\": " << writeJson(in.contrast) << ",\n"
|
||||
<< "\"vibrance\": " << writeJson(in.vibrance) << ",\n"
|
||||
<< "\"saturation\": " << writeJson(in.saturation) << ",\n"
|
||||
<< "\"slope\": " << writeJson(in.slope) << ",\n"
|
||||
<< "\"offset\": " << writeJson(in.offset) << ",\n"
|
||||
<< "\"power\": " << writeJson(in.power) << ",\n"
|
||||
<< "\"gamma\": " << writeJson(in.gamma) << ",\n"
|
||||
<< "\"midPoint\": " << writeJson(in.midPoint) << ",\n"
|
||||
<< "\"scale\": " << writeJson(in.scale) << ",\n"
|
||||
<< "\"linkedCurves\": " << writeJson(in.linkedCurves) << "\n"
|
||||
<< "}";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string writeJson(const AmbientOcclusionOptions& in) {
|
||||
std::ostringstream oss;
|
||||
oss << "{\n"
|
||||
<< "\"radius\": " << writeJson(in.radius) << ",\n"
|
||||
<< "\"power\": " << writeJson(in.power) << ",\n"
|
||||
<< "\"bias\": " << writeJson(in.bias) << ",\n"
|
||||
<< "\"resolution\": " << writeJson(in.resolution) << ",\n"
|
||||
<< "\"intensity\": " << writeJson(in.intensity) << ",\n"
|
||||
<< "\"quality\": " << writeJson(in.quality) << ",\n"
|
||||
<< "\"upsampling\": " << writeJson(in.upsampling) << ",\n"
|
||||
<< "\"enabled\": " << writeJson(in.enabled) << ",\n"
|
||||
<< "\"minHorizonAngleRad\": " << writeJson(in.minHorizonAngleRad) << "\n"
|
||||
<< "}";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string writeJson(const BloomOptions& in) {
|
||||
std::ostringstream oss;
|
||||
oss << "{\n"
|
||||
<< "\"strength\": " << writeJson(in.strength) << ",\n"
|
||||
<< "\"resolution\": " << writeJson(in.resolution) << ",\n"
|
||||
<< "\"anamorphism\": " << writeJson(in.anamorphism) << ",\n"
|
||||
<< "\"levels\": " << writeJson(in.levels) << ",\n"
|
||||
<< "\"blendMode\": " << writeJson(in.blendMode) << ",\n"
|
||||
<< "\"threshold\": " << writeJson(in.threshold) << ",\n"
|
||||
<< "\"enabled\": " << writeJson(in.enabled) << ",\n"
|
||||
<< "\"highlight\": " << writeJson(in.highlight) << "\n"
|
||||
<< "}";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string writeJson(const FogOptions& in) {
|
||||
std::ostringstream oss;
|
||||
oss << "{\n"
|
||||
<< "\"distance\": " << writeJson(in.distance) << ",\n"
|
||||
<< "\"maximumOpacity\": " << writeJson(in.maximumOpacity) << ",\n"
|
||||
<< "\"height\": " << writeJson(in.height) << ",\n"
|
||||
<< "\"heightFalloff\": " << writeJson(in.heightFalloff) << ",\n"
|
||||
<< "\"color\": " << writeJson(in.color) << ",\n"
|
||||
<< "\"density\": " << writeJson(in.density) << ",\n"
|
||||
<< "\"inScatteringStart\": " << writeJson(in.inScatteringStart) << ",\n"
|
||||
<< "\"inScatteringSize\": " << writeJson(in.inScatteringSize) << ",\n"
|
||||
<< "\"fogColorFromIbl\": " << writeJson(in.fogColorFromIbl) << ",\n"
|
||||
<< "\"enabled\": " << writeJson(in.enabled) << "\n"
|
||||
<< "}";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string writeJson(const DepthOfFieldOptions& in) {
|
||||
std::ostringstream oss;
|
||||
oss << "{\n"
|
||||
<< "\"focusDistance\": " << writeJson(in.focusDistance) << ",\n"
|
||||
<< "\"cocScale\": " << writeJson(in.cocScale) << ",\n"
|
||||
<< "\"maxApertureDiameter\": " << writeJson(in.maxApertureDiameter) << ",\n"
|
||||
<< "\"enabled\": " << writeJson(in.enabled) << "\n"
|
||||
<< "}";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string writeJson(const VignetteOptions& in) {
|
||||
std::ostringstream oss;
|
||||
oss << "{\n"
|
||||
<< "\"midPoint\": " << writeJson(in.midPoint) << ",\n"
|
||||
<< "\"roundness\": " << writeJson(in.roundness) << ",\n"
|
||||
<< "\"feather\": " << writeJson(in.feather) << ",\n"
|
||||
<< "\"color\": " << writeJson(in.color) << ",\n"
|
||||
<< "\"enabled\": " << writeJson(in.enabled) << "\n"
|
||||
<< "}";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string writeJson(const RenderQuality& in) {
|
||||
std::ostringstream oss;
|
||||
oss << "{\n"
|
||||
<< "\"hdrColorBuffer\": " << writeJson(in.hdrColorBuffer) << "\n"
|
||||
<< "}";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string writeJson(const DynamicLightingSettings& in) {
|
||||
std::ostringstream oss;
|
||||
oss << "{\n"
|
||||
<< "\"zLightNear\": " << writeJson(in.zLightNear) << ",\n"
|
||||
<< "\"zLightFar\": " << writeJson(in.zLightFar) << "\n"
|
||||
<< "}";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string writeJson(const ViewSettings& in) {
|
||||
std::ostringstream oss;
|
||||
oss << "{\n"
|
||||
<< "\"sampleCount\": " << writeJson(in.sampleCount) << ",\n"
|
||||
<< "\"antiAliasing\": " << writeJson(in.antiAliasing) << ",\n"
|
||||
<< "\"taa\": " << writeJson(in.taa) << ",\n"
|
||||
<< "\"colorGrading\": " << writeJson(in.colorGrading) << ",\n"
|
||||
<< "\"ssao\": " << writeJson(in.ssao) << ",\n"
|
||||
<< "\"bloom\": " << writeJson(in.bloom) << ",\n"
|
||||
<< "\"fog\": " << writeJson(in.fog) << ",\n"
|
||||
<< "\"dof\": " << writeJson(in.dof) << ",\n"
|
||||
<< "\"vignette\": " << writeJson(in.vignette) << ",\n"
|
||||
<< "\"dithering\": " << writeJson(in.dithering) << ",\n"
|
||||
<< "\"renderQuality\": " << writeJson(in.renderQuality) << ",\n"
|
||||
<< "\"dynamicLighting\": " << writeJson(in.dynamicLighting) << ",\n"
|
||||
<< "\"shadowType\": " << writeJson(in.shadowType) << ",\n"
|
||||
<< "\"postProcessingEnabled\": " << writeJson(in.postProcessingEnabled) << "\n"
|
||||
<< "}";
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
|
||||
} // namespace viewer
|
||||
} // namespace filament
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,209 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef GLTFIO_SIMPLEVIEWER_H
|
||||
#define GLTFIO_SIMPLEVIEWER_H
|
||||
|
||||
// NOTE: This is an optional header-only utility to avoid a hard dependency on imgui. To use
|
||||
// SimpleViewer, please add:
|
||||
//
|
||||
// #define GLTFIO_SIMPLEVIEWER_IMPLEMENTATION
|
||||
//
|
||||
// to one of your CPP source files to create the implementation. See gltf_viewer.cpp for an example.
|
||||
|
||||
#include <filament/Box.h>
|
||||
#include <filament/DebugRegistry.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/IndirectLight.h>
|
||||
#include <filament/Scene.h>
|
||||
#include <filament/View.h>
|
||||
|
||||
#include <gltfio/Animator.h>
|
||||
#include <gltfio/FilamentAsset.h>
|
||||
|
||||
#include <utils/Entity.h>
|
||||
|
||||
#include <math/vec3.h>
|
||||
|
||||
namespace gltfio {
|
||||
|
||||
/**
|
||||
* \class SimpleViewer SimpleViewer.h gltfio/SimpleViewer.h
|
||||
* \brief Manages the state for a simple glTF viewer with imgui controls and a tree view.
|
||||
*
|
||||
* This is a utility that can be used across multiple platforms, including web.
|
||||
*
|
||||
* \note If you don't need ImGui controls, there is no need to use this class, just use AssetLoader
|
||||
* instead.
|
||||
*/
|
||||
class SimpleViewer {
|
||||
public:
|
||||
|
||||
static constexpr int DEFAULT_SIDEBAR_WIDTH = 350;
|
||||
|
||||
/**
|
||||
* Constructs a SimpleViewer that has a fixed association with the given Filament objects.
|
||||
*
|
||||
* Upon construction, the simple viewer may create some additional Filament objects (such as
|
||||
* light sources) that it owns.
|
||||
*/
|
||||
SimpleViewer(filament::Engine* engine, filament::Scene* scene, filament::View* view,
|
||||
int sidebarWidth = DEFAULT_SIDEBAR_WIDTH);
|
||||
|
||||
/**
|
||||
* Destroys the SimpleViewer and any Filament entities that it owns.
|
||||
*/
|
||||
~SimpleViewer();
|
||||
|
||||
/**
|
||||
* Adds the asset's ready-to-render entities into the scene and optionally transforms the root
|
||||
* node to make it fit into a unit cube at the origin.
|
||||
*
|
||||
* The viewer does not claim ownership over the asset or its entities. Clients should use
|
||||
* AssetLoader and ResourceLoader to load an asset before passing it in.
|
||||
*
|
||||
* @param asset The asset to view.
|
||||
* @param scale Adds a transform to the root to fit the asset into a unit cube at the origin.
|
||||
* @param instanceToAnimate Optional instance from which to get the animator.
|
||||
*/
|
||||
void populateScene(FilamentAsset* asset, bool scale,
|
||||
FilamentInstance* instanceToAnimate = nullptr);
|
||||
|
||||
/**
|
||||
* Removes the current asset from the viewer.
|
||||
*
|
||||
* This removes all the asset entities from the Scene, but does not destroy them.
|
||||
*/
|
||||
void removeAsset();
|
||||
|
||||
/**
|
||||
* Sets or changes the current scene's IBL to allow the UI manipulate it.
|
||||
*/
|
||||
void setIndirectLight(filament::IndirectLight* ibl, filament::math::float3 const* sh3);
|
||||
|
||||
/**
|
||||
* Applies the currently-selected glTF animation to the transformation hierarchy and updates
|
||||
* the bone matrices on all renderables.
|
||||
*/
|
||||
void applyAnimation(double currentTime);
|
||||
|
||||
/**
|
||||
* Constructs ImGui controls for the current frame and responds to everything that the user has
|
||||
* changed since the previous frame.
|
||||
*
|
||||
* If desired this can be used in conjunction with the filagui library, which allows clients to
|
||||
* render ImGui controls with Filament.
|
||||
*/
|
||||
void updateUserInterface();
|
||||
|
||||
/**
|
||||
* Retrieves the current width of the ImGui "window" which we are using as a sidebar.
|
||||
* Clients can monitor this value to adjust the size of the view.
|
||||
*/
|
||||
int getSidebarWidth() const { return mSidebarWidth; }
|
||||
|
||||
/**
|
||||
* Allows clients to inject custom UI.
|
||||
*/
|
||||
void setUiCallback(std::function<void()> callback) { mCustomUI = callback; }
|
||||
|
||||
/**
|
||||
* Draws the bounding box of each renderable.
|
||||
* Defaults to false.
|
||||
*/
|
||||
void enableWireframe(bool b) { mEnableWireframe = b; }
|
||||
|
||||
/**
|
||||
* Enables a built-in light source (useful for creating shadows).
|
||||
* Defaults to true.
|
||||
*/
|
||||
void enableSunlight(bool b) { mEnableSunlight = b; }
|
||||
|
||||
/**
|
||||
* Enables dithering on the view.
|
||||
* Defaults to true.
|
||||
*/
|
||||
void enableDithering(bool b) { mEnableDithering = b; }
|
||||
|
||||
/**
|
||||
* Enables FXAA antialiasing in the post-process pipeline.
|
||||
* Defaults to true.
|
||||
*/
|
||||
void enableFxaa(bool b) { mEnableFxaa = b; }
|
||||
|
||||
/**
|
||||
* Enables hardware-based MSAA antialiasing.
|
||||
* Defaults to true.
|
||||
*/
|
||||
void enableMsaa(bool b) { mEnableMsaa = b; }
|
||||
|
||||
/**
|
||||
* Enables screen-space ambient occlusion in the post-process pipeline.
|
||||
* Defaults to true.
|
||||
*/
|
||||
void enableSSAO(bool b) { mSSAOOptions.enabled = b; }
|
||||
|
||||
/**
|
||||
* Enables Bloom.
|
||||
* Defaults to true.
|
||||
*/
|
||||
void enableBloom(bool bloom) {
|
||||
mBloomOptions.enabled = bloom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the intensity of the IBL.
|
||||
* See also filament::IndirectLight::setIntensity().
|
||||
* Defaults to 30000.0.
|
||||
*/
|
||||
void setIBLIntensity(float brightness) { mIblIntensity = brightness; }
|
||||
|
||||
private:
|
||||
void updateIndirectLight();
|
||||
|
||||
// Immutable properties set from the constructor.
|
||||
filament::Engine* const mEngine;
|
||||
filament::Scene* const mScene;
|
||||
filament::View* const mView;
|
||||
const utils::Entity mSunlight;
|
||||
|
||||
// Properties that can be changed from the application.
|
||||
FilamentAsset* mAsset = nullptr;
|
||||
Animator* mAnimator = nullptr;
|
||||
filament::IndirectLight* mIndirectLight = nullptr;
|
||||
std::function<void()> mCustomUI;
|
||||
|
||||
// Properties that can be changed from the UI.
|
||||
int mCurrentAnimation = 1;
|
||||
bool mResetAnimation = true;
|
||||
float mIblIntensity = 30000.0f;
|
||||
float mIblRotation = 0.0f;
|
||||
float mSunlightIntensity = 100000.0f; // <-- This value is overridden when loading an IBL.
|
||||
filament::math::float3 mSunlightColor = filament::Color::toLinear<filament::ACCURATE>({ 0.98, 0.92, 0.89});
|
||||
filament::math::float3 mSunlightDirection = {0.6, -1.0, -0.8};
|
||||
bool mEnableWireframe = false;
|
||||
bool mEnableSunlight = true;
|
||||
bool mEnableVsm = false;
|
||||
bool mEnableShadows = true;
|
||||
int mShadowCascades = 1;
|
||||
bool mEnableContactShadows = false;
|
||||
std::array<float, 3> mSplitPositions = {0.25f, 0.50f, 0.75f};
|
||||
bool mEnableDithering = true;
|
||||
bool mEnableFxaa = true;
|
||||
bool mEnableMsaa = true;
|
||||
filament::View::AmbientOcclusionOptions mSSAOOptions = { .enabled = true };
|
||||
filament::View::BloomOptions mBloomOptions = { .enabled = true };
|
||||
filament::View::FogOptions mFogOptions = {};
|
||||
filament::View::TemporalAntiAliasingOptions mTAAOptions = {};
|
||||
int mSidebarWidth;
|
||||
uint32_t mFlags;
|
||||
};
|
||||
|
||||
filament::math::mat4f fitIntoUnitCube(const filament::Aabb& bounds);
|
||||
|
||||
} // namespace gltfio
|
||||
|
||||
#ifdef GLTFIO_SIMPLEVIEWER_IMPLEMENTATION
|
||||
#include <viewer/SimpleViewer.h>
|
||||
|
||||
#include <filament/RenderableManager.h>
|
||||
#include <filament/TransformManager.h>
|
||||
@@ -231,9 +29,11 @@ filament::math::mat4f fitIntoUnitCube(const filament::Aabb& bounds);
|
||||
#include <imgui.h>
|
||||
#include <filagui/ImGuiExtensions.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace gltfio {
|
||||
namespace filament {
|
||||
namespace viewer {
|
||||
|
||||
filament::math::mat4f fitIntoUnitCube(const filament::Aabb& bounds) {
|
||||
using namespace filament::math;
|
||||
@@ -603,8 +403,5 @@ void SimpleViewer::updateUserInterface() {
|
||||
updateIndirectLight();
|
||||
}
|
||||
|
||||
} // namespace gltfio
|
||||
|
||||
#endif // GLTFIO_SIMPLEVIEWER_IMPLEMENTATION
|
||||
|
||||
#endif // GLTFIO_SIMPLEVIEWER_H
|
||||
} // namespace viewer
|
||||
} // namespace filament
|
||||
136
libs/viewer/tests/test_settings.cpp
Normal file
136
libs/viewer/tests/test_settings.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <viewer/Settings.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace filament::viewer;
|
||||
|
||||
class ViewSettingsTest : public testing::Test {};
|
||||
|
||||
static const char* JSON_TEST_DEFAULTS = R"TXT(
|
||||
{
|
||||
"view": {
|
||||
"sampleCount": 1,
|
||||
"antiAliasing": "FXAA",
|
||||
"taa": {
|
||||
"enabled": false,
|
||||
"filterWidth": 1.0,
|
||||
"feedback": 0.04
|
||||
},
|
||||
"colorGrading": {
|
||||
"enabled": true,
|
||||
"quality": "MEDIUM",
|
||||
"toneMapping": "ACES_LEGACY",
|
||||
"temperature": 0,
|
||||
"tint": 0,
|
||||
"outRed": [1.0, 0.0, 0.0],
|
||||
"outGreen": [0.0, 1.0, 0.0],
|
||||
"outBlue": [0.0, 0.0, 1.0],
|
||||
"shadows": [1.0, 1.0, 1.0, 0.0],
|
||||
"midtones": [1.0, 1.0, 1.0, 0.0],
|
||||
"highlights": [1.0, 1.0, 1.0, 0.0],
|
||||
"ranges": [0.0, 0.333, 0.550, 1.0],
|
||||
"contrast": 1.0,
|
||||
"vibrance": 1.0,
|
||||
"saturation": 1.0,
|
||||
"slope": [1.0, 1.0, 1.0],
|
||||
"offset": [0.0, 0.0, 0.0],
|
||||
"power": [1.0, 1.0, 1.0],
|
||||
"gamma": [1.0, 1.0, 1.0],
|
||||
"midPoint": [1.0, 1.0, 1.0],
|
||||
"scale": [1.0, 1.0, 1.0],
|
||||
"linkedCurves": false
|
||||
},
|
||||
"ssao": {
|
||||
"enabled": false,
|
||||
"radius": 0.3,
|
||||
"power": 1.0,
|
||||
"bias": 0.0005,
|
||||
"resolution": 0.5,
|
||||
"intensity": 1.0,
|
||||
"quality": "LOW",
|
||||
"upsampling": "LOW",
|
||||
"minHorizonAngleRad": 0.0
|
||||
},
|
||||
"bloom": {
|
||||
"enabled": false,
|
||||
"strength": 0.10,
|
||||
"resolution": 360,
|
||||
"anamorphism": 1.0,
|
||||
"levels": 6,
|
||||
"blendMode": "ADD",
|
||||
"threshold": true,
|
||||
"highlight": 1000.0
|
||||
},
|
||||
"fog": {
|
||||
"enabled": false,
|
||||
"distance": 0.0,
|
||||
"maximumOpacity": 1.0,
|
||||
"height": 0.0,
|
||||
"heightFalloff": 1.0,
|
||||
"color": [0.5, 0.5, 0.5],
|
||||
"density": 0.1,
|
||||
"inScatteringStart": 0.0,
|
||||
"inScatteringSize": -1.0,
|
||||
"fogColorFromIbl": false
|
||||
},
|
||||
"dof": {
|
||||
"enabled": false,
|
||||
"focusDistance": 10.0,
|
||||
"cocScale": 1.0,
|
||||
"maxApertureDiameter": 0.01
|
||||
},
|
||||
"vignette": {
|
||||
"enabled": false,
|
||||
"midPoint": 0.5,
|
||||
"roundness": 0.5,
|
||||
"feather": 0.5,
|
||||
"color": [0, 0, 0, 1]
|
||||
},
|
||||
"dithering": "TEMPORAL",
|
||||
"renderQuality": {
|
||||
"hdrColorBuffer": "HIGH"
|
||||
},
|
||||
"dynamicLighting": {
|
||||
"zLightNear": 5,
|
||||
"zLightFar": 100,
|
||||
},
|
||||
"shadowType": "PCF",
|
||||
"postProcessingEnabled": true
|
||||
}
|
||||
}
|
||||
)TXT";
|
||||
|
||||
TEST_F(ViewSettingsTest, JsonTestDefaults) {
|
||||
Settings settings1 = {0};
|
||||
ASSERT_TRUE(readJson(JSON_TEST_DEFAULTS, strlen(JSON_TEST_DEFAULTS), &settings1));
|
||||
|
||||
ASSERT_TRUE(settings1.view.bloom.threshold);
|
||||
|
||||
Settings settings2;
|
||||
ASSERT_TRUE(readJson("{}", strlen("{}"), &settings2));
|
||||
ASSERT_EQ(writeJson(settings1), writeJson(settings2));
|
||||
|
||||
Settings settings3;
|
||||
ASSERT_EQ(writeJson(settings1), writeJson(settings3));
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -240,8 +240,8 @@ if (NOT ANDROID)
|
||||
|
||||
# Sample app specific
|
||||
target_link_libraries(frame_generator PRIVATE imageio)
|
||||
target_link_libraries(gltf_viewer PRIVATE gltf-resources gltfio)
|
||||
target_link_libraries(gltf_instances PRIVATE gltf-resources gltfio)
|
||||
target_link_libraries(gltf_viewer PRIVATE gltf-resources gltfio viewer)
|
||||
target_link_libraries(gltf_instances PRIVATE gltf-resources gltfio viewer)
|
||||
target_link_libraries(hellopbr PRIVATE filameshio suzanne-resources)
|
||||
target_link_libraries(sample_cloth PRIVATE filameshio)
|
||||
target_link_libraries(sample_normal_map PRIVATE filameshio)
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define GLTFIO_SIMPLEVIEWER_IMPLEMENTATION
|
||||
|
||||
#include <filamentapp/Config.h>
|
||||
#include <filamentapp/FilamentApp.h>
|
||||
#include <filamentapp/IBL.h>
|
||||
@@ -23,12 +21,14 @@
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/Scene.h>
|
||||
#include <filament/Skybox.h>
|
||||
#include <filament/TransformManager.h>
|
||||
#include <filament/View.h>
|
||||
|
||||
#include <gltfio/AssetLoader.h>
|
||||
#include <gltfio/FilamentAsset.h>
|
||||
#include <gltfio/ResourceLoader.h>
|
||||
#include <gltfio/SimpleViewer.h>
|
||||
|
||||
#include <viewer/SimpleViewer.h>
|
||||
|
||||
#include <camutils/Manipulator.h>
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::math;
|
||||
using namespace filament::viewer;
|
||||
|
||||
using namespace gltfio;
|
||||
using namespace utils;
|
||||
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define GLTFIO_SIMPLEVIEWER_IMPLEMENTATION
|
||||
|
||||
#include <filamentapp/Config.h>
|
||||
#include <filamentapp/FilamentApp.h>
|
||||
#include <filamentapp/IBL.h>
|
||||
@@ -24,8 +22,10 @@
|
||||
#include <filament/ColorGrading.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/IndexBuffer.h>
|
||||
#include <filament/RenderableManager.h>
|
||||
#include <filament/Scene.h>
|
||||
#include <filament/Skybox.h>
|
||||
#include <filament/TransformManager.h>
|
||||
#include <filament/VertexBuffer.h>
|
||||
#include <filament/View.h>
|
||||
#include <filament/Renderer.h>
|
||||
@@ -33,7 +33,8 @@
|
||||
#include <gltfio/AssetLoader.h>
|
||||
#include <gltfio/FilamentAsset.h>
|
||||
#include <gltfio/ResourceLoader.h>
|
||||
#include <gltfio/SimpleViewer.h>
|
||||
|
||||
#include <viewer/SimpleViewer.h>
|
||||
|
||||
#include <camutils/Manipulator.h>
|
||||
|
||||
@@ -46,6 +47,9 @@
|
||||
#include <math/mat3.h>
|
||||
#include <math/norm.h>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <filagui/ImGuiExtensions.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
@@ -54,6 +58,8 @@
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::math;
|
||||
using namespace filament::viewer;
|
||||
|
||||
using namespace gltfio;
|
||||
using namespace utils;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user