Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b3cde8b39 | ||
|
|
c23f905858 | ||
|
|
8c7be0a1d0 | ||
|
|
878497b3d5 | ||
|
|
648314d730 | ||
|
|
fc3c3376b7 | ||
|
|
fcbc6d43a1 | ||
|
|
a01fa21209 | ||
|
|
60a6d4a348 | ||
|
|
6c740f060e | ||
|
|
5a8bf42ddb | ||
|
|
c8cc74e384 | ||
|
|
c82ae6a3a7 | ||
|
|
fbc43d24fe | ||
|
|
c0f8f3bdfe | ||
|
|
3461ec863b | ||
|
|
035f162ebc | ||
|
|
6754885795 | ||
|
|
42e4e5e3ae | ||
|
|
71a0f46b73 | ||
|
|
5f52afdc08 | ||
|
|
54706ad65e | ||
|
|
a96d5932a8 | ||
|
|
41c5615201 | ||
|
|
719427764c |
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.22.2'
|
||||
implementation 'com.google.android.filament:filament-android:1.23.0'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,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.22.2'
|
||||
pod 'Filament', '~> 1.23.0'
|
||||
```
|
||||
|
||||
### Snapshots
|
||||
|
||||
@@ -5,6 +5,14 @@ A new header is inserted each time a *tag* is created.
|
||||
|
||||
## main branch
|
||||
|
||||
## v1.23.0
|
||||
|
||||
- engine: Changed UBOs layout [⚠️ **Material breakage**].
|
||||
- engine: Normals on morphed models have been fixed (core Filament change).
|
||||
- Java: View has several minor changes due to generated code, such as field ordering.
|
||||
- gltfio: Fix crash when reloading glTF assets.
|
||||
- gltfio: introduce cross-fade animation API [**NEW API**].
|
||||
|
||||
## v1.22.2
|
||||
|
||||
- Java: Minor API change: rename `ssctStartTraceDistance` to `ssctShadowDistance`. [⚠️ **API Change**]
|
||||
|
||||
@@ -104,12 +104,12 @@ public class MorphTargetBuffer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates positions of morph target at the index.
|
||||
* Updates float4 positions for the given morph target.
|
||||
*
|
||||
* @param engine {@link Engine} instance
|
||||
* @param targetIndex The index of morph target to be updated
|
||||
* @param positions Pointer to at least count positions
|
||||
* @param count Number of position elements in positions
|
||||
* @param positions An array with at least count*4 floats
|
||||
* @param count Number of float4 vectors in positions to be consumed
|
||||
*/
|
||||
public void setPositionsAt(@NonNull Engine engine,
|
||||
@IntRange(from = 0) int targetIndex,
|
||||
@@ -122,12 +122,15 @@ public class MorphTargetBuffer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates tangents of morph target at the index.
|
||||
* Updates tangents for the given morph target.
|
||||
*
|
||||
* These quaternions must be represented as signed shorts, where real numbers in the [-1,+1]
|
||||
* range multiplied by 32767.
|
||||
*
|
||||
* @param engine {@link Engine} instance
|
||||
* @param targetIndex The index of morph target to be updated
|
||||
* @param tangents Pointer to at least count tangents
|
||||
* @param count Number of tangent elements in tangents
|
||||
* @param tangents An array with at least "count*4" shorts
|
||||
* @param count number of short4 quaternions in tangents
|
||||
*/
|
||||
public void setTangentsAt(@NonNull Engine engine,
|
||||
@IntRange(from = 0) int targetIndex,
|
||||
@@ -140,14 +143,14 @@ public class MorphTargetBuffer {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return number of vertex count in this {@link MorphTargetBuffer}
|
||||
* @return number of vertices in this {@link MorphTargetBuffer}
|
||||
*/
|
||||
public int getVertexCount() {
|
||||
return nGetVertexCount(mNativeObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return number of target count in this {@link MorphTargetBuffer}
|
||||
* @return number of morph targets in this {@link MorphTargetBuffer}
|
||||
*/
|
||||
public int getCount() {
|
||||
return nGetCount(mNativeObject);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -36,6 +36,13 @@ Java_com_google_android_filament_gltfio_Animator_nUpdateBoneMatrices(JNIEnv*, jc
|
||||
animator->updateBoneMatrices();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_Animator_nApplyCrossFade(JNIEnv*, jclass, jlong nativeAnimator,
|
||||
jint previousAnimIndex, jfloat previousAnimTime, jfloat alpha) {
|
||||
Animator* animator = (Animator*) nativeAnimator;
|
||||
animator->applyCrossFade(previousAnimIndex, previousAnimTime, alpha);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_gltfio_Animator_nResetBoneMatrices(JNIEnv*, jclass, jlong nativeAnimator) {
|
||||
Animator* animator = (Animator*) nativeAnimator;
|
||||
|
||||
@@ -66,6 +66,27 @@ public class Animator {
|
||||
nUpdateBoneMatrices(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a blended transform to the union of nodes affected by two animations.
|
||||
* Used for cross-fading from a previous skinning-based animation or rigid body animation.
|
||||
*
|
||||
* First, this stashes the current transform hierarchy into a transient memory buffer.
|
||||
*
|
||||
* Next, this applies previousAnimIndex / previousAnimTime to the actual asset by internally
|
||||
* calling applyAnimation().
|
||||
*
|
||||
* Finally, the stashed local transforms are lerped (via the scale / translation / rotation
|
||||
* components) with their live counterparts, and the results are pushed to the asset.
|
||||
*
|
||||
* To achieve a cross fade effect with skinned models, clients will typically call animator
|
||||
* methods in this order: (1) applyAnimation (2) applyCrossFade (3) updateBoneMatrices. The
|
||||
* animation that clients pass to applyAnimation is the "current" animation corresponding to
|
||||
* alpha=1, while the "previous" animation passed to applyCrossFade corresponds to alpha=0.
|
||||
*/
|
||||
public void applyCrossFade(int previousAnimIndex, float previousAnimTime, float alpha) {
|
||||
nApplyCrossFade(getNativeObject(), previousAnimIndex, previousAnimTime, alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass the identity matrix into all bone nodes, useful for returning to the T pose.
|
||||
*
|
||||
@@ -118,6 +139,7 @@ public class Animator {
|
||||
|
||||
private static native void nApplyAnimation(long nativeAnimator, int index, float time);
|
||||
private static native void nUpdateBoneMatrices(long nativeAnimator);
|
||||
private static native void nApplyCrossFade(long nativeAnimator, int animIndex, float animTime, float alpha);
|
||||
private static native void nResetBoneMatrices(long nativeAnimator);
|
||||
private static native int nGetAnimationCount(long nativeAnimator);
|
||||
private static native float nGetAnimationDuration(long nativeAnimator, int index);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.22.2
|
||||
VERSION_NAME=1.23.0
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -67,6 +67,8 @@ public:
|
||||
utils::Invocable<utils::io::ostream&(utils::io::ostream& out)>&& logger);
|
||||
|
||||
// sets one of the program's shader (e.g. vertex, fragment)
|
||||
// string-based shaders are null terminated, consequently the size parameter must include the
|
||||
// null terminating character.
|
||||
Program& shader(Shader shader, void const* data, size_t size) noexcept;
|
||||
|
||||
// sets the 'bindingPoint' uniform block's name for this program.
|
||||
@@ -84,10 +86,14 @@ public:
|
||||
Program& setSamplerGroup(size_t bindingPoint, ShaderStageFlags stageFlags,
|
||||
Sampler const* samplers, size_t count) noexcept;
|
||||
|
||||
// string-based shaders are null terminated, consequently the size parameter must include the
|
||||
// null terminating character.
|
||||
Program& withVertexShader(void const* data, size_t size) {
|
||||
return shader(Shader::VERTEX, data, size);
|
||||
}
|
||||
|
||||
// string-based shaders are null terminated, consequently the size parameter must include the
|
||||
// null terminating character.
|
||||
Program& withFragmentShader(void const* data, size_t size) {
|
||||
return shader(Shader::FRAGMENT, data, size);
|
||||
}
|
||||
|
||||
@@ -346,8 +346,11 @@ MetalProgram::MetalProgram(id<MTLDevice> device, const Program& program) noexcep
|
||||
continue;
|
||||
}
|
||||
|
||||
assert_invariant( source[source.size() - 1] == '\0' );
|
||||
|
||||
// the shader string is null terminated and the length includes the null character
|
||||
NSString* objcSource = [[NSString alloc] initWithBytes:source.data()
|
||||
length:source.size()
|
||||
length:source.size() - 1
|
||||
encoding:NSUTF8StringEncoding];
|
||||
NSError* error = nil;
|
||||
// When options is nil, Metal uses the most recent language version available.
|
||||
|
||||
@@ -186,7 +186,11 @@ highp uint packHalf2x16(vec2 v) {
|
||||
GLuint shaderId = glCreateShader(glShaderType);
|
||||
{ // scope for source/length (we don't want them to leak out)
|
||||
const char* const source = shaderView.data();
|
||||
const GLint length = (GLint)shaderView.length();
|
||||
|
||||
// the shader string is null terminated and the length includes the null character
|
||||
const GLint length = (GLint)shaderView.length() - 1;
|
||||
assert_invariant( source[length] == '\0' );
|
||||
|
||||
glShaderSource(shaderId, 1, &source, &length);
|
||||
glCompileShader(shaderId);
|
||||
#ifndef NDEBUG
|
||||
|
||||
@@ -78,43 +78,49 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the position of morph target at the index.
|
||||
* Updates positions for the given morph target.
|
||||
*
|
||||
* This is equivalent to the float4 method, but uses 1.0 for the 4th component.
|
||||
*
|
||||
* Both positions and tangents must be provided.
|
||||
*
|
||||
* @param engine Reference to the filament::Engine associated with this MorphTargetBuffer.
|
||||
* @param targetIndex the index of morph target to be updated.
|
||||
* @param weights pointer to at least count positions
|
||||
* @param count number of position elements in positions
|
||||
* @param positions pointer to at least "count" positions
|
||||
* @param count number of float3 vectors in positions
|
||||
* @param offset offset into the target buffer, expressed as a number of float4 vectors
|
||||
* @see setTangentsAt
|
||||
*/
|
||||
void setPositionsAt(Engine& engine, size_t targetIndex,
|
||||
math::float3 const* positions, size_t count, size_t offset = 0);
|
||||
|
||||
/**
|
||||
* Updates the position of morph target at the index.
|
||||
* Updates positions for the given morph target.
|
||||
*
|
||||
* Both positions and tangents must be provided.
|
||||
*
|
||||
* @param engine Reference to the filament::Engine associated with this MorphTargetBuffer.
|
||||
* @param targetIndex the index of morph target to be updated.
|
||||
* @param weights pointer to at least count positions
|
||||
* @param count number of position elements in positions
|
||||
* @see setPositionsAt
|
||||
* @param positions pointer to at least "count" positions
|
||||
* @param count number of float4 vectors in positions
|
||||
* @param offset offset into the target buffer, expressed as a number of float4 vectors
|
||||
* @see setTangentsAt
|
||||
*/
|
||||
void setPositionsAt(Engine& engine, size_t targetIndex,
|
||||
math::float4 const* positions, size_t count, size_t offset = 0);
|
||||
|
||||
/**
|
||||
* Updates the position of morph target at the index.
|
||||
* Updates tangents for the given morph target.
|
||||
*
|
||||
* Both positions and tangents must be provided.
|
||||
* These quaternions must be represented as signed shorts, where real numbers in the [-1,+1]
|
||||
* range multiplied by 32767.
|
||||
*
|
||||
* @param engine Reference to the filament::Engine associated with this MorphTargetBuffer.
|
||||
* @param targetIndex the index of morph target to be updated.
|
||||
* @param tangents pointer to at least count tangents
|
||||
* @param count number of tangent elements in tangents
|
||||
* @see setTangentsAt
|
||||
* @param tangents pointer to at least "count" tangents
|
||||
* @param count number of short4 quaternions in tangents
|
||||
* @param offset offset into the target buffer, expressed as a number of short4 vectors
|
||||
* @see setPositionsAt
|
||||
*/
|
||||
void setTangentsAt(Engine& engine, size_t targetIndex,
|
||||
math::short4 const* tangents, size_t count, size_t offset = 0);
|
||||
|
||||
@@ -275,17 +275,18 @@ struct AmbientOcclusionOptions {
|
||||
* Ambient shadows from dominant light
|
||||
*/
|
||||
struct Ssct {
|
||||
float lightConeRad = 1.0f; //!< full cone angle in radian, between 0 and pi/2
|
||||
float shadowDistance = 0.3f; //!< how far shadows can be cast
|
||||
float contactDistanceMax = 1.0f; //!< max distance for contact
|
||||
float intensity = 0.8f; //!< intensity
|
||||
float lightConeRad = 1.0f; //!< full cone angle in radian, between 0 and pi/2
|
||||
float shadowDistance = 0.3f; //!< how far shadows can be cast
|
||||
float contactDistanceMax = 1.0f; //!< max distance for contact
|
||||
float intensity = 0.8f; //!< intensity
|
||||
math::float3 lightDirection = { 0, -1, 0 }; //!< light direction
|
||||
float depthBias = 0.01f; //!< depth bias in world units (mitigate self shadowing)
|
||||
float depthSlopeBias = 0.01f; //!< depth slope bias (mitigate self shadowing)
|
||||
uint8_t sampleCount = 4; //!< tracing sample count, between 1 and 255
|
||||
uint8_t rayCount = 1; //!< # of rays to trace, between 1 and 255
|
||||
bool enabled = false; //!< enables or disables SSCT
|
||||
} ssct; // %codegen_skip_javascript% %codegen_java_flatten%
|
||||
float depthBias = 0.01f; //!< depth bias in world units (mitigate self shadowing)
|
||||
float depthSlopeBias = 0.01f; //!< depth slope bias (mitigate self shadowing)
|
||||
uint8_t sampleCount = 4; //!< tracing sample count, between 1 and 255
|
||||
uint8_t rayCount = 1; //!< # of rays to trace, between 1 and 255
|
||||
bool enabled = false; //!< enables or disables SSCT
|
||||
};
|
||||
Ssct ssct; // %codegen_skip_javascript% %codegen_java_flatten%
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,6 +51,7 @@ RenderPass::RenderPass(RenderPass const& rhs) = default;
|
||||
RenderPass::~RenderPass() noexcept = default;
|
||||
|
||||
RenderPass::Command* RenderPass::append(size_t count) noexcept {
|
||||
// this is like a "in-place" realloc(). Works only with LinearAllocator.
|
||||
Command* const curr = mCommandArena.alloc<Command>(count);
|
||||
assert_invariant(mCommandBegin == nullptr || curr == mCommandEnd);
|
||||
if (mCommandBegin == nullptr) {
|
||||
@@ -301,9 +302,10 @@ void RenderPass::generateCommandsImpl(uint32_t extraFlags,
|
||||
auto const* const UTILS_RESTRICT soaWorldAABBCenter = soa.data<FScene::WORLD_AABB_CENTER>();
|
||||
auto const* const UTILS_RESTRICT soaVisibility = soa.data<FScene::VISIBILITY_STATE>();
|
||||
auto const* const UTILS_RESTRICT soaPrimitives = soa.data<FScene::PRIMITIVES>();
|
||||
auto const* const UTILS_RESTRICT soaSkinning = soa.data<FScene::SKINNING_BUFFER>();
|
||||
auto const* const UTILS_RESTRICT soaMorphing = soa.data<FScene::MORPHING_BUFFER>();
|
||||
auto const* const UTILS_RESTRICT soaVisibilityMask = soa.data<FScene::VISIBLE_MASK>();
|
||||
auto const* const UTILS_RESTRICT soaInstanceCount = soa.data<FScene::INSTANCE_COUNT>();
|
||||
auto const* const UTILS_RESTRICT soaInstanceCount = soa.data<FScene::INSTANCE_COUNT>();
|
||||
|
||||
const bool hasShadowing = renderFlags & HAS_SHADOWING;
|
||||
const bool viewInverseFrontFaces = renderFlags & HAS_INVERSE_FRONT_FACES;
|
||||
@@ -396,6 +398,7 @@ void RenderPass::generateCommandsImpl(uint32_t extraFlags,
|
||||
const bool writeDepthForShadowCasters = depthContainsShadowCasters & shadowCaster;
|
||||
|
||||
const Slice<FRenderPrimitive>& primitives = soaPrimitives[i];
|
||||
const FRenderableManager::SkinningBindingInfo& skinning = soaSkinning[i];
|
||||
const FRenderableManager::MorphingBindingInfo& morphing = soaMorphing[i];
|
||||
|
||||
/*
|
||||
@@ -412,6 +415,8 @@ void RenderPass::generateCommandsImpl(uint32_t extraFlags,
|
||||
cmdColor.primitive.primitiveHandle = primitive.getHwHandle();
|
||||
RenderPass::setupColorCommand(cmdColor, variant, mi, inverseFrontFaces);
|
||||
|
||||
cmdColor.primitive.skinningHandle = skinning.handle;
|
||||
cmdColor.primitive.skinningOffset = skinning.offset;
|
||||
cmdColor.primitive.morphWeightBuffer = morphing.handle;
|
||||
cmdColor.primitive.morphTargetBuffer = morphTargets.buffer->getHwHandle();
|
||||
|
||||
@@ -506,6 +511,8 @@ void RenderPass::generateCommandsImpl(uint32_t extraFlags,
|
||||
cmdDepth.primitive.mi = mi;
|
||||
cmdDepth.primitive.rasterState.culling = mi->getCullingMode();
|
||||
|
||||
cmdDepth.primitive.skinningHandle = skinning.handle;
|
||||
cmdDepth.primitive.skinningOffset = skinning.offset;
|
||||
cmdDepth.primitive.morphWeightBuffer = morphing.handle;
|
||||
cmdDepth.primitive.morphTargetBuffer = morphTargets.buffer->getHwHandle();
|
||||
|
||||
@@ -552,22 +559,18 @@ void RenderPass::Executor::execute(const char* name,
|
||||
engine.flush();
|
||||
|
||||
driver.beginRenderPass(renderTarget, params);
|
||||
recordDriverCommands(engine, driver, mBegin, mEnd, mRenderableSoa, params.readOnlyDepthStencil);
|
||||
recordDriverCommands(engine, driver, mBegin, mEnd, params.readOnlyDepthStencil);
|
||||
driver.endRenderPass();
|
||||
}
|
||||
|
||||
UTILS_NOINLINE // no need to be inlined
|
||||
void RenderPass::Executor::recordDriverCommands(FEngine& engine,
|
||||
backend::DriverApi& driver,
|
||||
const Command* first, const Command* last,
|
||||
FScene::RenderableSoa const& soa, uint16_t readOnlyDepthStencil) const noexcept {
|
||||
void RenderPass::Executor::recordDriverCommands(FEngine& engine, backend::DriverApi& driver,
|
||||
const Command* first, const Command* last, uint16_t readOnlyDepthStencil) const noexcept {
|
||||
SYSTRACE_CALL();
|
||||
|
||||
if (first != last) {
|
||||
SYSTRACE_VALUE32("commandCount", last - first);
|
||||
|
||||
auto const* const UTILS_RESTRICT soaSkinning = soa.data<FScene::SKINNING_BUFFER>();
|
||||
|
||||
PolygonOffset dummyPolyOffset;
|
||||
PipelineState pipeline{ .polygonOffset = mPolygonOffset };
|
||||
PolygonOffset* const pPipelinePolygonOffset =
|
||||
@@ -614,14 +617,13 @@ void RenderPass::Executor::recordDriverCommands(FEngine& engine,
|
||||
driver.bindUniformBufferRange(BindingPoints::PER_RENDERABLE,
|
||||
uboHandle, offset, sizeof(PerRenderableUib));
|
||||
|
||||
auto skinning = soaSkinning[info.index];
|
||||
if (UTILS_UNLIKELY(skinning.handle)) {
|
||||
if (UTILS_UNLIKELY(info.skinningHandle)) {
|
||||
// note: we can't bind less than CONFIG_MAX_BONE_COUNT due to glsl limitations
|
||||
driver.bindUniformBufferRange(BindingPoints::PER_RENDERABLE_BONES,
|
||||
skinning.handle,
|
||||
skinning.offset * sizeof(PerRenderableUibBone),
|
||||
info.skinningHandle,
|
||||
info.skinningOffset * sizeof(PerRenderableUibBone),
|
||||
CONFIG_MAX_BONE_COUNT * sizeof(PerRenderableUibBone));
|
||||
// note: even if skinning is only enabled, binding morphTargetBuffer is needed.
|
||||
// note: even if only skinning is enabled, binding morphTargetBuffer is needed.
|
||||
driver.bindSamplers(BindingPoints::PER_RENDERABLE_MORPHING,
|
||||
info.morphTargetBuffer);
|
||||
}
|
||||
@@ -643,7 +645,7 @@ void RenderPass::Executor::recordDriverCommands(FEngine& engine,
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
RenderPass::Executor::Executor(RenderPass const* pass, Command const* b, Command const* e) noexcept
|
||||
: mEngine(pass->mEngine), mBegin(b), mEnd(e), mRenderableSoa(*pass->mRenderableSoa),
|
||||
: mEngine(pass->mEngine), mBegin(b), mEnd(e),
|
||||
mCustomCommands(pass->mCustomCommands), mUboHandle(pass->mUboHandle),
|
||||
mPolygonOffset(pass->mPolygonOffset),
|
||||
mPolygonOffsetOverride(pass->mPolygonOffsetOverride) {
|
||||
|
||||
@@ -213,25 +213,28 @@ public:
|
||||
return boolish ? std::numeric_limits<uint64_t>::max() : uint64_t(0);
|
||||
}
|
||||
|
||||
struct PrimitiveInfo { // 40 bytes
|
||||
struct PrimitiveInfo { // 48 bytes
|
||||
union {
|
||||
FMaterialInstance const* mi;
|
||||
uint64_t reserved0 = {}; // ensures mi is 8 bytes on all archs
|
||||
uint64_t padding = {}; // ensures mi is 8 bytes on all archs
|
||||
}; // 8 bytes
|
||||
backend::RasterState rasterState; // 8 bytes
|
||||
backend::Handle<backend::HwRenderPrimitive> primitiveHandle; // 4 bytes
|
||||
backend::Handle<backend::HwBufferObject> skinningHandle; // 4 bytes
|
||||
backend::Handle<backend::HwBufferObject> morphWeightBuffer; // 4 bytes
|
||||
backend::Handle<backend::HwSamplerGroup> morphTargetBuffer; // 4 bytes
|
||||
uint16_t index = 0; // 2 bytes
|
||||
uint32_t index = 0; // 4 bytes
|
||||
uint32_t skinningOffset = 0; // 4 bytes
|
||||
uint16_t instanceCount; // 2 bytes
|
||||
backend::RasterState rasterState; // 8 bytes
|
||||
Variant materialVariant; // 1 byte
|
||||
uint8_t reserved1[7] = {}; // 7 bytes
|
||||
uint8_t reserved[5] = {}; // 5 bytes
|
||||
};
|
||||
static_assert(sizeof(PrimitiveInfo) == 40);
|
||||
static_assert(sizeof(PrimitiveInfo) == 48);
|
||||
|
||||
struct alignas(8) Command { // 40 bytes
|
||||
struct alignas(8) Command { // 64 bytes
|
||||
CommandKey key = 0; // 8 bytes
|
||||
PrimitiveInfo primitive; // 40 bytes
|
||||
PrimitiveInfo primitive; // 48 bytes
|
||||
uint64_t reserved = 0; // 8 bytes
|
||||
bool operator < (Command const& rhs) const noexcept { return key < rhs.key; }
|
||||
// placement new declared as "throw" to avoid the compiler's null-check
|
||||
inline void* operator new (std::size_t, void* ptr) {
|
||||
@@ -239,7 +242,7 @@ public:
|
||||
return ptr;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(Command) == 48);
|
||||
static_assert(sizeof(Command) == 64);
|
||||
static_assert(std::is_trivially_destructible_v<Command>,
|
||||
"Command isn't trivially destructible");
|
||||
|
||||
@@ -249,7 +252,7 @@ public:
|
||||
|
||||
// Arena used for commands
|
||||
using Arena = utils::Arena<
|
||||
utils::LinearAllocator,
|
||||
utils::LinearAllocator, // note: can't change this allocator
|
||||
utils::LockingPolicy::NoLock,
|
||||
utils::TrackingPolicy::HighWatermark,
|
||||
utils::AreaPolicy::StaticArea>;
|
||||
@@ -319,7 +322,6 @@ public:
|
||||
FEngine& mEngine;
|
||||
Command const* mBegin;
|
||||
Command const* mEnd;
|
||||
FScene::RenderableSoa const& mRenderableSoa;
|
||||
const CustomCommandVector mCustomCommands;
|
||||
const backend::Handle<backend::HwBufferObject> mUboHandle;
|
||||
const backend::PolygonOffset mPolygonOffset;
|
||||
@@ -328,8 +330,7 @@ public:
|
||||
Executor(RenderPass const* pass, Command const* b, Command const* e) noexcept;
|
||||
|
||||
void recordDriverCommands(FEngine& engine, backend::DriverApi& driver,
|
||||
const Command* first, const Command* last,
|
||||
FScene::RenderableSoa const& soa, uint16_t readOnlyDepthStencil) const noexcept;
|
||||
const Command* first, const Command* last, uint16_t readOnlyDepthStencil) const noexcept;
|
||||
|
||||
public:
|
||||
Executor(Executor const& rhs);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace filament::backend;
|
||||
using namespace filament::math;
|
||||
using namespace utils;
|
||||
|
||||
@@ -196,7 +197,9 @@ void FScene::prepare(const mat4& worldOriginTransform, bool shadowReceiversAreCa
|
||||
}
|
||||
}
|
||||
|
||||
void FScene::updateUBOs(utils::Range<uint32_t> visibleRenderables, backend::Handle<backend::HwBufferObject> renderableUbh) noexcept {
|
||||
void FScene::updateUBOs(
|
||||
Range<uint32_t> visibleRenderables,
|
||||
Handle<HwBufferObject> renderableUbh) noexcept {
|
||||
FEngine::DriverApi& driver = mEngine.getDriverApi();
|
||||
FRenderableManager& rcm = mEngine.getRenderableManager();
|
||||
|
||||
@@ -219,7 +222,7 @@ void FScene::updateUBOs(utils::Range<uint32_t> visibleRenderables, backend::Hand
|
||||
|
||||
// Using mat3f::getTransformForNormals handles non-uniform scaling, but DOESN'T guarantee that
|
||||
// the transformed normals will have unit-length, therefore they need to be normalized
|
||||
// in the shader (that's already the case anyways, since normalization is needed after
|
||||
// in the shader (that's already the case anyway, since normalization is needed after
|
||||
// interpolation).
|
||||
//
|
||||
// We pre-scale normals by the inverse of the largest scale factor to avoid
|
||||
@@ -247,20 +250,17 @@ void FScene::updateUBOs(utils::Range<uint32_t> visibleRenderables, backend::Hand
|
||||
hasContactShadows = hasContactShadows || visibility.screenSpaceContactShadows;
|
||||
|
||||
UniformBuffer::setUniform(buffer,
|
||||
offset + offsetof(PerRenderableUib, flags),
|
||||
PerRenderableUib::packFlags(
|
||||
offset + offsetof(PerRenderableUib, flagsChannels),
|
||||
PerRenderableUib::packFlagsChannels(
|
||||
visibility.skinning,
|
||||
visibility.morphing,
|
||||
visibility.screenSpaceContactShadows));
|
||||
visibility.screenSpaceContactShadows,
|
||||
sceneData.elementAt<CHANNELS>(i)));
|
||||
|
||||
UniformBuffer::setUniform(buffer,
|
||||
offset + offsetof(PerRenderableUib, morphTargetCount),
|
||||
sceneData.elementAt<MORPHING_BUFFER>(i).count);
|
||||
|
||||
UniformBuffer::setUniform(buffer,
|
||||
offset + offsetof(PerRenderableUib, channels),
|
||||
(uint32_t)sceneData.elementAt<CHANNELS>(i));
|
||||
|
||||
UniformBuffer::setUniform(buffer,
|
||||
offset + offsetof(PerRenderableUib, objectId),
|
||||
rcm.getEntity(ri).getId()); // we could also store the entity in sceneData
|
||||
@@ -287,7 +287,7 @@ void FScene::terminate(FEngine& engine) {
|
||||
}
|
||||
|
||||
void FScene::prepareDynamicLights(const CameraInfo& camera, ArenaScope& rootArena,
|
||||
backend::Handle<backend::HwBufferObject> lightUbh) noexcept {
|
||||
Handle<HwBufferObject> lightUbh) noexcept {
|
||||
FEngine::DriverApi& driver = mEngine.getDriverApi();
|
||||
FLightManager& lcm = mEngine.getLightManager();
|
||||
FScene::LightSoa& lightData = getLightData();
|
||||
@@ -450,7 +450,7 @@ bool FScene::hasContactShadows() const noexcept {
|
||||
}
|
||||
|
||||
UTILS_NOINLINE
|
||||
void FScene::forEach(Invocable<void(utils::Entity)>&& functor) const noexcept {
|
||||
void FScene::forEach(Invocable<void(Entity)>&& functor) const noexcept {
|
||||
std::for_each(mEntities.begin(), mEntities.end(), std::move(functor));
|
||||
}
|
||||
|
||||
|
||||
@@ -84,8 +84,8 @@ public:
|
||||
enum {
|
||||
RENDERABLE_INSTANCE, // 4 | instance of the Renderable component
|
||||
WORLD_TRANSFORM, // 16 | instance of the Transform component
|
||||
VISIBILITY_STATE, // 1 | visibility data of the component
|
||||
SKINNING_BUFFER, // 8 | bones uniform buffer handle, count, offset
|
||||
VISIBILITY_STATE, // 2 | visibility data of the component
|
||||
SKINNING_BUFFER, // 8 | bones uniform buffer handle, offset
|
||||
MORPHING_BUFFER, // 16 | weights uniform buffer handle, count, morph targets
|
||||
WORLD_AABB_CENTER, // 12 | world-space bounding box center of the renderable
|
||||
VISIBLE_MASK, // 2 | each bit represents a visibility in a pass
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.22.2"
|
||||
spec.version = "1.23.0"
|
||||
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||
spec.homepage = "https://google.github.io/filament"
|
||||
spec.authors = "Google LLC."
|
||||
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
||||
spec.platform = :ios, "11.0"
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.22.2/filament-v1.22.2-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.23.0/filament-v1.23.0-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -88,7 +88,7 @@ from scratch.
|
||||
|
||||
## XcodeGen
|
||||
|
||||
[XcodeGen](https://github.com/yonaskolb/XcodeGen) version 2.14.0 is used to generate the Xcode
|
||||
[XcodeGen](https://github.com/yonaskolb/XcodeGen) version 2.29.0 is used to generate the Xcode
|
||||
projects. While not required to run the samples, XcodeGen makes modifying them easier. Each sample
|
||||
folder contains the `project.yml` file used for the sample, which includes a global
|
||||
`app-template.yml` file. Simply run
|
||||
@@ -99,3 +99,17 @@ $ xcodegen
|
||||
|
||||
within a sample folder to re-generate the Xcode project. You may need to close and re-open the
|
||||
project in Xcode to see changes take effect.
|
||||
|
||||
## Building iOS Samples with ASan / UBSan
|
||||
|
||||
1. Turn on ASan / UBSan in Filament's top-level CMakeLists.txt by uncommenting the following line:
|
||||
|
||||
```
|
||||
set(EXTRA_SANITIZE_OPTIONS "-fsanitize=undefined -fsanitize=address")
|
||||
```
|
||||
|
||||
2. In the Xcode project, navigate to Product -> Scheme -> Edit Scheme... Under the Diagnostics tab,
|
||||
check the box next for Address Sanitizer and Undefined Behavior.
|
||||
|
||||
3. Build Filament and run the iOS sample as usual. Any errors will cause an exception to raise and
|
||||
diagnostics to print in the console.
|
||||
|
||||
@@ -22,6 +22,9 @@ targetTemplates:
|
||||
OTHER_LDFLAGS: ["-lfilament", "-lbackend", "-lfilaflat", "-lktxreader",
|
||||
"-lfilabridge", "-lutils", "-lsmol-v", "-lgeometry", "-libl"]
|
||||
ENABLE_BITCODE: NO
|
||||
CLANG_CXX_LANGUAGE_STANDARD: gnu++17
|
||||
# This allows users to not have to specify a unique bundle ID when building the sample apps.
|
||||
SAMPLE_CODE_DISAMBIGUATOR: ${DEVELOPMENT_TEAM}
|
||||
configs:
|
||||
debug:
|
||||
HEADER_SEARCH_PATHS: ["../../../out/ios-debug/filament/include", "generated"]
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
};
|
||||
};
|
||||
buildConfigurationList = E89E1EEA671E49DBAC9D5A9C /* Build configuration list for PBXProject "backend-test" */;
|
||||
compatibilityVersion = "Xcode 10.0";
|
||||
compatibilityVersion = "Xcode 11.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
@@ -165,7 +165,7 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@@ -218,6 +218,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -242,6 +243,7 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
@@ -250,7 +252,8 @@
|
||||
"-lfilamat",
|
||||
"-force_load ../../../out/ios-debug/filament/lib/arm64/libbackend_test.a",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.backend-test";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.backend-test";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -262,7 +265,7 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@@ -322,6 +325,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -346,6 +350,7 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
@@ -354,7 +359,8 @@
|
||||
"-lfilamat",
|
||||
"-force_load ../../../out/ios-debug/filament/lib/arm64/libbackend_test.a",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.backend-test";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.backend-test";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -366,7 +372,7 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@@ -419,6 +425,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -443,6 +450,7 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
@@ -451,7 +459,8 @@
|
||||
"-lfilamat",
|
||||
"-force_load ../../../out/ios-debug/filament/lib/arm64/libbackend_test.a",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.backend-test";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.backend-test";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -461,6 +470,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -485,6 +495,7 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
@@ -493,7 +504,8 @@
|
||||
"-lfilamat",
|
||||
"-force_load ../../../out/ios-debug/filament/lib/arm64/libbackend_test.a",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.backend-test";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.backend-test";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -505,7 +517,7 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:backend-test.xcodeproj">
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.3">
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
buildImplicitDependencies = "YES"
|
||||
runPostActionsOnFailure = "NO">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.3">
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
buildImplicitDependencies = "YES"
|
||||
runPostActionsOnFailure = "NO">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: backend-test
|
||||
options:
|
||||
bundleIdPrefix: google.filament
|
||||
bundleIdPrefix: ${SAMPLE_CODE_DISAMBIGUATOR}.google.filament
|
||||
include: ../app-template.yml
|
||||
targets:
|
||||
backend-test:
|
||||
|
||||
11
ios/samples/generate-samples.sh
Executable file
11
ios/samples/generate-samples.sh
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -ex
|
||||
|
||||
cd backend-test && xcodegen && cd ..
|
||||
cd gltf-viewer && xcodegen && cd ..
|
||||
cd hello-ar && xcodegen && cd ..
|
||||
cd hello-gltf && xcodegen && cd ..
|
||||
cd hello-pbr && xcodegen && cd ..
|
||||
cd hello-triangle && xcodegen && cd ..
|
||||
cd transparent-rendering && xcodegen && cd ..
|
||||
@@ -123,7 +123,7 @@
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 90327DE42AE5DF12C4BD2113 /* Build configuration list for PBXProject "gltf-viewer" */;
|
||||
compatibilityVersion = "Xcode 10.0";
|
||||
compatibilityVersion = "Xcode 11.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
@@ -219,7 +219,7 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@@ -281,7 +281,7 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@@ -336,7 +336,7 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@@ -389,6 +389,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -431,7 +432,8 @@
|
||||
"-lcivetweb",
|
||||
"-lktxreader",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.gltf-viewer";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.gltf-viewer";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -441,6 +443,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -483,7 +486,8 @@
|
||||
"-lcivetweb",
|
||||
"-lktxreader",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.gltf-viewer";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.gltf-viewer";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -495,7 +499,7 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@@ -555,6 +559,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -597,7 +602,8 @@
|
||||
"-lcivetweb",
|
||||
"-lktxreader",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.gltf-viewer";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.gltf-viewer";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -607,6 +613,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -649,7 +656,8 @@
|
||||
"-lcivetweb",
|
||||
"-lktxreader",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.gltf-viewer";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.gltf-viewer";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.3">
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.3">
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES"
|
||||
|
||||
@@ -56,6 +56,8 @@ using namespace ktxreader;
|
||||
Texture* _iblTexture;
|
||||
IndirectLight* _indirectLight;
|
||||
Entity _sun;
|
||||
|
||||
UITapGestureRecognizer* _doubleTapRecognizer;
|
||||
}
|
||||
|
||||
#pragma mark UIViewController methods
|
||||
@@ -91,6 +93,10 @@ using namespace ktxreader;
|
||||
|
||||
_server = new viewer::RemoteServer();
|
||||
_automation = viewer::AutomationEngine::createDefault();
|
||||
|
||||
_doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(reloadModel)];
|
||||
_doubleTapRecognizer.numberOfTapsRequired = 2;
|
||||
[self.modelView addGestureRecognizer:_doubleTapRecognizer];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
@@ -101,6 +107,8 @@ using namespace ktxreader;
|
||||
[self stopDisplayLink];
|
||||
}
|
||||
|
||||
#pragma mark Private
|
||||
|
||||
- (void)startDisplayLink {
|
||||
[self stopDisplayLink];
|
||||
|
||||
@@ -116,8 +124,6 @@ using namespace ktxreader;
|
||||
_displayLink = nil;
|
||||
}
|
||||
|
||||
#pragma mark Private
|
||||
|
||||
- (void)createRenderablesFromPath:(NSString*)model {
|
||||
// Retrieve the full path to the model in the documents directory.
|
||||
NSString* documentPath = [NSSearchPathForDirectoriesInDomains(
|
||||
@@ -257,6 +263,11 @@ using namespace ktxreader;
|
||||
[self.modelView render];
|
||||
}
|
||||
|
||||
- (void)reloadModel {
|
||||
[self.modelView destroyModel];
|
||||
[self createDefaultRenderables];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
delete _server;
|
||||
delete _automation;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: gltf-viewer
|
||||
options:
|
||||
bundleIdPrefix: google.filament
|
||||
bundleIdPrefix: ${SAMPLE_CODE_DISAMBIGUATOR}.google.filament
|
||||
include: ../app-template.yml
|
||||
targets:
|
||||
gltf-viewer:
|
||||
|
||||
@@ -160,16 +160,17 @@
|
||||
392626AFF36D607FEB6176BE /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1020;
|
||||
LastUpgradeCheck = 1200;
|
||||
TargetAttributes = {
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 281E763643B2F1F3B903864B /* Build configuration list for PBXProject "hello-ar" */;
|
||||
compatibilityVersion = "Xcode 10.0";
|
||||
compatibilityVersion = "Xcode 11.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
Base,
|
||||
en,
|
||||
);
|
||||
mainGroup = 316A56C698744769908E6F88;
|
||||
projectDirPath = "";
|
||||
@@ -255,6 +256,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -279,6 +281,7 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
@@ -286,10 +289,11 @@
|
||||
"-libl",
|
||||
"-lfilameshio",
|
||||
"-lmeshoptimizer",
|
||||
"-lktxreader",
|
||||
"-limage",
|
||||
"-lktxreader",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.hello-ar";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.hello-ar";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -299,6 +303,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -323,6 +328,7 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
@@ -330,10 +336,11 @@
|
||||
"-libl",
|
||||
"-lfilameshio",
|
||||
"-lmeshoptimizer",
|
||||
"-lktxreader",
|
||||
"-limage",
|
||||
"-lktxreader",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.hello-ar";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.hello-ar";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -345,10 +352,11 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
@@ -364,6 +372,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -388,7 +397,8 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -402,6 +412,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -426,6 +437,7 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
@@ -433,10 +445,11 @@
|
||||
"-libl",
|
||||
"-lfilameshio",
|
||||
"-lmeshoptimizer",
|
||||
"-lktxreader",
|
||||
"-limage",
|
||||
"-lktxreader",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.hello-ar";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.hello-ar";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -448,10 +461,11 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
@@ -467,6 +481,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -491,7 +506,8 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -507,10 +523,11 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
@@ -526,6 +543,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -544,11 +562,13 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = "Metal Release";
|
||||
};
|
||||
@@ -556,6 +576,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -580,6 +601,7 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
@@ -587,10 +609,11 @@
|
||||
"-libl",
|
||||
"-lfilameshio",
|
||||
"-lmeshoptimizer",
|
||||
"-lktxreader",
|
||||
"-limage",
|
||||
"-lktxreader",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.hello-ar";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.hello-ar";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -602,10 +625,11 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
@@ -621,6 +645,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -639,11 +664,13 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = "OpenGL Release";
|
||||
};
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:hello-ar.xcodeproj">
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
buildImplicitDependencies = "YES"
|
||||
runPostActionsOnFailure = "NO">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
@@ -41,10 +42,6 @@
|
||||
</MacroExpansion>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
<CodeCoverageTargets>
|
||||
</CodeCoverageTargets>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Metal Debug"
|
||||
@@ -68,8 +65,6 @@
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Metal Release"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
buildImplicitDependencies = "YES"
|
||||
runPostActionsOnFailure = "NO">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
@@ -41,10 +42,6 @@
|
||||
</MacroExpansion>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
<CodeCoverageTargets>
|
||||
</CodeCoverageTargets>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "OpenGL Debug"
|
||||
@@ -68,8 +65,6 @@
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "OpenGL Release"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: hello-ar
|
||||
options:
|
||||
bundleIdPrefix: google.filament
|
||||
bundleIdPrefix: ${SAMPLE_CODE_DISAMBIGUATOR}.google.filament
|
||||
include: ../app-template.yml
|
||||
targets:
|
||||
hello-ar:
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
};
|
||||
};
|
||||
buildConfigurationList = C7514DDCFDA3C5F803E239F9 /* Build configuration list for PBXProject "hello-gltf" */;
|
||||
compatibilityVersion = "Xcode 10.0";
|
||||
compatibilityVersion = "Xcode 11.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
@@ -232,7 +232,7 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@@ -292,6 +292,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -330,7 +331,8 @@
|
||||
"-lktxreader",
|
||||
"-lstb",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.hello-gltf";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.hello-gltf";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -340,6 +342,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -378,7 +381,8 @@
|
||||
"-lktxreader",
|
||||
"-lstb",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.hello-gltf";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.hello-gltf";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -390,7 +394,7 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@@ -452,7 +456,7 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@@ -507,7 +511,7 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@@ -560,6 +564,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -598,7 +603,8 @@
|
||||
"-lktxreader",
|
||||
"-lstb",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.hello-gltf";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.hello-gltf";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -608,6 +614,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -646,7 +653,8 @@
|
||||
"-lktxreader",
|
||||
"-lstb",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.hello-gltf";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.hello-gltf";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.3">
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.3">
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: hello-gltf
|
||||
options:
|
||||
bundleIdPrefix: google.filament
|
||||
bundleIdPrefix: ${SAMPLE_CODE_DISAMBIGUATOR}.google.filament
|
||||
include: ../app-template.yml
|
||||
targets:
|
||||
hello-gltf:
|
||||
|
||||
@@ -115,16 +115,17 @@
|
||||
55C50CCB1B22D6D3E534BB59 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1020;
|
||||
LastUpgradeCheck = 1200;
|
||||
TargetAttributes = {
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 0479354FB8D9A411347D91A6 /* Build configuration list for PBXProject "hello-pbr" */;
|
||||
compatibilityVersion = "Xcode 10.0";
|
||||
compatibilityVersion = "Xcode 11.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
Base,
|
||||
en,
|
||||
);
|
||||
mainGroup = 8B171658B4A1227B9CA44459;
|
||||
projectDirPath = "";
|
||||
@@ -212,10 +213,11 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
@@ -231,6 +233,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -255,7 +258,8 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -269,6 +273,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -293,17 +298,19 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
"-lgeometry",
|
||||
"-libl",
|
||||
"-lktxreader",
|
||||
"-lfilameshio",
|
||||
"-lmeshoptimizer",
|
||||
"-limage",
|
||||
"-lktxreader",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.hello-pbr";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.hello-pbr";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -313,6 +320,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -337,17 +345,19 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
"-lgeometry",
|
||||
"-libl",
|
||||
"-lktxreader",
|
||||
"-lfilameshio",
|
||||
"-lmeshoptimizer",
|
||||
"-limage",
|
||||
"-lktxreader",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.hello-pbr";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.hello-pbr";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -357,6 +367,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -381,17 +392,19 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
"-lgeometry",
|
||||
"-libl",
|
||||
"-lktxreader",
|
||||
"-lfilameshio",
|
||||
"-lmeshoptimizer",
|
||||
"-limage",
|
||||
"-lktxreader",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.hello-pbr";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.hello-pbr";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -403,10 +416,11 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
@@ -422,6 +436,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -440,11 +455,13 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = "Metal Release";
|
||||
};
|
||||
@@ -454,10 +471,11 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
@@ -473,6 +491,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -491,11 +510,13 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = "OpenGL Release";
|
||||
};
|
||||
@@ -503,6 +524,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -527,17 +549,19 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
"-lgeometry",
|
||||
"-libl",
|
||||
"-lktxreader",
|
||||
"-lfilameshio",
|
||||
"-lmeshoptimizer",
|
||||
"-limage",
|
||||
"-lktxreader",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.hello-pbr";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.hello-pbr";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -549,10 +573,11 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
@@ -568,6 +593,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -592,7 +618,8 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:hello-pbr.xcodeproj">
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
buildImplicitDependencies = "YES"
|
||||
runPostActionsOnFailure = "NO">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
@@ -41,10 +42,6 @@
|
||||
</MacroExpansion>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
<CodeCoverageTargets>
|
||||
</CodeCoverageTargets>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Metal Debug"
|
||||
@@ -68,8 +65,6 @@
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Metal Release"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
buildImplicitDependencies = "YES"
|
||||
runPostActionsOnFailure = "NO">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
@@ -41,10 +42,6 @@
|
||||
</MacroExpansion>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
<CodeCoverageTargets>
|
||||
</CodeCoverageTargets>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "OpenGL Debug"
|
||||
@@ -68,8 +65,6 @@
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "OpenGL Release"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: hello-pbr
|
||||
options:
|
||||
bundleIdPrefix: google.filament
|
||||
bundleIdPrefix: ${SAMPLE_CODE_DISAMBIGUATOR}.google.filament
|
||||
include: ../app-template.yml
|
||||
targets:
|
||||
hello-pbr:
|
||||
|
||||
@@ -102,16 +102,17 @@
|
||||
72185E8715083808BEBA6666 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1020;
|
||||
LastUpgradeCheck = 1200;
|
||||
TargetAttributes = {
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 69A012BABE82CB5D1986B1BB /* Build configuration list for PBXProject "hello-triangle" */;
|
||||
compatibilityVersion = "Xcode 10.0";
|
||||
compatibilityVersion = "Xcode 11.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
Base,
|
||||
en,
|
||||
);
|
||||
mainGroup = 5B3E3AAF5C75644908492410;
|
||||
projectDirPath = "";
|
||||
@@ -194,6 +195,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -218,13 +220,15 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
"-lgeometry",
|
||||
"-libl",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.hello-triangle";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.hello-triangle";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -236,10 +240,11 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
@@ -255,6 +260,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -279,7 +285,8 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -293,6 +300,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -317,13 +325,15 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
"-lgeometry",
|
||||
"-libl",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.hello-triangle";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.hello-triangle";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -333,6 +343,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -357,13 +368,15 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
"-lgeometry",
|
||||
"-libl",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.hello-triangle";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.hello-triangle";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -375,10 +388,11 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
@@ -394,6 +408,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -412,11 +427,13 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = "Metal Release";
|
||||
};
|
||||
@@ -426,10 +443,11 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
@@ -445,6 +463,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -463,11 +482,13 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = "OpenGL Release";
|
||||
};
|
||||
@@ -475,6 +496,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -499,13 +521,15 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
"-lgeometry",
|
||||
"-libl",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.hello-triangle";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.hello-triangle";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -517,10 +541,11 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
@@ -536,6 +561,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -560,7 +586,8 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:hello-triangle.xcodeproj">
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
buildImplicitDependencies = "YES"
|
||||
runPostActionsOnFailure = "NO">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
@@ -41,10 +42,6 @@
|
||||
</MacroExpansion>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
<CodeCoverageTargets>
|
||||
</CodeCoverageTargets>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Metal Debug"
|
||||
@@ -68,8 +65,6 @@
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Metal Release"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
buildImplicitDependencies = "YES"
|
||||
runPostActionsOnFailure = "NO">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
@@ -41,10 +42,6 @@
|
||||
</MacroExpansion>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
<CodeCoverageTargets>
|
||||
</CodeCoverageTargets>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "OpenGL Debug"
|
||||
@@ -68,8 +65,6 @@
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "OpenGL Release"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: hello-triangle
|
||||
options:
|
||||
bundleIdPrefix: google.filament
|
||||
bundleIdPrefix: ${SAMPLE_CODE_DISAMBIGUATOR}.google.filament
|
||||
include: ../app-template.yml
|
||||
targets:
|
||||
hello-triangle:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: transparent-rendering
|
||||
options:
|
||||
bundleIdPrefix: google.filament
|
||||
bundleIdPrefix: ${SAMPLE_CODE_DISAMBIGUATOR}.google.filament
|
||||
include: ../app-template.yml
|
||||
targets:
|
||||
transparent-rendering:
|
||||
|
||||
@@ -92,16 +92,17 @@
|
||||
81DCFDD51562B31512E28C40 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 1020;
|
||||
LastUpgradeCheck = 1200;
|
||||
TargetAttributes = {
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 8A22BD23DB15965551506480 /* Build configuration list for PBXProject "transparent-rendering" */;
|
||||
compatibilityVersion = "Xcode 10.0";
|
||||
compatibilityVersion = "Xcode 11.0";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
Base,
|
||||
en,
|
||||
);
|
||||
mainGroup = 4C27390036DEB15C67D5A664;
|
||||
projectDirPath = "";
|
||||
@@ -186,10 +187,11 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
@@ -205,6 +207,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -223,11 +226,13 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = "OpenGL Release";
|
||||
};
|
||||
@@ -237,10 +242,11 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
@@ -256,6 +262,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -280,7 +287,8 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
@@ -296,10 +304,11 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
@@ -315,6 +324,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -333,11 +343,13 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = "Metal Release";
|
||||
};
|
||||
@@ -345,6 +357,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -369,13 +382,15 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
"-lgeometry",
|
||||
"-libl",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.transparent-rendering";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.transparent-rendering";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -385,6 +400,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -409,13 +425,15 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
"-lgeometry",
|
||||
"-libl",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.transparent-rendering";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.transparent-rendering";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -425,6 +443,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -449,13 +468,15 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
"-lgeometry",
|
||||
"-libl",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.transparent-rendering";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.transparent-rendering";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -465,6 +486,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
@@ -489,13 +511,15 @@
|
||||
"-lfilament",
|
||||
"-lbackend",
|
||||
"-lfilaflat",
|
||||
"-lktxreader",
|
||||
"-lfilabridge",
|
||||
"-lutils",
|
||||
"-lsmol-v",
|
||||
"-lgeometry",
|
||||
"-libl",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "google.filament.transparent-rendering";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${SAMPLE_CODE_DISAMBIGUATOR}.google.filament.transparent-rendering";
|
||||
SAMPLE_CODE_DISAMBIGUATOR = "${DEVELOPMENT_TEAM}";
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -507,10 +531,11 @@
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
@@ -526,6 +551,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@@ -550,7 +576,8 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SDKROOT = iphoneos;
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:transparent-rendering.xcodeproj">
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
buildImplicitDependencies = "YES"
|
||||
runPostActionsOnFailure = "NO">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
@@ -41,10 +42,6 @@
|
||||
</MacroExpansion>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
<CodeCoverageTargets>
|
||||
</CodeCoverageTargets>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Metal Debug"
|
||||
@@ -68,8 +65,6 @@
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Metal Release"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1020"
|
||||
version = "1.3">
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
buildImplicitDependencies = "YES"
|
||||
runPostActionsOnFailure = "NO">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
@@ -41,10 +42,6 @@
|
||||
</MacroExpansion>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
<CodeCoverageTargets>
|
||||
</CodeCoverageTargets>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "OpenGL Debug"
|
||||
@@ -68,8 +65,6 @@
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
</CommandLineArguments>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "OpenGL Release"
|
||||
|
||||
@@ -177,7 +177,7 @@ public:
|
||||
|
||||
Bookmark getHomeBookmark() const override {
|
||||
Bookmark bookmark;
|
||||
bookmark.flight.position = Base::mProps.flightStartPosition;;
|
||||
bookmark.flight.position = Base::mProps.flightStartPosition;
|
||||
bookmark.flight.pitch = Base::mProps.flightStartPitch;
|
||||
bookmark.flight.yaw = Base::mProps.flightStartYaw;
|
||||
return bookmark;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
namespace filament {
|
||||
|
||||
// update this when a new version of filament wouldn't work with older materials
|
||||
static constexpr size_t MATERIAL_VERSION = 22;
|
||||
static constexpr size_t MATERIAL_VERSION = 23;
|
||||
|
||||
/**
|
||||
* Supported shading models
|
||||
|
||||
@@ -177,19 +177,22 @@ struct alignas(256) PerRenderableUib { // NOLINT(cppcoreguidelines-pro-type-memb
|
||||
math::mat4f worldFromModelMatrix;
|
||||
math::mat3f worldFromModelNormalMatrix; // this gets expanded to 48 bytes during the copy to the UBO
|
||||
alignas(16) uint32_t morphTargetCount;
|
||||
uint32_t flags; // see packFlags() below
|
||||
uint32_t channels; // 0x000000ll
|
||||
uint32_t flagsChannels; // see packFlags() below (0x00000fll)
|
||||
uint32_t objectId; // used for picking
|
||||
// TODO: We need a better solution, this currently holds the average local scale for the renderable
|
||||
float userData;
|
||||
math::float4 reserved[8];
|
||||
|
||||
static uint32_t packFlags(bool skinning, bool morphing, bool contactShadows) noexcept {
|
||||
return (skinning ? 1 : 0) |
|
||||
(morphing ? 2 : 0) |
|
||||
(contactShadows ? 4 : 0);
|
||||
static uint32_t packFlagsChannels(
|
||||
bool skinning, bool morphing, bool contactShadows, uint8_t channels) noexcept {
|
||||
return (skinning ? 0x100 : 0) |
|
||||
(morphing ? 0x200 : 0) |
|
||||
(contactShadows ? 0x400 : 0) |
|
||||
channels;
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(PerRenderableUib) % 256 == 0, "sizeof(Transform) should be a multiple of 256");
|
||||
|
||||
static_assert(sizeof(PerRenderableUib) == 256, "sizeof(PerRenderableUib) must be 256 bytes");
|
||||
|
||||
struct LightsUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
static constexpr utils::StaticString _name{ "LightsUniforms" };
|
||||
|
||||
@@ -152,10 +152,10 @@ UniformInterfaceBlock const& UibGenerator::getPerRenderableUib() noexcept {
|
||||
.add("worldFromModelMatrix", 1, UniformInterfaceBlock::Type::MAT4, Precision::HIGH)
|
||||
.add("worldFromModelNormalMatrix", 1, UniformInterfaceBlock::Type::MAT3, Precision::HIGH)
|
||||
.add("morphTargetCount", 1, UniformInterfaceBlock::Type::UINT)
|
||||
.add("flags", 1, UniformInterfaceBlock::Type::UINT)
|
||||
.add("channels", 1, UniformInterfaceBlock::Type::UINT)
|
||||
.add("flagsChannels", 1, UniformInterfaceBlock::Type::UINT)
|
||||
.add("objectId", 1, UniformInterfaceBlock::Type::UINT)
|
||||
.add("userData", 1, UniformInterfaceBlock::Type::FLOAT)
|
||||
.add("reserved", 8, UniformInterfaceBlock::Type::FLOAT4)
|
||||
.build();
|
||||
return uib;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,25 @@ public:
|
||||
*/
|
||||
void updateBoneMatrices();
|
||||
|
||||
/**
|
||||
* Applies a blended transform to the union of nodes affected by two animations.
|
||||
* Used for cross-fading from a previous skinning-based animation or rigid body animation.
|
||||
*
|
||||
* First, this stashes the current transform hierarchy into a transient memory buffer.
|
||||
*
|
||||
* Next, this applies previousAnimIndex / previousAnimTime to the actual asset by internally
|
||||
* calling applyAnimation().
|
||||
*
|
||||
* Finally, the stashed local transforms are lerped (via the scale / translation / rotation
|
||||
* components) with their live counterparts, and the results are pushed to the asset.
|
||||
*
|
||||
* To achieve a cross fade effect with skinned models, clients will typically call animator
|
||||
* methods in this order: (1) applyAnimation (2) applyCrossFade (3) updateBoneMatrices. The
|
||||
* animation that clients pass to applyAnimation is the "current" animation corresponding to
|
||||
* alpha=1, while the "previous" animation passed to applyCrossFade corresponds to alpha=0.
|
||||
*/
|
||||
void applyCrossFade(size_t previousAnimIndex, float previousAnimTime, float alpha);
|
||||
|
||||
/**
|
||||
* Pass the identity matrix into all bone nodes, useful for returning to the T pose.
|
||||
*
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace gltfio {
|
||||
|
||||
using TimeValues = map<float, size_t>;
|
||||
using SourceValues = vector<float>;
|
||||
using BoneVector = vector<filament::math::mat4f>;
|
||||
using BoneVector = vector<mat4f>;
|
||||
|
||||
struct Sampler {
|
||||
TimeValues times;
|
||||
@@ -75,8 +75,11 @@ struct AnimatorImpl {
|
||||
RenderableManager* renderableManager;
|
||||
TransformManager* transformManager;
|
||||
vector<float> weights;
|
||||
FixedCapacityVector<mat4f> crossFade;
|
||||
void addChannels(const NodeMap& nodeMap, const cgltf_animation& srcAnim, Animation& dst);
|
||||
void applyAnimation(const Channel& channel, float t, size_t prevIndex, size_t nextIndex);
|
||||
void stashCrossFade();
|
||||
void applyCrossFade(float alpha);
|
||||
};
|
||||
|
||||
static void createSampler(const cgltf_animation_sampler& src, Sampler& dst) {
|
||||
@@ -221,6 +224,12 @@ Animator::Animator(FFilamentAsset* asset, FFilamentInstance* instance) {
|
||||
}
|
||||
}
|
||||
|
||||
void Animator::applyCrossFade(size_t previousAnimIndex, float previousAnimTime, float alpha) {
|
||||
mImpl->stashCrossFade();
|
||||
applyAnimation(previousAnimIndex, previousAnimTime);
|
||||
mImpl->applyCrossFade(alpha);
|
||||
}
|
||||
|
||||
void Animator::addInstance(FFilamentInstance* instance) {
|
||||
const cgltf_data* srcAsset = mImpl->asset->mSourceAsset->hierarchy;
|
||||
const cgltf_animation* srcAnims = srcAsset->animations;
|
||||
@@ -367,6 +376,58 @@ const char* Animator::getAnimationName(size_t animationIndex) const {
|
||||
return mImpl->animations[animationIndex].name.c_str();
|
||||
}
|
||||
|
||||
void AnimatorImpl::stashCrossFade() {
|
||||
using Instance = TransformManager::Instance;
|
||||
auto& tm = *this->transformManager;
|
||||
auto& stash = this->crossFade;
|
||||
|
||||
// Count the total number of transformable nodes to preallocate the stash memory.
|
||||
// We considered caching this count, but the cache would need to be invalidated when entities
|
||||
// are added into the hierarchy.
|
||||
auto recursiveCount = [&tm](Instance node, size_t count, auto& fn) -> size_t {
|
||||
++count;
|
||||
for (auto iter = tm.getChildrenBegin(node); iter != tm.getChildrenEnd(node); ++iter) {
|
||||
count = fn(*iter, count, fn);
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
auto recursiveStash = [&tm, &stash](Instance node, size_t index, auto& fn) -> size_t {
|
||||
stash[index++] = tm.getTransform(node);
|
||||
for (auto iter = tm.getChildrenBegin(node); iter != tm.getChildrenEnd(node); ++iter) {
|
||||
index = fn(*iter, index, fn);
|
||||
}
|
||||
return index;
|
||||
};
|
||||
|
||||
const Instance root = tm.getInstance(asset->mRoot);
|
||||
const size_t count = recursiveCount(root, 0, recursiveCount);
|
||||
crossFade.reserve(count);
|
||||
crossFade.resize(count);
|
||||
recursiveStash(root, 0, recursiveStash);
|
||||
}
|
||||
|
||||
void AnimatorImpl::applyCrossFade(float alpha) {
|
||||
using Instance = TransformManager::Instance;
|
||||
auto& tm = *this->transformManager;
|
||||
auto& stash = this->crossFade;
|
||||
auto recursiveFn = [&tm, &stash, alpha](Instance node, size_t index, auto& fn) -> size_t {
|
||||
float3 scale0, scale1;
|
||||
quatf rotation0, rotation1;
|
||||
float3 translation0, translation1;
|
||||
decomposeMatrix(stash[index++], &translation1, &rotation1, &scale1);
|
||||
decomposeMatrix(tm.getTransform(node), &translation0, &rotation0, &scale0);
|
||||
const float3 scale = mix(scale0, scale1, alpha);
|
||||
const quatf rotation = slerp(rotation0, rotation1, alpha);
|
||||
const float3 translation = mix(translation0, translation1, alpha);
|
||||
tm.setTransform(node, composeMatrix(translation, rotation, scale));
|
||||
for (auto iter = tm.getChildrenBegin(node); iter != tm.getChildrenEnd(node); ++iter) {
|
||||
index = fn(*iter, index, fn);
|
||||
}
|
||||
return index;
|
||||
};
|
||||
recursiveFn(tm.getInstance(asset->mRoot), 0, recursiveFn);
|
||||
}
|
||||
|
||||
void AnimatorImpl::addChannels(const NodeMap& nodeMap, const cgltf_animation& srcAnim,
|
||||
Animation& dst) {
|
||||
|
||||
@@ -342,6 +342,11 @@ bool ResourceLoader::loadResources(FFilamentAsset* asset, bool async) {
|
||||
SYSTRACE_CONTEXT();
|
||||
SYSTRACE_ASYNC_END("addResourceData", 1);
|
||||
|
||||
// Clear our texture caches. Previous calls to loadResources may have populated these, but the
|
||||
// Texture objects could have since been destroyed.
|
||||
pImpl->mBufferTextureCache.clear();
|
||||
pImpl->mFilepathTextureCache.clear();
|
||||
|
||||
if (asset->mResourcesLoaded) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ add_library(${TARGET} STATIC ${PUBLIC_HDRS} ${SRCS})
|
||||
|
||||
target_include_directories(${TARGET} PUBLIC ${PUBLIC_HDR_DIR})
|
||||
|
||||
target_link_libraries(${TARGET} PUBLIC image math png tinyexr utils z stb basis_encoder)
|
||||
target_link_libraries(${TARGET} PUBLIC image math png tinyexr utils z basis_encoder)
|
||||
if (WIN32)
|
||||
target_link_libraries(${TARGET} PRIVATE wsock32)
|
||||
endif()
|
||||
|
||||
@@ -509,7 +509,7 @@ private:
|
||||
mSize = needed;
|
||||
}
|
||||
|
||||
// this calculate the offset adjusted for all data alignment of a given array
|
||||
// this calculates the offset adjusted for all data alignment of a given array
|
||||
static inline size_t getOffset(size_t index, size_t capacity) noexcept {
|
||||
auto offsets = getOffsets(capacity);
|
||||
return offsets[index];
|
||||
|
||||
@@ -196,7 +196,7 @@ struct LightSettings {
|
||||
LightManager::ShadowOptions shadowOptions;
|
||||
SoftShadowOptions softShadowOptions;
|
||||
float sunlightIntensity = 100000.0f;
|
||||
math::float3 sunlightDirection = {0.6, -1.0, -0.8};;
|
||||
math::float3 sunlightDirection = {0.6, -1.0, -0.8};
|
||||
math::float3 sunlightColor = filament::Color::toLinear<filament::ACCURATE>({ 0.98, 0.92, 0.89});
|
||||
float iblIntensity = 30000.0f;
|
||||
float iblRotation = 0.0f;
|
||||
|
||||
@@ -255,7 +255,6 @@ private:
|
||||
// Properties that can be changed from the UI.
|
||||
int mCurrentAnimation = 1; // It is a 1-based index and 0 means not playing animation
|
||||
int mCurrentVariant = 0;
|
||||
bool mResetAnimation = true;
|
||||
bool mEnableWireframe = false;
|
||||
int mVsmMsaaSamplesLog2 = 1;
|
||||
Settings mSettings;
|
||||
@@ -269,6 +268,13 @@ private:
|
||||
// 0 is the default "free camera". Additional cameras come from the gltf file (1-based index).
|
||||
int mCurrentCamera = 0;
|
||||
|
||||
// Cross fade animation parameters.
|
||||
float mCrossFadeDuration = 0.5f; // number of seconds to transition between animations
|
||||
int mPreviousAnimation = 0; // one-based index of the previous animation
|
||||
double mCurrentStartTime = 0.0f; // start time of most recent cross-fade (seconds)
|
||||
double mPreviousStartTime = 0.0f; // start time of previous cross-fade (seconds)
|
||||
bool mResetAnimation = true; // set when building ImGui widgets, honored in applyAnimation
|
||||
|
||||
// Color grading UI state.
|
||||
float mToneMapPlot[1024];
|
||||
float mRangePlot[1024 * 3];
|
||||
|
||||
@@ -500,17 +500,20 @@ void ViewerGui::sceneSelectionUI() {
|
||||
|
||||
void ViewerGui::applyAnimation(double currentTime) {
|
||||
assert_invariant(!isRemoteMode());
|
||||
static double startTime = 0;
|
||||
const size_t numAnimations = mAnimator->getAnimationCount();
|
||||
if (mResetAnimation) {
|
||||
startTime = currentTime;
|
||||
for (size_t i = 0; i < numAnimations; i++) {
|
||||
mAnimator->applyAnimation(i, 0);
|
||||
}
|
||||
mPreviousStartTime = mCurrentStartTime;
|
||||
mCurrentStartTime = currentTime;
|
||||
mResetAnimation = false;
|
||||
}
|
||||
const double elapsedSeconds = currentTime - mCurrentStartTime;
|
||||
if (numAnimations > 0 && mCurrentAnimation > 0) {
|
||||
mAnimator->applyAnimation(mCurrentAnimation - 1, currentTime - startTime);
|
||||
mAnimator->applyAnimation(mCurrentAnimation - 1, elapsedSeconds);
|
||||
if (elapsedSeconds < mCrossFadeDuration && mPreviousAnimation > 0) {
|
||||
const double previousSeconds = currentTime - mPreviousStartTime;
|
||||
const float lerpFactor = elapsedSeconds / mCrossFadeDuration;
|
||||
mAnimator->applyCrossFade(mPreviousAnimation - 1, previousSeconds, lerpFactor);
|
||||
}
|
||||
}
|
||||
if (mShowingRestPose) {
|
||||
mAnimator->resetBoneMatrices();
|
||||
@@ -1031,6 +1034,8 @@ void ViewerGui::updateUserInterface() {
|
||||
ImGui::Indent();
|
||||
int selectedAnimation = mCurrentAnimation;
|
||||
ImGui::RadioButton("Disable", &selectedAnimation, 0);
|
||||
ImGui::SliderFloat("Cross fade", &mCrossFadeDuration, 0.0f, 2.0f,
|
||||
"%4.2f seconds", ImGuiSliderFlags_AlwaysClamp);
|
||||
for (size_t i = 0, count = mAnimator->getAnimationCount(); i < count; ++i) {
|
||||
std::string label = mAnimator->getAnimationName(i);
|
||||
if (label.empty()) {
|
||||
@@ -1039,6 +1044,7 @@ void ViewerGui::updateUserInterface() {
|
||||
ImGui::RadioButton(label.c_str(), &selectedAnimation, i + 1);
|
||||
}
|
||||
if (selectedAnimation != mCurrentAnimation) {
|
||||
mPreviousAnimation = mCurrentAnimation;
|
||||
mCurrentAnimation = selectedAnimation;
|
||||
mResetAnimation = true;
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ fragment {
|
||||
material.baseColor = bg;
|
||||
} else {
|
||||
uv.t = 1.0 - uv.t;
|
||||
vec4 color = texture(materialParams_image, uv.st);
|
||||
vec4 color = max(texture(materialParams_image, uv.st), 0.0);
|
||||
color.rgb *= color.a;
|
||||
// Manual, pre-multiplied srcOver with opaque destination optimization
|
||||
material.baseColor.rgb = color.rgb + bg.rgb * (1.0 - color.a);
|
||||
|
||||
@@ -69,9 +69,9 @@ highp vec2 uvToRenderTargetUV(highp vec2 uv) {
|
||||
|
||||
// TODO: below shouldn't be accessible from post-process materials
|
||||
|
||||
#define FILAMENT_OBJECT_SKINNING_ENABLED_BIT 0x1u
|
||||
#define FILAMENT_OBJECT_MORPHING_ENABLED_BIT 0x2u
|
||||
#define FILAMENT_OBJECT_CONTACT_SHADOWS_BIT 0x4u
|
||||
#define FILAMENT_OBJECT_SKINNING_ENABLED_BIT 0x100u
|
||||
#define FILAMENT_OBJECT_MORPHING_ENABLED_BIT 0x200u
|
||||
#define FILAMENT_OBJECT_CONTACT_SHADOWS_BIT 0x400u
|
||||
|
||||
/** @public-api */
|
||||
highp vec4 getResolution() {
|
||||
|
||||
@@ -96,6 +96,7 @@ void morphPosition(inout vec4 p) {
|
||||
}
|
||||
|
||||
void morphNormal(inout vec3 n) {
|
||||
vec3 baseNormal = n;
|
||||
ivec3 texcoord = ivec3(getVertexIndex() % MAX_MORPH_TARGET_BUFFER_WIDTH, getVertexIndex() / MAX_MORPH_TARGET_BUFFER_WIDTH, 0);
|
||||
for (uint i = 0u; i < objectUniforms.morphTargetCount; ++i) {
|
||||
float w = morphingUniforms.weights[i][0];
|
||||
@@ -104,7 +105,7 @@ void morphNormal(inout vec3 n) {
|
||||
ivec4 tangent = texelFetch(morphTargetBuffer_tangents, texcoord, 0);
|
||||
vec3 normal;
|
||||
toTangentFrame(float4(tangent) * (1.0 / 32767.0), normal);
|
||||
n += w * normal;
|
||||
n += w * (normal - baseNormal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,7 +117,7 @@ vec4 getPosition() {
|
||||
|
||||
#if defined(VARIANT_HAS_SKINNING_OR_MORPHING)
|
||||
|
||||
if ((objectUniforms.flags & FILAMENT_OBJECT_MORPHING_ENABLED_BIT) != 0u) {
|
||||
if ((objectUniforms.flagsChannels & FILAMENT_OBJECT_MORPHING_ENABLED_BIT) != 0u) {
|
||||
#if defined(LEGACY_MORPHING)
|
||||
pos += morphingUniforms.weights[0] * mesh_custom0;
|
||||
pos += morphingUniforms.weights[1] * mesh_custom1;
|
||||
@@ -127,7 +128,7 @@ vec4 getPosition() {
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((objectUniforms.flags & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) {
|
||||
if ((objectUniforms.flagsChannels & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) {
|
||||
skinPosition(pos.xyz, mesh_bone_indices, mesh_bone_weights);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ void evaluateDirectionalLight(const MaterialInputs material,
|
||||
|
||||
Light light = getDirectionalLight();
|
||||
|
||||
uint channels = objectUniforms.channels & 0xFFu;
|
||||
uint channels = objectUniforms.flagsChannels & 0xFFu;
|
||||
if ((light.channels & channels) == 0u) {
|
||||
return;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ void evaluateDirectionalLight(const MaterialInputs material,
|
||||
visibility = shadow(true, light_shadowMap, layer, 0u, cascade);
|
||||
}
|
||||
if ((frameUniforms.directionalShadows & 0x2u) != 0u && visibility > 0.0) {
|
||||
if ((objectUniforms.flags & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {
|
||||
if ((objectUniforms.flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {
|
||||
ssContactShadowOcclusion = screenSpaceContactShadow(light.l);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ void evaluatePunctualLights(const MaterialInputs material,
|
||||
|
||||
uint index = froxel.recordOffset;
|
||||
uint end = index + froxel.count;
|
||||
uint channels = objectUniforms.channels & 0xFFu;
|
||||
uint channels = objectUniforms.flagsChannels & 0xFFu;
|
||||
|
||||
// Iterate point lights
|
||||
for ( ; index < end; index++) {
|
||||
@@ -217,7 +217,7 @@ void evaluatePunctualLights(const MaterialInputs material,
|
||||
visibility = shadow(false, light_shadowMap, light.shadowLayer, light.shadowIndex, 0u);
|
||||
}
|
||||
if (light.contactShadows && visibility > 0.0) {
|
||||
if ((objectUniforms.flags & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {
|
||||
if ((objectUniforms.flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {
|
||||
visibility *= 1.0 - screenSpaceContactShadow(light.l);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,24 +35,25 @@ void main() {
|
||||
toTangentFrame(mesh_tangents, material.worldNormal, vertex_worldTangent.xyz);
|
||||
|
||||
#if defined(VARIANT_HAS_SKINNING_OR_MORPHING)
|
||||
if ((objectUniforms.flags & FILAMENT_OBJECT_MORPHING_ENABLED_BIT) != 0u) {
|
||||
if ((objectUniforms.flagsChannels & FILAMENT_OBJECT_MORPHING_ENABLED_BIT) != 0u) {
|
||||
#if defined(LEGACY_MORPHING)
|
||||
vec3 normal0, normal1, normal2, normal3;
|
||||
toTangentFrame(mesh_custom4, normal0);
|
||||
toTangentFrame(mesh_custom5, normal1);
|
||||
toTangentFrame(mesh_custom6, normal2);
|
||||
toTangentFrame(mesh_custom7, normal3);
|
||||
material.worldNormal += morphingUniforms.weights[0].xyz * normal0;
|
||||
material.worldNormal += morphingUniforms.weights[1].xyz * normal1;
|
||||
material.worldNormal += morphingUniforms.weights[2].xyz * normal2;
|
||||
material.worldNormal += morphingUniforms.weights[3].xyz * normal3;
|
||||
vec3 baseNormal = material.worldNormal;
|
||||
material.worldNormal += morphingUniforms.weights[0].xyz * (normal0 - baseNormal);
|
||||
material.worldNormal += morphingUniforms.weights[1].xyz * (normal1 - baseNormal);
|
||||
material.worldNormal += morphingUniforms.weights[2].xyz * (normal2 - baseNormal);
|
||||
material.worldNormal += morphingUniforms.weights[3].xyz * (normal3 - baseNormal);
|
||||
#else
|
||||
morphNormal(material.worldNormal);
|
||||
material.worldNormal = normalize(material.worldNormal);
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((objectUniforms.flags & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) {
|
||||
if ((objectUniforms.flagsChannels & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) {
|
||||
skinNormal(material.worldNormal, mesh_bone_indices, mesh_bone_weights);
|
||||
skinNormal(vertex_worldTangent.xyz, mesh_bone_indices, mesh_bone_weights);
|
||||
}
|
||||
@@ -70,9 +71,27 @@ void main() {
|
||||
toTangentFrame(mesh_tangents, material.worldNormal);
|
||||
|
||||
#if defined(VARIANT_HAS_SKINNING_OR_MORPHING)
|
||||
if ((objectUniforms.flags & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) {
|
||||
skinNormal(material.worldNormal, mesh_bone_indices, mesh_bone_weights);
|
||||
}
|
||||
if ((objectUniforms.flagsChannels & FILAMENT_OBJECT_MORPHING_ENABLED_BIT) != 0u) {
|
||||
#if defined(LEGACY_MORPHING)
|
||||
vec3 normal0, normal1, normal2, normal3;
|
||||
toTangentFrame(mesh_custom4, normal0);
|
||||
toTangentFrame(mesh_custom5, normal1);
|
||||
toTangentFrame(mesh_custom6, normal2);
|
||||
toTangentFrame(mesh_custom7, normal3);
|
||||
vec3 baseNormal = material.worldNormal;
|
||||
material.worldNormal += morphingUniforms.weights[0].xyz * (normal0 - baseNormal);
|
||||
material.worldNormal += morphingUniforms.weights[1].xyz * (normal1 - baseNormal);
|
||||
material.worldNormal += morphingUniforms.weights[2].xyz * (normal2 - baseNormal);
|
||||
material.worldNormal += morphingUniforms.weights[3].xyz * (normal3 - baseNormal);
|
||||
#else
|
||||
morphNormal(material.worldNormal);
|
||||
material.worldNormal = normalize(material.worldNormal);
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((objectUniforms.flagsChannels & FILAMENT_OBJECT_SKINNING_ENABLED_BIT) != 0u) {
|
||||
skinNormal(material.worldNormal, mesh_bone_indices, mesh_bone_weights);
|
||||
}
|
||||
#endif
|
||||
|
||||
material.worldNormal = objectUniforms.worldFromModelNormalMatrix * material.worldNormal;
|
||||
|
||||
@@ -54,7 +54,7 @@ vec4 evaluateMaterial(const MaterialInputs material) {
|
||||
visibility = shadow(true, light_shadowMap, layer, 0u, cascade);
|
||||
}
|
||||
if ((frameUniforms.directionalShadows & 0x2u) != 0u && visibility > 0.0) {
|
||||
if ((objectUniforms.flags & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {
|
||||
if ((objectUniforms.flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {
|
||||
visibility *= (1.0 - screenSpaceContactShadow(frameUniforms.lightDirection));
|
||||
}
|
||||
}
|
||||
|
||||
13
third_party/basisu/tnt/CMakeLists.txt
vendored
13
third_party/basisu/tnt/CMakeLists.txt
vendored
@@ -51,20 +51,23 @@ else()
|
||||
set (BASIS_CONFIG ${BASIS_CONFIG} BASISD_SUPPORT_DXT5A=0 BASISD_SUPPORT_DXT1=0)
|
||||
endif()
|
||||
|
||||
add_executable(basisu ${ENCODER_SRC} ${TRANSCODER_SRC} ../basisu_tool.cpp)
|
||||
add_library(basis_encoder ${ENCODER_SRC} ${TRANSCODER_SRC})
|
||||
add_library(basis_transcoder ${TRANSCODER_SRC})
|
||||
|
||||
target_include_directories(basis_encoder PUBLIC ../encoder)
|
||||
target_include_directories(basis_transcoder PUBLIC ../transcoder)
|
||||
|
||||
target_compile_definitions(basisu PRIVATE ${BASIS_CONFIG})
|
||||
target_compile_definitions(basis_encoder PRIVATE ${BASIS_CONFIG})
|
||||
target_compile_definitions(basis_transcoder PRIVATE ${BASIS_CONFIG})
|
||||
|
||||
if (NOT MSVC AND NOT ANDROID)
|
||||
target_link_libraries(basisu m pthread)
|
||||
if (IS_HOST_PLATFORM)
|
||||
add_executable(basisu ${ENCODER_SRC} ${TRANSCODER_SRC} ../basisu_tool.cpp)
|
||||
target_compile_definitions(basisu PRIVATE ${BASIS_CONFIG})
|
||||
install(TARGETS basisu DESTINATION bin)
|
||||
|
||||
if (NOT MSVC AND NOT ANDROID)
|
||||
target_link_libraries(basisu m pthread)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
install(TARGETS basisu DESTINATION bin)
|
||||
install(TARGETS basis_transcoder ARCHIVE DESTINATION lib/${DIST_DIR})
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
|
||||
- [Description](#description)
|
||||
- [Instructions](#instructions)
|
||||
- [Input Limitations](#input-limitations)
|
||||
- [Emitter Flags](#emitter-flags)
|
||||
- [Input Files](#input-files)
|
||||
- [Source Files](#source-files)
|
||||
- [Output Files](#output-files)
|
||||
- [Input Format](#input-format)
|
||||
|
||||
### Description
|
||||
## Description
|
||||
|
||||
This Go program consumes C++ header file(s) and generates Java bindings, JavaScript bindings, and
|
||||
C++ code that performs JSON serialization.
|
||||
|
||||
### Instructions
|
||||
## Instructions
|
||||
|
||||
To install the Go compiler on macOS, just do:
|
||||
|
||||
@@ -22,19 +22,7 @@ To build and invoke the code generator, do:
|
||||
|
||||
cd tools/beamsplitter ; go run .
|
||||
|
||||
### Input Limitations
|
||||
|
||||
The source files must have very simple C++ syntax. Some of the limitations include:
|
||||
|
||||
- Only `enum class` is supported; no old-style enums.
|
||||
- Opening braces for `enum` and `struct` must live at the end of a codeline.
|
||||
- Enum values must be sequential and cannot have custom values.
|
||||
- There are no namespaces other than the top-level namespace.
|
||||
- Every struct field must supply a default value on a single codeline using the = operator.
|
||||
- If the default value of a field is a vector, it must be in the form: `{ x, y, z }`.
|
||||
- There must be no string literals that contain keywords.
|
||||
|
||||
### Emitter Flags
|
||||
## Emitter Flags
|
||||
|
||||
Special directives in the form `%codegen_foo%` are called *emitter flags*. They are typically
|
||||
embedded in a comment associated with a particular struct field.
|
||||
@@ -43,14 +31,14 @@ flag | description
|
||||
--------------------------- | ----
|
||||
**codegen_skip_json** | Field is skipped when generating JSON serialization code.
|
||||
**codegen_skip_javascript** | Field is skipped when generating JavaScript and TypeScript bindings.
|
||||
**codegen_java_flatten** | Field is replaced with constituent sub-fields. (TBD)
|
||||
**codegen_java_flatten** | Field is replaced with constituent sub-fields.
|
||||
**codegen_java_float** | Field will be forced to have a `float` representation in Java.
|
||||
|
||||
### Input Files
|
||||
## Source Files
|
||||
|
||||
- `filament/include/filament/Options.h`
|
||||
|
||||
### Output Files
|
||||
## Output Files
|
||||
|
||||
The following files are created:
|
||||
|
||||
@@ -59,9 +47,98 @@ flag | description
|
||||
- `web/filament-js/jsbindings_generated.cpp`
|
||||
- `web/filament-js/jsenums_generated.cpp`
|
||||
- `web/filament-js/extensions_generated.js`
|
||||
- `android/filament-android/src/main/cpp/View_generated.cpp` (TBD)
|
||||
|
||||
Additionally, in-place edits are made to the following files:
|
||||
|
||||
- `web/filament-js/filament.d.ts`
|
||||
- `android/filament-android/src/main/java/.../View.java` (TBD)
|
||||
- `android/filament-android/src/main/java/.../View.java`
|
||||
|
||||
## Input Format
|
||||
|
||||
There are many ways in which the source file format is more restrictive than the full C++
|
||||
language, but here are some of the highlights:
|
||||
|
||||
- All enums must be class enums.
|
||||
- External headers pulled in with `#include` files are ignored.
|
||||
- Expressions in the RHS of default value assignments are not parsed, they are just exposed by
|
||||
the lexer as blobs.
|
||||
- Struct fields, class fields, and method arguments must have fairly simple types. e.g. they cannot
|
||||
have parentheses. If a type is C style callback, then it should be specified with an alias.
|
||||
- Multiline strings and macro definitions are not allowed.
|
||||
- Enum values must be sequential and cannot have custom values.
|
||||
|
||||
The following formal grammar describes the above limitations in greater detail, but with some
|
||||
caveats:
|
||||
|
||||
- All C preprocessor directives are discarded during lexical analysis; they do not exist in the AST.
|
||||
- Whitespace is similarly discarded, so there is no "space" concept in the AST.
|
||||
- Macro invocations are also removed by the lexer if they are known Filament-specific macros (e.g.
|
||||
`UTILS_PUBLIC` and `UTILS_DEPRECATED`).
|
||||
- Comments are removed by the lexer and are generally not part of the resulting AST. However
|
||||
the lexer proffers a mapping from line numbers to comments to allow for docstring extraction.
|
||||
- Emitter flags in the form `%codegen_foo%` are detected in a post-processing phase and removed from
|
||||
all comments.
|
||||
|
||||
### Grammar
|
||||
|
||||
```eBNF
|
||||
root = namespace ;
|
||||
namespace = "namespace" , [ ident ] , "{" , { block } , "}" ;
|
||||
block = class | struct | enum | namespace | using | forward_declaration;
|
||||
forward_declaration = ("class" | "struct" ) , ident , ";" ;
|
||||
template = "template" , "TemplateArgs" ;
|
||||
class = [template] , "class" , ident , [ ":" , [ "public" ] , "SimpleType" ]
|
||||
, "{" , struct_body , "}" , ";" ;
|
||||
struct = [template] , "struct" , ident , "{" , struct_body , "}" , ";" ;
|
||||
enum = "enum" , "class" , ident , [ ":" , type ]
|
||||
, "{" , , ident , { "," , ident } , [ "," ] , "}" , ";" ;
|
||||
using = "using" , ident , "=", type , ";" ;
|
||||
struct_body = { access_specifier | field | method | block } ;
|
||||
access_specifier = ("public" | "private" | "protected" ) , ":" ;
|
||||
method = [template] , { "constexpr" , "friend" } ,
|
||||
, type , ident , "MethodArgs" , specifiers , ( ";" | "MethodBody" ) ;
|
||||
specifiers = { "const" | "noexcept" } ;
|
||||
field = type , ident , [ array ] , [ "=" , "DefaultValue" ] ";" ;
|
||||
array = "[" , "ArrayLength", "]" ;
|
||||
type = "SimpleType" ;
|
||||
ident = "Identifier" ;
|
||||
```
|
||||
The above grammar uses the following notation:
|
||||
- `" ... "` denotes a terminal
|
||||
- `{ ... }` denotes zero or more repetition
|
||||
- `[ ... ]` denotes an optional quantity
|
||||
- `( ... )` is used for grouping
|
||||
- `a | b` denotes a choice
|
||||
- `a , b` denotes concatenation
|
||||
- `;` terminates a production
|
||||
|
||||
Terminal name | Description
|
||||
--------------------------- | ----
|
||||
SimpleType (*) | examples: `Texture* const`, `uint8_t`, `BlendMode`
|
||||
MethodBody | unparsed implementation of a function or method, including outer `{}`
|
||||
MethodArgs | similar to above; an unparsed blob, but delimited with `()`
|
||||
TemplateArgs | similar to above; an unparsed blob, but delimited with `<>`
|
||||
DefaultValue (**) | an unparsed expression with certain restrictions
|
||||
Identifier | `[A-Za-z_][A-Za-z0-9_]*`
|
||||
ArrayLength | `[1-9][0-9]*`
|
||||
|
||||
(*) `SimpleType` should not contain parentheses or commas, so C callbacks are not allowed unless
|
||||
you alias them first.
|
||||
|
||||
(**) If `DefaultValue` is a vector, it must be in the form: `{ x, y, z }`.
|
||||
|
||||
## References
|
||||
|
||||
Initially inspired by the following Rob Pike talk.
|
||||
- https://www.youtube.com/watch?v=HxaD_trXwRE
|
||||
|
||||
Beamsplitter does not use the state machine described in the above prezo, but it does use a channel
|
||||
for separating the parser from the lexer. The beamsplitter lexer is actually a recursive descent
|
||||
parser with simple lookahead functionality. This makes it easy for the "real" parser to create a
|
||||
coarse-grained AST.
|
||||
|
||||
The companion to the above talk is Go's template lexer, which can be studied here:
|
||||
- https://cs.opensource.google/go/go/+/master:src/text/template/parse/lex.go
|
||||
|
||||
Wikipedia has a good example of recursive descent:
|
||||
- https://en.wikipedia.org/wiki/Recursive_descent_parser
|
||||
|
||||
332
tools/beamsplitter/database/database.go
Normal file
332
tools/beamsplitter/database/database.go
Normal file
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package database
|
||||
|
||||
import (
|
||||
"beamsplitter/parse"
|
||||
"bufio"
|
||||
"io"
|
||||
"log"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Create(root *parse.RootNode, contents string) []TypeDefinition {
|
||||
context := gatherContext{}
|
||||
context.compileRegexps()
|
||||
|
||||
// Line numbers are 1-based in beamsplitter, so we add an extra newline at the top.
|
||||
context.codelines = strings.Split("\n"+contents, "\n")
|
||||
context.commentBlocks = gatherCommentBlocks(strings.NewReader(contents))
|
||||
|
||||
// Recurse into the AST using pre-order traversal, gathering type information along the way.
|
||||
context.gatherTypeDefinitions(root.Child, "", nil)
|
||||
|
||||
context.addTypeQualifiers()
|
||||
|
||||
return context.definitions
|
||||
}
|
||||
|
||||
type TypeDefinition interface {
|
||||
BaseName() string
|
||||
QualifiedName() string
|
||||
Parent() TypeDefinition
|
||||
}
|
||||
|
||||
type StructField struct {
|
||||
TypeString string
|
||||
Name string
|
||||
DefaultValue string
|
||||
Description string
|
||||
EmitterFlags map[string]struct{}
|
||||
CustomType TypeDefinition
|
||||
}
|
||||
|
||||
type StructDefinition struct {
|
||||
name string
|
||||
qualifier string
|
||||
Fields []StructField
|
||||
Description string
|
||||
parent TypeDefinition
|
||||
}
|
||||
|
||||
func (defn StructDefinition) BaseName() string { return defn.name }
|
||||
func (defn StructDefinition) QualifiedName() string { return defn.qualifier + defn.name }
|
||||
func (defn StructDefinition) Parent() TypeDefinition { return defn.parent }
|
||||
|
||||
type EnumValue struct {
|
||||
Description string
|
||||
Name string
|
||||
}
|
||||
|
||||
type EnumDefinition struct {
|
||||
name string
|
||||
qualifier string
|
||||
Values []EnumValue
|
||||
Description string
|
||||
parent TypeDefinition
|
||||
}
|
||||
|
||||
func (defn EnumDefinition) BaseName() string { return defn.name }
|
||||
func (defn EnumDefinition) QualifiedName() string { return defn.qualifier + defn.name }
|
||||
func (defn EnumDefinition) Parent() TypeDefinition { return defn.parent }
|
||||
|
||||
type Documented interface{ GetDoc() string }
|
||||
|
||||
func (defn EnumDefinition) GetDoc() string { return defn.Description }
|
||||
func (defn StructDefinition) GetDoc() string { return defn.Description }
|
||||
func (field StructField) GetDoc() string { return field.Description }
|
||||
func (value EnumValue) GetDoc() string { return value.Description }
|
||||
|
||||
type generalScope struct{}
|
||||
|
||||
type scope interface {
|
||||
BaseName() string
|
||||
QualifiedName() string
|
||||
Parent() TypeDefinition
|
||||
}
|
||||
|
||||
func (defn generalScope) BaseName() string { return "" }
|
||||
func (defn generalScope) QualifiedName() string { return "" }
|
||||
func (defn generalScope) Parent() TypeDefinition { return nil }
|
||||
|
||||
type gatherContext struct {
|
||||
definitions []TypeDefinition
|
||||
stack []scope
|
||||
commentBlocks map[int]string
|
||||
codelines []string
|
||||
floatMatcher *regexp.Regexp
|
||||
vectorMatcher *regexp.Regexp
|
||||
fieldDocParser *regexp.Regexp
|
||||
emitterFlagFinder *regexp.Regexp
|
||||
}
|
||||
|
||||
// https://github.com/google/re2/wiki/Syntax
|
||||
func (context *gatherContext) compileRegexps() {
|
||||
context.floatMatcher = regexp.MustCompile(`(\-?[0-9]+\.[0-9]*)f?`)
|
||||
context.vectorMatcher = regexp.MustCompile(`\{(\s*\-?[0-9\.]+\s*(,\s*\-?[0-9\.]+\s*){1,})\}`)
|
||||
context.emitterFlagFinder = regexp.MustCompile(`\s*\%codegen_([a-zA-Z0-9_]+)\%\s*`)
|
||||
context.fieldDocParser = regexp.MustCompile(`(?://\s*\!\<\s*(.*))`)
|
||||
}
|
||||
|
||||
// Creates a mapping from line numbers to strings, where the strings are entire block comments
|
||||
// and the line numbers correspond to the last line of each block comment.
|
||||
func gatherCommentBlocks(sourceFile io.Reader) map[int]string {
|
||||
comments := make(map[int]string)
|
||||
scanner := bufio.NewScanner(sourceFile)
|
||||
var comment = ""
|
||||
var indention = 0
|
||||
for lineNumber := 1; scanner.Scan(); lineNumber++ {
|
||||
codeline := scanner.Text()
|
||||
if strings.Contains(codeline, `/**`) {
|
||||
indention = strings.Index(codeline, `/**`)
|
||||
if strings.Contains(codeline, `*/`) {
|
||||
comments[lineNumber] = codeline[indention:] + "\n"
|
||||
continue
|
||||
}
|
||||
comment = codeline[indention:] + "\n"
|
||||
continue
|
||||
}
|
||||
if comment != "" {
|
||||
if len(codeline) > indention {
|
||||
codeline = codeline[indention:]
|
||||
}
|
||||
comment += codeline + "\n"
|
||||
if strings.Contains(codeline, `*/`) {
|
||||
comments[lineNumber] = comment
|
||||
comment = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return comments
|
||||
}
|
||||
|
||||
// Annotates struct fields that have custom types (i.e. enums or structs).
|
||||
func (context gatherContext) addTypeQualifiers() {
|
||||
typeMap := make(map[string]TypeDefinition)
|
||||
for _, defn := range context.definitions {
|
||||
typeMap[defn.QualifiedName()] = defn
|
||||
}
|
||||
for _, defn := range context.definitions {
|
||||
structDefn, isStruct := defn.(*StructDefinition)
|
||||
if !isStruct {
|
||||
continue
|
||||
}
|
||||
for fieldIndex, field := range structDefn.Fields {
|
||||
// Extract the namespace prefix (if any) explicitly specified for this field type.
|
||||
var namespace string
|
||||
localTypeName := field.TypeString
|
||||
if index := strings.LastIndex(field.TypeString, "::"); index > -1 {
|
||||
namespace = field.TypeString[:index]
|
||||
localTypeName = field.TypeString[index+2:]
|
||||
}
|
||||
|
||||
// Prepend additional qualifiers to the type string by searching upward through
|
||||
// the current namespace hierarchy, and looking for a match.
|
||||
mutable := &structDefn.Fields[fieldIndex]
|
||||
for ancestor := defn; ; ancestor = ancestor.Parent() {
|
||||
var qualified string
|
||||
if namespace != "" && strings.HasSuffix(ancestor.QualifiedName(), namespace) {
|
||||
qualified = ancestor.QualifiedName() + "::" + localTypeName
|
||||
} else {
|
||||
qualified = ancestor.QualifiedName() + "::" + field.TypeString
|
||||
}
|
||||
if fieldType, found := typeMap[qualified]; found {
|
||||
mutable.TypeString = qualified
|
||||
mutable.CustomType = fieldType
|
||||
break
|
||||
}
|
||||
if ancestor.Parent() == nil {
|
||||
if fieldType, found := typeMap[field.TypeString]; found {
|
||||
mutable.CustomType = fieldType
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if mutable.CustomType == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Prepend additional qualifiers to the value string if it is a known enum.
|
||||
var fieldType TypeDefinition = structDefn.Fields[fieldIndex].CustomType
|
||||
enumDefn, isEnum := fieldType.(*EnumDefinition)
|
||||
if isEnum {
|
||||
selectedEnum := field.DefaultValue
|
||||
if index := strings.LastIndex(field.DefaultValue, "::"); index > -1 {
|
||||
selectedEnum = field.DefaultValue[index+2:]
|
||||
}
|
||||
mutable.DefaultValue = enumDefn.QualifiedName() + "::" + selectedEnum
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validates and transforms the RHS of an assignment.
|
||||
// For vectors, this converts curly braces into square brackets.
|
||||
func (context gatherContext) distillValue(cppvalue string, lineNumber int) string {
|
||||
cppvalue = strings.TrimSpace(cppvalue)
|
||||
|
||||
// Remove trailing "f" from floats, which isn't allowed in JavaScript.
|
||||
if context.floatMatcher.MatchString(cppvalue) {
|
||||
cppvalue = context.floatMatcher.ReplaceAllString(cppvalue, "$1")
|
||||
}
|
||||
|
||||
// There are many ways to declare vector values (multi-arg constructor, single-arg
|
||||
// constructor, curly braces with type, curly braces without type), so just poop out if
|
||||
// the syntax is anything other than "curly braces without type".
|
||||
if strings.Contains(cppvalue, "math::") || strings.Contains(cppvalue, "Color") {
|
||||
log.Fatalf("%d: vectors must have the form {x, y ...}", lineNumber)
|
||||
}
|
||||
|
||||
// Assume it's a vector if there's a curly brace.
|
||||
if strings.Contains(cppvalue, "{") {
|
||||
if context.vectorMatcher.MatchString(cppvalue) {
|
||||
cppvalue = context.vectorMatcher.ReplaceAllString(cppvalue, "[$1]")
|
||||
} else {
|
||||
log.Fatalf("%d: vectors must have the form {x, y ...}", lineNumber)
|
||||
}
|
||||
}
|
||||
return cppvalue
|
||||
}
|
||||
|
||||
func (context *gatherContext) getDescription(line int) string {
|
||||
desc := context.commentBlocks[line-1]
|
||||
if desc == "" {
|
||||
codeline := context.codelines[line]
|
||||
if matches := context.fieldDocParser.FindStringSubmatch(codeline); matches != nil {
|
||||
desc = matches[1]
|
||||
}
|
||||
}
|
||||
return context.emitterFlagFinder.ReplaceAllString(desc, "")
|
||||
}
|
||||
|
||||
func (context *gatherContext) getEmitterFlags(line int) map[string]struct{} {
|
||||
codeline := context.codelines[line]
|
||||
if matches := context.emitterFlagFinder.FindAllStringSubmatch(codeline, -1); matches != nil {
|
||||
result := make(map[string]struct{}, len(matches))
|
||||
for _, flag := range matches {
|
||||
result[flag[1]] = struct{}{}
|
||||
}
|
||||
return result
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Search for all enums and structs and gather them into a flat list of type definitions.
|
||||
func (context *gatherContext) gatherTypeDefinitions(node parse.Node, prefix string, parent TypeDefinition) {
|
||||
switch concrete := node.(type) {
|
||||
case *parse.NamespaceNode:
|
||||
// HACK: filament namespace is a special case, remove it from the type database.
|
||||
if concrete.Name != "filament" {
|
||||
prefix = prefix + concrete.Name + "::"
|
||||
}
|
||||
for _, child := range concrete.Children {
|
||||
context.gatherTypeDefinitions(child, prefix, parent)
|
||||
}
|
||||
case *parse.EnumNode:
|
||||
defn := &EnumDefinition{
|
||||
name: concrete.Name,
|
||||
qualifier: prefix,
|
||||
Values: make([]EnumValue, len(concrete.Values)),
|
||||
Description: context.getDescription(int(concrete.Line)),
|
||||
parent: parent,
|
||||
}
|
||||
for i, val := range concrete.Values {
|
||||
defn.Values[i] = EnumValue{
|
||||
Name: val,
|
||||
Description: context.getDescription(int(concrete.ValueLines[i])),
|
||||
}
|
||||
}
|
||||
context.definitions = append(context.definitions, defn)
|
||||
case *parse.StructNode:
|
||||
defn := &StructDefinition{
|
||||
name: concrete.Name,
|
||||
qualifier: prefix,
|
||||
Fields: make([]StructField, 0),
|
||||
Description: context.getDescription(int(concrete.Line)),
|
||||
parent: parent,
|
||||
}
|
||||
prefix = prefix + concrete.Name + "::"
|
||||
for _, child := range concrete.Members {
|
||||
switch member := child.(type) {
|
||||
case *parse.StructNode, *parse.ClassNode, *parse.EnumNode, *parse.NamespaceNode:
|
||||
context.gatherTypeDefinitions(child, prefix, defn)
|
||||
case *parse.FieldNode:
|
||||
defn.Fields = append(defn.Fields, StructField{
|
||||
TypeString: member.Type,
|
||||
Name: member.Name,
|
||||
DefaultValue: context.distillValue(member.Rhs, int(member.Line)),
|
||||
Description: context.getDescription(int(member.Line)),
|
||||
EmitterFlags: context.getEmitterFlags(int(member.Line)),
|
||||
})
|
||||
}
|
||||
}
|
||||
context.definitions = append(context.definitions, defn)
|
||||
case *parse.ClassNode:
|
||||
prefix = prefix + concrete.Name + "::"
|
||||
for _, child := range concrete.Members {
|
||||
switch child.(type) {
|
||||
case *parse.StructNode, *parse.ClassNode, *parse.EnumNode, *parse.NamespaceNode:
|
||||
context.gatherTypeDefinitions(child, prefix, parent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
285
tools/beamsplitter/emitters/java.go
Normal file
285
tools/beamsplitter/emitters/java.go
Normal file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package emitters
|
||||
|
||||
import (
|
||||
db "beamsplitter/database"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func EditJava(definitions []db.TypeDefinition, classname string, folder string) {
|
||||
path := filepath.Join(folder, classname+".java")
|
||||
var codelines []string
|
||||
{
|
||||
sourceFile, err := os.Open(path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer sourceFile.Close()
|
||||
lineScanner := bufio.NewScanner(sourceFile)
|
||||
foundMarker := false
|
||||
for lineNumber := 1; lineScanner.Scan(); lineNumber++ {
|
||||
codeline := lineScanner.Text()
|
||||
if strings.Contains(codeline, kCodelineMarker) {
|
||||
foundMarker = true
|
||||
break
|
||||
}
|
||||
codelines = append(codelines, codeline)
|
||||
}
|
||||
if !foundMarker {
|
||||
log.Fatal("Unable to find marker line in Java file.")
|
||||
}
|
||||
}
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer file.Close()
|
||||
defer fmt.Println("Edited " + path)
|
||||
for _, codeline := range codelines {
|
||||
file.WriteString(codeline)
|
||||
file.WriteString("\n")
|
||||
}
|
||||
file.WriteString(" // " + kCodelineMarker + "\n")
|
||||
|
||||
// Forward declarations for usage in a closure.
|
||||
var flattener func(*db.StructDefinition) string
|
||||
var sharedExtensions template.FuncMap
|
||||
|
||||
javifyType := func(field db.StructField) string {
|
||||
if _, exists := field.EmitterFlags["java_float"]; exists {
|
||||
return " float"
|
||||
}
|
||||
switch field.TypeString {
|
||||
case "math::float2", "math::float3", "math::float4", "LinearColor", "LinearColorA":
|
||||
return " float[]"
|
||||
case "bool":
|
||||
return " boolean"
|
||||
case "uint8_t", "uint16_t", "uint32_t":
|
||||
return " int"
|
||||
}
|
||||
result := strings.ReplaceAll(field.TypeString, "*", "")
|
||||
result = strings.ReplaceAll(result, "::", ".")
|
||||
return " " + result
|
||||
}
|
||||
|
||||
javifyValue := func(field db.StructField) string {
|
||||
|
||||
// When forcing an array to be bound to a float, extract the first component and use
|
||||
// that as the default value.
|
||||
if _, exists := field.EmitterFlags["java_float"]; exists {
|
||||
arrayContents := strings.Trim(field.DefaultValue, " []")
|
||||
if comma := strings.Index(arrayContents, ","); comma > -1 {
|
||||
arrayContents = arrayContents[:comma]
|
||||
}
|
||||
if !strings.HasSuffix(arrayContents, "f") {
|
||||
arrayContents += "f"
|
||||
}
|
||||
return " " + arrayContents
|
||||
}
|
||||
|
||||
if field.DefaultValue == "nullptr" {
|
||||
return " null"
|
||||
}
|
||||
|
||||
// Handle enums
|
||||
value := strings.ReplaceAll(field.DefaultValue, "::", ".")
|
||||
|
||||
// Add "f" suffix for scalars
|
||||
if field.TypeString == "float" {
|
||||
value += "f"
|
||||
|
||||
} else if c := len(value); c > 1 && value[0] == '[' && value[c-1] == ']' {
|
||||
// For vector types, replace [] with {} and add "f" suffix to components.
|
||||
switch field.TypeString {
|
||||
case "math::float2", "math::float3", "math::float4", "LinearColor", "LinearColorA":
|
||||
slices := strings.Split(value[1:c-1], ",")
|
||||
for i := range slices {
|
||||
slices[i] = strings.TrimSpace(slices[i])
|
||||
if !strings.HasSuffix(slices[i], "f") {
|
||||
slices[i] += "f"
|
||||
}
|
||||
}
|
||||
value = "{" + strings.Join(slices, ", ") + "}"
|
||||
default:
|
||||
value = "{" + value[1:c-1] + "}"
|
||||
}
|
||||
}
|
||||
return " " + value
|
||||
}
|
||||
|
||||
getDocBlock := func(defn db.Documented, depth int) string {
|
||||
doc := defn.GetDoc()
|
||||
if doc == "" {
|
||||
return ""
|
||||
}
|
||||
indent := strings.Repeat(" ", depth)
|
||||
if strings.Count(doc, "\n") > 0 {
|
||||
return strings.ReplaceAll(doc, "\n", "\n"+indent)
|
||||
}
|
||||
return "/**\n" + indent + " * " + doc + "\n" + indent + " */\n" + indent
|
||||
}
|
||||
|
||||
getFieldAnnotation := func(field db.StructField, depth int) string {
|
||||
if _, exists := field.EmitterFlags["java_float"]; exists {
|
||||
return ""
|
||||
}
|
||||
annotation := ""
|
||||
switch {
|
||||
case field.DefaultValue == "nullptr":
|
||||
annotation = "@Nullable"
|
||||
case field.TypeString == "math::float2":
|
||||
annotation = "@NonNull @Size(min = 2)"
|
||||
case field.TypeString == "math::float3" || field.TypeString == "LinearColor":
|
||||
annotation = "@NonNull @Size(min = 3)"
|
||||
case field.TypeString == "math::float4" || field.TypeString == "LinearColorA":
|
||||
annotation = "@NonNull @Size(min = 4)"
|
||||
case strings.Contains(field.DefaultValue, "::"):
|
||||
annotation = "@NonNull"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
return annotation + "\n" + strings.Repeat(" ", depth)
|
||||
}
|
||||
|
||||
flattenStruct := func(defn *db.StructDefinition) string {
|
||||
prefix := strings.ToLower(defn.BaseName())
|
||||
buf := &bytes.Buffer{}
|
||||
for _, field := range defn.Fields {
|
||||
doc := getDocBlock(defn, 0)
|
||||
buf.WriteString(doc)
|
||||
buf.WriteString(getFieldAnnotation(field, 0))
|
||||
buf.WriteString("public")
|
||||
buf.WriteString(javifyType(field))
|
||||
buf.WriteByte(' ')
|
||||
buf.WriteString(prefix + strings.ToUpper(field.Name[0:1]) + field.Name[1:])
|
||||
buf.WriteString(" =")
|
||||
buf.WriteString(javifyValue(field))
|
||||
buf.WriteString(";\n")
|
||||
}
|
||||
return indent(buf.String(), 2)
|
||||
}
|
||||
flattener = flattenStruct
|
||||
|
||||
// These template extensions are used to transmogrify C++ symbols and value literals to Java.
|
||||
customExtensions := template.FuncMap{
|
||||
"docblock": getDocBlock,
|
||||
"nested_type_declarations": func(parent db.TypeDefinition) string {
|
||||
// Look for all fields that request flattening since we should skip their emission.
|
||||
flattenedTypes := make(map[db.TypeDefinition]struct{})
|
||||
if structDefn, isStruct := parent.(*db.StructDefinition); isStruct {
|
||||
for _, field := range structDefn.Fields {
|
||||
_, flatten := field.EmitterFlags["java_flatten"]
|
||||
if flatten && field.CustomType != nil {
|
||||
flattenedTypes[field.CustomType] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find all child types and emit them.
|
||||
generate := createJavaCodeGenerator(sharedExtensions)
|
||||
buf := &bytes.Buffer{}
|
||||
for _, definition := range definitions {
|
||||
if definition.Parent() != parent {
|
||||
continue
|
||||
}
|
||||
_, skip := flattenedTypes[definition]
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
switch definition.(type) {
|
||||
case *db.StructDefinition:
|
||||
generate(buf, "Struct", definition)
|
||||
case *db.EnumDefinition:
|
||||
generate(buf, "Enum", definition)
|
||||
}
|
||||
}
|
||||
return indent(buf.String(), 1)
|
||||
},
|
||||
"annotation": getFieldAnnotation,
|
||||
"java_type": javifyType,
|
||||
"java_value": javifyValue,
|
||||
"flatten": func(field *db.StructField) string {
|
||||
if structDefn, isStruct := field.CustomType.(*db.StructDefinition); isStruct {
|
||||
return strings.TrimLeft(flattener(structDefn), " ")
|
||||
}
|
||||
log.Fatal("Unexpected flatten flag.")
|
||||
return ""
|
||||
},
|
||||
"flag": func(field *db.StructField, flag string) bool {
|
||||
_, exists := field.EmitterFlags[flag]
|
||||
return exists
|
||||
},
|
||||
}
|
||||
|
||||
sharedExtensions = customExtensions
|
||||
|
||||
generate := createJavaCodeGenerator(customExtensions)
|
||||
for _, definition := range definitions {
|
||||
if definition.Parent() != nil {
|
||||
continue
|
||||
}
|
||||
switch definition.(type) {
|
||||
case *db.StructDefinition:
|
||||
generate(file, "Struct", definition)
|
||||
case *db.EnumDefinition:
|
||||
generate(file, "Enum", definition)
|
||||
}
|
||||
}
|
||||
|
||||
file.WriteString("}\n")
|
||||
}
|
||||
|
||||
// Adds one level of indention to the given multi-line string.
|
||||
// Isolated newlines are intentially not indented.
|
||||
func indent(src string, depth int) string {
|
||||
dst := &bytes.Buffer{}
|
||||
buf := bytes.NewBufferString(src)
|
||||
scanner := bufio.NewScanner(buf)
|
||||
for scanner.Scan() {
|
||||
codeline := scanner.Text()
|
||||
if codeline != "" {
|
||||
dst.WriteString(strings.Repeat(" ", depth))
|
||||
dst.WriteString(scanner.Text())
|
||||
}
|
||||
dst.WriteByte('\n')
|
||||
}
|
||||
return dst.String()
|
||||
}
|
||||
|
||||
// Wrapper for ExecuteTemplate that performs error checking. Takes an output stream, a template name
|
||||
// to invoke, and a template context object.
|
||||
type templateFn = func(io.Writer, string, db.TypeDefinition)
|
||||
|
||||
func createJavaCodeGenerator(customExtensions template.FuncMap) templateFn {
|
||||
templ := template.New("beamsplitter").Funcs(customExtensions)
|
||||
templ = template.Must(templ.ParseFiles("emitters/java.template"))
|
||||
return func(writer io.Writer, section string, definition db.TypeDefinition) {
|
||||
err := templ.ExecuteTemplate(writer, section, definition)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,16 @@
|
||||
{{ docblock . 1 }}public static class {{ .BaseName }} {
|
||||
{{- nested_type_declarations . }}
|
||||
{{- range $index, $field := .Fields}}
|
||||
{{ docblock . 2 }}{{ annotation $field 2 }}public
|
||||
{{ docblock . 2 }}
|
||||
{{- if flag $field "java_flatten" }}
|
||||
{{- flatten $field }}
|
||||
{{- else}}
|
||||
{{- annotation $field 2 }}public
|
||||
{{- java_type $field }} {{ $field.Name }} =
|
||||
{{- java_value $field}};
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
};
|
||||
}
|
||||
{{ end }}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -16,5 +21,5 @@
|
||||
{{- range .Values}}
|
||||
{{ docblock . 2 }}{{ .Name }},
|
||||
{{- end }}
|
||||
};
|
||||
}
|
||||
{{ end }}
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
package emitters
|
||||
|
||||
import (
|
||||
"beamsplitter/parse"
|
||||
db "beamsplitter/database"
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
@@ -27,74 +27,9 @@ import (
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// Returns a templating function that automatically checks for fatal errors. The returned function
|
||||
// takes an output stream, a template name to invoke, and a template context object.
|
||||
func createJsCodeGenerator(namespace string) func(*os.File, string, parse.TypeDefinition) {
|
||||
jsPrefix := ""
|
||||
classPrefix := ""
|
||||
cppPrefix := ""
|
||||
if namespace != "" {
|
||||
jsPrefix = namespace + "$"
|
||||
classPrefix = namespace + ".prototype."
|
||||
cppPrefix = namespace + "::"
|
||||
}
|
||||
// These template extensions are used to transmogrify C++ symbols and value literals into
|
||||
// JavaScript. We mostly don't need to do anything since the parser has already done some
|
||||
// massaging and verification (e.g. it removed the trailing "f" from floating point literals).
|
||||
// However enums need some special care here. Emscripten bindings are flat, so our own
|
||||
// convention is to use $ for the scoping delimiter, which is a legal symbol character in JS.
|
||||
// However we still use . to separate the enum value from the enum type, because emscripten has
|
||||
// first-class support for class enums.
|
||||
customExtensions := template.FuncMap{
|
||||
"qualifiedtype": func(typename string) string {
|
||||
typename = strings.ReplaceAll(typename, "::", "$")
|
||||
return typename
|
||||
},
|
||||
"flag": func(field *parse.StructField, flag string) bool {
|
||||
_, exists := field.EmitterFlags[flag]
|
||||
return exists
|
||||
},
|
||||
"qualifiedvalue": func(name string) string {
|
||||
count := strings.Count(name, "::")
|
||||
if count > 0 {
|
||||
name = "Filament." + jsPrefix + name
|
||||
}
|
||||
name = strings.Replace(name, "::", "$", count-1)
|
||||
name = strings.Replace(name, "::", ".", 1)
|
||||
return name
|
||||
},
|
||||
"tstype": func(cpptype string) string {
|
||||
if strings.HasPrefix(cpptype, "math::") {
|
||||
return cpptype[6:]
|
||||
}
|
||||
switch cpptype {
|
||||
case "float", "uint8_t", "uint32_t", "uint16_t":
|
||||
return "number"
|
||||
case "bool":
|
||||
return "boolean"
|
||||
case "LinearColorA":
|
||||
return "float4"
|
||||
case "LinearColor":
|
||||
return "float3"
|
||||
}
|
||||
return jsPrefix + strings.ReplaceAll(cpptype, "::", "$")
|
||||
},
|
||||
"jsprefix": func() string { return jsPrefix },
|
||||
"cprefix": func() string { return cppPrefix },
|
||||
"classprefix": func() string { return classPrefix },
|
||||
}
|
||||
const kCodelineMarker = "The remainder of this file is generated by beamsplitter"
|
||||
|
||||
templ := template.New("beamsplitter").Funcs(customExtensions)
|
||||
templ = template.Must(templ.ParseFiles("javascript.template"))
|
||||
return func(file *os.File, section string, definition parse.TypeDefinition) {
|
||||
err := templ.ExecuteTemplate(file, section, definition)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func emitJavaScript(definitions []parse.TypeDefinition, namespace string, outputFolder string) {
|
||||
func EmitJavaScript(definitions []db.TypeDefinition, namespace string, outputFolder string) {
|
||||
generate := createJsCodeGenerator(namespace)
|
||||
{
|
||||
path := filepath.Join(outputFolder, "jsbindings_generated.cpp")
|
||||
@@ -109,7 +44,7 @@ func emitJavaScript(definitions []parse.TypeDefinition, namespace string, output
|
||||
|
||||
for _, definition := range definitions {
|
||||
switch definition.(type) {
|
||||
case *parse.StructDefinition:
|
||||
case *db.StructDefinition:
|
||||
generate(file, "JsBindingsStruct", definition)
|
||||
}
|
||||
}
|
||||
@@ -128,7 +63,7 @@ func emitJavaScript(definitions []parse.TypeDefinition, namespace string, output
|
||||
|
||||
for _, definition := range definitions {
|
||||
switch definition.(type) {
|
||||
case *parse.EnumDefinition:
|
||||
case *db.EnumDefinition:
|
||||
generate(file, "JsEnum", definition)
|
||||
}
|
||||
}
|
||||
@@ -148,7 +83,7 @@ func emitJavaScript(definitions []parse.TypeDefinition, namespace string, output
|
||||
|
||||
for _, definition := range definitions {
|
||||
switch definition.(type) {
|
||||
case *parse.StructDefinition:
|
||||
case *db.StructDefinition:
|
||||
generate(file, "JsExtension", definition)
|
||||
}
|
||||
}
|
||||
@@ -156,7 +91,7 @@ func emitJavaScript(definitions []parse.TypeDefinition, namespace string, output
|
||||
}
|
||||
}
|
||||
|
||||
func editTypeScript(definitions []parse.TypeDefinition, namespace string, folder string) {
|
||||
func EditTypeScript(definitions []db.TypeDefinition, namespace string, folder string) {
|
||||
path := filepath.Join(folder, "filament.d.ts")
|
||||
var codelines []string
|
||||
{
|
||||
@@ -196,10 +131,88 @@ func editTypeScript(definitions []parse.TypeDefinition, namespace string, folder
|
||||
generate := createJsCodeGenerator(namespace)
|
||||
for _, definition := range definitions {
|
||||
switch definition.(type) {
|
||||
case *parse.StructDefinition:
|
||||
case *db.StructDefinition:
|
||||
generate(file, "TsStruct", definition)
|
||||
case *parse.EnumDefinition:
|
||||
case *db.EnumDefinition:
|
||||
generate(file, "TsEnum", definition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a templating function that automatically checks for fatal errors. The returned function
|
||||
// takes an output stream, a template name to invoke, and a template context object.
|
||||
func createJsCodeGenerator(namespace string) func(*os.File, string, db.TypeDefinition) {
|
||||
jsPrefix := ""
|
||||
classPrefix := ""
|
||||
cppPrefix := ""
|
||||
if namespace != "" {
|
||||
jsPrefix = namespace + "$"
|
||||
classPrefix = namespace + ".prototype."
|
||||
cppPrefix = namespace + "::"
|
||||
}
|
||||
// These template extensions are used to transmogrify C++ symbols and value literals into
|
||||
// JavaScript. We mostly don't need to do anything since the parser has already done some
|
||||
// massaging and verification (e.g. it removed the trailing "f" from floating point literals).
|
||||
// However enums need some special care here. Emscripten bindings are flat, so our own
|
||||
// convention is to use $ for the scoping delimiter, which is a legal symbol character in JS.
|
||||
// However we still use . to separate the enum value from the enum type, because emscripten has
|
||||
// first-class support for class enums.
|
||||
customExtensions := template.FuncMap{
|
||||
"qualifiedtype": func(typename string) string {
|
||||
typename = strings.ReplaceAll(typename, "::", "$")
|
||||
return typename
|
||||
},
|
||||
"flag": func(field *db.StructField, flag string) bool {
|
||||
_, exists := field.EmitterFlags[flag]
|
||||
return exists
|
||||
},
|
||||
"qualifiedvalue": func(name string) string {
|
||||
count := strings.Count(name, "::")
|
||||
if count > 0 {
|
||||
name = "Filament." + jsPrefix + name
|
||||
}
|
||||
name = strings.Replace(name, "::", "$", count-1)
|
||||
name = strings.Replace(name, "::", ".", 1)
|
||||
return name
|
||||
},
|
||||
"tstype": func(cpptype string) string {
|
||||
if strings.HasPrefix(cpptype, "math::") {
|
||||
return cpptype[6:]
|
||||
}
|
||||
switch cpptype {
|
||||
case "float", "uint8_t", "uint32_t", "uint16_t":
|
||||
return "number"
|
||||
case "bool":
|
||||
return "boolean"
|
||||
case "LinearColorA":
|
||||
return "float4"
|
||||
case "LinearColor":
|
||||
return "float3"
|
||||
}
|
||||
return jsPrefix + strings.ReplaceAll(cpptype, "::", "$")
|
||||
},
|
||||
"jsprefix": func() string { return jsPrefix },
|
||||
"cprefix": func() string { return cppPrefix },
|
||||
"classprefix": func() string { return classPrefix },
|
||||
"docblock": func(defn db.Documented, depth int) string {
|
||||
doc := defn.GetDoc()
|
||||
if doc == "" {
|
||||
return ""
|
||||
}
|
||||
indent := strings.Repeat(" ", depth)
|
||||
if strings.Count(doc, "\n") > 0 {
|
||||
return strings.ReplaceAll(doc, "\n", "\n"+indent)
|
||||
}
|
||||
return "/**\n" + indent + " * " + doc + "\n" + indent + " */\n" + indent
|
||||
},
|
||||
}
|
||||
|
||||
templ := template.New("beamsplitter").Funcs(customExtensions)
|
||||
templ = template.Must(templ.ParseFiles("emitters/javascript.template"))
|
||||
return func(file *os.File, section string, definition db.TypeDefinition) {
|
||||
err := templ.ExecuteTemplate(file, section, definition)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,8 +91,8 @@ Filament.loadGeneratedExtensions = function() {
|
||||
{{- if flag $field "skip_javascript" }}
|
||||
// JavaScript binding for {{$field.Name}} is not yet supported, must use default value.
|
||||
{{- else }}
|
||||
{{ $field.Name }}?: {{ tstype $field.TypeString }};
|
||||
{{- if $field.Description}} // {{ $field.Description }}{{end}}
|
||||
{{ docblock $field 1 }}
|
||||
{{- $field.Name }}?: {{ tstype $field.TypeString }};
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
}
|
||||
@@ -14,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
package emitters
|
||||
|
||||
import (
|
||||
"beamsplitter/parse"
|
||||
db "beamsplitter/database"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func emitSerializer(definitions []parse.TypeDefinition, outputFolder string) {
|
||||
func EmitSerializer(definitions []db.TypeDefinition, outputFolder string) {
|
||||
// The following template extensions make it possible to generate valid C++ code with
|
||||
// fewer if-then-else blocks in the template file.
|
||||
customExtensions := template.FuncMap{
|
||||
@@ -35,7 +35,7 @@ func emitSerializer(definitions []parse.TypeDefinition, outputFolder string) {
|
||||
}
|
||||
return ","
|
||||
},
|
||||
"flag": func(field *parse.StructField, flag string) bool {
|
||||
"flag": func(field *db.StructField, flag string) bool {
|
||||
_, exists := field.EmitterFlags[flag]
|
||||
return exists
|
||||
},
|
||||
@@ -63,9 +63,9 @@ func emitSerializer(definitions []parse.TypeDefinition, outputFolder string) {
|
||||
}
|
||||
|
||||
codegen := template.New("beamsplitter").Funcs(customExtensions)
|
||||
codegen = template.Must(codegen.ParseFiles("serializer.template"))
|
||||
codegen = template.Must(codegen.ParseFiles("emitters/serializer.template"))
|
||||
|
||||
generate := func(file *os.File, section string, definition parse.TypeDefinition) {
|
||||
generate := func(file *os.File, section string, definition db.TypeDefinition) {
|
||||
err := codegen.ExecuteTemplate(file, section, definition)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
@@ -83,10 +83,10 @@ func emitSerializer(definitions []parse.TypeDefinition, outputFolder string) {
|
||||
generate(file, "CppHeader", nil)
|
||||
for _, definition := range definitions {
|
||||
switch definition.(type) {
|
||||
case *parse.StructDefinition:
|
||||
case *db.StructDefinition:
|
||||
generate(file, "CppStructReader", definition)
|
||||
generate(file, "CppStructWriter", definition)
|
||||
case *parse.EnumDefinition:
|
||||
case *db.EnumDefinition:
|
||||
generate(file, "CppEnumReader", definition)
|
||||
generate(file, "CppEnumWriter", definition)
|
||||
}
|
||||
@@ -104,9 +104,9 @@ func emitSerializer(definitions []parse.TypeDefinition, outputFolder string) {
|
||||
generate(file, "HppHeader", nil)
|
||||
for _, definition := range definitions {
|
||||
switch definition.(type) {
|
||||
case *parse.StructDefinition:
|
||||
case *db.StructDefinition:
|
||||
generate(file, "HppStruct", definition)
|
||||
case *parse.EnumDefinition:
|
||||
case *db.EnumDefinition:
|
||||
generate(file, "HppEnum", definition)
|
||||
}
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"beamsplitter/parse"
|
||||
)
|
||||
|
||||
// Adds one level of indention to the given multi-line string.
|
||||
// Isolated newlines are intentially not indented.
|
||||
func indent(src string) string {
|
||||
dst := &bytes.Buffer{}
|
||||
buf := bytes.NewBufferString(src)
|
||||
scanner := bufio.NewScanner(buf)
|
||||
for scanner.Scan() {
|
||||
codeline := scanner.Text()
|
||||
if codeline != "" {
|
||||
dst.WriteString(" ")
|
||||
dst.WriteString(scanner.Text())
|
||||
}
|
||||
dst.WriteByte('\n')
|
||||
}
|
||||
return dst.String()
|
||||
}
|
||||
|
||||
// Wrapper for ExecuteTemplate that performs error checking. Takes an output stream, a template name
|
||||
// to invoke, and a template context object.
|
||||
type templateFn = func(io.Writer, string, parse.TypeDefinition)
|
||||
|
||||
func createJavaCodeGenerator(customExtensions template.FuncMap) templateFn {
|
||||
templ := template.New("beamsplitter").Funcs(customExtensions)
|
||||
templ = template.Must(templ.ParseFiles("java.template"))
|
||||
return func(writer io.Writer, section string, definition parse.TypeDefinition) {
|
||||
err := templ.ExecuteTemplate(writer, section, definition)
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func editJava(definitions []parse.TypeDefinition, classname string, folder string) {
|
||||
path := filepath.Join(folder, classname+".java")
|
||||
var codelines []string
|
||||
{
|
||||
sourceFile, err := os.Open(path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer sourceFile.Close()
|
||||
lineScanner := bufio.NewScanner(sourceFile)
|
||||
foundMarker := false
|
||||
for lineNumber := 1; lineScanner.Scan(); lineNumber++ {
|
||||
codeline := lineScanner.Text()
|
||||
if strings.Contains(codeline, kCodelineMarker) {
|
||||
foundMarker = true
|
||||
break
|
||||
}
|
||||
codelines = append(codelines, codeline)
|
||||
}
|
||||
if !foundMarker {
|
||||
log.Fatal("Unable to find marker line in Java file.")
|
||||
}
|
||||
}
|
||||
file, err := os.Create(path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer file.Close()
|
||||
defer fmt.Println("Edited " + path)
|
||||
for _, codeline := range codelines {
|
||||
file.WriteString(codeline)
|
||||
file.WriteString("\n")
|
||||
}
|
||||
file.WriteString(" // " + kCodelineMarker + "\n")
|
||||
|
||||
// Declare a closure variable to handle nested types.
|
||||
var sharedExtensions template.FuncMap
|
||||
|
||||
// These template extensions are used to transmogrify C++ symbols and value literals to Java.
|
||||
customExtensions := template.FuncMap{
|
||||
"docblock": func(defn parse.Documented, depth int) string {
|
||||
doc := defn.GetDoc()
|
||||
if doc == "" {
|
||||
return ""
|
||||
}
|
||||
indent := strings.Repeat(" ", depth)
|
||||
if strings.Count(doc, "\n") > 0 {
|
||||
return strings.ReplaceAll(doc, "\n", "\n"+indent)
|
||||
}
|
||||
return "/**\n" + indent + " * " + doc + "\n" + indent + " */\n" + indent
|
||||
},
|
||||
"nested_type_declarations": func(parent parse.TypeDefinition) string {
|
||||
generate := createJavaCodeGenerator(sharedExtensions)
|
||||
buf := &bytes.Buffer{}
|
||||
for _, definition := range definitions {
|
||||
if definition.Parent() != parent {
|
||||
continue
|
||||
}
|
||||
switch definition.(type) {
|
||||
case *parse.StructDefinition:
|
||||
generate(buf, "Struct", definition)
|
||||
case *parse.EnumDefinition:
|
||||
generate(buf, "Enum", definition)
|
||||
}
|
||||
}
|
||||
return indent(buf.String())
|
||||
},
|
||||
"annotation": func(field parse.StructField, depth int) string {
|
||||
if _, exists := field.EmitterFlags["java_float"]; exists {
|
||||
return ""
|
||||
}
|
||||
annotation := ""
|
||||
switch {
|
||||
case field.DefaultValue == "nullptr":
|
||||
annotation = "@Nullable"
|
||||
case field.TypeString == "math::float2":
|
||||
annotation = "@NonNull @Size(min = 2)"
|
||||
case field.TypeString == "math::float3" || field.TypeString == "LinearColor":
|
||||
annotation = "@NonNull @Size(min = 3)"
|
||||
case field.TypeString == "math::float4" || field.TypeString == "LinearColorA":
|
||||
annotation = "@NonNull @Size(min = 4)"
|
||||
case strings.Contains(field.DefaultValue, "::"):
|
||||
annotation = "@NonNull"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
return annotation + "\n" + strings.Repeat(" ", depth)
|
||||
},
|
||||
"java_type": func(field parse.StructField) string {
|
||||
if _, exists := field.EmitterFlags["java_float"]; exists {
|
||||
return " float"
|
||||
}
|
||||
switch field.TypeString {
|
||||
case "math::float2", "math::float3", "math::float4", "LinearColor", "LinearColorA":
|
||||
return " float[]"
|
||||
case "bool":
|
||||
return " boolean"
|
||||
case "uint8_t", "uint16_t", "uint32_t":
|
||||
return " int"
|
||||
}
|
||||
return " " + strings.ReplaceAll(field.TypeString, "*", "")
|
||||
},
|
||||
"java_value": func(field parse.StructField) string {
|
||||
if _, exists := field.EmitterFlags["java_float"]; exists {
|
||||
arrayContents := strings.Trim(field.DefaultValue, " []")
|
||||
|
||||
// If we're forcing an array to be bound to a flat, then extract the first component
|
||||
// and use that as the default value.
|
||||
if comma := strings.Index(arrayContents, ","); comma > -1 {
|
||||
return " " + arrayContents[:comma]
|
||||
}
|
||||
|
||||
return " " + arrayContents
|
||||
}
|
||||
if field.DefaultValue == "nullptr" {
|
||||
return " null"
|
||||
}
|
||||
value := strings.ReplaceAll(field.DefaultValue, "::", ".")
|
||||
if field.TypeString == "float" {
|
||||
value += "f"
|
||||
} else if c := len(value); c > 1 && value[0] == '[' && value[c-1] == ']' {
|
||||
value = "{" + value[1:c-1] + "}"
|
||||
}
|
||||
return " " + value
|
||||
},
|
||||
}
|
||||
|
||||
sharedExtensions = customExtensions
|
||||
|
||||
generate := createJavaCodeGenerator(customExtensions)
|
||||
for _, definition := range definitions {
|
||||
if definition.Parent() != nil {
|
||||
continue
|
||||
}
|
||||
switch definition.(type) {
|
||||
case *parse.StructDefinition:
|
||||
generate(file, "Struct", definition)
|
||||
case *parse.EnumDefinition:
|
||||
generate(file, "Enum", definition)
|
||||
}
|
||||
}
|
||||
|
||||
file.WriteString("}\n")
|
||||
}
|
||||
@@ -23,10 +23,12 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
db "beamsplitter/database"
|
||||
"beamsplitter/emitters"
|
||||
"beamsplitter/parse"
|
||||
)
|
||||
|
||||
const kCodelineMarker = "The remainder of this file is generated by beamsplitter"
|
||||
var CHECK_API_SYNTAX = false
|
||||
|
||||
func findFilamentRoot() string {
|
||||
var (
|
||||
@@ -43,36 +45,25 @@ func main() {
|
||||
log.SetPrefix(sourceFilename + ":")
|
||||
root := findFilamentRoot()
|
||||
sourcePath := filepath.Join(root, "filament", "include", "filament", sourceFilename)
|
||||
definitions := parse.Parse(sourcePath)
|
||||
|
||||
// For diagnostic purposes, this dumps out the database that was gathered from
|
||||
// the parsing phase.
|
||||
if len(os.Args) > 1 && os.Args[1] == "--verbose" {
|
||||
for _, defn := range definitions {
|
||||
switch concrete := defn.(type) {
|
||||
case *parse.StructDefinition:
|
||||
fmt.Println("STRUCT:", concrete.QualifiedName())
|
||||
for _, field := range concrete.Fields {
|
||||
fmt.Println("\t", field.TypeString, "...", field.Name, "...", field.DefaultValue)
|
||||
}
|
||||
case *parse.EnumDefinition:
|
||||
fmt.Println(" ENUM:", concrete.QualifiedName())
|
||||
for _, value := range concrete.Values {
|
||||
fmt.Println("\t", value)
|
||||
}
|
||||
}
|
||||
}
|
||||
data, err := os.ReadFile(sourcePath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
emitSerializer(definitions, filepath.Join(root, "libs", "viewer", "src"))
|
||||
contents := string(data)
|
||||
ast := parse.Parse(contents)
|
||||
definitions := db.Create(ast, contents)
|
||||
|
||||
emitters.EmitSerializer(definitions, filepath.Join(root, "libs", "viewer", "src"))
|
||||
|
||||
jsfolder := filepath.Join(root, "web", "filament-js")
|
||||
emitJavaScript(definitions, "View", jsfolder)
|
||||
editTypeScript(definitions, "View", jsfolder)
|
||||
emitters.EmitJavaScript(definitions, "View", jsfolder)
|
||||
emitters.EditTypeScript(definitions, "View", jsfolder)
|
||||
|
||||
javafolder := filepath.FromSlash("com/google/android/filament")
|
||||
javafolder = filepath.Join(root, "android/filament-android/src/main/java", javafolder)
|
||||
editJava(definitions, "View", javafolder)
|
||||
emitters.EditJava(definitions, "View", javafolder)
|
||||
|
||||
fmt.Print(`
|
||||
Note that this tool does not generate bindings for setter methods on
|
||||
@@ -88,4 +79,22 @@ will likely need to manually modify the following files:
|
||||
- android/filament-android/src/main/java/.../View.java
|
||||
- android/filament-android/src/main/cpp/View.cpp
|
||||
`)
|
||||
|
||||
if CHECK_API_SYNTAX {
|
||||
sources := []string{}
|
||||
apiPath := filepath.Join(root, "filament", "include", "filament")
|
||||
entries, err := os.ReadDir(apiPath)
|
||||
for _, entry := range entries {
|
||||
sources = append(sources, filepath.Join(apiPath, entry.Name()))
|
||||
}
|
||||
for _, source := range sources {
|
||||
log.SetPrefix(filepath.Base(source) + ":")
|
||||
data, err = os.ReadFile(source)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
contents = string(data)
|
||||
parse.Parse(contents)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
79
tools/beamsplitter/parse/ast.go
Normal file
79
tools/beamsplitter/parse/ast.go
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package parse
|
||||
|
||||
type Node interface{}
|
||||
|
||||
type RootNode struct {
|
||||
Line int
|
||||
Child *NamespaceNode
|
||||
}
|
||||
|
||||
type NamespaceNode struct {
|
||||
Line int
|
||||
Name string
|
||||
Children []Node
|
||||
}
|
||||
|
||||
type ClassNode struct {
|
||||
Line int
|
||||
Name string
|
||||
Members []Node
|
||||
IsTemplate bool
|
||||
}
|
||||
|
||||
type StructNode struct {
|
||||
Line int
|
||||
Name string
|
||||
Members []Node
|
||||
IsTemplate bool
|
||||
}
|
||||
|
||||
type EnumNode struct {
|
||||
Line int
|
||||
Name string
|
||||
Values []string
|
||||
ValueLines []int // used to find docstring for each enum value
|
||||
}
|
||||
|
||||
type UsingNode struct {
|
||||
Line int
|
||||
Name string
|
||||
Rhs string
|
||||
}
|
||||
|
||||
type AccessSpecifierNode struct {
|
||||
Line int
|
||||
Access string
|
||||
}
|
||||
|
||||
type MethodNode struct {
|
||||
Line int
|
||||
Name string
|
||||
ReturnType string
|
||||
Arguments string
|
||||
Body string
|
||||
IsTemplate bool
|
||||
}
|
||||
|
||||
type FieldNode struct {
|
||||
Line int
|
||||
Name string
|
||||
Type string
|
||||
Rhs string
|
||||
ArrayLength int
|
||||
}
|
||||
802
tools/beamsplitter/parse/lex.go
Normal file
802
tools/beamsplitter/parse/lex.go
Normal file
@@ -0,0 +1,802 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package parse
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
var VERBOSE_LEXER = false
|
||||
var KNOWN_MACROS = []string{"UTILS_PUBLIC"}
|
||||
|
||||
// item represents a token or text string returned from the scanner.
|
||||
type item struct {
|
||||
typ itemType // The type of this item.
|
||||
pos int // The starting position, in bytes, of this item in the input string.
|
||||
val string // The value of this item.
|
||||
line int // The line number at the start of this item.
|
||||
}
|
||||
|
||||
func (i item) String() string {
|
||||
dbg := strings.ReplaceAll(i.val, "\n", "\\n")
|
||||
switch {
|
||||
case i.typ == itemEOF:
|
||||
return "EOF"
|
||||
case i.typ == itemError:
|
||||
return i.val
|
||||
case i.typ > itemKeywords_:
|
||||
return dbg
|
||||
case len(i.val) > 30:
|
||||
return dbg[:10] + "..." + dbg[len(dbg)-10:]
|
||||
}
|
||||
return dbg
|
||||
}
|
||||
|
||||
// itemType identifies the type of lex items.
|
||||
type itemType int
|
||||
|
||||
const (
|
||||
itemError itemType = iota // error occurred; value is text of error
|
||||
itemSimpleType // examples: `Texture* const`, `uint8_t`, `BlendMode`
|
||||
itemMethodBody // unparsed blob, includes outermost { and }
|
||||
itemMethodArgs // unparsed blob, includes outermost ( and )
|
||||
itemTemplateArgs // unparsed blob, includes outermost < and >
|
||||
itemDefaultValue // the unparsed RHS of an expression
|
||||
itemIdentifier // legal C++ identifier
|
||||
itemEOF
|
||||
|
||||
itemCloseBrace
|
||||
itemColon
|
||||
itemComma
|
||||
itemEquals
|
||||
itemOpenBrace
|
||||
itemSemicolon
|
||||
itemOpenBracket
|
||||
itemCloseBracket
|
||||
itemArrayLength
|
||||
|
||||
itemKeywords_ // unused enum separator
|
||||
itemClass
|
||||
itemConst
|
||||
itemConstexpr
|
||||
itemEnum
|
||||
itemFriend
|
||||
itemNamespace
|
||||
itemNoexcept
|
||||
itemPrivate
|
||||
itemProtected
|
||||
itemPublic
|
||||
itemStruct
|
||||
itemTemplate
|
||||
itemUsing
|
||||
)
|
||||
|
||||
const eof = -1
|
||||
|
||||
// lexer holds the state of the scanner.
|
||||
type lexer struct {
|
||||
input string // the entire contents of the file being scanned
|
||||
items chan item // channel of scanned items
|
||||
line int // 1+number of newlines seen
|
||||
startLine int // start line of this item
|
||||
pos int // current position in the input
|
||||
start int // start position of this item
|
||||
atEOF bool // we have hit the end of input
|
||||
lookahead []item
|
||||
}
|
||||
|
||||
// next returns the next rune in the input.
|
||||
func (l *lexer) next() rune {
|
||||
if int(l.pos) >= len(l.input) {
|
||||
l.atEOF = true
|
||||
return eof
|
||||
}
|
||||
r, w := utf8.DecodeRuneInString(l.input[l.pos:])
|
||||
l.pos += w
|
||||
if r == '\n' {
|
||||
l.line++
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// backup steps back one rune.
|
||||
func (l *lexer) backup() {
|
||||
if !l.atEOF && l.pos > 0 {
|
||||
r, w := utf8.DecodeLastRuneInString(l.input[:l.pos])
|
||||
l.pos -= w
|
||||
// Correct newline count.
|
||||
if r == '\n' {
|
||||
l.line--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (lex *lexer) backupMultiple(count int) {
|
||||
for i := 0; i < count; i++ {
|
||||
lex.backup()
|
||||
}
|
||||
}
|
||||
|
||||
func (lex *lexer) backupKeyword() {
|
||||
lex.backup()
|
||||
for unicode.IsLetter(rune(lex.input[lex.pos])) {
|
||||
lex.backup()
|
||||
}
|
||||
lex.next()
|
||||
}
|
||||
|
||||
// Passes an item back to the parser and moves the start pointer to catch up to the cursor.
|
||||
// The start pointer marks the beginning of the next item.
|
||||
// It helps to imagine a crawling worm whose tail catches up with its head in one movement.
|
||||
func (l *lexer) emit(t itemType) {
|
||||
text := strings.TrimSpace(l.input[l.start:l.pos])
|
||||
if text == "" {
|
||||
column := l.pos - l.findLineStartPos()
|
||||
// Can occur when calling emit() twice in a row without "accepting" anything in between.
|
||||
log.Fatalf("%d: internal error at column %d\n", l.line, column)
|
||||
}
|
||||
token := item{t, l.start, text, l.startLine}
|
||||
if l.lookahead != nil {
|
||||
if VERBOSE_LEXER {
|
||||
fmt.Printf("%03d Stashing %s\n", token.line, token.String())
|
||||
}
|
||||
l.lookahead = append(l.lookahead, token)
|
||||
} else {
|
||||
if VERBOSE_LEXER {
|
||||
fmt.Printf("%03d Emitting %s\n", token.line, token.String())
|
||||
}
|
||||
l.items <- token
|
||||
}
|
||||
l.start = l.pos
|
||||
l.startLine = l.line
|
||||
l.discardOptionalSpace()
|
||||
}
|
||||
|
||||
// Moves the start pointer to catch up to the cursor but does not pass the item to the parser.
|
||||
// This function is like emit, except that it throws the item in the trash.
|
||||
func (l *lexer) discard() {
|
||||
if VERBOSE_LEXER {
|
||||
dbg := l.input[l.start:l.pos]
|
||||
dbg = strings.ReplaceAll(dbg, "\n", "\\n")
|
||||
if len(dbg) > 30 {
|
||||
dbg = dbg[:10] + "..." + dbg[len(dbg)-10:]
|
||||
}
|
||||
fmt.Printf("%03d Trashing [[%s]]\n", l.line, dbg)
|
||||
}
|
||||
l.start = l.pos
|
||||
l.startLine = l.line
|
||||
}
|
||||
|
||||
func (l *lexer) acceptAny(valid string) bool {
|
||||
if strings.ContainsRune(valid, l.next()) {
|
||||
return true
|
||||
}
|
||||
l.backup()
|
||||
return false
|
||||
}
|
||||
|
||||
func (lex *lexer) acceptAlphaNumeric() bool {
|
||||
next := lex.next()
|
||||
if isAlphaNumeric(next) {
|
||||
return true
|
||||
}
|
||||
lex.backup()
|
||||
return false
|
||||
}
|
||||
|
||||
func (lex *lexer) acceptPositiveInteger() bool {
|
||||
next := lex.next()
|
||||
if !unicode.IsDigit(next) || next == '0' {
|
||||
lex.backup()
|
||||
return false
|
||||
}
|
||||
lex.acceptRun("123456789")
|
||||
return true
|
||||
}
|
||||
|
||||
// Consumes a run of runes from the valid set.
|
||||
func (l *lexer) acceptRun(valid string) {
|
||||
for strings.ContainsRune(valid, l.next()) {
|
||||
}
|
||||
l.backup()
|
||||
}
|
||||
|
||||
func (lex *lexer) acceptSpace() bool {
|
||||
return lex.acceptAny(" \t\n")
|
||||
}
|
||||
|
||||
func (l *lexer) acceptRune(expected rune) bool {
|
||||
if l.next() == expected {
|
||||
return true
|
||||
}
|
||||
l.backup()
|
||||
return false
|
||||
}
|
||||
|
||||
func (lex *lexer) acceptString(expectedString string) bool {
|
||||
for i, c := range expectedString {
|
||||
if lex.next() != c {
|
||||
lex.backupMultiple(i + 1)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (lex *lexer) acceptIdentifier() bool {
|
||||
next := lex.next()
|
||||
if next != '_' && !unicode.IsLetter(next) {
|
||||
lex.backup()
|
||||
return false
|
||||
}
|
||||
for isAlphaNumeric(lex.next()) {
|
||||
}
|
||||
lex.backup()
|
||||
return true
|
||||
}
|
||||
|
||||
func (lex *lexer) acceptKeyword(keyword string) bool {
|
||||
start := lex.pos
|
||||
if !lex.acceptString(keyword) {
|
||||
return false
|
||||
}
|
||||
if lex.eof() {
|
||||
return true
|
||||
}
|
||||
if lex.acceptAlphaNumeric() {
|
||||
lex.backupMultiple(lex.pos - start)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (lex *lexer) acceptKeywords(keywords []string) bool {
|
||||
for _, keyword := range keywords {
|
||||
if lex.acceptKeyword(keyword) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Accepts a blob of unparsed text up until the given terminator, which is not included.
|
||||
func (lex *lexer) acceptTerminatedBlob(term rune) bool {
|
||||
previous := lex.pos
|
||||
for {
|
||||
if lex.next() == term {
|
||||
lex.backup()
|
||||
return true
|
||||
}
|
||||
if lex.atEOF {
|
||||
lex.backupMultiple(lex.pos - previous)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Accepts a blob of unparsed text with the given delimiters, which can be nested.
|
||||
func (lex *lexer) acceptDelimitedBlob(start rune, stop rune) bool {
|
||||
previous := lex.pos
|
||||
next := lex.next()
|
||||
if next != start {
|
||||
lex.backup()
|
||||
return false
|
||||
}
|
||||
for depth := 1; next != eof; {
|
||||
switch lex.next() {
|
||||
case start:
|
||||
depth++
|
||||
case stop:
|
||||
depth--
|
||||
if depth == 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
lex.backupMultiple(lex.pos - previous)
|
||||
return false
|
||||
}
|
||||
|
||||
// Discards whitespace, linefeeds, comments, and C preprocessor directives.
|
||||
func (lex *lexer) discardOptionalSpace() {
|
||||
for {
|
||||
for _, macro := range KNOWN_MACROS {
|
||||
if lex.acceptKeyword(macro) {
|
||||
lex.discard()
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case lex.acceptSpace():
|
||||
lex.acceptRun(" \n\t")
|
||||
lex.discard()
|
||||
case lex.acceptString("/*"):
|
||||
for !lex.acceptString("*/") {
|
||||
lex.next()
|
||||
}
|
||||
lex.discard()
|
||||
case lex.acceptString("//") || lex.acceptRune('#'):
|
||||
for !lex.acceptRune('\n') {
|
||||
lex.next()
|
||||
}
|
||||
lex.discard()
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the next item from the input.
|
||||
// Called by the parser, not in the lexing goroutine.
|
||||
func (l *lexer) nextItem() item {
|
||||
return <-l.items
|
||||
}
|
||||
|
||||
// Drains the output so the lexing goroutine will exit.
|
||||
// Called by the parser, not in the lexing goroutine.
|
||||
func (l *lexer) drain() {
|
||||
for range l.items {
|
||||
}
|
||||
}
|
||||
|
||||
func (lex *lexer) eof() bool {
|
||||
return lex.pos >= len(lex.input)
|
||||
}
|
||||
|
||||
// Creates a new scanner for the input string.
|
||||
func createLexer(input string) *lexer {
|
||||
l := &lexer{
|
||||
input: input,
|
||||
items: make(chan item),
|
||||
line: 1,
|
||||
startLine: 1,
|
||||
}
|
||||
go l.run()
|
||||
return l
|
||||
}
|
||||
|
||||
func (lex *lexer) run() {
|
||||
if err := lexRoot(lex); err != nil {
|
||||
column := lex.pos - lex.findLineStartPos()
|
||||
log.Fatalf("%d:%d: lexer expected %s", lex.line, column, err.Error())
|
||||
}
|
||||
close(lex.items)
|
||||
}
|
||||
|
||||
func (lex *lexer) findLineStartPos() int {
|
||||
lineNo := 1
|
||||
for pos, c := range lex.input {
|
||||
if c != '\n' {
|
||||
continue
|
||||
}
|
||||
lineNo++
|
||||
if lineNo == lex.line {
|
||||
return pos
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func isAlphaNumeric(r rune) bool {
|
||||
return r == '_' || unicode.IsLetter(r) || unicode.IsDigit(r)
|
||||
}
|
||||
|
||||
// Causes the lexer to enter a special "lookahead state" in which it stashes
|
||||
// the lexer state and buffers all emitted items.
|
||||
func lookahead(lex *lexer, cb func(*lexer) error) bool {
|
||||
if lex.lookahead != nil {
|
||||
log.Fatal("Nested lookahead.")
|
||||
}
|
||||
lex.lookahead = make([]item, 0)
|
||||
previousStart := lex.start
|
||||
previousStartLine := lex.startLine
|
||||
previousPos := lex.pos
|
||||
previousLine := lex.line
|
||||
if err := cb(lex); err == nil {
|
||||
for _, item := range lex.lookahead {
|
||||
if VERBOSE_LEXER {
|
||||
fmt.Printf("%03d Emitting %s\n", item.line, item.String())
|
||||
}
|
||||
lex.items <- item
|
||||
}
|
||||
lex.lookahead = nil
|
||||
return true
|
||||
}
|
||||
lex.lookahead = nil
|
||||
lex.start = previousStart
|
||||
lex.startLine = previousStartLine
|
||||
lex.line = previousLine
|
||||
lex.pos = previousPos
|
||||
return false
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
// The remainder of this file has one function for each nonterminal in the BNF.
|
||||
// The ordering should be consistent with the grammar in the README.
|
||||
// These functions are all prefixed with "lex" and return an error or nil.
|
||||
// Error strings are automatically prefixed with the line number and "lexer expected ".
|
||||
// In lookahead situations, the returned error might be intentionally discarded.
|
||||
// -------------------------------------------------------------------------------------------------
|
||||
|
||||
func lexRoot(lex *lexer) error {
|
||||
if lex.eof() {
|
||||
return nil
|
||||
}
|
||||
lex.discardOptionalSpace()
|
||||
if lex.acceptKeyword("namespace") {
|
||||
return lexNamespace(lex)
|
||||
}
|
||||
return errors.New("namespace")
|
||||
}
|
||||
|
||||
// Assumptions: cursor is just past the namespace keyword
|
||||
// Directly emits: keyword, the optional identifier, opening and closing braces
|
||||
// Indirectly emits: content of the namespace
|
||||
func lexNamespace(lex *lexer) error {
|
||||
lex.emit(itemNamespace)
|
||||
if lex.acceptIdentifier() {
|
||||
lex.emit(itemIdentifier)
|
||||
}
|
||||
if !lex.acceptRune('{') {
|
||||
return errors.New("{")
|
||||
}
|
||||
lex.emit(itemOpenBrace)
|
||||
for !lex.acceptRune('}') {
|
||||
if err := lexBlock(lex); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
lex.emit(itemCloseBrace)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Assumptions: cursor is just before one of the block keywords
|
||||
// Directly emits: struct or class keywords
|
||||
// Indirectly emits: the block keyword, its braces, contents, semicolons
|
||||
func lexBlock(lex *lexer) error {
|
||||
switch {
|
||||
case lex.acceptKeyword("namespace"):
|
||||
return lexNamespace(lex)
|
||||
case lex.acceptKeyword("template"):
|
||||
lex.emit(itemTemplate)
|
||||
if !lex.acceptDelimitedBlob('<', '>') {
|
||||
return errors.New("template arguments")
|
||||
}
|
||||
lex.emit(itemTemplateArgs)
|
||||
if !lex.acceptKeywords([]string{"class", "struct"}) {
|
||||
return errors.New("class or struct")
|
||||
}
|
||||
lex.backupKeyword()
|
||||
return lexBlock(lex)
|
||||
case lex.acceptKeyword("struct"):
|
||||
lex.emit(itemStruct)
|
||||
if lookahead(lex, lexForwardDeclaration) {
|
||||
return nil
|
||||
}
|
||||
return lexStruct(lex)
|
||||
case lex.acceptKeyword("class"):
|
||||
lex.emit(itemClass)
|
||||
if lookahead(lex, lexForwardDeclaration) {
|
||||
return nil
|
||||
}
|
||||
return lexClass(lex)
|
||||
case lex.acceptKeyword("using"):
|
||||
return lexUsing(lex)
|
||||
case lex.acceptKeyword("enum"):
|
||||
return lexEnum(lex)
|
||||
}
|
||||
return errors.New("namespace, struct, class, enum, or using")
|
||||
}
|
||||
|
||||
func lexForwardDeclaration(lex *lexer) error {
|
||||
if !lex.acceptIdentifier() {
|
||||
return errors.New("identifier")
|
||||
}
|
||||
lex.emit(itemIdentifier)
|
||||
if !lex.acceptRune(';') {
|
||||
return errors.New("; after forward declaration")
|
||||
}
|
||||
lex.emit(itemSemicolon)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Assumptions: cursor is just past the class keyword
|
||||
// Directly emits: identifier, opening and closing braces, semicolon
|
||||
// Indirectly emits: content of the struct
|
||||
func lexClass(lex *lexer) error {
|
||||
if !lex.acceptIdentifier() {
|
||||
return errors.New("does not allow anonymous classes")
|
||||
}
|
||||
lex.emit(itemIdentifier)
|
||||
if lex.acceptRune(':') {
|
||||
lex.emit(itemColon)
|
||||
if lex.acceptKeyword("public") {
|
||||
lex.emit(itemPublic)
|
||||
}
|
||||
if err := lexSimpleType(lex); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !lex.acceptRune('{') {
|
||||
return errors.New("{ before class body")
|
||||
}
|
||||
lex.emit(itemOpenBrace)
|
||||
if err := lexStructBody(lex); err != nil {
|
||||
return err
|
||||
}
|
||||
lex.emit(itemCloseBrace)
|
||||
if !lex.acceptRune(';') {
|
||||
return errors.New(": after class")
|
||||
}
|
||||
lex.emit(itemSemicolon)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Assumptions: cursor is just past the struct keyword
|
||||
// Directly emits: the optional identifier, opening and closing braces, semicolon
|
||||
// Indirect emits: content of the struct
|
||||
func lexStruct(lex *lexer) error {
|
||||
if lex.acceptIdentifier() {
|
||||
lex.emit(itemIdentifier)
|
||||
}
|
||||
if !lex.acceptRune('{') {
|
||||
return errors.New("{ before struct body")
|
||||
}
|
||||
lex.emit(itemOpenBrace)
|
||||
if err := lexStructBody(lex); err != nil {
|
||||
return err
|
||||
}
|
||||
lex.emit(itemCloseBrace)
|
||||
if !lex.acceptRune(';') {
|
||||
return errors.New("; after struct body")
|
||||
}
|
||||
lex.emit(itemSemicolon)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Assumptions: cursor is just past the enum keyword
|
||||
// Directly emits: all parts of the enum, including the trailing semicolon
|
||||
func lexEnum(lex *lexer) error {
|
||||
lex.emit(itemEnum)
|
||||
if !lex.acceptKeyword("class") {
|
||||
return errors.New("class-style enum")
|
||||
}
|
||||
lex.emit(itemClass)
|
||||
if !lex.acceptIdentifier() {
|
||||
return errors.New("valid identifier (anonymous enums are not supported)")
|
||||
}
|
||||
lex.emit(itemIdentifier)
|
||||
if lex.acceptRune(':') {
|
||||
lex.emit(itemColon)
|
||||
if err := lexSimpleType(lex); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if !lex.acceptRune('{') {
|
||||
return errors.New("{ before enum definition")
|
||||
}
|
||||
lex.emit(itemOpenBrace)
|
||||
|
||||
if !lex.acceptIdentifier() {
|
||||
return errors.New("at least one value in the enum")
|
||||
}
|
||||
lex.emit(itemIdentifier)
|
||||
|
||||
for !lex.acceptRune('}') {
|
||||
if !lex.acceptRune(',') {
|
||||
return errors.New(", between enum values")
|
||||
}
|
||||
lex.emit(itemComma)
|
||||
if lex.acceptRune('}') {
|
||||
break
|
||||
}
|
||||
if !lex.acceptIdentifier() {
|
||||
return errors.New("valid identifier in enum")
|
||||
}
|
||||
lex.emit(itemIdentifier)
|
||||
}
|
||||
lex.emit(itemCloseBrace)
|
||||
if !lex.acceptRune(';') {
|
||||
return errors.New("; after enum definition")
|
||||
}
|
||||
lex.emit(itemSemicolon)
|
||||
return nil
|
||||
}
|
||||
|
||||
func lexUsing(lex *lexer) error {
|
||||
lex.emit(itemUsing)
|
||||
if !lex.acceptIdentifier() {
|
||||
return errors.New("valid identifier in type alias")
|
||||
}
|
||||
lex.emit(itemIdentifier)
|
||||
if !lex.acceptRune('=') {
|
||||
return errors.New("= in type alias")
|
||||
}
|
||||
lex.emit(itemEquals)
|
||||
if err := lexSimpleType(lex); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !lex.acceptRune(';') {
|
||||
return errors.New("; after type alias")
|
||||
}
|
||||
lex.emit(itemSemicolon)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Assumptions: cursor is just past the opening brace of a struct or class
|
||||
// Directly emits: nothing
|
||||
// Indirect emits: entire content of the struct or class, but not the outer braces
|
||||
func lexStructBody(lex *lexer) error {
|
||||
accessKeywords := []string{"public", "private", "protected"}
|
||||
blockKeywords := []string{"class", "struct", "enum", "using", "template", "namespace"}
|
||||
for {
|
||||
switch {
|
||||
case lex.acceptRune('}'):
|
||||
return nil
|
||||
case lex.acceptKeywords(accessKeywords):
|
||||
lex.backupKeyword()
|
||||
if err := lexAccessSpecifier(lex); err != nil {
|
||||
return err
|
||||
}
|
||||
case lex.acceptKeywords(blockKeywords):
|
||||
lex.backupKeyword()
|
||||
if err := lexBlock(lex); err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if lookahead(lex, lexMethod) {
|
||||
continue
|
||||
}
|
||||
if err := lexField(lex); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assumptions: cursor is just before one of the access keywords
|
||||
// Directly emits: the access keyword and the colon
|
||||
func lexAccessSpecifier(lex *lexer) error {
|
||||
switch {
|
||||
case lex.acceptKeyword("public"):
|
||||
lex.emit(itemPublic)
|
||||
case lex.acceptKeyword("protected"):
|
||||
lex.emit(itemProtected)
|
||||
case lex.acceptKeyword("private"):
|
||||
lex.emit(itemPrivate)
|
||||
default:
|
||||
return errors.New("legal access specifier")
|
||||
}
|
||||
if !lex.acceptRune(':') {
|
||||
return errors.New(": after access specifier")
|
||||
}
|
||||
lex.emit(itemColon)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Assumptions: cursor is just before a method declaration or implementation
|
||||
// Directly emits: entire content of the method declaration or implementation
|
||||
func lexMethod(lex *lexer) error {
|
||||
if lex.acceptKeyword("template") {
|
||||
lex.emit(itemTemplate)
|
||||
if !lex.acceptDelimitedBlob('<', '>') {
|
||||
return errors.New("template arguments")
|
||||
}
|
||||
lex.emit(itemTemplateArgs)
|
||||
}
|
||||
if lex.acceptKeyword("friend") {
|
||||
lex.emit(itemFriend)
|
||||
}
|
||||
if lex.acceptKeyword("constexpr") {
|
||||
lex.emit(itemConstexpr)
|
||||
}
|
||||
if err := lexSimpleType(lex); err != nil {
|
||||
return err
|
||||
}
|
||||
if !lex.acceptIdentifier() {
|
||||
return errors.New("valid identifier")
|
||||
}
|
||||
lex.emit(itemIdentifier)
|
||||
if !lex.acceptDelimitedBlob('(', ')') {
|
||||
return errors.New("function arguments")
|
||||
}
|
||||
lex.emit(itemMethodArgs)
|
||||
if lex.acceptKeyword("const") {
|
||||
lex.emit(itemConst)
|
||||
}
|
||||
if lex.acceptKeyword("noexcept") {
|
||||
lex.emit(itemNoexcept)
|
||||
}
|
||||
if lex.acceptRune(';') {
|
||||
lex.emit(itemSemicolon)
|
||||
return nil
|
||||
}
|
||||
if !lex.acceptDelimitedBlob('{', '}') {
|
||||
return errors.New("function body or ;")
|
||||
}
|
||||
lex.emit(itemMethodBody)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Assumptions: cursor is just before a data field declaration in a class or struct
|
||||
// Directly emits: entire content of the method declaration or implementation
|
||||
func lexField(lex *lexer) error {
|
||||
if err := lexSimpleType(lex); err != nil {
|
||||
return err
|
||||
}
|
||||
if !lex.acceptIdentifier() {
|
||||
return errors.New("valid identifier")
|
||||
}
|
||||
lex.emit(itemIdentifier)
|
||||
if lex.acceptRune('[') {
|
||||
lex.emit(itemOpenBracket)
|
||||
if !lex.acceptPositiveInteger() {
|
||||
return errors.New("positive integer")
|
||||
}
|
||||
lex.emit(itemArrayLength)
|
||||
if !lex.acceptRune(']') {
|
||||
return errors.New("valid array length")
|
||||
}
|
||||
lex.emit(itemCloseBracket)
|
||||
}
|
||||
if lex.acceptRune('=') {
|
||||
lex.emit(itemEquals)
|
||||
if !lex.acceptTerminatedBlob(';') {
|
||||
return errors.New("right-hand side of assignment terminated by ;")
|
||||
}
|
||||
lex.emit(itemDefaultValue)
|
||||
}
|
||||
if !lex.acceptRune(';') {
|
||||
return errors.New("; after field")
|
||||
}
|
||||
lex.emit(itemSemicolon)
|
||||
return nil
|
||||
}
|
||||
|
||||
// For now, SimpleType is a very restrictive subset of the C++ type expression language. It should
|
||||
// not contain parentheses or commas, so C callbacks are not allowed unless you alias them first.
|
||||
// Basically, a type is a bag of tokens that must include exactly one valid C identifier, along with
|
||||
// a mix of spaces, "*", "&", "::", "const", "<", ">".
|
||||
//
|
||||
// Assumptions: cursor is just before a type identifier
|
||||
// Directly emits: itemSimpleType
|
||||
func lexSimpleType(lex *lexer) error {
|
||||
encounteredIdentifier := false
|
||||
for {
|
||||
switch {
|
||||
case lex.acceptString("::"), lex.acceptRune('<'):
|
||||
encounteredIdentifier = false
|
||||
continue
|
||||
case lex.acceptAny("*& >\t\n"):
|
||||
continue
|
||||
case lex.acceptKeyword("const"):
|
||||
continue
|
||||
case encounteredIdentifier:
|
||||
lex.emit(itemSimpleType)
|
||||
return nil
|
||||
case lex.acceptIdentifier():
|
||||
encounteredIdentifier = true
|
||||
default:
|
||||
return errors.New("valid type identifier")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,424 +17,291 @@
|
||||
package parse
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Consumes a C++ header file and produces a type database.
|
||||
func Parse(sourcePath string) []TypeDefinition {
|
||||
sourceFile, err := os.Open(sourcePath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
// Consumes the entire content of a C++ header file and produces an abstract syntax tree.
|
||||
func Parse(contents string) *RootNode {
|
||||
lexer := createLexer(contents)
|
||||
return parseRoot(lexer)
|
||||
}
|
||||
|
||||
// Assumes that we have just consumed the open brace from the lexer.
|
||||
// This consumes all lexemes in the entire struct, including the outer end brace.
|
||||
// It does not consume anything after the end brace.
|
||||
func parseStructBody(lex *lexer) []Node {
|
||||
var members []Node
|
||||
append := func(node Node) {
|
||||
members = append(members, node)
|
||||
}
|
||||
defer sourceFile.Close()
|
||||
|
||||
// In the first pass, gather all block-style comments.
|
||||
context := parserContext{}
|
||||
context.commentBlocks = gatherCommentBlocks(sourceFile)
|
||||
sourceFile.Seek(0, 0)
|
||||
|
||||
// In the second pass, pry apart each C++ codeline.
|
||||
lineScanner := bufio.NewScanner(sourceFile)
|
||||
for lineNumber := 1; lineScanner.Scan(); lineNumber++ {
|
||||
context.scanCppCodeline(lineScanner.Text(), lineNumber)
|
||||
}
|
||||
if err := lineScanner.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
context.addTypeQualifiers()
|
||||
return context.definitions
|
||||
}
|
||||
|
||||
type TypeDefinition interface {
|
||||
BaseName() string
|
||||
QualifiedName() string
|
||||
Parent() TypeDefinition
|
||||
}
|
||||
|
||||
type StructField struct {
|
||||
TypeString string
|
||||
Name string
|
||||
DefaultValue string
|
||||
Description string
|
||||
LineNumber int
|
||||
EmitterFlags map[string]struct{}
|
||||
CustomType TypeDefinition
|
||||
}
|
||||
|
||||
type StructDefinition struct {
|
||||
name string
|
||||
qualifier string
|
||||
Fields []StructField
|
||||
Description string
|
||||
parent TypeDefinition
|
||||
}
|
||||
|
||||
func (defn StructDefinition) BaseName() string { return defn.name }
|
||||
func (defn StructDefinition) QualifiedName() string { return defn.qualifier + defn.name }
|
||||
func (defn StructDefinition) Parent() TypeDefinition { return defn.parent }
|
||||
|
||||
type EnumValue struct {
|
||||
Description string
|
||||
Name string
|
||||
}
|
||||
|
||||
type EnumDefinition struct {
|
||||
name string
|
||||
qualifier string
|
||||
Values []EnumValue
|
||||
Description string
|
||||
parent TypeDefinition
|
||||
}
|
||||
|
||||
func (defn EnumDefinition) BaseName() string { return defn.name }
|
||||
func (defn EnumDefinition) QualifiedName() string { return defn.qualifier + defn.name }
|
||||
func (defn EnumDefinition) Parent() TypeDefinition { return defn.parent }
|
||||
|
||||
type Documented interface{ GetDoc() string }
|
||||
|
||||
func (defn EnumDefinition) GetDoc() string { return defn.Description }
|
||||
func (defn StructDefinition) GetDoc() string { return defn.Description }
|
||||
func (field StructField) GetDoc() string { return field.Description }
|
||||
func (value EnumValue) GetDoc() string { return value.Description }
|
||||
|
||||
type generalScope struct{}
|
||||
|
||||
type scope interface {
|
||||
BaseName() string
|
||||
QualifiedName() string
|
||||
Parent() TypeDefinition
|
||||
}
|
||||
|
||||
func (defn generalScope) BaseName() string { return "" }
|
||||
func (defn generalScope) QualifiedName() string { return "" }
|
||||
func (defn generalScope) Parent() TypeDefinition { return nil }
|
||||
|
||||
type parserContext struct {
|
||||
definitions []TypeDefinition
|
||||
stack []scope
|
||||
insideComment bool
|
||||
commentBlocks map[int]string
|
||||
cppTokenizer *regexp.Regexp
|
||||
floatMatcher *regexp.Regexp
|
||||
vectorMatcher *regexp.Regexp
|
||||
fieldParser *regexp.Regexp
|
||||
fieldDescParser *regexp.Regexp
|
||||
customFlagFinder *regexp.Regexp
|
||||
}
|
||||
|
||||
// https://github.com/google/re2/wiki/Syntax
|
||||
func (context *parserContext) compileRegexps() {
|
||||
context.cppTokenizer = regexp.MustCompile(`((?:/\*)|(?:\*/)|(?:;)|(?://)|(?:\})|(?:\{))`)
|
||||
context.floatMatcher = regexp.MustCompile(`(\-?[0-9]+\.[0-9]*)f?`)
|
||||
context.vectorMatcher = regexp.MustCompile(`\{(\s*\-?[0-9\.]+\s*(,\s*\-?[0-9\.]+\s*){1,})\}`)
|
||||
context.customFlagFinder = regexp.MustCompile(`\s*\%codegen_([a-zA-Z0-9_]+)\%\s*`)
|
||||
|
||||
const kFieldType = `(?P<type>.*)`
|
||||
const kFieldName = `(?P<name>[A-Za-z0-9_]+)`
|
||||
const kFieldValue = `(?P<value>(.*?))`
|
||||
const kFieldDesc = `(?://\s*\!\<\s*(?P<description>.*))?`
|
||||
context.fieldParser = regexp.MustCompile(
|
||||
`^\s*` + kFieldType + `\s+` + kFieldName + `\s*=\s*` + kFieldValue + `\s*;\s*` + kFieldDesc)
|
||||
|
||||
context.fieldDescParser = regexp.MustCompile(`(?://\s*\!\<\s*(.*))`)
|
||||
}
|
||||
|
||||
// Creates a mapping from line numbers to strings, where the strings are entire block comments
|
||||
// and the line numbers correspond to the last line of each block comment.
|
||||
func gatherCommentBlocks(sourceFile *os.File) map[int]string {
|
||||
comments := make(map[int]string)
|
||||
scanner := bufio.NewScanner(sourceFile)
|
||||
var comment = ""
|
||||
var indention = 0
|
||||
for lineNumber := 1; scanner.Scan(); lineNumber++ {
|
||||
codeline := scanner.Text()
|
||||
if strings.Contains(codeline, `/**`) {
|
||||
indention = strings.Index(codeline, `/**`)
|
||||
comment = codeline[indention:] + "\n"
|
||||
continue
|
||||
// Assumes that we have just consumed the end paren in the argument list.
|
||||
parseMethod := func(name, returns, args item, isTemplate bool) *MethodNode {
|
||||
item := lex.nextItem()
|
||||
for item.typ == itemConst || item.typ == itemNoexcept {
|
||||
item = lex.nextItem()
|
||||
}
|
||||
if comment != "" {
|
||||
if len(codeline) > indention {
|
||||
codeline = codeline[indention:]
|
||||
}
|
||||
comment += codeline + "\n"
|
||||
if strings.Contains(codeline, `*/`) {
|
||||
comments[lineNumber] = comment
|
||||
comment = ""
|
||||
}
|
||||
for item.typ == itemConst || item.typ == itemNoexcept {
|
||||
item = lex.nextItem()
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return comments
|
||||
}
|
||||
|
||||
func (context parserContext) generateQualifier() string {
|
||||
qualifier := ""
|
||||
for _, defn := range context.stack {
|
||||
if defn.BaseName() != "" {
|
||||
qualifier = qualifier + defn.BaseName() + "::"
|
||||
method := &MethodNode{
|
||||
Line: item.line,
|
||||
Name: name.val,
|
||||
ReturnType: returns.val,
|
||||
Arguments: args.val,
|
||||
Body: "",
|
||||
IsTemplate: isTemplate,
|
||||
}
|
||||
}
|
||||
return qualifier
|
||||
}
|
||||
|
||||
func (context parserContext) findParent() TypeDefinition {
|
||||
for i := len(context.stack) - 1; i >= 0; i-- {
|
||||
switch defn := context.stack[i].(type) {
|
||||
case *StructDefinition, *EnumDefinition:
|
||||
var result TypeDefinition = defn
|
||||
return result
|
||||
switch item.typ {
|
||||
case itemMethodBody:
|
||||
method.Body = item.val
|
||||
case itemSemicolon:
|
||||
default:
|
||||
panic(lex, item)
|
||||
return nil
|
||||
}
|
||||
return method
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Annotates struct fields that have custom types (i.e. enums or structs).
|
||||
func (context parserContext) addTypeQualifiers() {
|
||||
typeMap := make(map[string]TypeDefinition)
|
||||
for _, defn := range context.definitions {
|
||||
typeMap[defn.QualifiedName()] = defn
|
||||
}
|
||||
for _, defn := range context.definitions {
|
||||
structDefn, isStruct := defn.(*StructDefinition)
|
||||
if !isStruct {
|
||||
continue
|
||||
}
|
||||
for fieldIndex, field := range structDefn.Fields {
|
||||
// Extract the namespace prefix (if any) explicitly specified for this field type.
|
||||
var namespace string
|
||||
localTypeName := field.TypeString
|
||||
if index := strings.LastIndex(field.TypeString, "::"); index > -1 {
|
||||
namespace = field.TypeString[:index]
|
||||
localTypeName = field.TypeString[index+2:]
|
||||
}
|
||||
|
||||
// Prepend additional qualifiers to the type string by searching upward through
|
||||
// the current namespace hierarchy, and looking for a match.
|
||||
mutable := &structDefn.Fields[fieldIndex]
|
||||
for ancestor := defn; ; ancestor = ancestor.Parent() {
|
||||
var qualified string
|
||||
if namespace != "" && strings.HasSuffix(ancestor.QualifiedName(), namespace) {
|
||||
qualified = ancestor.QualifiedName() + "::" + localTypeName
|
||||
} else {
|
||||
qualified = ancestor.QualifiedName() + "::" + field.TypeString
|
||||
}
|
||||
if fieldType, found := typeMap[qualified]; found {
|
||||
mutable.TypeString = qualified
|
||||
mutable.CustomType = fieldType
|
||||
break
|
||||
}
|
||||
if ancestor.Parent() == nil {
|
||||
if fieldType, found := typeMap[field.TypeString]; found {
|
||||
mutable.CustomType = fieldType
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if mutable.CustomType == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// Prepend additional qualifiers to the value string if it is a known enum.
|
||||
var fieldType TypeDefinition = structDefn.Fields[fieldIndex].CustomType
|
||||
enumDefn, isEnum := fieldType.(*EnumDefinition)
|
||||
if isEnum {
|
||||
selectedEnum := field.DefaultValue
|
||||
if index := strings.LastIndex(field.DefaultValue, "::"); index > -1 {
|
||||
selectedEnum = field.DefaultValue[index+2:]
|
||||
}
|
||||
mutable.DefaultValue = enumDefn.QualifiedName() + "::" + selectedEnum
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validates and transforms the RHS of an assignment.
|
||||
// For vectors, this converts curly braces into square brackets.
|
||||
func (context parserContext) distillValue(cppvalue string, lineNumber int) string {
|
||||
cppvalue = strings.TrimSpace(cppvalue)
|
||||
|
||||
// Remove trailing "f" from floats, which isn't allowed in JavaScript.
|
||||
if context.floatMatcher.MatchString(cppvalue) {
|
||||
cppvalue = context.floatMatcher.ReplaceAllString(cppvalue, "$1")
|
||||
}
|
||||
|
||||
// There are many ways to declare vector values (multi-arg constructor, single-arg
|
||||
// constructor, curly braces with type, curly braces without type), so just poop out if
|
||||
// the syntax is anything other than "curly braces without type".
|
||||
if strings.Contains(cppvalue, "math::") || strings.Contains(cppvalue, "Color") {
|
||||
log.Fatalf("%d: vectors must have the form {x, y ...}", lineNumber)
|
||||
}
|
||||
|
||||
// Assume it's a vector if there's a curly brace.
|
||||
if strings.Contains(cppvalue, "{") {
|
||||
if context.vectorMatcher.MatchString(cppvalue) {
|
||||
cppvalue = context.vectorMatcher.ReplaceAllString(cppvalue, "[$1]")
|
||||
} else {
|
||||
log.Fatalf("%d: vectors must have the form {x, y ...}", lineNumber)
|
||||
}
|
||||
}
|
||||
|
||||
if len(cppvalue) == 0 {
|
||||
log.Fatalf("%d: empty value specified", lineNumber)
|
||||
}
|
||||
|
||||
return cppvalue
|
||||
}
|
||||
|
||||
func (context *parserContext) scanCppCodeline(codeline string, lineNumber int) {
|
||||
if context.cppTokenizer == nil {
|
||||
context.compileRegexps()
|
||||
}
|
||||
codeline = context.cppTokenizer.ReplaceAllString(codeline, " $1 ")
|
||||
scanner := bufio.NewScanner(strings.NewReader(codeline))
|
||||
scanner.Split(bufio.ScanWords)
|
||||
inPlaceDefinition := ""
|
||||
|
||||
scanStructField := func(defn *StructDefinition, firstWord string) {
|
||||
var field = StructField{
|
||||
LineNumber: lineNumber,
|
||||
}
|
||||
|
||||
// Extract all custom flags into a string set. These are special backend-specific directives
|
||||
// delimited by percent signs, e.g. %codegen_skip_javascript%
|
||||
if matches := context.customFlagFinder.FindAllStringSubmatch(codeline, -1); matches != nil {
|
||||
field.EmitterFlags = make(map[string]struct{}, len(matches))
|
||||
for _, flag := range matches {
|
||||
field.EmitterFlags[flag[1]] = struct{}{}
|
||||
}
|
||||
}
|
||||
codeline = context.customFlagFinder.ReplaceAllString(codeline, "")
|
||||
|
||||
// Normally when we're inside a struct, the first word on each codeline is the field type,
|
||||
// and the second word is the field name. However if a nested struct is defined, then the
|
||||
// type is potentially anonymous and the first word is the field name.
|
||||
if !scanner.Scan() {
|
||||
log.Fatalf("%d: bad struct field", lineNumber)
|
||||
}
|
||||
|
||||
// Check if this field type has an in place definition. For example:
|
||||
// struct OuterType {
|
||||
// int foo;
|
||||
// struct Baz { int bar } baz;
|
||||
// };
|
||||
// In the above example, inPlaceDefinition == Baz.
|
||||
if inPlaceDefinition != "" {
|
||||
field.TypeString = inPlaceDefinition
|
||||
field.Name = firstWord
|
||||
defn.Fields = append(defn.Fields, field)
|
||||
return
|
||||
}
|
||||
|
||||
if !context.fieldParser.MatchString(codeline) {
|
||||
log.Fatalf("%d: unexpected form in struct field declaration", lineNumber)
|
||||
}
|
||||
|
||||
// To make the regex usage somewhat readable, extract the named subgroups into a map rather
|
||||
// than referring to each result by index.
|
||||
subexpList := context.fieldParser.FindStringSubmatch(codeline)
|
||||
subexpMap := make(map[string]string)
|
||||
for i, name := range context.fieldParser.SubexpNames() {
|
||||
if i != 0 && name != "" {
|
||||
subexpMap[name] = subexpList[i]
|
||||
}
|
||||
}
|
||||
|
||||
field.TypeString = subexpMap["type"]
|
||||
field.Name = subexpMap["name"]
|
||||
field.Description = subexpMap["description"]
|
||||
field.DefaultValue = context.distillValue(subexpMap["value"], lineNumber)
|
||||
|
||||
defn.Fields = append(defn.Fields, field)
|
||||
}
|
||||
|
||||
for scanner.Scan() {
|
||||
depth := len(context.stack) - 1
|
||||
token := scanner.Text()
|
||||
for item := lex.nextItem(); item.typ != itemCloseBrace; item = lex.nextItem() {
|
||||
switch {
|
||||
case token == "//":
|
||||
return
|
||||
case token == "/*":
|
||||
context.insideComment = true
|
||||
case token == "*/":
|
||||
if !context.insideComment {
|
||||
log.Fatalf("%d: strange comment", lineNumber)
|
||||
case item.val == "constexpr", item.val == "friend":
|
||||
// do nothing for these annotations
|
||||
case item.val == "enum":
|
||||
append(parseEnum(lex))
|
||||
case item.val == "struct":
|
||||
append(parseStruct(lex))
|
||||
case item.val == "class":
|
||||
append(parseClass(lex))
|
||||
case item.val == "namespace":
|
||||
append(parseNamespace(lex))
|
||||
case item.val == "using":
|
||||
append(parseUsing(lex))
|
||||
case item.val == "public", item.val == "private", item.val == "protected":
|
||||
expect(lex, itemColon)
|
||||
append(&AccessSpecifierNode{
|
||||
Line: item.line,
|
||||
Access: item.val,
|
||||
})
|
||||
case item.typ == itemCloseBrace:
|
||||
break
|
||||
case item.typ == itemSimpleType:
|
||||
name := expect(lex, itemIdentifier)
|
||||
nextItem := lex.nextItem()
|
||||
arrayLength := 0
|
||||
if nextItem.typ == itemOpenBracket {
|
||||
arrayLength, _ = strconv.Atoi(expect(lex, itemArrayLength).val)
|
||||
expect(lex, itemCloseBracket)
|
||||
nextItem = lex.nextItem()
|
||||
}
|
||||
context.insideComment = false
|
||||
case context.insideComment:
|
||||
// Do nothing.
|
||||
case token == ";":
|
||||
// Do nothing.
|
||||
case token == "{":
|
||||
context.stack = append(context.stack, &generalScope{})
|
||||
case token == "}":
|
||||
if depth < 0 {
|
||||
log.Fatalf("%d: bizarre nesting", lineNumber)
|
||||
switch nextItem.typ {
|
||||
case itemMethodArgs:
|
||||
parseMethod(name, item, nextItem, false)
|
||||
case itemSemicolon:
|
||||
append(&FieldNode{
|
||||
Line: item.line,
|
||||
Name: name.val,
|
||||
Type: item.val,
|
||||
Rhs: "",
|
||||
ArrayLength: arrayLength,
|
||||
})
|
||||
case itemEquals:
|
||||
rhs := expect(lex, itemDefaultValue)
|
||||
expect(lex, itemSemicolon)
|
||||
append(&FieldNode{
|
||||
Line: item.line,
|
||||
Name: name.val,
|
||||
Type: item.val,
|
||||
Rhs: rhs.val,
|
||||
ArrayLength: arrayLength,
|
||||
})
|
||||
}
|
||||
switch defn := context.stack[depth].(type) {
|
||||
case *StructDefinition, *EnumDefinition:
|
||||
inPlaceDefinition = defn.BaseName()
|
||||
context.definitions = append(context.definitions, defn)
|
||||
}
|
||||
context.stack = context.stack[:depth]
|
||||
case token == "struct":
|
||||
if !scanner.Scan() {
|
||||
log.Fatalf("%d: bizarre struct", lineNumber)
|
||||
}
|
||||
if !strings.Contains(codeline, "{") || strings.Contains(codeline, "}") {
|
||||
log.Fatalf("%d: bad formatting", lineNumber)
|
||||
}
|
||||
stackEntry := StructDefinition{
|
||||
name: scanner.Text(),
|
||||
qualifier: context.generateQualifier(),
|
||||
Description: context.commentBlocks[lineNumber-1],
|
||||
parent: context.findParent(),
|
||||
}
|
||||
context.stack = append(context.stack, &stackEntry)
|
||||
return
|
||||
case token == "enum":
|
||||
if !scanner.Scan() || scanner.Text() != "class" || !scanner.Scan() {
|
||||
log.Fatalf("%d: bad enum", lineNumber)
|
||||
}
|
||||
if !strings.Contains(codeline, "{") || strings.Contains(codeline, "}") {
|
||||
log.Fatalf("%d: bad formatting", lineNumber)
|
||||
}
|
||||
stackEntry := EnumDefinition{
|
||||
name: scanner.Text(),
|
||||
qualifier: context.generateQualifier(),
|
||||
Description: context.commentBlocks[lineNumber-1],
|
||||
parent: context.findParent(),
|
||||
}
|
||||
context.stack = append(context.stack, &stackEntry)
|
||||
return
|
||||
case depth > 0:
|
||||
switch defn := context.stack[depth].(type) {
|
||||
case *StructDefinition:
|
||||
scanStructField(defn, token)
|
||||
case item.typ == itemTemplate:
|
||||
expect(lex, itemTemplateArgs)
|
||||
returns := expect(lex, itemSimpleType)
|
||||
name := expect(lex, itemIdentifier)
|
||||
args := expect(lex, itemMethodArgs)
|
||||
append(parseMethod(name, returns, args, true))
|
||||
default:
|
||||
panic(lex, item)
|
||||
}
|
||||
}
|
||||
return members
|
||||
}
|
||||
|
||||
// Assumes that we have just consumed the "class" keyword from the lexer.
|
||||
// Consumes everything up to (and including) the trailing semicolon.
|
||||
func parseClass(lex *lexer) *ClassNode {
|
||||
name := expect(lex, itemIdentifier)
|
||||
item := lex.nextItem()
|
||||
if item.typ == itemSemicolon {
|
||||
// We don't have an AST node for forward declarations, just skip it.
|
||||
return nil
|
||||
}
|
||||
if item.typ == itemColon {
|
||||
// Only one base class is allowed.
|
||||
item = lex.nextItem()
|
||||
if item.typ == itemPublic {
|
||||
item = lex.nextItem()
|
||||
}
|
||||
expect(lex, itemSimpleType)
|
||||
item = lex.nextItem()
|
||||
}
|
||||
if item.typ != itemOpenBrace {
|
||||
panic(lex, item)
|
||||
}
|
||||
members := parseStructBody(lex)
|
||||
expect(lex, itemSemicolon)
|
||||
return &ClassNode{
|
||||
Line: name.line,
|
||||
Name: name.val,
|
||||
Members: members,
|
||||
}
|
||||
}
|
||||
|
||||
// Assumes that we have just consumed the "struct" keyword from the lexer.
|
||||
// Consumes everything up to (and including) the trailing semicolon.
|
||||
func parseStruct(lex *lexer) *StructNode {
|
||||
name := expect(lex, itemIdentifier)
|
||||
item := lex.nextItem()
|
||||
if item.typ == itemSemicolon {
|
||||
// We don't have an AST node for forward declarations, just skip it.
|
||||
return nil
|
||||
}
|
||||
if item.typ != itemOpenBrace {
|
||||
panic(lex, item)
|
||||
}
|
||||
members := parseStructBody(lex)
|
||||
expect(lex, itemSemicolon)
|
||||
return &StructNode{
|
||||
Line: name.line,
|
||||
Name: name.val,
|
||||
Members: members,
|
||||
}
|
||||
}
|
||||
|
||||
// Assumes that we have just consumed the "enum" keyword from the lexer.
|
||||
// Consumes everything up to (and including) the trailing semicolon.
|
||||
func parseEnum(lex *lexer) *EnumNode {
|
||||
expect(lex, itemClass)
|
||||
name := expect(lex, itemIdentifier)
|
||||
item := lex.nextItem()
|
||||
if item.typ == itemColon {
|
||||
expect(lex, itemSimpleType)
|
||||
item = lex.nextItem()
|
||||
}
|
||||
if item.typ != itemOpenBrace {
|
||||
panic(lex, item)
|
||||
}
|
||||
firstVal := expect(lex, itemIdentifier)
|
||||
node := &EnumNode{
|
||||
Name: name.val,
|
||||
Line: name.line,
|
||||
Values: []string{firstVal.val},
|
||||
ValueLines: []int{firstVal.line},
|
||||
}
|
||||
for item = lex.nextItem(); item.typ != itemCloseBrace; {
|
||||
if item.typ != itemComma {
|
||||
panic(lex, item)
|
||||
}
|
||||
item = lex.nextItem()
|
||||
if item.typ == itemCloseBrace {
|
||||
break
|
||||
}
|
||||
if item.typ != itemIdentifier {
|
||||
panic(lex, item)
|
||||
}
|
||||
node.Values = append(node.Values, item.val)
|
||||
node.ValueLines = append(node.ValueLines, item.line)
|
||||
item = lex.nextItem()
|
||||
}
|
||||
expect(lex, itemSemicolon)
|
||||
return node
|
||||
}
|
||||
|
||||
// Assumes that we have just consumed the "using" keyword from the lexer.
|
||||
// Consumes everything up to (and including) the trailing semicolon.
|
||||
func parseUsing(lex *lexer) *UsingNode {
|
||||
name := expect(lex, itemIdentifier)
|
||||
expect(lex, itemEquals)
|
||||
rhs := expect(lex, itemSimpleType)
|
||||
expect(lex, itemSemicolon)
|
||||
return &UsingNode{name.line, name.val, rhs.val}
|
||||
}
|
||||
|
||||
// Assumes that we have just consumed the "namespace" keyword from the lexer.
|
||||
// Consumes everything up to (and including) the closing brace.
|
||||
func parseNamespace(lex *lexer) *NamespaceNode {
|
||||
name := expect(lex, itemIdentifier)
|
||||
expect(lex, itemOpenBrace)
|
||||
ns := &NamespaceNode{name.line, name.val, nil}
|
||||
item := lex.nextItem()
|
||||
|
||||
// Filter out nil nodes (e.g. forward declarations)
|
||||
// Note that checking for nil is tricky due to a classic Go gotcha.
|
||||
append := func(child Node) {
|
||||
switch concrete := child.(type) {
|
||||
case *StructNode:
|
||||
if concrete == nil {
|
||||
return
|
||||
case *EnumDefinition:
|
||||
if strings.Contains(codeline, "=") {
|
||||
log.Fatalf("%d: custom values are not allowed", lineNumber)
|
||||
}
|
||||
value := EnumValue{
|
||||
Name: strings.Trim(token, ","),
|
||||
}
|
||||
if matches := context.fieldDescParser.FindStringSubmatch(codeline); matches != nil {
|
||||
value.Description = matches[1]
|
||||
}
|
||||
defn.Values = append(defn.Values, value)
|
||||
}
|
||||
case *ClassNode:
|
||||
if concrete == nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
ns.Children = append(ns.Children, child)
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
log.Fatalf("%d: %s", lineNumber, err)
|
||||
|
||||
for ; item.typ != itemCloseBrace; item = lex.nextItem() {
|
||||
switch item.typ {
|
||||
case itemTemplate:
|
||||
expect(lex, itemTemplateArgs)
|
||||
switch lex.nextItem().typ {
|
||||
case itemClass:
|
||||
node := parseClass(lex)
|
||||
node.IsTemplate = true
|
||||
append(node)
|
||||
case itemStruct:
|
||||
node := parseStruct(lex)
|
||||
node.IsTemplate = true
|
||||
append(node)
|
||||
default:
|
||||
panic(lex, item)
|
||||
}
|
||||
case itemClass:
|
||||
append(parseClass(lex))
|
||||
case itemStruct:
|
||||
append(parseStruct(lex))
|
||||
case itemEnum:
|
||||
append(parseEnum(lex))
|
||||
case itemUsing:
|
||||
append(parseUsing(lex))
|
||||
case itemNamespace:
|
||||
append(parseNamespace(lex))
|
||||
default:
|
||||
panic(lex, item)
|
||||
}
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
func parseRoot(lex *lexer) *RootNode {
|
||||
expect(lex, itemNamespace)
|
||||
ns := parseNamespace(lex)
|
||||
return &RootNode{0, ns}
|
||||
}
|
||||
|
||||
func expect(lex *lexer, expectedType itemType) item {
|
||||
item := lex.nextItem()
|
||||
if item.typ != expectedType {
|
||||
panic(lex, item)
|
||||
}
|
||||
return item
|
||||
}
|
||||
|
||||
func panic(lex *lexer, unexpected item) {
|
||||
lex.drain()
|
||||
// Very useful local hack: change this to Panicf to see a call stack.
|
||||
log.Fatalf("%d: parser sees unexpected lexeme %s", unexpected.line, unexpected.String())
|
||||
}
|
||||
|
||||
@@ -182,18 +182,18 @@ bool MeshWriter::serialize(ostream& out, Mesh& mesh) {
|
||||
header.strideTangents = sizeof(Vertex);
|
||||
header.strideColor = sizeof(Vertex);
|
||||
header.strideUV0 = sizeof(Vertex);
|
||||
header.strideUV1 = numeric_limits<uint32_t>::max();;
|
||||
header.strideUV1 = numeric_limits<uint32_t>::max();
|
||||
} else {
|
||||
header.offsetPosition = 0;
|
||||
header.offsetTangents = mesh.vertexCount * sizeof(Vertex::position);
|
||||
header.offsetColor = header.offsetTangents + mesh.vertexCount * sizeof(Vertex::tangents);
|
||||
header.offsetUV0 = header.offsetColor + mesh.vertexCount * sizeof(Vertex::color);
|
||||
header.offsetUV1 = numeric_limits<uint32_t>::max();;
|
||||
header.offsetUV1 = numeric_limits<uint32_t>::max();
|
||||
header.stridePosition = 0;
|
||||
header.strideTangents = 0;
|
||||
header.strideColor = 0;
|
||||
header.strideUV0 = 0;
|
||||
header.strideUV1 = numeric_limits<uint32_t>::max();;
|
||||
header.strideUV1 = numeric_limits<uint32_t>::max();
|
||||
if (hasUV1) {
|
||||
header.offsetUV1 = header.offsetUV0 + mesh.vertexCount * sizeof(Vertex::uv0);
|
||||
header.strideUV1 = 0;
|
||||
|
||||
@@ -1756,15 +1756,15 @@ int main(int argc, char* argv[]) {
|
||||
std::cout << "Rec.709 to LMSR matrix (4x3, column major):" << std::endl;
|
||||
std::cout << std::fixed << std::setprecision(6) << l.r << ", ";
|
||||
std::cout << std::fixed << std::setprecision(6) << l.g << ", ";
|
||||
std::cout << std::fixed << std::setprecision(6) << l.b << ", ";;
|
||||
std::cout << std::fixed << std::setprecision(6) << l.b << ", ";
|
||||
std::cout << std::endl;
|
||||
std::cout << std::fixed << std::setprecision(6) << m.r << ", ";
|
||||
std::cout << std::fixed << std::setprecision(6) << m.g << ", ";
|
||||
std::cout << std::fixed << std::setprecision(6) << m.b << ", ";;
|
||||
std::cout << std::fixed << std::setprecision(6) << m.b << ", ";
|
||||
std::cout << std::endl;
|
||||
std::cout << std::fixed << std::setprecision(6) << s.r << ", ";
|
||||
std::cout << std::fixed << std::setprecision(6) << s.g << ", ";
|
||||
std::cout << std::fixed << std::setprecision(6) << s.b << ", ";;
|
||||
std::cout << std::fixed << std::setprecision(6) << s.b << ", ";
|
||||
std::cout << std::endl;
|
||||
std::cout << std::fixed << std::setprecision(6) << r.r << ", ";
|
||||
std::cout << std::fixed << std::setprecision(6) << r.g << ", ";
|
||||
|
||||
@@ -4,8 +4,8 @@ Filament.loadGeneratedExtensions = function() {
|
||||
|
||||
Filament.View.prototype.setDynamicResolutionOptionsDefaults = function(overrides) {
|
||||
const options = {
|
||||
minScale: [ 0.5, 0.5 ],
|
||||
maxScale: [ 1.0, 1.0 ],
|
||||
minScale: [0.5, 0.5],
|
||||
maxScale: [1.0, 1.0],
|
||||
sharpness: 0.9,
|
||||
enabled: false,
|
||||
homogeneousScaling: false,
|
||||
@@ -45,7 +45,7 @@ Filament.loadGeneratedExtensions = function() {
|
||||
maximumOpacity: 1.0,
|
||||
height: 0.0,
|
||||
heightFalloff: 1.0,
|
||||
color: [ 0.5, 0.5, 0.5 ],
|
||||
color: [0.5, 0.5, 0.5],
|
||||
density: 0.1,
|
||||
inScatteringStart: 0.0,
|
||||
inScatteringSize: -1.0,
|
||||
@@ -76,7 +76,7 @@ Filament.loadGeneratedExtensions = function() {
|
||||
midPoint: 0.5,
|
||||
roundness: 0.5,
|
||||
feather: 0.5,
|
||||
color: [ 0.0, 0.0, 0.0, 1.0 ],
|
||||
color: [0.0, 0.0, 0.0, 1.0],
|
||||
enabled: false,
|
||||
};
|
||||
return Object.assign(options, overrides);
|
||||
@@ -95,7 +95,7 @@ Filament.loadGeneratedExtensions = function() {
|
||||
shadowDistance: 0.3,
|
||||
contactDistanceMax: 1.0,
|
||||
intensity: 0.8,
|
||||
lightDirection: [ 0, -1, 0 ],
|
||||
lightDirection: [ 0, -1, 0 ],
|
||||
depthBias: 0.01,
|
||||
depthSlopeBias: 0.01,
|
||||
sampleCount: 4,
|
||||
|
||||
455
web/filament-js/filament.d.ts
vendored
455
web/filament-js/filament.d.ts
vendored
@@ -598,6 +598,7 @@ export class gltfio$FilamentInstance {
|
||||
|
||||
export class gltfio$Animator {
|
||||
public applyAnimation(index: number): void;
|
||||
public applyCrossFade(previousAnimIndex: number, previousAnimTime: number, alpha: number): void;
|
||||
public updateBoneMatrices(): void;
|
||||
public resetBoneMatrices(): void;
|
||||
public getAnimationCount(): number;
|
||||
@@ -1088,11 +1089,36 @@ export enum View$BlendMode {
|
||||
*
|
||||
*/
|
||||
export interface View$DynamicResolutionOptions {
|
||||
minScale?: float2; // minimum scale factors in x and y
|
||||
maxScale?: float2; // maximum scale factors in x and y
|
||||
sharpness?: number; // sharpness when QualityLevel::MEDIUM or higher is used [0 (disabled), 1 (sharpest)]
|
||||
enabled?: boolean; // enable or disable dynamic resolution
|
||||
homogeneousScaling?: boolean; // set to true to force homogeneous scaling
|
||||
/**
|
||||
* minimum scale factors in x and y
|
||||
*/
|
||||
minScale?: float2;
|
||||
/**
|
||||
* maximum scale factors in x and y
|
||||
*/
|
||||
maxScale?: float2;
|
||||
/**
|
||||
* sharpness when QualityLevel::MEDIUM or higher is used [0 (disabled), 1 (sharpest)]
|
||||
*/
|
||||
sharpness?: number;
|
||||
/**
|
||||
* enable or disable dynamic resolution
|
||||
*/
|
||||
enabled?: boolean;
|
||||
/**
|
||||
* set to true to force homogeneous scaling
|
||||
*/
|
||||
homogeneousScaling?: boolean;
|
||||
/**
|
||||
* Upscaling quality
|
||||
* LOW: bilinear filtered blit. Fastest, poor quality
|
||||
* MEDIUM: AMD FidelityFX FSR1 w/ mobile optimizations
|
||||
* HIGH: AMD FidelityFX FSR1 w/ mobile optimizations
|
||||
* ULTRA: AMD FidelityFX FSR1
|
||||
* FSR1 require a well anti-aliased (MSAA or TAA), noise free scene.
|
||||
*
|
||||
* The default upscaling quality is set to LOW.
|
||||
*/
|
||||
quality?: View$QualityLevel;
|
||||
}
|
||||
|
||||
@@ -1136,39 +1162,120 @@ export enum View$BloomOptions$BlendMode {
|
||||
export interface View$BloomOptions {
|
||||
// JavaScript binding for dirt is not yet supported, must use default value.
|
||||
// JavaScript binding for dirtStrength is not yet supported, must use default value.
|
||||
strength?: number; // bloom's strength between 0.0 and 1.0
|
||||
resolution?: number; // resolution of vertical axis (2^levels to 2048)
|
||||
anamorphism?: number; // bloom x/y aspect-ratio (1/32 to 32)
|
||||
levels?: number; // number of blur levels (3 to 11)
|
||||
blendMode?: View$BloomOptions$BlendMode; // how the bloom effect is applied
|
||||
threshold?: boolean; // whether to threshold the source
|
||||
enabled?: boolean; // enable or disable bloom
|
||||
highlight?: number; // limit highlights to this value before bloom [10, +inf]
|
||||
lensFlare?: boolean; // enable screen-space lens flare
|
||||
starburst?: boolean; // enable starburst effect on lens flare
|
||||
chromaticAberration?: number; // amount of chromatic aberration
|
||||
ghostCount?: number; // number of flare "ghosts"
|
||||
ghostSpacing?: number; // spacing of the ghost in screen units [0, 1[
|
||||
ghostThreshold?: number; // hdr threshold for the ghosts
|
||||
haloThickness?: number; // thickness of halo in vertical screen units, 0 to disable
|
||||
haloRadius?: number; // radius of halo in vertical screen units [0, 0.5]
|
||||
haloThreshold?: number; // hdr threshold for the halo
|
||||
/**
|
||||
* bloom's strength between 0.0 and 1.0
|
||||
*/
|
||||
strength?: number;
|
||||
/**
|
||||
* resolution of vertical axis (2^levels to 2048)
|
||||
*/
|
||||
resolution?: number;
|
||||
/**
|
||||
* bloom x/y aspect-ratio (1/32 to 32)
|
||||
*/
|
||||
anamorphism?: number;
|
||||
/**
|
||||
* number of blur levels (3 to 11)
|
||||
*/
|
||||
levels?: number;
|
||||
/**
|
||||
* how the bloom effect is applied
|
||||
*/
|
||||
blendMode?: View$BloomOptions$BlendMode;
|
||||
/**
|
||||
* whether to threshold the source
|
||||
*/
|
||||
threshold?: boolean;
|
||||
/**
|
||||
* enable or disable bloom
|
||||
*/
|
||||
enabled?: boolean;
|
||||
/**
|
||||
* limit highlights to this value before bloom [10, +inf]
|
||||
*/
|
||||
highlight?: number;
|
||||
/**
|
||||
* enable screen-space lens flare
|
||||
*/
|
||||
lensFlare?: boolean;
|
||||
/**
|
||||
* enable starburst effect on lens flare
|
||||
*/
|
||||
starburst?: boolean;
|
||||
/**
|
||||
* amount of chromatic aberration
|
||||
*/
|
||||
chromaticAberration?: number;
|
||||
/**
|
||||
* number of flare "ghosts"
|
||||
*/
|
||||
ghostCount?: number;
|
||||
/**
|
||||
* spacing of the ghost in screen units [0, 1[
|
||||
*/
|
||||
ghostSpacing?: number;
|
||||
/**
|
||||
* hdr threshold for the ghosts
|
||||
*/
|
||||
ghostThreshold?: number;
|
||||
/**
|
||||
* thickness of halo in vertical screen units, 0 to disable
|
||||
*/
|
||||
haloThickness?: number;
|
||||
/**
|
||||
* radius of halo in vertical screen units [0, 0.5]
|
||||
*/
|
||||
haloRadius?: number;
|
||||
/**
|
||||
* hdr threshold for the halo
|
||||
*/
|
||||
haloThreshold?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options to control fog in the scene
|
||||
*/
|
||||
export interface View$FogOptions {
|
||||
distance?: number; // distance in world units from the camera where the fog starts ( >= 0.0 )
|
||||
maximumOpacity?: number; // fog's maximum opacity between 0 and 1
|
||||
height?: number; // fog's floor in world units
|
||||
heightFalloff?: number; // how fast fog dissipates with altitude
|
||||
color?: float3; // fog's color (linear), see fogColorFromIbl
|
||||
density?: number; // fog's density at altitude given by 'height'
|
||||
inScatteringStart?: number; // distance in world units from the camera where in-scattering starts
|
||||
inScatteringSize?: number; // size of in-scattering (>0 to activate). Good values are >> 1 (e.g. ~10 - 100).
|
||||
fogColorFromIbl?: boolean; // Fog color will be modulated by the IBL color in the view direction.
|
||||
enabled?: boolean; // enable or disable fog
|
||||
/**
|
||||
* distance in world units from the camera where the fog starts ( >= 0.0 )
|
||||
*/
|
||||
distance?: number;
|
||||
/**
|
||||
* fog's maximum opacity between 0 and 1
|
||||
*/
|
||||
maximumOpacity?: number;
|
||||
/**
|
||||
* fog's floor in world units
|
||||
*/
|
||||
height?: number;
|
||||
/**
|
||||
* how fast fog dissipates with altitude
|
||||
*/
|
||||
heightFalloff?: number;
|
||||
/**
|
||||
* fog's color (linear), see fogColorFromIbl
|
||||
*/
|
||||
color?: float3;
|
||||
/**
|
||||
* fog's density at altitude given by 'height'
|
||||
*/
|
||||
density?: number;
|
||||
/**
|
||||
* distance in world units from the camera where in-scattering starts
|
||||
*/
|
||||
inScatteringStart?: number;
|
||||
/**
|
||||
* size of in-scattering (>0 to activate). Good values are >> 1 (e.g. ~10 - 100).
|
||||
*/
|
||||
inScatteringSize?: number;
|
||||
/**
|
||||
* Fog color will be modulated by the IBL color in the view direction.
|
||||
*/
|
||||
fogColorFromIbl?: boolean;
|
||||
/**
|
||||
* enable or disable fog
|
||||
*/
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export enum View$DepthOfFieldOptions$Filter {
|
||||
@@ -1187,15 +1294,64 @@ export enum View$DepthOfFieldOptions$Filter {
|
||||
* @see Camera
|
||||
*/
|
||||
export interface View$DepthOfFieldOptions {
|
||||
cocScale?: number; // circle of confusion scale factor (amount of blur)
|
||||
maxApertureDiameter?: number; // maximum aperture diameter in meters (zero to disable rotation)
|
||||
enabled?: boolean; // enable or disable depth of field effect
|
||||
filter?: View$DepthOfFieldOptions$Filter; // filter to use for filling gaps in the kernel
|
||||
nativeResolution?: boolean; // perform DoF processing at native resolution
|
||||
foregroundRingCount?: number; // number of kernel rings for foreground tiles
|
||||
backgroundRingCount?: number; // number of kernel rings for background tiles
|
||||
fastGatherRingCount?: number; // number of kernel rings for fast tiles
|
||||
/**
|
||||
* circle of confusion scale factor (amount of blur)
|
||||
*/
|
||||
cocScale?: number;
|
||||
/**
|
||||
* maximum aperture diameter in meters (zero to disable rotation)
|
||||
*/
|
||||
maxApertureDiameter?: number;
|
||||
/**
|
||||
* enable or disable depth of field effect
|
||||
*/
|
||||
enabled?: boolean;
|
||||
/**
|
||||
* filter to use for filling gaps in the kernel
|
||||
*/
|
||||
filter?: View$DepthOfFieldOptions$Filter;
|
||||
/**
|
||||
* perform DoF processing at native resolution
|
||||
*/
|
||||
nativeResolution?: boolean;
|
||||
/**
|
||||
* Number of of rings used by the gather kernels. The number of rings affects quality
|
||||
* and performance. The actual number of sample per pixel is defined
|
||||
* as (ringCount * 2 - 1)^2. Here are a few commonly used values:
|
||||
* 3 rings : 25 ( 5x 5 grid)
|
||||
* 4 rings : 49 ( 7x 7 grid)
|
||||
* 5 rings : 81 ( 9x 9 grid)
|
||||
* 17 rings : 1089 (33x33 grid)
|
||||
*
|
||||
* With a maximum circle-of-confusion of 32, it is never necessary to use more than 17 rings.
|
||||
*
|
||||
* Usually all three settings below are set to the same value, however, it is often
|
||||
* acceptable to use a lower ring count for the "fast tiles", which improves performance.
|
||||
* Fast tiles are regions of the screen where every pixels have a similar
|
||||
* circle-of-confusion radius.
|
||||
*
|
||||
* A value of 0 means default, which is 5 on desktop and 3 on mobile.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
foregroundRingCount?: number;
|
||||
/**
|
||||
* number of kernel rings for background tiles
|
||||
*/
|
||||
backgroundRingCount?: number;
|
||||
/**
|
||||
* number of kernel rings for fast tiles
|
||||
*/
|
||||
fastGatherRingCount?: number;
|
||||
/**
|
||||
* maximum circle-of-confusion in pixels for the foreground, must be in [0, 32] range.
|
||||
* A value of 0 means default, which is 32 on desktop and 24 on mobile.
|
||||
*/
|
||||
maxForegroundCOC?: number;
|
||||
/**
|
||||
* maximum circle-of-confusion in pixels for the background, must be in [0, 32] range.
|
||||
* A value of 0 means default, which is 32 on desktop and 24 on mobile.
|
||||
*/
|
||||
maxBackgroundCOC?: number;
|
||||
}
|
||||
|
||||
@@ -1203,11 +1359,26 @@ export interface View$DepthOfFieldOptions {
|
||||
* Options to control the vignetting effect.
|
||||
*/
|
||||
export interface View$VignetteOptions {
|
||||
midPoint?: number; // high values restrict the vignette closer to the corners, between 0 and 1
|
||||
roundness?: number; // controls the shape of the vignette, from a rounded rectangle (0.0), to an oval (0.5), to a circle (1.0)
|
||||
feather?: number; // softening amount of the vignette effect, between 0 and 1
|
||||
color?: float4; // color of the vignette effect, alpha is currently ignored
|
||||
enabled?: boolean; // enables or disables the vignette effect
|
||||
/**
|
||||
* high values restrict the vignette closer to the corners, between 0 and 1
|
||||
*/
|
||||
midPoint?: number;
|
||||
/**
|
||||
* controls the shape of the vignette, from a rounded rectangle (0.0), to an oval (0.5), to a circle (1.0)
|
||||
*/
|
||||
roundness?: number;
|
||||
/**
|
||||
* softening amount of the vignette effect, between 0 and 1
|
||||
*/
|
||||
feather?: number;
|
||||
/**
|
||||
* color of the vignette effect, alpha is currently ignored
|
||||
*/
|
||||
color?: float4;
|
||||
/**
|
||||
* enables or disables the vignette effect
|
||||
*/
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1216,6 +1387,15 @@ export interface View$VignetteOptions {
|
||||
* @see setRenderQuality, getRenderQuality
|
||||
*/
|
||||
export interface View$RenderQuality {
|
||||
/**
|
||||
* Sets the quality of the HDR color buffer.
|
||||
*
|
||||
* A quality of HIGH or ULTRA means using an RGB16F or RGBA16F color buffer. This means
|
||||
* colors in the LDR range (0..1) have a 10 bit precision. A quality of LOW or MEDIUM means
|
||||
* using an R11G11B10F opaque color buffer or an RGBA16F transparent color buffer. With
|
||||
* R11G11B10F colors in the LDR range have a precision of either 6 bits (red and green
|
||||
* channels) or 5 bits (blue channel).
|
||||
*/
|
||||
hdrColorBuffer?: View$QualityLevel;
|
||||
}
|
||||
|
||||
@@ -1224,16 +1404,46 @@ export interface View$RenderQuality {
|
||||
* Ambient shadows from dominant light
|
||||
*/
|
||||
export interface View$AmbientOcclusionOptions$Ssct {
|
||||
lightConeRad?: number; // full cone angle in radian, between 0 and pi/2
|
||||
shadowDistance?: number; // how far shadows can be cast
|
||||
contactDistanceMax?: number; // max distance for contact
|
||||
intensity?: number; // intensity
|
||||
lightDirection?: float3; // light direction
|
||||
depthBias?: number; // depth bias in world units (mitigate self shadowing)
|
||||
depthSlopeBias?: number; // depth slope bias (mitigate self shadowing)
|
||||
sampleCount?: number; // tracing sample count, between 1 and 255
|
||||
rayCount?: number; // # of rays to trace, between 1 and 255
|
||||
enabled?: boolean; // enables or disables SSCT
|
||||
/**
|
||||
* full cone angle in radian, between 0 and pi/2
|
||||
*/
|
||||
lightConeRad?: number;
|
||||
/**
|
||||
* how far shadows can be cast
|
||||
*/
|
||||
shadowDistance?: number;
|
||||
/**
|
||||
* max distance for contact
|
||||
*/
|
||||
contactDistanceMax?: number;
|
||||
/**
|
||||
* intensity
|
||||
*/
|
||||
intensity?: number;
|
||||
/**
|
||||
* light direction
|
||||
*/
|
||||
lightDirection?: float3;
|
||||
/**
|
||||
* depth bias in world units (mitigate self shadowing)
|
||||
*/
|
||||
depthBias?: number;
|
||||
/**
|
||||
* depth slope bias (mitigate self shadowing)
|
||||
*/
|
||||
depthSlopeBias?: number;
|
||||
/**
|
||||
* tracing sample count, between 1 and 255
|
||||
*/
|
||||
sampleCount?: number;
|
||||
/**
|
||||
* # of rays to trace, between 1 and 255
|
||||
*/
|
||||
rayCount?: number;
|
||||
/**
|
||||
* enables or disables SSCT
|
||||
*/
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1241,18 +1451,54 @@ export interface View$AmbientOcclusionOptions$Ssct {
|
||||
* @see setAmbientOcclusionOptions()
|
||||
*/
|
||||
export interface View$AmbientOcclusionOptions {
|
||||
radius?: number; // Ambient Occlusion radius in meters, between 0 and ~10.
|
||||
power?: number; // Controls ambient occlusion's contrast. Must be positive.
|
||||
bias?: number; // Self-occlusion bias in meters. Use to avoid self-occlusion. Between 0 and a few mm.
|
||||
resolution?: number; // How each dimension of the AO buffer is scaled. Must be either 0.5 or 1.0.
|
||||
intensity?: number; // Strength of the Ambient Occlusion effect.
|
||||
bilateralThreshold?: number; // depth distance that constitute an edge for filtering
|
||||
quality?: View$QualityLevel; // affects # of samples used for AO.
|
||||
lowPassFilter?: View$QualityLevel; // affects AO smoothness
|
||||
upsampling?: View$QualityLevel; // affects AO buffer upsampling quality
|
||||
enabled?: boolean; // enables or disables screen-space ambient occlusion
|
||||
bentNormals?: boolean; // enables bent normals computation from AO, and specular AO
|
||||
minHorizonAngleRad?: number; // min angle in radian to consider
|
||||
/**
|
||||
* Ambient Occlusion radius in meters, between 0 and ~10.
|
||||
*/
|
||||
radius?: number;
|
||||
/**
|
||||
* Controls ambient occlusion's contrast. Must be positive.
|
||||
*/
|
||||
power?: number;
|
||||
/**
|
||||
* Self-occlusion bias in meters. Use to avoid self-occlusion. Between 0 and a few mm.
|
||||
*/
|
||||
bias?: number;
|
||||
/**
|
||||
* How each dimension of the AO buffer is scaled. Must be either 0.5 or 1.0.
|
||||
*/
|
||||
resolution?: number;
|
||||
/**
|
||||
* Strength of the Ambient Occlusion effect.
|
||||
*/
|
||||
intensity?: number;
|
||||
/**
|
||||
* depth distance that constitute an edge for filtering
|
||||
*/
|
||||
bilateralThreshold?: number;
|
||||
/**
|
||||
* affects # of samples used for AO.
|
||||
*/
|
||||
quality?: View$QualityLevel;
|
||||
/**
|
||||
* affects AO smoothness
|
||||
*/
|
||||
lowPassFilter?: View$QualityLevel;
|
||||
/**
|
||||
* affects AO buffer upsampling quality
|
||||
*/
|
||||
upsampling?: View$QualityLevel;
|
||||
/**
|
||||
* enables or disables screen-space ambient occlusion
|
||||
*/
|
||||
enabled?: boolean;
|
||||
/**
|
||||
* enables bent normals computation from AO, and specular AO
|
||||
*/
|
||||
bentNormals?: boolean;
|
||||
/**
|
||||
* min angle in radian to consider
|
||||
*/
|
||||
minHorizonAngleRad?: number;
|
||||
// JavaScript binding for ssct is not yet supported, must use default value.
|
||||
}
|
||||
|
||||
@@ -1261,8 +1507,21 @@ export interface View$AmbientOcclusionOptions {
|
||||
* @see setMultiSampleAntiAliasingOptions()
|
||||
*/
|
||||
export interface View$MultiSampleAntiAliasingOptions {
|
||||
enabled?: boolean; // enables or disables msaa
|
||||
/**
|
||||
* enables or disables msaa
|
||||
*/
|
||||
enabled?: boolean;
|
||||
/**
|
||||
* sampleCount number of samples to use for multi-sampled anti-aliasing.\n
|
||||
* 0: treated as 1
|
||||
* 1: no anti-aliasing
|
||||
* n: sample count. Effective sample could be different depending on the
|
||||
* GPU capabilities.
|
||||
*/
|
||||
sampleCount?: number;
|
||||
/**
|
||||
* custom resolve improves quality for HDR scenes, but may impact performance.
|
||||
*/
|
||||
customResolve?: boolean;
|
||||
}
|
||||
|
||||
@@ -1271,9 +1530,18 @@ export interface View$MultiSampleAntiAliasingOptions {
|
||||
* @see setTemporalAntiAliasingOptions()
|
||||
*/
|
||||
export interface View$TemporalAntiAliasingOptions {
|
||||
filterWidth?: number; // reconstruction filter width typically between 0 (sharper, aliased) and 1 (smoother)
|
||||
feedback?: number; // history feedback, between 0 (maximum temporal AA) and 1 (no temporal AA).
|
||||
enabled?: boolean; // enables or disables temporal anti-aliasing
|
||||
/**
|
||||
* reconstruction filter width typically between 0 (sharper, aliased) and 1 (smoother)
|
||||
*/
|
||||
filterWidth?: number;
|
||||
/**
|
||||
* history feedback, between 0 (maximum temporal AA) and 1 (no temporal AA).
|
||||
*/
|
||||
feedback?: number;
|
||||
/**
|
||||
* enables or disables temporal anti-aliasing
|
||||
*/
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1281,10 +1549,22 @@ export interface View$TemporalAntiAliasingOptions {
|
||||
* @see setScreenSpaceReflectionsOptions()
|
||||
*/
|
||||
export interface View$ScreenSpaceReflectionsOptions {
|
||||
thickness?: number; // ray thickness, in world units
|
||||
bias?: number; // bias, in world units, to prevent self-intersections
|
||||
maxDistance?: number; // maximum distance, in world units, to raycast
|
||||
stride?: number; // stride, in texels, for samples along the ray.
|
||||
/**
|
||||
* ray thickness, in world units
|
||||
*/
|
||||
thickness?: number;
|
||||
/**
|
||||
* bias, in world units, to prevent self-intersections
|
||||
*/
|
||||
bias?: number;
|
||||
/**
|
||||
* maximum distance, in world units, to raycast
|
||||
*/
|
||||
maxDistance?: number;
|
||||
/**
|
||||
* stride, in texels, for samples along the ray.
|
||||
*/
|
||||
stride?: number;
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
@@ -1332,9 +1612,24 @@ export enum View$ShadowType {
|
||||
* @warning This API is still experimental and subject to change.
|
||||
*/
|
||||
export interface View$VsmShadowOptions {
|
||||
/**
|
||||
* Sets the number of anisotropic samples to use when sampling a VSM shadow map. If greater
|
||||
* than 0, mipmaps will automatically be generated each frame for all lights.
|
||||
*
|
||||
* The number of anisotropic samples = 2 ^ vsmAnisotropy.
|
||||
*/
|
||||
anisotropy?: number;
|
||||
/**
|
||||
* Whether to generate mipmaps for all VSM shadow maps.
|
||||
*/
|
||||
mipmapping?: boolean;
|
||||
/**
|
||||
* VSM minimum variance scale, must be positive.
|
||||
*/
|
||||
minVarianceScale?: number;
|
||||
/**
|
||||
* VSM light bleeding reduction amount, between 0 and 1.
|
||||
*/
|
||||
lightBleedReduction?: number;
|
||||
}
|
||||
|
||||
@@ -1344,6 +1639,16 @@ export interface View$VsmShadowOptions {
|
||||
* @warning This API is still experimental and subject to change.
|
||||
*/
|
||||
export interface View$SoftShadowOptions {
|
||||
/**
|
||||
* Globally scales the penumbra of all DPCF and PCSS shadows
|
||||
* Acceptable values are greater than 0
|
||||
*/
|
||||
penumbraScale?: number;
|
||||
/**
|
||||
* Globally scales the computed penumbra ratio of all DPCF and PCSS shadows.
|
||||
* This effectively controls the strength of contact hardening effect and is useful for
|
||||
* artistic purposes. Higher values make the shadows become softer faster.
|
||||
* Acceptable values are equal to or greater than 1.
|
||||
*/
|
||||
penumbraRatioScale?: number;
|
||||
}
|
||||
|
||||
@@ -1707,6 +1707,7 @@ class_<SurfaceOrientation>("SurfaceOrientation")
|
||||
class_<Animator>("gltfio$Animator")
|
||||
.function("applyAnimation", &Animator::applyAnimation)
|
||||
.function("updateBoneMatrices", &Animator::updateBoneMatrices)
|
||||
.function("applyCrossFade", &Animator::applyCrossFade)
|
||||
.function("resetBoneMatrices", &Animator::resetBoneMatrices)
|
||||
.function("getAnimationCount", &Animator::getAnimationCount)
|
||||
.function("getAnimationDuration", &Animator::getAnimationDuration)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.22.2",
|
||||
"version": "1.23.0",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user